Common patterns
The examples below use an SDK client, client,
or cURL with the Extract base URL. Use the generated
OpenAPI document for route-specific statuses and schemas.
Waiting for a Run
Runs are asynchronous. The SDKs wait for a Run when they start it. For a Run
started elsewhere, or with wait=False, wait() polls until finished is
true and raises JobFailedError if the Run failed. With cURL, poll until
finished is true, then read status for the outcome: completed,
stopped, or failed.
run = client.extract.runs.wait(run_id, timeout=3600) # polls with backoff
print(run.status)Use a client-side timeout and a bounded polling interval. Completion time depends on source coverage, crawl scope, and queue state.
Handling errors
Check the status before decoding a success payload. API errors use the stable
{ "error": { "code", "message", "request_id" } } envelope; retain the
request ID when contacting support.
from extralt import APIStatusError, RateLimitError
try:
run = client.extract.runs.create(robot_id=robot_id, budget=100)
except RateLimitError:
... # raised only after the SDK's own retries
except APIStatusError as error:
print(error.status_code, error.code, error.request_id)For create and restart requests, retry the same payload with the original
Idempotency-Key; the SDKs do this for their own retries. This returns the original result instead of duplicating
work. A key reused with a different payload returns 409 Conflict.
Pagination
List responses use cursor pagination. Pass a non-null next_cursor as the
cursor query parameter for the next page.
captures = list(client.extract.captures.list(run_id=run_id))Treat cursors as opaque. Do not decode, construct, or replace one with a
resource id. Preserve the same endpoint, filters, and sort across pages; the
next request may choose a different valid limit.
Pagination reads live data rather than holding a database transaction across HTTP requests. On unchanged data, keyset cursors traverse deterministically. Rows written between requests can affect the remaining pages, so restart without a cursor when you need a refreshed traversal.
Explore Analysis pages
Pageable Explore Analysis responses use the same data and next_cursor
fields. Their summary, coverage, and freshness describe the complete selected
Analysis scope, while data contains only the current evidence page. On
unchanged data, those scope-level values repeat on later pages. A non-null
next_cursor is the only continuation signal.
Timestamps
Every point in time, in requests and responses, is an RFC 3339 timestamp such
as 2026-01-31T00:00:00Z. Explore time windows take from and to query
parameters in that format; to is exclusive.
Rate-limit handling
A 429 response is authoritative. Honor Retry-After when present, then retry
with exponential backoff, random jitter, and a maximum attempt count. The SDKs
do this for every operation that is safe to repeat. Do not
build against an observed request rate as if it were a permanent quota;
operational limits can change.
Reads are generally safe to retry. Retry a mutation only with the same
Idempotency-Key and payload, or when the operation is otherwise documented as
idempotent.
Bulk Capture export
Use the Capture export route instead of paginating when you need all Captures from one Run or Import as JSONL or Parquet. Stream the response to disk rather than loading the entire file in memory. See Working with Captures.