HYPERSR
API v1WebsiteDashboard
HyperSR / Developer documentation

Build with HyperSR.

Find a Sentinel-2 acquisition, review the processing cost, and retrieve georeferenced multispectral products through the REST API or Python SDK.

Understand the output. A 2.5 m grid describes reconstructed pixel spacing. It is not a native 2.5 m satellite observation. Preserve source, model and mask metadata when interpreting the result.
Get started

Overview

HyperSR processes one supported Sentinel-2 Level-2A scene and a WGS84 bounding box per job. Discovery, quoting and processing are separate requests. A search costs no processing credits; confirming a quote reserves the required amount.

01 / DiscoverFind an acquisitionChoose a target date or supply a known scene ID.
02 / ReviewInspect the quoteCheck the scene, footprint, model, bands and credits.
03 / ConfirmSubmit explicitlyQueue a job using the quote and an idempotency key.
04 / RetrieveDownload productsPoll for completion and request signed artifact links.

Connect to your deployment

The versioned base path is /v1. A configured local API commonly uses http://localhost:8000/v1; the intended hosted address is https://api.hypersr.com/v1. These examples describe the implemented contract and do not imply that a hosted service or model is enabled.

Download the customer OpenAPI specification to import into your API client. The endpoint reference below includes parameters, request fields and response examples on this page. FastAPI also serves its deployment schema at /openapi.json and interactive reference at /docs on the API origin.

First request

Quickstart

Use Python 3.11 or newer. Install the published Python SDK in your project. No repository checkout is needed.

Install the SDKShell
uv init my-hypersr-project
cd my-hypersr-project
uv add hypersr
# Save the Python example as quickstart.py, then run: uv run quickstart.py
# Existing pip environment: python -m pip install hypersr
Configure your environmentShell
export HYPERSR_API_KEY="<your-api-key>"
export HYPERSR_API_BASE="http://localhost:8000/v1"
# For a hosted deployment, use its configured HTTPS API address.

Set HYPERSR_API_KEY and HYPERSR_API_BASE for your configured deployment. Discover enabled models first with GET /v1/models; use the model's slug in quotes. The example requires hypersr_v1 to be enabled, suitable scene coverage and enough credits.

Python quickstartPython
import os
from uuid import uuid4
from hypersr import HyperSR

# Set these for your configured local, staging or production API.
with HyperSR(
    api_key=os.environ["HYPERSR_API_KEY"],
    base_url=os.environ["HYPERSR_API_BASE"],
) as client:
    bbox = (2.10, 41.30, 2.12, 41.32)  # replace with your area
    search = client.scenes.search(
        bbox=bbox, target_date="2024-01-10",
        days_before=7, days_after=3,
        max_cloud_cover=20, selection="nearest",
    )
    scene = search.selected
    print("Acquisition:", scene.scene_id, scene.acquired_at)
    print("Scene cloud cover:", scene.cloud_cover)
    if input("Use this acquisition? [y/N] ").lower() != "y":
        raise SystemExit("No processing requested.")

    quote = client.jobs.quote(
        scene_id=scene.scene_id, bbox=bbox, model="hypersr_v1",
    )
    print("Credits:", quote.required_credits / 1000)
    print("Quote expires:", quote.expires_at)
    if input("Confirm processing? [y/N] ").lower() != "y":
        raise SystemExit("Quote was not submitted.")

    # Persist this key if your application needs to retry after restarting.
    key = str(uuid4())
    job = client.jobs.submit(quote_id=quote.id, idempotency_key=key)
    result = client.jobs.wait(job.id, timeout=1800, poll_interval=5)
    if result.status != "completed":
        raise RuntimeError(f"{result.status}: {result.error_message}")
    for role in ("reflectance", "scl", "cloud_mask", "provenance"):
        suffix = ".json" if role == "provenance" else ".tif"
        client.jobs.download_role(job.id, role, f"{role}{suffix}")

Run the JavaScript example as a Node.js 22 .mjs script on a trusted machine. The cURL example uses Bash and jq. Both prompt before submitting the quote. A polling timeout leaves the job running; inspect the saved job ID before deciding what to do next.

The dashboard follows the same acquisition review → quote → explicit confirmation flow. Local mock-4x outputs are synthetic development artifacts. Dedicated GPU, real-provider processing and hosted storage acceptance are separate from local API and SDK checks.

Authentication

Customer requests use a HyperSR API key or a Supabase session access token in the Authorization header. Credentials identify the account; request bodies cannot select another owner.

Authentication headerHTTP
Authorization: Bearer <HYPERSR_API_KEY>

Create a named key in the dashboard or with POST /v1/api-keys. The secret is returned once; store it securely. Key lists expose only metadata and a prefix. Revoke an owned key with DELETE /v1/api-keys/{key_id}.

Keep API keys on trusted servers or in local environment variables. Do not put them in URLs, public JavaScript or logs. Authenticated API responses use Cache-Control: no-store. Signed storage URLs are separate credentials and must not receive your API bearer header.

Areas & inputs

Bounds are [west, south, east, north] in longitude/latitude degrees, EPSG:4326. Coordinates must be finite and ordered. Antimeridian-spanning boxes need to be split. The API calculates area geodetically and enforces its configured per-job minimum and maximum. The current default processing range is 1–10 km² per scene; saving an AOI does not bypass processing limits. Quickstart bounds cover approximately 3.72 km².

A scene ID is a provider catalogue identifier such as S2B_31TDF_20240112_0_L2A, not a download URL. The current ingestion provider is Earth Search's Sentinel-2 L2A collection. The requested footprint must be covered by a single supported scene. Arbitrary imagery URLs and uploads are not accepted by this API.

Omit bands or send an empty list to use the model defaults. Otherwise, choose a subset of its supported_bands. The supported output_format is cog.

Quotes & confirmation

POST /v1/jobs/quote creates an expiring, account-owned quote bound to the scene, area, model and bands. It does not reserve processing credits. Prices and processing limits come from the server. Every SR scene must cover at least 1 km² and at most the deployment's per-job limit; smaller areas are rejected before processing.

Quote requestJSON
{
  "scene_id": "S2B_31TDF_20240112_0_L2A",
  "bbox": [
    2.1,
    41.3,
    2.12,
    41.32
  ],
  "model": "hypersr_v1",
  "bands": [
    "B02",
    "B03",
    "B04",
    "B08"
  ],
  "output_format": "cog"
}
Illustrative quote response — amounts are examplesJSON
{
  "quote_id": "quote_example",
  "model": "hypersr_v1",
  "area_km2": 3.72,
  "required_credits": 3720,
  "expires_at": "2030-01-10T12:05:00Z"
}

required_credits uses integer internal units: divide by 1,000 for displayed credits. The example's 3720 units mean 3.720 credits. The server quote is authoritative; approximate area or price calculations cannot replace it.

Confirm once, retry safely

Confirm the reviewed quoteHTTP
POST /v1/jobs
Authorization: Bearer <HYPERSR_API_KEY>
Content-Type: application/json
Idempotency-Key: <unique-stable-operation-key>

{"quote_id":"quote_example"}

Confirmation reserves credits and creates the queued job atomically. Reuse the same key and quote when retrying an uncertain submission. A key reused with different parameters returns 409 IDEMPOTENCY_CONFLICT. Use a new key for a new processing operation. Expired quotes require a new quote and another review.

Jobs & polling

Processing is asynchronous. Poll GET /v1/jobs/{job_id} or use client.jobs.wait(). A job includes its scene, model/version, bands, bounds, credit amounts, timestamps and any safe error details. Progress can be null; only reported processing progress should be displayed.

