Docs
View as Markdown

Testing your integration

There is no separate sandbox host: tests run against the real API with a real key, so the aim is to test as much as possible without spending credits, and to cap what the rest can spend.

Use a separate capped key#

Create a key for tests in the dashboard and give it a credit limit. When the limit is reached calls fail with KEY_BUDGET_EXCEEDED and your balance is untouched, so a loop in a test cannot drain the account.

Start with free calls#

These cost nothing, so a test suite can call them freely (still within the rate limit):

CallWhat it proves
GET /v1/accountThe key works and what the balance is.
GET /v1/platformsThe catalog and each endpoint's price, parameters and status.
GET /v1/statusPer-platform health. Public, no key. See Status.
GET /v1/errorsEvery error type your client may need to handle.
A request with a bad parameterA free 422 INVALID_PARAMS or 400 (never charged), so you can test your error path.
A repeat of a call within its cache windowA free cache hit: X-Cache: HIT, credits_charged: 0.

For multi-leg calls, dry_run=true on universal search and the reports returns the plan and the worst-case price for 0 credits.

Record a fixture and test your parser#

Every endpoint page has a recorded response in the real envelope. Save one as a fixture and run your parser against it. Then add cases for the awkward shapes:

  • A field that is null (unknown). Do not coerce it to zero.
  • A field the endpoint does not map at all (absent). See Data availability.
  • An empty list: data: [] is a normal success.
  • An extra field your code has never seen. It must be ignored.
  • metadata.stale: true and metadata.cached: true.

Test the failure paths#

Send these on purpose and assert what your code does:

SendExpect
No x-api-key or a wrong one401 UNAUTHORIZED. Not retried.
A missing required parameter422. Not retried.
A record that does not exist404 NOT_FOUND. Not charged, not retried.
A burst over the limit429 with Retry-After. Your client waits and retries.

Test retries with idempotency#

Send the same request twice with one Idempotency-Key. The second answer has metadata.idempotent_replay: true, credits_charged: 0 and the header X-Idempotent-Replay: true. Send the same key with different parameters and you get IDEMPOTENCY_KEY_REUSED. See Idempotency.

Test webhook delivery#

For monitors, call POST /v1/monitors/{id}/webhook/test to send a signed test event to your endpoint without waiting for a schedule. Assert that your handler:

  1. Reads the raw body bytes before parsing.
  2. Verifies Onekey-Signature in constant time and rejects a timestamp more than 300 seconds old.
  3. Answers 2xx within 5 seconds.
  4. Ignores a second delivery with the same Onekey-Delivery-Id.

The webhook verifier tool checks a captured body and signature in your browser.

One live smoke test#

Keep one cheap real call in CI, on a stable endpoint, to catch a bad key or a changed contract:

shell
curl "https://api.onekey.dev/v1/github/profile?username=torvalds" \
  -H "x-api-key: $ONEKEY_API_KEY"

Clean up#

Delete test monitors when a run finishes (DELETE /v1/monitors/{id}), since a monitor keeps running and billing on its schedule until paused or deleted. See Monitors.

Next#