Touba Group

Partner API v1

Sell hotspot vouchers from your wallet or bank app.

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.

Authentication

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.

Endpoints

GET /api/v1/locations?q= areas a customer can buy in
GET /api/v1/locations/{id}/hotspots who sells there
GET /api/v1/hotspots/{id}/bundles price, validity, live stock
POST /api/v1/orders reserve one code · 90s TTL
POST /api/v1/orders/{ref}/fulfil idempotent → returns the code
POST /api/v1/orders/{ref}/cancel release the reservation
GET /api/v1/settlements?period= what you owe each hotspot
GET /api/v1/payouts/unsettled balance owed, per hotspot, right now
POST /api/v1/payouts build a settlement run for a period
POST /api/v1/payouts/{id}/submit send a draft to your approvers
POST /api/v1/payouts/{id}/approve approve — required before paying
POST /api/v1/payouts/{id}/paid record the transfer reference
POST /api/v1/payouts/{id}/reverse undo a payment; sales return to the pool

The buying flow

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.

Paying the hotspots

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.

Edge cases you must handle

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.

Want test keys?

The platform team issues a key pair on the test deployment in minutes.

Talk to the platform team