queued→claimed→running→completed

Transient failures can move through retry_pending back to queued. Permanent failed and cancelled states are terminal, as is completed. Failed jobs release their reservations. Completion charges once.

POST /v1/jobs/{job_id}/cancel cancels jobs that are still queued or claimed. Later cancellation returns 409 JOB_NOT_CANCELLABLE. An SDK polling timeout ends your wait; it does not cancel the job.

List and inspect jobsHTTP
GET /v1/jobs?offset=0&limit=20&status=completed&search=S2B
GET /v1/jobs/{job_id}
POST /v1/jobs/{job_id}/cancel

Job lists return items and a filtered total. Use offset and limit (maximum 100), exact status, and a literal case-insensitive search over scene or job identifiers. Lists include only the current account's resources.

Outputs & downloads

New completed products contain four typed artifacts. Request GET /v1/jobs/{job_id}/outputs; use each item's role to select it. Older products can have no role field.

reflectanceMultispectral imageCOG on a 2.5 m grid, retaining supported source encoding and spatial metadata.
sclScene classificationFull Sentinel-2 SCL, categorically resampled to the output grid.
cloud_maskCloud flagsAligned binary mask for SCL cloud classes 8, 9 and 10.
provenanceProcessing recordJSON with source scene, model, settings, encoding and validation metadata.
Output response shape — one illustrative itemJSON
{
  "items": [
    {
      "role": "reflectance",
      "format": "cog",
      "filename": "reflectance.tif",
      "size_bytes": 123456,
      "checksum": "<sha256-hex>",
      "download_url": "https://storage.example.invalid/object?signature=...",
      "expires_at": "2030-01-10T12:15:00Z"
    }
  ],
  "total": 1
}

Output metadata includes format, filename, size_bytes, SHA-256 checksum, download_url and URL expires_at. Download separately from the signed URL without forwarding the API Authorization header. Treat the URL as a secret until it expires.

URL expiry and product retention are separate. Request new links while the files are retained; expired products cannot receive fresh links. A job that has not completed returns an empty output list. The SDK writes downloads atomically and checks available size, checksum and expiry information.

Clouds and reflectance interpretation

Clouds, shadows and snow remain in model inputs. HyperSR does not claim cloud removal. True nodata and defective observations remain invalid. Use SCL and cloud flags in downstream analysis. Categorical masks use nearest sampling; they do not add fine-scale cloud observations.

Read each GeoTIFF's datatype, scale, offset, nodata and band descriptions. Internal normalization does not mean the downloaded values are normalized reflectance. Source DN encoding can be preserved; apply its scale and offset exactly once when converting to physical reflectance.

Models & bands

GET /v1/models lists enabled models with id, slug, version, optional bundle_sha256, supported_bands and output_resolution. Use slug as the quote's model; the database ID is a separate value.

The selected hypersr_v1 release supports ten Sentinel-2 bands. Availability still depends on the deployment's enabled catalogue. Read returned metadata rather than assuming all models or bands are available.

B02 · blueB03 · greenB04 · redB05 · red edgeB06 · red edgeB07 · red edgeB08 · NIRB8A · narrow NIRB11 · SWIRB12 · SWIR

Native input spacing is 10 m or 20 m depending on the band. B10 is absent from Level-2A surface reflectance. B01 and B09, and other 60 m atmospheric inputs, are outside this model's contract. A 2.5 m output grid does not establish equivalent effective resolution or new observational information.

Python SDK

The typed HyperSR client uses a context manager for connection cleanup. The SDK defaults to the intended hosted base URL; pass base_url explicitly for local or staging work. HTTP timeouts, bounded retries and typed response models are included.

AreaClient methodsUse
Discoverymodels(), scenes.search(...)Discover enabled models and review acquisitions.
Processingjobs.quote(), submit(), get(), list(), cancel()Submit only a reviewed, unexpired quote.
Resultsjobs.wait(), outputs(), download_role()Poll to a terminal state; download by stable artifact role.
Creditscredits(), credit_transactions()Inspect balances, expiry lots and immutable movements.
Billingbilling_packages(), checkout(), billing_history()Discover packages and create an explicit Checkout.
Workspaceaois(), get_aoi(), create_aoi(), update_aoi(), delete_aoi()Manage reusable WGS84 boundaries.
Accountaccount(), update_account(), account_summary()Read and update permitted account fields.
Preferencesnotification_preferences(), update_notification_preferences()Control completion and failure notices.
Keysapi_keys(), create_api_key(), revoke_api_key()Store a newly returned key securely.

Methods in the processing and results rows belong to client.jobs. Search uses client.scenes.search. Other methods are on client. API quote_id and job_id are available as SDK quote.id and job.id.

Handle a polling timeoutPython
from hypersr import TimeoutError as HyperSRTimeoutError

try:
    result = client.jobs.wait(job.id, timeout=1800, poll_interval=5)
except HyperSRTimeoutError:
    print("Still waiting; inspect later:", job.id)
else:
    print(result.status, result.error_code, result.error_message)

Process multiple reviewed scenes

Each scene needs its own quote and idempotency key, and consumes credits separately. This sequential example prompts for each quote and keeps requests within the deployment's queue limits. Supply scene IDs you have already reviewed and that cover the same bounds.

Multiple scenesPython
import os
from uuid import uuid4
from hypersr import HyperSR

scene_ids = os.environ["HYPERSR_SCENE_IDS"].split(",")
bbox = (2.10, 41.30, 2.12, 41.32)
with HyperSR(os.environ["HYPERSR_API_KEY"],
             base_url=os.environ["HYPERSR_API_BASE"]) as client:
    for scene_id in scene_ids:
        quote = client.jobs.quote(
            scene_id=scene_id.strip(), bbox=bbox, model="hypersr_v1",
        )
        print(scene_id, "credits:", quote.required_credits / 1000,
              "expires:", quote.expires_at)
        if input("Confirm this quote? [y/N] ").lower() != "y":
            continue
        key = str(uuid4())  # persist per operation for recovery/retries
        job = client.jobs.submit(quote_id=quote.id, idempotency_key=key)
        result = client.jobs.wait(job.id, timeout=1800, poll_interval=5)
        if result.status != "completed":
            print(job.id, result.status, result.error_message)
            continue
        client.jobs.download_role(job.id, "reflectance", f"{job.id}.tif")

Read reflectance and band metadata

Install uv add "hypersr[rasterio]" to inspect a downloaded COG. Read the delivered band descriptions, scales, offsets and validity mask. Apply scale and offset exactly once; cloud and classification artifacts remain separate.

Inspect a COG with RasterioPython
import rasterio

with rasterio.open("reflectance.tif") as dataset:
    print("CRS:", dataset.crs, "grid:", dataset.res)
    print("Bands:", dataset.descriptions)
    print("Encoding:", dataset.dtypes, dataset.scales, dataset.offsets)
    # Iterate windows to bound memory use for large images.
    for _, window in dataset.block_windows(1):
        band = dataset.read(1, window=window, masked=True)
        reflectance = band * dataset.scales[0] + dataset.offsets[0]
        # Analyze valid observations; consult scl.tif and cloud_mask.tif too.
        print(window, reflectance.count())

Handle an API error

Handle an API failurePython
from hypersr import APIError, RequestError

try:
    quote = client.jobs.quote(
        scene_id=scene_id, bbox=bbox, model="hypersr_v1",
    )
except APIError as error:
    print(error.code, str(error), error.request_id)
    # Correct invalid inputs before retrying. Keep credentials out of logs.
