Skip to content

Searching and continuation

POST /v1/search

Root request:

POST /v1/search
Authorization: Bearer sk_live_...
Idempotency-Key: 6c84fb90-c1b9-4c26-9d0e-2d4a6a1f9c33

{
  "query": {"domain": "example.org"},
  "billing": {"max_rows": 1000, "max_cost_cents": 40000}
}

Both billing fields are optional and independently settable to null (the default).

On success the API responds 303 See Other with an empty body and a Location header pointing at your CSV — follow it with a plain GET (no auth):

HTTP/1.1 303 See Other
Location: /v1/files/ord_9f8e7d6a....csv

An empty match still succeeds: the CSV contains only the header row and the order costs 0 cents.

Billing guards

Guard Role On trip
billing.max_rows Cap — deliver only the first N units in delivery order Nothing trips; the remainder stays retrievable via continuation
billing.max_cost_cents Guard — abort if the chunk would cost more 402 cost_exceeds_max_cost, atomically: nothing charged, nothing delivered
  • max_rows: positive integer up to 10,000,000, or null.
  • max_cost_cents: positive integer up to 1,000,000,000, or null. null means "my current balance" — you can never overdraft.
  • Evaluation order is fixed: cap by max_rows first, then cost-check the capped set, then debit. The server never silently shrinks N to fit under your cost limit — you either get exactly N rows or a 402.
  • A 402 is completely safe to retry after funding or loosening the guard.

Continuation

POST /v1/search
{"continue": "ord_9f8e7d6a...", "billing": {"max_rows": 1000, "max_cost_cents": 40000}}
  • query must be absent on continuations (422 query_with_continue otherwise). The original query is immutable for the lineage.
  • Any order id in the lineage — root or child — works as the continue value.
  • Each continuation returns a fresh 303 with its own file containing the next units in delivery order.
  • On a continuation, max_cost_cents guards that chunk's incremental charge only, not the lineage total.
  • Terminal states: 410 order_exhausted when nothing remains; 410 order_expired past the TTL.

TTL

Every order in a lineage expires 72 hours after the root order was created. Children inherit the root's expires_at; continuations never extend it. After expiry, files return 410 file_expired, but the order records (and your ledger) persist forever.

Idempotency

Send an Idempotency-Key header (any unique string, e.g. a UUID) on every /v1/search call:

  • Same key + same body → the stored response is replayed verbatim (same 303, same file, zero additional charge). This holds for stored 402s too.
  • Same key + different body → 422 idempotency_key_conflict. This catches client bugs that would otherwise silently bill the wrong query.
  • Same key while the first request is still executing → 409 idempotency_in_progress; retry shortly.
  • Keys are scoped to your token and remembered for 24 hours.

File security

File URLs carry no authentication — the 128-bit random id is the credential. Treat file URLs with the same care as your sk_live_ secret: anyone holding the URL can download the file until it expires.