Partner API v1
Seven endpoints. Reserve a voucher, take the customer's money, fulfil to get the code. Everything is idempotent, every response is JSON, and stock is always real.
Every request carries your API key and an HMAC-SHA256 signature over the timestamp, method, path and raw body. Timestamps more than 300 seconds off are rejected.
X-Api-Key: hk_…
X-Timestamp: 1755691200
X-Signature: hex_hmac_sha256(
"{timestamp}.{METHOD}.{path}.{body}",
api_secret
)
The test deployment behaves identically, so you can run the full flow before you are issued keys on production.
1 · Show bundles
GET /api/v1/locations GET /api/v1/locations/3/hotspots GET /api/v1/hotspots/7/bundles
2 · Reserve, then charge
POST /api/v1/orders
X-Idempotency-Key: wv-8842190
{ "bundle_id": 12 }
→ reserved_until (90s)
→ debit the customer now
3 · Fulfil
POST /api/v1/orders/{ref}/fulfil
→ { "voucher": { "code": "33943695" } }
Retry with the same ref if you
did not get the response.
You hold the customer's money, so you settle each hotspot. Do it from the console, or run the same state machine over the API. Nothing moves without an approval, and every step is reversible.
1 · Build the run
POST /api/v1/payouts
{
"from": "2026-08-10",
"to": "2026-08-16",
"idempotency_key": "wk33"
}
→ one draft payout per hotspot
→ retrying the key returns the same run
2 · Approve
POST /api/v1/payouts/91/submit POST /api/v1/payouts/91/approve → state: approved Set your account to automatic and runs arrive pre-approved, with an optional amount threshold that still stops for a human.
3 · Pay and record
POST /api/v1/payouts/91/paid
{ "reference": "WAVE-8842190" }
→ state: paid
→ the hotspot sees the reference
Wrong account?
POST /api/v1/payouts/91/reverse
draft
Built, editable, not visible to the hotspot as money on the way.
awaiting_approval
A second person has to approve. In the console the preparer cannot.
approved
Cleared to pay. This is the only state POST /paid accepts.
paid · failed · void
Paid is final unless reversed; failed can be retried; void releases the sales.
Stock ran out mid-payment
The reservation expires, so void the authorisation before capture and show “try another bundle”.
Payment succeeded, delivery failed
The code stays reserved against that order — retry fulfil with the same reference. Never issue two codes for one payment.
Customer lost the code
Keep it in wallet history. We keep the mapping; the operator never sees the code.
Batch deactivated
Grey the bundle out immediately — a webhook tells you, and bundle listings drop it.
Suspended hotspot
Orders return 409 batch_unavailable. Refresh the hotspot list.
Signature errors
401 with an error code: missing_signature, stale_timestamp or invalid_signature.
Double settlement
A sale can only ever belong to one payout. Build with an idempotency_key and retries are free.
Paid the wrong account
POST /reverse with a reason: the payout closes as reversed and its sales return to the unsettled pool for the next run.
Transfer bounced
POST /failed keeps the payout attached to its sales so you can fix the account and pay again.
The platform team issues a key pair on the test deployment in minutes.
Talk to the platform team