Queek docs

Building safe integrations

Idempotent writes, cursor reads, rate limits, errors, and a checklist for Merchant API clients.

Build for retries, partial failures, and changes that arrive while you are offline. The Merchant API reference is the source for each operation's parameters and response schema.

Make writes safe to retry

Send an Idempotency-Key on every write. Reuse the same key only when retrying the same logical request to the same operation with the same body. A completed response is kept for 24 hours. A matching retry receives the stored status and JSON response with Idempotent-Replayed: true; it does not execute the operation again.

The key is scoped to the store, caller key, HTTP method and path. Reusing it with a different body returns 409 idempotency_key_reuse. If a matching request is still running, the concurrent request waits up to 15 seconds; if it is still in progress, Queek returns 409 idempotency_key_in_progress. Use a new key for a new logical write. Error responses with status 400 or higher are not stored, so retrying that key will run the request again.

See Idempotency & rate limits for the complete contract and examples.

Walk cursor-paginated lists

List responses use data, has_more, and next_cursor. Send the previous response's next_cursor as starting_after to request the next page. Treat cursor values as opaque: store and return them unchanged, and do not decode or construct them. The limit parameter is bounded by the operation. The core resource lists GET /orders, GET /products, and GET /customers accept a limit from 1 through 100.

These lists use a deterministic sort with a unique id tie-breaker, so items with equal sort values can be paged consistently while new rows are inserted. A cursor walk is not an event history or a snapshot of all changes. Use the object's updated_at when reconciling your local copy, and repeat the walk to catch later changes.

GET /orders?limit=100
GET /orders?limit=100&starting_after={next_cursor from the previous response}

For an event that names a resource you already know, fetch its current representation directly, such as GET /orders/{order}, GET /products/{product}, or GET /customers/{customer}. If a delivery was missed, combine that read with a fresh cursor walk of the relevant list.

Handle quotas and errors

Each private API key has a per-minute quota determined by its store plan. The current quotas are free 60, social_media 120, starter 120, growth 240, scale 1200, and enterprise 2400 requests per minute. Requests made with an app installation key use the same per-key quota. Calls using one key share that key's quota across Merchant API and Storefront API requests.

Some app writes also have a separate per-installation cap. The defaults are 20 alerts per hour and 5 error-severity alerts per day for POST /app/alerts, plus 30 record submissions per minute and 2000 per day for POST /records. These caps can be configured for a deployment. When one of these caps is reached, Queek returns 429 with Retry-After in seconds; accepted records remain stored.

When the quota is exceeded, the API returns 429 with error.code set to too_many_requests and a Retry-After header. Wait for the indicated interval before retrying. For transient 500 server_error and 503 service_unavailable responses, retry with backoff. For 409 idempotency_key_in_progress, retry the original write with its same key after the in-flight request has had time to finish.

Errors use an error object with a stable code, human-readable message, doc_url, and request_id; validation errors may also include field and errors. Switch on error.code, not message.

ResponseHow to handle it
429 too_many_requestsWait for Retry-After, then retry.
500 server_error, 503 service_unavailableRetry with backoff. Reuse the same idempotency key for a write.
409 idempotency_key_in_progressRetry the same logical write with the same key after the in-flight call can finish.
409 idempotency_key_reuseDo not retry with that key and body. Use a new key for a new logical request; investigate accidental key reuse.
401 or 403 auth/scope errorsCorrect the key, mode, plan, or granted scope before retrying.
404 not_found or 422 validation_failedCorrect the resource id or request fields before retrying.
Other 409 conflict responsesRe-read current resource state and resolve the conflict before retrying.

Integration checklist

  • Keep the private key on your server and grant only the scopes the integration uses.
  • Give each new write a fresh idempotency key; reuse it only for retries of that same write.
  • On webhook receipt, verify the raw-body signature and durably deduplicate the event id before acknowledging it. See Webhooks.
  • Treat webhook events as notifications; fetch the resource by id when you need current state.
  • Save cursors exactly as returned and continue only while has_more is true.
  • Honor Retry-After on 429; use backoff for transient server errors.
  • Branch on error.code, retain request_id for support, and never make retry decisions from the human-readable message.

On this page