Payments
What happens between checkout_url and orders/paid, the Idempotency-Key contract, and stores that collect through their own provider account.
Your integration never touches a payment. The Storefront API ends at checkout_url; Queek's
hosted checkout takes the shopper through address, delivery and payment; a
webhook tells you the order exists and then that it is paid. This page is what
happens in between, so you can reason about it — not a payment API to call.
The flow, from your side
you Queek checkout you
│ POST /store/cart/items │ │
│ POST /store/cart/validate │ │
│ redirect to checkout_url ──►│ │
│ │ order created ────── orders/create ►│
│ │ payment initialised │
│ │ shopper pays (redirect or inline) │
│ │ charge verified │
│ │ order finalised ────── orders/paid ►│
│ │ orders/updated ►│- Build the cart with
X-Cart-Session, thenPOST /store/cart/validateso stock and prices are current. Every cart reply carriescheckout_url. - Send the shopper to
checkout_url. Queek shows exactly this cart and creates the order once the shopper commits. Yourorders/createwebhook fires here; for an online paymentpayment_statusis not yetpaid. - Payment is initialised against the store's payment provider. Checkout either redirects the shopper to the provider's hosted page or drives the provider's inline widget — the shopper never sees a Queek card form, and neither do you.
- The charge is verified. Whatever door reports success — the provider's browser redirect, checkout's own verify call, the provider's webhook — is only a trigger. Checkout re-queries the provider for the transaction and requires the confirmed amount and currency to equal the transaction's before anything is marked paid.
- The order is finalised and
orders/paidfires (withorders/updatedalongside it).data.payment_statusis nowpaidanddata.payment_methodnames how.
Confirmation is idempotent on Queek's side: a redirect and a provider webhook confirming the
same reference finalise the order once. You will receive orders/paid once per order; dedupe
on webhook-id regardless.
Treat orders/paid as the fact
Do not fulfil on orders/create. An order can be created and never paid, and the shopper can
abandon the provider page. payment_status on orders/paid — or a later orders/updated
whose data.payment_status is paid — is the signal money arrived.
When the provider's answer does not match
If the provider confirms a charge whose amount or currency is not the transaction's, the order
is left unpaid and flagged for a human to reconcile. Checkout surfaces this as
409 payment_amount_mismatch; you will not receive orders/paid for that order until it is
resolved by the merchant.
Offline methods
A store may also accept bank transfer or cash, depending on its settings and the delivery
method. Such an order stays unpaid until the merchant confirms receipt, at which point
orders/paid fires exactly as above. Read data.payment_method if the distinction matters to
you.
Idempotency-Key
Idempotency-Key is the platform-wide retry contract for writes. An operation that honours it
lists the header as a parameter in the reference; send a fresh random
key per logical request and retry with the same key on a network failure, and the second
request cannot execute twice.
Which operations
In the current reference no storefront operation lists the header yet — the cart endpoints
are natural upserts and checkout_url hands the order itself to Queek. The header is optional
and additive everywhere: an operation that does not list it ignores it, so sending it costs
nothing and a future write that adopts it needs no change on your side.
curl -X POST https://client.usequeek.com/v1/<a write that lists the header> \
-H "X-Client-Key: sk_live_your_key_here" \
-H "Idempotency-Key: 7d3c4c1a-2c50-4c0f-8f0f-3a4d1a2b9c77" \
-H "Content-Type: application/json" \
-d '{ … }'The contract, exactly:
| Situation | Result |
|---|---|
| Same key, same body | The stored response is replayed byte for byte, with Idempotent-Replayed: true. |
| Same key, different body | 409 idempotency_key_reuse. The key already means something else. |
| Same key, two requests in flight | The second waits up to 15s for the first to finish, then replays it. Past that it is 409 idempotency_key_in_progress — retry in a moment; nothing ran twice. |
The first attempt failed (4xx/5xx) | Nothing is stored. A retry with the same key is a real retry. |
| 24 hours later | The stored response has expired; the same key starts a new request. |
The slot is store + caller + METHOD:path + key. The body is the fingerprint, not part of
the slot — which is what makes reuse with a different body a refusal rather than a silent
second execution. GET requests ignore the header; they are safe to retry as they are.
Collecting through the merchant's own account
By default Queek collects payments and settles the merchant. A store on an eligible plan, with identity verification complete, may instead collect straight into its own provider account — its own Paystack account today. The merchant enables this in the dashboard; there is nothing for you to configure.
What changes for an integrator is almost nothing:
- The provider's hosted page is served from the merchant's own account, so the shopper sees the merchant's identity with the provider rather than Queek's.
- Verification happens against the merchant's account, using the merchant's stored keys.
checkout_url, the webhooks,payment_statusandpayment_methodare identical.
The dashboard's own errors for this feature are named in the vocabulary — you may see them quoted by a merchant, never on this API:
error.code | Status | Cause |
|---|---|---|
custom_gateway_forbidden | 403 | Only the store owner can change where payments are collected. |
custom_gateway_plan_required | 403 | The store's plan does not include collecting into its own account. |
custom_gateway_kyc_required | 403 | Identity verification is not complete. |
custom_gateway_store_ineligible | 403 | A template or dev store cannot collect real payments. |
custom_gateway_not_verified | 409 | No provider account has been verified yet. |
custom_gateway_not_configured | 404 | The provider's keys have not been saved. |
custom_gateway_verification_failed | 422 | The saved keys did not pass the verification round-trip. |
Providers
| Provider | Status |
|---|---|
| Paystack | Live. Also the provider a merchant can connect as their own account. |
| Bank transfer, cash | Live, confirmed manually by the merchant. |
| Flutterwave, Bachs, Nomba, Stripe | Registered, not yet available. |
Which methods a given store offers is the merchant's setting and can change without notice.
Read data.payment_method on the order rather than assuming a provider.