except RequestError:
    print("Transport failed; check connectivity before retrying.")

QGIS integration

The local QGIS connector supports catalogue search, native-source downloads, map/layer areas, quote review, job monitoring and loading downloaded rasters. Its current catalogue search uses explicit start/end dates and manual scene selection; the target-date search above is available through the REST API, Python SDK and dashboard. See the QGIS installation guide for packaging and desktop acceptance details.

Credits & billing

All API credit amounts use integer internal units. 1 displayed credit = 1,000 units; one displayed credit covers 1 km² at the base model rate. The configured global price is €0.25/km², with no subscriptions or automatic renewal. Model multipliers and geodetic footprint rounding are reflected in the server quote.

GET /v1/credits returns available, reserved, balance, total, credit_lots and nullable next_expiry. Each lot reports remaining units and its actual expiry. Purchases and trial grants expire six calendar months after issue. New purchases do not extend older lots.

Reservations accepted before expiry can settle later. Failure or cancellation releases the original allocation with its original expiry; an already expired release cannot fund new work. Use /credits/transactions for immutable signed ledger entries.

Discover current top-ups with GET /v1/billing/packages. The configured packs are €10/40 credits, €25/100 credits and €100/400 credits; API credit quantities are internal units. The verified-account trial is configured as 10 credits. Availability and eligibility are enforced by the service.

Create an explicit Checkout sessionHTTP
POST /v1/billing/checkout
Authorization: Bearer <HYPERSR_API_KEY>
Idempotency-Key: <unique-stable-checkout-key>
Content-Type: application/json

{"package_id":"<id-from-billing-packages>"}

The response supplies a hosted Checkout URL. Reusing a Checkout key with different parameters returns 409 IDEMPOTENCY_KEY_CONFLICT; job submission uses IDEMPOTENCY_CONFLICT. Payment completion is confirmed through verified provider events, not the browser redirect. Read /billing/history for your account's payment records. Test-mode configuration and live payments are separate deployment steps.

Account & workspace

Saved areas: create with name, bbox and optional description. Names are trimmed and limited to 120 characters; descriptions to 500. Read, update or delete by the saved area's ID. Saving an area neither quotes nor processes imagery, so saved AOIs may remain smaller than the 1 km² SR minimum until used for a quote.

Profile: GET /account reads your account; PATCH /account accepts only display_name. Identity and authorization fields are server controlled. /account/summary provides customer-safe workspace aggregates.

Notifications: GET/PATCH /account/notifications uses the boolean fields job_completed and job_failed. Preferences default to enabled, while actual email delivery depends on the deployment's configured provider. Unknown fields and explicit nulls are rejected.

Jobs, areas, keys, payments and output access are scoped to your authenticated account. Missing and other-account resource IDs are not a way to discover another account's data.

Errors & limits

Failures use an error envelope. Keep the returned request_id or X-Request-ID header for troubleshooting, without recording credentials or signed URLs.

Error responseJSON
{
  "error": {
    "code": "QUOTE_EXPIRED",
    "message": "Quote is missing or expired",
    "request_id": "request_example"
  }
}
HTTPExamplesAction
400 / 422INVALID_REQUEST, INVALID_SCENE, INVALID_AOI, AOI_TOO_LARGE, UNSUPPORTED_BANDSCorrect inputs; do not repeat the same invalid request.
401 / 403Authentication or authorization failureCheck the credential, session and account permissions.
402INSUFFICIENT_CREDITSCheck available credits or reduce the processing area.
404SCENES_NOT_FOUND, JOB_NOT_FOUNDAdjust search criteria or check your own resource ID.
409IDEMPOTENCY_CONFLICT, JOB_NOT_CANCELLABLEInspect the original operation or current job state.
429RATE_LIMIT_EXCEEDED, USER_JOB_LIMITBack off; respect Retry-After when supplied.
502 / 503CATALOG_*, SUBMISSIONS_PAUSED, storage/billing availabilityRetry temporary failures with bounded backoff; retain submission keys.

The SDK exposes AuthenticationError, ValidationError, NotFoundError, ConflictError, RateLimitError, RequestError and TimeoutError. Inspect the error code as well as the HTTP status.

Safe reads retry selected transient failures with bounded backoff. Mutation retries require an idempotency key, and not every endpoint guarantees duplicate-operation suppression. Submission and Checkout explicitly enforce idempotency. Do not blindly replay key or AOI creation.

Page sizes, AOI area, queue capacity, quote lifetime, rate limits and output retention are deployment controlled. Offset-paginated lists are bounded to 100 items per page. Acquisition candidates use a bounded catalogue search rather than account-history pagination.

REST API v1

Endpoint reference

Paths below are relative to /v1. “Bearer + key” requires both Authorization and an Idempotency-Key header. Public catalogue visibility does not establish that processing is commercially enabled.

Choose an operation for its copyable cURL request, field types, constraints and illustrative JSON response. Replace example IDs with values returned by your deployment. Monetary and credit values in examples are illustrative.

GET/healthHealth

GET /v1/health

Liveness: {status: "ok"}.

Authentication: Public.

GET /health requestShell
curl --fail-with-body -sS -X GET "$HYPERSR_API_BASE/health"

Success response · HTTP 200

FieldTypeRequiredConstraints
statusstringYes—
GET /health illustrative responseJSON
{
  "status": "ok"
}

Error responses

HTTPError codes
413REQUEST_TOO_LARGE
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

GET/modelsModels

GET /v1/models

Enabled models in {items, total}; use slug in quote requests.

Authentication: Public.

The enabled model catalogue is deployment-specific. Use slug in quote requests.

GET /models requestShell
curl --fail-with-body -sS -X GET "$HYPERSR_API_BASE/models"

Success response · HTTP 200

FieldTypeRequiredConstraints
itemsarray<object>Yes—
items[].bundle_sha256string | nullNo—
items[].descriptionstringYes—
items[].display_namestringYes—
items[].enabledbooleanYes—
items[].idstringYes—
items[].output_resolutionnumberYes—
items[].slugstringYes—
items[].supported_bandsarray<string>Yes—
items[].versionstringYes—
totalintegerYes—
GET /models illustrative responseJSON
{
  "items": [
    {
      "id": "model_example",
      "slug": "hypersr_v1",
      "version": "1.0.0+sen2neon.20261110",
      "bundle_sha256": "<sha256-hex>",
      "display_name": "HyperSR v1",
      "description": "Enabled multispectral model",
      "supported_bands": [
        "B02",
        "B03",
        "B04",
        "B05",
        "B06",
        "B07",
        "B08",
        "B8A",
        "B11",
        "B12"
      ],
      "output_resolution": 2.5,
      "enabled": true
    }
  ],
  "total": 1
}

Error responses

HTTPError codes
413REQUEST_TOO_LARGE
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

POST/scenes/searchSearch Scene Catalog

POST /v1/scenes/search

Read-only acquisition discovery. See temporal search parameters.

Authentication: Bearer.

Discovery is read-only and does not reserve credits.

JSON request body

FieldTypeRequiredConstraints
bboxarray<number>YesMin items: 4 · Max items: 4
days_afterintegerNoDefault: 3 · Minimum: 0 · Maximum: 3
days_beforeintegerNoDefault: 7 · Minimum: 0 · Maximum: 90
max_cloud_covernumberNoDefault: 100 · Minimum: 0 · Maximum: 100
selection"nearest" | "clearest"NoDefault: "nearest"
target_datestring (date)Yes—
POST /scenes/search requestShell
curl --fail-with-body -sS -X POST "$HYPERSR_API_BASE/scenes/search" \
  -H "Authorization: Bearer $HYPERSR_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{"bbox":[2.1,41.3,2.12,41.32],"target_date":"2024-01-10","days_before":7,"days_after":3,"max_cloud_cover":20,"selection":"nearest"}'

