Production checklist
What to settle before an integration runs unattended. Each item links to the page that has the detail.
One request wrapper#
Send every call through one function so the rules below live in one place. It should:
- Add the
x-api-keyheader from an environment variable (never from source control or browser code). See Authentication. - Set a timeout. Fresh fetches from hard-to-reach platforms take longer than cache hits; start with 30 seconds for single calls and longer for batch and universal search.
- Check
successbefore readingdata. A failure hasdata: nulland anerrorblock with atype. See Response format. - Log
metadata.request_id(also theX-Request-Idheader) on every call. It is the one thing we need if you write to us. - Return the
error.typeto the caller so it can branch.
Retry only what can succeed#
| Answer | Retry? |
|---|---|
429 RATE_LIMITED, 503 and the idempotency 409 | Yes, after the Retry-After header. |
500, 502, 504 (UPSTREAM_ERROR, UPSTREAM_TIMEOUT) | Yes, with backoff: 1 s, 2 s, 4 s plus jitter, 3 or 4 tries. These calls were refunded. |
400, 401, 402, 403, 404, 405, 422 | No. The same request fails the same way. |
See Rate limits for the full rule and Errors for each type.
Make retries safe#
A call that timed out may or may not have been billed. Send an Idempotency-Key on any call you might repeat: the retry within 24 hours is replayed from the stored answer for 0 credits. See Idempotency. Generate the key once per logical operation, not once per attempt.
Drain pages properly#
Loop on pagination.has_more and send pagination.next_cursor back untouched as cursor with the same other parameters. Never build or edit a cursor. See Pagination.
Control rate and spend#
- The default is 600 requests per minute per key and 50 requests in flight at once;
X-RateLimit-Remainingon every response tells you where you are. Slow down before it reaches zero, and keep your worker pool below the in-flight cap. See Rate limits. - Use one key per app and environment, and give each a credit limit, so a bug in one cannot drain the account.
- For bulk work use batch: the call checks the worst case first and bills only the rows that returned data.
- Watch your balance with
GET /v1/account(free). TheX-Credits-Remainingheader is authoritative on any call that charged something.
Decide what stale means#
Cache hits are free and fast, and a stale copy is served when the source is down. If your use needs a live number, read metadata.cached, metadata.stale and metadata.age_s and decide in code. See Caching.
Check the source before you panic#
If one platform keeps failing, call the free status endpoint. A platform reported down will not recover by retrying faster.
Prefer a monitor over a poll#
If the job is "tell me when it changes", create a monitor: it re-runs on a schedule and sends a signed webhook. Verify the signature on every delivery, answer 2xx within 5 seconds, and de-duplicate on Onekey-Delivery-Id.
Stable before beta#
Beta endpoints are not yet verified against the live source. Do not build anything critical on them without a fallback. See Data availability.
Deployment checklist#
- [ ] Key in a secret store, one key per app and environment, each with a credit limit.
- [ ] One request wrapper with timeout,
successcheck andrequest_idlogging. - [ ] Retries only on
429,5xx; backoff with jitter;Retry-Afterhonoured. - [ ]
Idempotency-Keyon every call that may be repeated. - [ ] Pagination loop on
has_more, cursor passed back verbatim. - [ ] Unknown response fields and unknown error types tolerated.
- [ ]
nullhandled as unknown, not as zero. - [ ] Alerting on
402(balance) andKEY_BUDGET_EXCEEDED. - [ ] A failing platform checked against
/v1/statusbefore retries are escalated.