postreef
View as Markdown

Errors & limits

Every non-2xx response uses one envelope with a stable machine-readable code, and every authenticated response carries rate-limit headers.

The error envelope

{
  "error": {
    "code": "insufficient_credits",
    "message": "insufficient credits",
    "details": { "balance": 120, "cost": 636 }
  }
}

code is stable, so branch on it. message is human-readable and may change. details appears only when there's structured context to give.

Error codes

Code Status Meaning Retry?
unauthorized 401 Missing, invalid or revoked API key. Don't retry: fix the key.
invalid_request 400 Malformed JSON or invalid fields (bad inputs, oversized schema, bad webhookUrl, bad limit/cursor…). The message says which. Don't retry: fix the request.
invalid_url 400 The url field isn't a parseable URL. Don't retry: fix the URL.
unsupported_url 400 The URL parses but isn't a supported video platform link. Don't retry with the same URL.
insufficient_credits 402 Your balance can't cover the quoted price. details.balance and details.cost are in credits. Retry after topping up credits.
rate_limited 429 Per-minute request window exceeded for this endpoint. Retry after the Retry-After header (seconds).
not_found 404 No such extraction/file/schema belongs to your account. Don't retry: check the id.
conflict 409 Idempotency-Key reused with a different request body. Don't retry: use a new key or the original body.
internal_error 500 / 502 Something failed on our side (502 when the video couldn't be fetched right now). Safe to retry with backoff; use an Idempotency-Key on submits.

Rate limits

Limits are per account, per endpoint, on a fixed one-minute window. Every authenticated response includes:

X-RateLimit-Limit: 60       # ceiling for this window
X-RateLimit-Remaining: 58   # requests left
X-RateLimit-Reset: 1765459200  # unix seconds when the window resets
Endpoint Limit
POST /v1/extractions (and /v1/extract) 6 / minute
POST /v1/probe 10 / minute
GET /v1/extractions/:id and /:id/result (shared bucket) 60 / minute
All other endpoints 60 / minute each

On 429 rate_limited a Retry-After header (seconds) tells you exactly how long to wait. Separately from request limits, at most 2 extractions run per account at once. Extra submissions are accepted with status queued and start automatically when a slot frees.

Idempotency

Submits are not safely retryable by default: a retried POST /v1/extractions creates (and charges) a second extraction. Send an Idempotency-Key header (any unique string, e.g. a UUID) to make them safe:

  • First request with a key: normal behaviour, 201.
  • Retry with the same key and same body: the original extraction is returned with 200, and nothing new is created or charged.
  • Same key, different body: 409 conflict.

Pagination

List endpoints use cursor pagination. Pass limit (1–100, default 20) and the next_cursor from the previous page as cursor:

{
  "data": [ ... ],
  "has_more": true,
  "next_cursor": "eyJ0IjoiMjAyNi0wNi0xMVQ..."
}

Cursors are opaque, so never construct or modify them. Results are ordered newest first.