Success response · HTTP 200

FieldTypeRequiredConstraints
candidatesarray<object>Yes—
candidates[].acquired_atstring (date-time)Yes—
candidates[].cloud_covernumber | nullYes—
candidates[].scene_idstringYes—
cloud_cover_scope"scene"Yes—
searched_endstring (date-time)Yes—
searched_startstring (date-time)Yes—
selectedobjectYes—
selected.acquired_atstring (date-time)Yes—
selected.cloud_covernumber | nullYes—
selected.scene_idstringYes—
selection"nearest" | "clearest"Yes—
target_datestring (date)Yes—
POST /scenes/search illustrative responseJSON
{
  "selected": {
    "scene_id": "S2B_31TDF_20240112_0_L2A",
    "acquired_at": "2024-01-12T10:49:39.287Z",
    "cloud_cover": 0.012893
  },
  "candidates": [
    {
      "scene_id": "S2B_31TDF_20240112_0_L2A",
      "acquired_at": "2024-01-12T10:49:39.287Z",
      "cloud_cover": 0.012893
    }
  ],
  "target_date": "2024-01-10",
  "searched_start": "2024-01-03T00:00:00Z",
  "searched_end": "2024-01-14T00:00:00Z",
  "cloud_cover_scope": "scene",
  "selection": "nearest"
}

Error responses

HTTPError codes
400INVALID_DATE_WINDOW
401UNAUTHENTICATED
403FORBIDDEN
404SCENES_NOT_FOUND
413REQUEST_TOO_LARGE
422INVALID_REQUESTINVALID_AOIAOI_TOO_LARGE
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR
502CATALOG_INVALID_METADATACATALOG_INVALID_PAGINATIONCATALOG_INVALID_RESPONSECATALOG_REQUEST_FAILEDCATALOG_RESPONSE_TOO_LARGECATALOG_RESULT_LIMITCATALOG_TRUNCATED

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

POST/jobs/quoteCreate Quote

POST /v1/jobs/quote

Bind scene_id, bbox, model, optional bands and output_format="cog".

Authentication: Bearer.

The server quote is authoritative and expires at expires_at.

JSON request body

FieldTypeRequiredConstraints
bandsarray<string>No—
bboxarray<number>YesMin items: 4 · Max items: 4
modelstringYes—
output_format"cog"NoDefault: "cog"
scene_idstringYesMin length: 3 · Max length: 200 · Pattern: ^[A-Za-z0-9_.:-]+$
POST /jobs/quote requestShell
curl --fail-with-body -sS -X POST "$HYPERSR_API_BASE/jobs/quote" \
  -H "Authorization: Bearer $HYPERSR_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{"scene_id":"S2B_31TDF_20240112_0_L2A","bbox":[2.1,41.3,2.12,41.32],"model":"hypersr_v1","bands":["B02","B03","B04","B08"],"output_format":"cog"}'

Success response · HTTP 200

FieldTypeRequiredConstraints
area_km2numberYes—
expires_atstring (date-time)Yes—
modelstringYes—
quote_idstringYes—
required_creditsintegerYes—
POST /jobs/quote illustrative responseJSON
{
  "quote_id": "quote_example",
  "model": "hypersr_v1",
  "area_km2": 3.72,
  "required_credits": 3720,
  "expires_at": "2030-01-10T12:05:00Z"
}

Error responses

HTTPError codes
400INVALID_SCENEMODEL_UNAVAILABLEUNSUPPORTED_BANDSINVALID_AOI
401UNAUTHENTICATED
403FORBIDDEN
413REQUEST_TOO_LARGE
422INVALID_REQUESTINVALID_SCENEINVALID_AOI
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

POST/jobsCreate Job

POST /v1/jobs

Confirm {quote_id}. Requires Idempotency-Key. Returns a queued job.

Authentication: Bearer + key. Keep the idempotency key stable for retries of the same operation.

Keep the same Idempotency-Key when retrying an uncertain submission.

Parameters & headers

NameLocationTypeRequired / constraints
Idempotency-KeyheaderstringRequired · Unique key that makes a retry safe and deterministic. · Min length: 1 · Max length: 255

JSON request body

FieldTypeRequiredConstraints
quote_idstringYes—
POST /jobs requestShell
curl --fail-with-body -sS -X POST "$HYPERSR_API_BASE/jobs" \
  -H "Authorization: Bearer $HYPERSR_API_KEY" \
  -H "Idempotency-Key: $HYPERSR_REQUEST_KEY" \
  -H "Content-Type: application/json" \
  --data '{"quote_id":"quote_example"}'

Success response · HTTP 200

FieldTypeRequiredConstraints
bboxarray<number> | nullNo—
charged_creditsintegerYes—
completed_atstring (date-time) | nullNo—
created_atstring (date-time)Yes—
error_codestring | nullNo—
error_messagestring | nullNo—
input_scene_idstring | nullNo—
job_idstringYes—
modelstring | nullNo—
model_versionstring | nullNo—
progressnumber | nullNo—
quoted_creditsintegerNoDefault: 0
requested_bandsarray<string>No—
reserved_creditsintegerYes—
started_atstring (date-time) | nullNo—
statusstringYes—
POST /jobs illustrative responseJSON
{
  "job_id": "job_example",
  "status": "queued",
  "reserved_credits": 3720,
  "charged_credits": 0,
  "progress": null,
  "created_at": "2030-01-10T12:05:00Z",
  "started_at": null,
  "completed_at": null,
  "error_code": null,
  "error_message": null,
  "input_scene_id": "S2B_31TDF_20240112_0_L2A",
  "bbox": [
    2.1,
    41.3,
    2.12,
    41.32
  ],
  "model": "hypersr_v1",
  "model_version": "1.0.0+sen2neon.20261110",
  "requested_bands": [
    "B02",
    "B03",
    "B04",
    "B08"
  ],
  "quoted_credits": 3720
}

Error responses

HTTPError codes
400IDEMPOTENCY_KEY_REQUIREDQUOTE_EXPIREDMODEL_UNAVAILABLEINVALID_AOI
401UNAUTHENTICATED
402INSUFFICIENT_CREDITS
403FORBIDDEN
409IDEMPOTENCY_CONFLICT
413REQUEST_TOO_LARGE
422INVALID_REQUEST
429RATE_LIMIT_EXCEEDEDUSER_JOB_LIMIT
500INTERNAL_ERROR
503SUBMISSIONS_PAUSED

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

GET/jobsList Jobs

GET /v1/jobs

Own jobs; offset, limit, exact status and literal scene/job search.

Authentication: Bearer.

Parameters & headers

NameLocationTypeRequired / constraints
offsetqueryintegerOptional · Default: 0 · Minimum: 0
limitqueryintegerOptional · Default: 50 · Minimum: 1 · Maximum: 100
statusquerystring | nullOptional
searchquerystring | nullOptional
GET /jobs requestShell
curl --fail-with-body -sS -X GET "$HYPERSR_API_BASE/jobs?offset=0&limit=20&status=completed&search=S2B" \
  -H "Authorization: Bearer $HYPERSR_API_KEY"

Success response · HTTP 200

