Reseller API · v2.0

Integrate Qboon gift vouchers into your platform.

One base URL for sandbox and production — swap your API key when you go live, no code changes required. Prefunded wallet, synchronous issuance, and idempotent order placement built for reseller integrations.

01 — Quickstart

Six steps to your first order#

From receiving keys to placing a live transaction. Each step links to its full reference page.

01
Receive your API key
Issued by your Qboon account manager. qrk_test_… for sandbox, qrk_live_… for production.
Key formats →
02
Send it on every request
Authenticate every authenticated call with the X-Api-Key header. No OAuth, no token refresh.
Authentication →
03
Verify connectivity
Hit GET /health — no auth required. Returns { "status": "ok", "time": "…" }.
Health endpoint →
04
List your assigned brands
GET /catalog returns assigned brands with priced denominations. Pick faceValueInCents + currency for ordering. scope: catalog.read
Catalog reference →
05
Place an order
POST /orders with Idempotency-Key. One request issues one code; response includes issuedCode when status is ISSUED. scope: orders.write
Orders reference →
06
Check your balance
GET /wallet returns availableInCents, reservedInCents, and balanceInCents. Monitor balance to avoid 402 insufficient_funds. scope: wallet.read
Wallet reference →
02 — Core concepts

Auth and idempotency#

Two ideas to internalize before writing your first integration. The rest of the API follows from them.

Authentication

Static API keys in the format qrk_{test|live}_{opaque}. The key prefix selects your workspace — test keys route to sandbox, live keys to production. No code changes required to switch environments.

Source IPs must be on the allowlist registered with your account manager. Scopes (catalog.read, orders.read, orders.write, wallet.read) are bound to the key at issuance.

StatusMeaning
401Missing, invalid, revoked, or expired key (unauthorized)
403Source IP not on allowlist, or missing scope (forbidden)
402Wallet below required amount (insufficient_funds)
409Idempotency key in progress or rate card missing
422Out of stock, activation failed, or activation timeout
410Idempotency key expired (24 h TTL)
429Rate limited — check Retry-After

Idempotency & retries

POST /orders requires an Idempotency-Key header. Retrying with the same key and body replays the original response — the same issuedCode, the same wallet debit, exactly once.

If you receive 504 Gateway Timeout, retry the same request with the same idempotency key. Do not generate a new key until you intend a new order.

Pitfall. Don't regenerate the key inside your retry loop. Generate once when you decide to place the order, and reuse it for every retry of that order.
// keys are UUIDv4 strings
Idempotency-Key: 7c1d9a4f-2f9c-4e8b-9a3d-b06d24fe11ac
03 — Example

Place an order#

A complete request for one voucher. Use denominationInCents from GET /catalog; optional metadata stores your reconciliation tags.

04 — Endpoints

What you can call#

The full API surface — seven endpoints across catalog, orders, and wallet. Each links into the Scalar reference for schemas and try-it.

GET /health no auth
Liveness probe. Returns status and server time.
GET /catalog catalog.read
Paginated brands assigned to you, each with priced denominations (faceValueInCents, netCostInCents).
POST /orders orders.write
Place one voucher order (requires Idempotency-Key). Debits wallet synchronously; returns issuedCode on success.
GET /orders orders.read
Paginated order list. Filter by status, startDatetime, or endDatetime.
GET /orders/{orderId} orders.read
Fetch one order by id, including issuedCode when status is ISSUED.
GET /wallet wallet.read
balanceInCents, reservedInCents, and spendable availableInCents for your currency.
GET /wallet/transactions wallet.read
Append-only ledger (newest first). Filter by type, date range, or reference.

Ready to read the full reference?

Schemas, request/response examples, and a try-it console for every endpoint. Hosted on Scalar — bring your sandbox key.