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, ornull.max_cost_cents: positive integer up to 1,000,000,000, ornull.nullmeans "my current balance" — you can never overdraft.- Evaluation order is fixed: cap by
max_rowsfirst, 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}}
querymust be absent on continuations (422 query_with_continueotherwise). The original query is immutable for the lineage.- Any order id in the lineage — root or child — works as the
continuevalue. - Each continuation returns a fresh
303with its own file containing the next units in delivery order. - On a continuation,
max_cost_centsguards that chunk's incremental charge only, not the lineage total. - Terminal states:
410 order_exhaustedwhen nothing remains;410 order_expiredpast 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.