FieldTypeRequiredConstraints
itemsarray<object>Yes—
items[].bboxarray<number> | nullNo—
items[].charged_creditsintegerYes—
items[].completed_atstring (date-time) | nullNo—
items[].created_atstring (date-time)Yes—
items[].error_codestring | nullNo—
items[].error_messagestring | nullNo—
items[].input_scene_idstring | nullNo—
items[].job_idstringYes—
items[].modelstring | nullNo—
items[].model_versionstring | nullNo—
items[].progressnumber | nullNo—
items[].quoted_creditsintegerNoDefault: 0
items[].requested_bandsarray<string>No—
items[].reserved_creditsintegerYes—
items[].started_atstring (date-time) | nullNo—
items[].statusstringYes—
totalintegerYes—
GET /jobs illustrative responseJSON
{
  "items": [],
  "total": 0
}

Error responses

HTTPError codes
401UNAUTHENTICATED
403FORBIDDEN
413REQUEST_TOO_LARGE
422INVALID_REQUEST
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

GET/jobs/{job_id}Get Job

GET /v1/jobs/{job_id}

Job state, scene, model/version, bands, bounds, credits and timestamps.

Authentication: Bearer.

Parameters & headers

NameLocationTypeRequired / constraints
job_idpathstringRequired
GET /jobs/{job_id} requestShell
curl --fail-with-body -sS -X GET "$HYPERSR_API_BASE/jobs/$JOB_ID" \
  -H "Authorization: Bearer $HYPERSR_API_KEY"

Success response · HTTP 200

FieldTypeRequiredConstraints
bboxarray<number> | nullNo—
charged_creditsintegerYes—
completed_atstring (date-time) | nullNo—
created_atstring (date-time)Yes—
error_codestring | nullNo—
error_messagestring | nullNo—
input_scene_idstring | nullNo—
job_idstringYes—
modelstring | nullNo—
model_versionstring | nullNo—
progressnumber | nullNo—
quoted_creditsintegerNoDefault: 0
requested_bandsarray<string>No—
reserved_creditsintegerYes—
started_atstring (date-time) | nullNo—
statusstringYes—
GET /jobs/{job_id} illustrative responseJSON
{
  "job_id": "job_example",
  "status": "completed",
  "reserved_credits": 0,
  "charged_credits": 3720,
  "progress": 1,
  "created_at": "2030-01-10T12:05:00Z",
  "started_at": "2030-01-10T12:05:02Z",
  "completed_at": "2030-01-10T12:07:30Z",
  "error_code": null,
  "error_message": null,
  "input_scene_id": "S2B_31TDF_20240112_0_L2A",
  "bbox": [
    2.1,
    41.3,
    2.12,
    41.32
  ],
  "model": "hypersr_v1",
  "model_version": "1.0.0+sen2neon.20261110",
  "requested_bands": [
    "B02",
    "B03",
    "B04",
    "B08"
  ],
  "quoted_credits": 3720
}

Error responses

HTTPError codes
401UNAUTHENTICATED
403FORBIDDEN
404JOB_NOT_FOUND
413REQUEST_TOO_LARGE
422INVALID_REQUEST
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

POST/jobs/{job_id}/cancelCancel Job

POST /v1/jobs/{job_id}/cancel

Cancel queued or claimed jobs and release reserved credits.

Authentication: Bearer.

Only queued and claimed jobs can be cancelled.

Parameters & headers

NameLocationTypeRequired / constraints
job_idpathstringRequired
POST /jobs/{job_id}/cancel requestShell
curl --fail-with-body -sS -X POST "$HYPERSR_API_BASE/jobs/$JOB_ID/cancel" \
  -H "Authorization: Bearer $HYPERSR_API_KEY"

Success response · HTTP 200

FieldTypeRequiredConstraints
bboxarray<number> | nullNo—
charged_creditsintegerYes—
completed_atstring (date-time) | nullNo—
created_atstring (date-time)Yes—
error_codestring | nullNo—
error_messagestring | nullNo—
input_scene_idstring | nullNo—
job_idstringYes—
modelstring | nullNo—
model_versionstring | nullNo—
progressnumber | nullNo—
quoted_creditsintegerNoDefault: 0
requested_bandsarray<string>No—
reserved_creditsintegerYes—
started_atstring (date-time) | nullNo—
statusstringYes—
POST /jobs/{job_id}/cancel illustrative responseJSON
{
  "job_id": "job_example",
  "status": "cancelled",
  "reserved_credits": 0,
  "charged_credits": 0,
  "progress": null,
  "created_at": "2030-01-10T12:05:00Z",
  "started_at": null,
  "completed_at": null,
  "error_code": null,
  "error_message": null,
  "input_scene_id": "S2B_31TDF_20240112_0_L2A",
  "bbox": [
    2.1,
    41.3,
    2.12,
    41.32
  ],
  "model": "hypersr_v1",
  "model_version": "1.0.0+sen2neon.20261110",
  "requested_bands": [
    "B02",
    "B03",
    "B04",
    "B08"
  ],
  "quoted_credits": 3720
}

Error responses

HTTPError codes
401UNAUTHENTICATED
403FORBIDDEN
404JOB_NOT_FOUND
409JOB_NOT_CANCELLABLE
413REQUEST_TOO_LARGE
422INVALID_REQUEST
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

GET/jobs/{job_id}/outputsOutputs

GET /v1/jobs/{job_id}/outputs

Retained outputs in {items, total}, with fresh signed URLs.

Authentication: Bearer.

New products expose reflectance, SCL, cloud_mask and provenance roles.

Parameters & headers

NameLocationTypeRequired / constraints
job_idpathstringRequired
GET /jobs/{job_id}/outputs requestShell
curl --fail-with-body -sS -X GET "$HYPERSR_API_BASE/jobs/$JOB_ID/outputs" \
  -H "Authorization: Bearer $HYPERSR_API_KEY"

Success response · HTTP 200

FieldTypeRequiredConstraints
itemsarray<object>Yes—
items[].checksumstring | nullNo—
items[].download_urlstringYes—
items[].expires_atstring (date-time) | nullYes—
items[].filenamestringYes—
items[].formatstringYes—
items[].role"reflectance" | "scl" | "cloud_mask" | "provenance" | nullNo—
items[].size_bytesinteger | nullYes—
totalintegerYes—
GET /jobs/{job_id}/outputs illustrative responseJSON
{
  "items": [
    {
      "role": "reflectance",
      "format": "cog",
      "filename": "reflectance.tif",
      "size_bytes": 123456,
      "checksum": "<sha256-hex>",
      "download_url": "https://storage.example.invalid/object?signature=...",
      "expires_at": "2030-01-10T12:15:00Z"
    },
    {
      "role": "scl",
      "format": "cog",
      "filename": "scl.tif",
      "size_bytes": 45678,
      "checksum": "<sha256-hex>",
      "download_url": "https://storage.example.invalid/object?signature=...",
      "expires_at": "2030-01-10T12:15:00Z"
    },
    {
      "role": "cloud_mask",
      "format": "cog",
      "filename": "cloud_mask.tif",
      "size_bytes": 23456,
      "checksum": "<sha256-hex>",
      "download_url": "https://storage.example.invalid/object?signature=...",
      "expires_at": "2030-01-10T12:15:00Z"
    },
    {
      "role": "provenance",
      "format": "json",
      "filename": "provenance.json",
      "size_bytes": 3456,
      "checksum": "<sha256-hex>",
      "download_url": "https://storage.example.invalid/object?signature=...",
      "expires_at": "2030-01-10T12:15:00Z"
    }
  ],
  "total": 4
}

Error responses

HTTPError codes
401UNAUTHENTICATED
403FORBIDDEN
404JOB_NOT_FOUND
413REQUEST_TOO_LARGE
422INVALID_REQUEST
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR
503STORAGE_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

