About 8 minutes
DESIGN FOR RATE LIMITS.
Read the limits on your key before a job starts, slow down from response headers, and retry without duplicating a write.
Steps
1. Get a key
Workspace admins issue keys in the app at /app/api-keys. Start with a sandbox key: it is bound to a showroom workspace and can never touch live data. Keep the secret server-side.
export QN_API_KEY="qn_sandbox_…" curl "$QN_BASE/me" -H "Authorization: Bearer $QN_API_KEY"2. Read the allowance
Call GET /limits before a large sync. It returns the burst and daily windows that apply to the current key, so the integration does not need a hardcoded allowance.
curl "$QN_BASE/limits" \ -H "Authorization: Bearer $QN_API_KEY"3. Use the response headers
Read RateLimit-Remaining and RateLimit-Reset on every response. When a 429 arrives, wait for Retry-After. The TypeScript and Python clients do this automatically for safe retries.
4. Make writes repeatable
Send an Idempotency-Key with event and actuals writes. A retry with the same key returns the original result instead of creating a second write.
curl -X POST "$QN_BASE/events" \ -H "Authorization: Bearer $QN_API_KEY" \ -H "Idempotency-Key: job_2026_09_20_batch_01" \ -H "Content-Type: application/json" \ --data @events.json
Done when
The integration completes without exceeding the declared windows, and replaying a write with the same idempotency key does not create a duplicate.