GET/outputs/{output_id}/downloadDownload Output

GET /v1/outputs/{output_id}/download

Download one retained artifact; use the signed URL returned by the outputs endpoint.

Authentication: Signed URL.

Use the complete signed download_url from the outputs response; do not add the API bearer token.

Parameters & headers

NameLocationTypeRequired / constraints
output_idpathstringRequired
expiresqueryintegerRequired
signaturequerystringRequired
GET /outputs/{output_id}/download requestShell
curl --fail-with-body --location "$DOWNLOAD_URL" --output artifact.tif
# Use download_url verbatim; it already includes its signature and expiry.

Success response · HTTP 200

GET /outputs/{output_id}/download illustrative responseHTTP body
Binary artifact (image/tiff or application/json)

Error responses

HTTPError codes
403DOWNLOAD_URL_INVALIDOUTPUT_FORBIDDEN
404OUTPUT_NOT_FOUND
410OUTPUT_EXPIRED
413REQUEST_TOO_LARGE
422INVALID_REQUEST
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR
503STORAGE_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

GET/creditsCredits

GET /v1/credits

Integer available/reserved balances, credit_lots and next_expiry.

Authentication: Bearer.

Amounts are integer internal units; 1 displayed credit equals 1,000 units.

GET /credits requestShell
curl --fail-with-body -sS -X GET "$HYPERSR_API_BASE/credits" \
  -H "Authorization: Bearer $HYPERSR_API_KEY"

Success response · HTTP 200

FieldTypeRequiredConstraints
availableintegerYes—
balanceintegerYes—
credit_lotsarray<object>Yes—
credit_lots[].expires_atstring (date-time) | nullYes—
credit_lots[].remainingintegerYes—
next_expiryobject | nullYes—
next_expiry.amountintegerYes—
next_expiry.expires_atstring (date-time) | nullYes—
reservedintegerYes—
totalintegerYes—
GET /credits illustrative responseJSON
{
  "balance": 10000,
  "available": 10000,
  "reserved": 0,
  "total": 10000,
  "credit_lots": [
    {
      "remaining": 10000,
      "expires_at": "2030-07-10T00:00:00Z"
    }
  ],
  "next_expiry": {
    "amount": 10000,
    "expires_at": "2030-07-10T00:00:00Z"
  }
}

Error responses

HTTPError codes
401UNAUTHENTICATED
403FORBIDDEN
413REQUEST_TOO_LARGE
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

GET/credits/transactionsCredit Transactions

GET /v1/credits/transactions

Immutable signed ledger movements; offset and limit.

Authentication: Bearer.

Parameters & headers

NameLocationTypeRequired / constraints
offsetqueryintegerOptional · Default: 0 · Minimum: 0
limitqueryintegerOptional · Default: 50 · Minimum: 1 · Maximum: 100
GET /credits/transactions requestShell
curl --fail-with-body -sS -X GET "$HYPERSR_API_BASE/credits/transactions?offset=0&limit=50" \
  -H "Authorization: Bearer $HYPERSR_API_KEY"

Success response · HTTP 200

FieldTypeRequiredConstraints
itemsarray<object>Yes—
items[].amountintegerYes—
items[].created_atstring (date-time)Yes—
items[].idstringYes—
items[].job_idstring | nullYes—
items[].metadataobjectNo—
items[].payment_idstring | nullYes—
items[].transaction_typestringYes—
totalintegerYes—
GET /credits/transactions illustrative responseJSON
{
  "items": [
    {
      "id": "ledger_example",
      "amount": 10000,
      "transaction_type": "trial_grant",
      "job_id": null,
      "payment_id": null,
      "created_at": "2030-01-10T12:00:00Z",
      "metadata": {}
    }
  ],
  "total": 1
}

Error responses

HTTPError codes
401UNAUTHENTICATED
403FORBIDDEN
413REQUEST_TOO_LARGE
422INVALID_REQUEST
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

GET/billing/packagesPackages

GET /v1/billing/packages

Configured packs: id, name, amount_cents, currency and credit units.

Authentication: Bearer.

Packages are deployment-configured; do not hard-code prices in clients.

GET /billing/packages requestShell
curl --fail-with-body -sS -X GET "$HYPERSR_API_BASE/billing/packages" \
  -H "Authorization: Bearer $HYPERSR_API_KEY"

Success response · HTTP 200

FieldTypeRequiredConstraints
itemsarray<object>Yes—
items[].amount_centsintegerYes—
items[].creditsintegerYes—
items[].currencystringYes—
items[].idstringYes—
items[].namestringYes—
GET /billing/packages illustrative responseJSON
{
  "items": [
    {
      "id": "starter",
      "name": "Starter",
      "amount_cents": 1000,
      "credits": 40000,
      "currency": "eur"
    }
  ]
}

Error responses

HTTPError codes
401UNAUTHENTICATED
403FORBIDDEN
413REQUEST_TOO_LARGE
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR
503BILLING_MISCONFIGURED

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

POST/billing/checkoutCheckout

POST /v1/billing/checkout

Create Checkout from {package_id}; requires Idempotency-Key.

Authentication: Bearer + key. Keep the idempotency key stable for retries of the same operation.

Credits are granted only after verified payment events.

Parameters & headers

NameLocationTypeRequired / constraints
Idempotency-KeyheaderstringRequired · Unique key that makes a retry safe and deterministic. · Min length: 1 · Max length: 255

JSON request body

FieldTypeRequiredConstraints
package_idstringYes—
POST /billing/checkout requestShell
curl --fail-with-body -sS -X POST "$HYPERSR_API_BASE/billing/checkout" \
  -H "Authorization: Bearer $HYPERSR_API_KEY" \
  -H "Idempotency-Key: $HYPERSR_REQUEST_KEY" \
  -H "Content-Type: application/json" \
  --data '{"package_id":"starter"}'

Success response · HTTP 200

FieldTypeRequiredConstraints
checkout_urlstringYes—
session_idstringYes—
POST /billing/checkout illustrative responseJSON
{
  "checkout_url": "https://checkout.stripe.com/c/pay/cs_test_...",
  "session_id": "cs_test_example"
}

Error responses

HTTPError codes
400IDEMPOTENCY_KEY_REQUIREDINVALID_PACKAGE
401UNAUTHENTICATED
403FORBIDDEN
409IDEMPOTENCY_KEY_CONFLICT
413REQUEST_TOO_LARGE
422INVALID_REQUEST
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR
502BILLING_PROVIDER_ERROR
503BILLING_UNAVAILABLEBILLING_MISCONFIGURED

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

GET/billing/historyHistory

GET /v1/billing/history

Own payment history; offset and limit.

Authentication: Bearer.

Parameters & headers

NameLocationTypeRequired / constraints
offsetqueryintegerOptional · Default: 0
limitqueryintegerOptional · Default: 50
GET /billing/history requestShell
curl --fail-with-body -sS -X GET "$HYPERSR_API_BASE/billing/history?offset=0&limit=50" \
  -H "Authorization: Bearer $HYPERSR_API_KEY"

Success response · HTTP 200

FieldTypeRequiredConstraints
itemsarray<object>Yes—
items[].amountintegerYes—
items[].created_atstring (date-time)Yes—
items[].creditsintegerYes—
items[].currencystringYes—
items[].idstringYes—
items[].statusstringYes—
totalintegerYes—
GET /billing/history illustrative responseJSON
{
  "items": [
    {
      "id": "payment_example",
      "amount": 1000,
      "credits": 40000,
      "currency": "eur",
      "status": "paid",
      "created_at": "2030-01-10T12:00:00Z"
    }
  ],
  "total": 1
}

Error responses

HTTPError codes
401UNAUTHENTICATED
403FORBIDDEN
413REQUEST_TOO_LARGE
422INVALID_REQUEST
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

GET/api-keysList Api Keys

GET /v1/api-keys

Key metadata and prefixes; no plaintext secret.

Authentication: Bearer.

Plaintext secrets are never returned by this endpoint.

GET /api-keys requestShell
curl --fail-with-body -sS -X GET "$HYPERSR_API_BASE/api-keys" \
  -H "Authorization: Bearer $HYPERSR_API_KEY"

Success response · HTTP 200

FieldTypeRequiredConstraints
itemsarray<object>Yes—
items[].created_atstring (date-time)Yes—
items[].idstringYes—
items[].key_prefixstringYes—
items[].last_used_atstring (date-time) | nullYes—
items[].namestringYes—
items[].revoked_atstring (date-time) | nullYes—
totalintegerYes—
GET /api-keys illustrative responseJSON
{
  "items": [
    {
      "id": "key_example",
      "name": "production-worker",
      "key_prefix": "hs_live_abc123",
      "created_at": "2030-01-10T12:00:00Z",
      "last_used_at": null,
      "revoked_at": null
    }
  ],
  "total": 1
}

Error responses

HTTPError codes
401UNAUTHENTICATED
403FORBIDDEN
413REQUEST_TOO_LARGE
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

POST/api-keysCreate Api Key

POST /v1/api-keys

Create from {name}; secret appears once in this response.

Authentication: Bearer.

The secret is shown once. Store it securely before leaving the response.

JSON request body

FieldTypeRequiredConstraints
namestringYesMin length: 1 · Max length: 120
POST /api-keys requestShell
curl --fail-with-body -sS -X POST "$HYPERSR_API_BASE/api-keys" \
  -H "Authorization: Bearer $HYPERSR_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{"name":"production-worker"}'

Success response · HTTP 200

FieldTypeRequiredConstraints
created_atstring (date-time)Yes—
idstringYes—
key_prefixstringYes—
last_used_atstring (date-time) | nullYes—
namestringYes—
revoked_atstring (date-time) | nullYes—
secretstringYes—
POST /api-keys illustrative responseJSON
{
  "id": "key_example",
  "name": "production-worker",
  "key_prefix": "hs_live_abc123",
  "secret": "hs_live_<shown-once>",
  "created_at": "2030-01-10T12:00:00Z",
  "last_used_at": null,
  "revoked_at": null
}

Error responses

HTTPError codes
401UNAUTHENTICATED
403FORBIDDEN
413REQUEST_TOO_LARGE
422INVALID_REQUEST
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

DELETE/api-keys/{key_id}Revoke Api Key

DELETE /v1/api-keys/{key_id}

Revoke an owned key. Subsequent use is rejected.

Authentication: Bearer.

Parameters & headers

NameLocationTypeRequired / constraints
key_idpathstringRequired
DELETE /api-keys/{key_id} requestShell
curl --fail-with-body -sS -X DELETE "$HYPERSR_API_BASE/api-keys/$KEY_ID" \
  -H "Authorization: Bearer $HYPERSR_API_KEY"

Success response · HTTP 200

FieldTypeRequiredConstraints
statusstringYes—
DELETE /api-keys/{key_id} illustrative responseJSON
{
  "status": "revoked"
}

Error responses

HTTPError codes
401UNAUTHENTICATED
403FORBIDDEN
404KEY_NOT_FOUND
413REQUEST_TOO_LARGE
422INVALID_REQUEST
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

GET/accountGet Account

GET /v1/account

Own account/profile. Identity and roles are server controlled.

Authentication: Bearer.

GET /account requestShell
curl --fail-with-body -sS -X GET "$HYPERSR_API_BASE/account" \
  -H "Authorization: Bearer $HYPERSR_API_KEY"

Success response · HTTP 200

FieldTypeRequiredConstraints
display_namestring | nullYes—
emailstringYes—
idstringYes—
rolestringYes—
GET /account illustrative responseJSON
{
  "id": "user_example",
  "email": "developer@example.com",
  "display_name": "Developer",
  "role": "user"
}

Error responses

HTTPError codes
401UNAUTHENTICATED
403FORBIDDEN
413REQUEST_TOO_LARGE
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

PATCH/accountUpdate Account

PATCH /v1/account

Update {display_name}; unknown fields are rejected.

Authentication: Bearer.

Only display_name is customer-editable.

JSON request body

FieldTypeRequiredConstraints
display_namestring | nullNo—
PATCH /account requestShell
curl --fail-with-body -sS -X PATCH "$HYPERSR_API_BASE/account" \
  -H "Authorization: Bearer $HYPERSR_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{"display_name":"Updated name"}'

Success response · HTTP 200

FieldTypeRequiredConstraints
display_namestring | nullYes—
emailstringYes—
idstringYes—
rolestringYes—
PATCH /account illustrative responseJSON
{
  "id": "user_example",
  "email": "developer@example.com",
  "display_name": "Updated name",
  "role": "user"
}

Error responses

HTTPError codes
401UNAUTHENTICATED
403FORBIDDEN
413REQUEST_TOO_LARGE
422INVALID_REQUEST
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

GET/account/summaryAccount Summary

GET /v1/account/summary

Balances, active/completed runs, area and safe worker availability.

Authentication: Bearer.

GET /account/summary requestShell
curl --fail-with-body -sS -X GET "$HYPERSR_API_BASE/account/summary" \
  -H "Authorization: Bearer $HYPERSR_API_KEY"

Success response · HTTP 200

FieldTypeRequiredConstraints
active_jobsintegerYes—
available_creditsintegerYes—
completed_jobsintegerYes—
processed_area_km2numberYes—
reserved_creditsintegerYes—
total_creditsintegerYes—
worker_availablebooleanYes—
GET /account/summary illustrative responseJSON
{
  "available_credits": 10000,
  "reserved_credits": 0,
  "total_credits": 10000,
  "processed_area_km2": 3.72,
  "active_jobs": 0,
  "completed_jobs": 1,
  "worker_available": true
}

Error responses

HTTPError codes
401UNAUTHENTICATED
403FORBIDDEN
413REQUEST_TOO_LARGE
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

GET/account/notificationsGet Notification Preferences

GET /v1/account/notifications

Completion/failure notification preferences.

Authentication: Bearer.

GET /account/notifications requestShell
curl --fail-with-body -sS -X GET "$HYPERSR_API_BASE/account/notifications" \
  -H "Authorization: Bearer $HYPERSR_API_KEY"

Success response · HTTP 200

FieldTypeRequiredConstraints
job_completedbooleanYes—
job_failedbooleanYes—
GET /account/notifications illustrative responseJSON
{
  "job_completed": true,
  "job_failed": true
}

Error responses

HTTPError codes
401UNAUTHENTICATED
403FORBIDDEN
413REQUEST_TOO_LARGE
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

PATCH/account/notificationsUpdate Notification Preferences

PATCH /v1/account/notifications

Set job_completed and/or job_failed booleans.

Authentication: Bearer.

At least one known boolean may be sent; explicit null values are rejected.

JSON request body

FieldTypeRequiredConstraints
job_completedboolean | nullNo—
job_failedboolean | nullNo—
PATCH /account/notifications requestShell
curl --fail-with-body -sS -X PATCH "$HYPERSR_API_BASE/account/notifications" \
  -H "Authorization: Bearer $HYPERSR_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{"job_completed":true,"job_failed":false}'

Success response · HTTP 200

FieldTypeRequiredConstraints
job_completedbooleanYes—
job_failedbooleanYes—
PATCH /account/notifications illustrative responseJSON
{
  "job_completed": true,
  "job_failed": false
}

Error responses

HTTPError codes
401UNAUTHENTICATED
403FORBIDDEN
413REQUEST_TOO_LARGE
422INVALID_REQUEST
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

GET/aoisList Aois

GET /v1/aois

Own saved areas in {items, total}; offset and limit.

Authentication: Bearer.

Parameters & headers

NameLocationTypeRequired / constraints
offsetqueryintegerOptional · Default: 0 · Minimum: 0
limitqueryintegerOptional · Default: 50 · Minimum: 1 · Maximum: 100
GET /aois requestShell
curl --fail-with-body -sS -X GET "$HYPERSR_API_BASE/aois?offset=0&limit=50" \
  -H "Authorization: Bearer $HYPERSR_API_KEY"

Success response · HTTP 200

FieldTypeRequiredConstraints
itemsarray<object>Yes—
items[].area_km2numberYes—
items[].bboxarray<number>Yes—
items[].created_atstring (date-time)Yes—
items[].descriptionstringYes—
items[].idstringYes—
items[].namestringYes—
items[].updated_atstring (date-time)Yes—
totalintegerYes—
GET /aois illustrative responseJSON
{
  "items": [
    {
      "id": "aoi_example",
      "name": "Barcelona test area",
      "description": "Optional internal label",
      "bbox": [
        2.1,
        41.3,
        2.12,
        41.32
      ],
      "area_km2": 3.72,
      "created_at": "2030-01-10T12:00:00Z",
      "updated_at": "2030-01-10T12:00:00Z"
    }
  ],
  "total": 1
}

Error responses

HTTPError codes
401UNAUTHENTICATED
403FORBIDDEN
413REQUEST_TOO_LARGE
422INVALID_REQUEST
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

POST/aoisCreate Aoi

POST /v1/aois

Save {name, bbox, description?}; returns 201 and the area.

Authentication: Bearer.

JSON request body

FieldTypeRequiredConstraints
bboxarray<number>YesMin items: 4 · Max items: 4
descriptionstringNoDefault: "" · Max length: 500
namestringYesMin length: 1 · Max length: 120
POST /aois requestShell
curl --fail-with-body -sS -X POST "$HYPERSR_API_BASE/aois" \
  -H "Authorization: Bearer $HYPERSR_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{"name":"Barcelona test area","description":"Optional internal label","bbox":[2.1,41.3,2.12,41.32]}'

Success response · HTTP 201

FieldTypeRequiredConstraints
area_km2numberYes—
bboxarray<number>Yes—
created_atstring (date-time)Yes—
descriptionstringYes—
idstringYes—
namestringYes—
updated_atstring (date-time)Yes—
POST /aois illustrative responseJSON
{
  "id": "aoi_example",
  "name": "Barcelona test area",
  "description": "Optional internal label",
  "bbox": [
    2.1,
    41.3,
    2.12,
    41.32
  ],
  "area_km2": 3.72,
  "created_at": "2030-01-10T12:00:00Z",
  "updated_at": "2030-01-10T12:00:00Z"
}

Error responses

HTTPError codes
401UNAUTHENTICATED
403FORBIDDEN
413REQUEST_TOO_LARGE
422INVALID_REQUESTINVALID_AOI
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

GET/aois/{aoi_id}Get Aoi

GET /v1/aois/{aoi_id}

One owned area, geodetic area and timestamps.

Authentication: Bearer.

Parameters & headers

NameLocationTypeRequired / constraints
aoi_idpathstringRequired
GET /aois/{aoi_id} requestShell
curl --fail-with-body -sS -X GET "$HYPERSR_API_BASE/aois/$AOI_ID" \
  -H "Authorization: Bearer $HYPERSR_API_KEY"

Success response · HTTP 200

FieldTypeRequiredConstraints
area_km2numberYes—
bboxarray<number>Yes—
created_atstring (date-time)Yes—
descriptionstringYes—
idstringYes—
namestringYes—
updated_atstring (date-time)Yes—
GET /aois/{aoi_id} illustrative responseJSON
{
  "id": "aoi_example",
  "name": "Barcelona test area",
  "description": "Optional internal label",
  "bbox": [
    2.1,
    41.3,
    2.12,
    41.32
  ],
  "area_km2": 3.72,
  "created_at": "2030-01-10T12:00:00Z",
  "updated_at": "2030-01-10T12:00:00Z"
}

Error responses

HTTPError codes
401UNAUTHENTICATED
403FORBIDDEN
404AOI_NOT_FOUND
413REQUEST_TOO_LARGE
422INVALID_REQUEST
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

PATCH/aois/{aoi_id}Update Aoi

PATCH /v1/aois/{aoi_id}

Change supplied name, description or bbox fields.

Authentication: Bearer.

Send only fields to change; explicit null values are rejected.

Parameters & headers

NameLocationTypeRequired / constraints
aoi_idpathstringRequired

JSON request body

FieldTypeRequiredConstraints
bboxarray<number> | nullNo—
descriptionstring | nullNo—
namestring | nullNo—
PATCH /aois/{aoi_id} requestShell
curl --fail-with-body -sS -X PATCH "$HYPERSR_API_BASE/aois/$AOI_ID" \
  -H "Authorization: Bearer $HYPERSR_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{"description":"Updated label"}'

Success response · HTTP 200

FieldTypeRequiredConstraints
area_km2numberYes—
bboxarray<number>Yes—
created_atstring (date-time)Yes—
descriptionstringYes—
idstringYes—
namestringYes—
updated_atstring (date-time)Yes—
PATCH /aois/{aoi_id} illustrative responseJSON
{
  "id": "aoi_example",
  "name": "Barcelona test area",
  "description": "Updated label",
  "bbox": [
    2.1,
    41.3,
    2.12,
    41.32
  ],
  "area_km2": 3.72,
  "created_at": "2030-01-10T12:00:00Z",
  "updated_at": "2030-01-10T12:00:00Z"
}

Error responses

HTTPError codes
401UNAUTHENTICATED
403FORBIDDEN
404AOI_NOT_FOUND
413REQUEST_TOO_LARGE
422INVALID_REQUEST
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

DELETE/aois/{aoi_id}Delete Aoi

DELETE /v1/aois/{aoi_id}

Delete the saved area; existing jobs keep their bounds.

Authentication: Bearer.

Parameters & headers

NameLocationTypeRequired / constraints
aoi_idpathstringRequired
DELETE /aois/{aoi_id} requestShell
curl --fail-with-body -sS -X DELETE "$HYPERSR_API_BASE/aois/$AOI_ID" \
  -H "Authorization: Bearer $HYPERSR_API_KEY"

Success response · HTTP 200

FieldTypeRequiredConstraints
statusstringYes—
DELETE /aois/{aoi_id} illustrative responseJSON
{
  "status": "deleted"
}

Error responses

HTTPError codes
401UNAUTHENTICATED
403FORBIDDEN
404AOI_NOT_FOUND
413REQUEST_TOO_LARGE
422INVALID_REQUEST
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Errors use the shared error envelope. Field validation also checks the geospatial and account rules explained in the guides above. Required nested fields apply when their parent object is present.

Download OpenAPI JSON. Stripe webhooks and private worker/operator operations are managed by HyperSR and are outside the customer integration contract.