Accept XAF payments with one REST call.
A single endpoint creates a hosted-checkout intent. Redirect the customer, listen for the webhook, ship. No payment form to build, no terminal.
- Idempotency keys built in
- HMAC-SHA256 webhook signatures
- Sandbox keys with simulated wallets
- Test → live in one secret swap
curl -X POST https://api.quatapay.com/api/v1/gateway/sandbox/payments \
-H "Authorization: Bearer qpay_test_…" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"amount": 5000,
"currency": "XAF",
"customer_reference": "order_12345",
"return_url": "https://shop.example.com/pay/return"
}'
# → 201
{
"success": true,
"data": {
"payment": {
"id": "pay_01HZ9X...",
"status": "requested",
"slug": "abcd1234"
},
"checkout_url": "https://quatapay.com/checkout/abcd1234"
},
"error": null
}REST
API style
JSON over HTTPS
60 / 60 s
Rate limit
Per API key and route
5
Webhook attempts
5 s timeout each
v1
API version
Path-versioned: /api/v1
Why us
Designed by engineers who got tired of payment APIs.
Every choice here was made because the alternative wasted somebody's afternoon.
Single source of truth
One JSON envelope on every response: `{ data, error, code }`. No bespoke field names per endpoint.
Idempotency keys
Send a UUID in `Idempotency-Key` on every POST. Replays return the cached response — never double-charge.
Signed webhooks
HMAC-SHA256 with your endpoint secret. Reject anything that doesn't match. Failed deliveries are retried up to 5 times.
Test/live key prefixes
`qpay_test_…` and `qpay_live_…` — impossible to ship sandbox keys to prod by accident.
Sandbox wallets
Test mode runs against sandbox data, with no real money involved.
Hosted checkout
We host the checkout page, so you build no payment form.
How it works
Three calls. That's it.
1. Create intent
POST /api/v1/gateway/payments with amount + currency + your order reference. We return a checkout URL.
2. Redirect customer
Send them to the checkout URL. They confirm in the QuataPay app or pay via mobile money. We bring them back to your success / cancel URL.
3. Listen for webhook
We POST to your endpoint on payment.succeeded / .failed / .refunded. You verify the signature and fulfil the order.
Reliable delivery, every time.
Webhooks are signed with HMAC-SHA256 over a timestamp and the body. If your endpoint does not answer 2xx within 5 seconds, we retry after 1 minute, 5 minutes, 30 minutes and 2 hours (five attempts in all) — and every attempt shows in your delivery log so it doesn't get lost.
- Event types: payment.* / refund.* / settlement.* / dispute.*
- Up to 10 endpoints per merchant — fan out to backend, analytics, ops Slack
- Replay any past event from the merchant panel
POST /webhooks/qpay HTTP/1.1
Host: shop.example.com
X-QuataPay-Timestamp: 1791370800
X-QuataPay-Signature: sha256=a3f1c0…
Content-Type: application/json
{
"event": "gateway.payment.succeeded",
"data": {
"id": "pay_01HZ9X...",
"customer_reference": "order_12345",
"amount": 5000,
"currency": "XAF",
"status": "succeeded"
}
}The toolkit
Everything a payment integration actually needs.
API reference
Every endpoint, every field, with examples in cURL, JS, Python, PHP.
ReadSandbox
Test keys + simulated wallets. Fund / drain / reset from the merchant panel.
ReadCode examples
Drop-in snippets for Node, Python, PHP. Includes webhook verification + idempotency loops.
ReadWebhook guide
Event types, signature verification, retry policy, debugging tips.
ReadBase URL + environments
Sandbox vs production endpoints, IP allow-listing, TLS requirements.
ReadAuth + access tokens
API keys, Bearer tokens, JWT access tokens for user-side calls, rotation.
ReadBuild today
Test with sandbox keys.
Create a merchant account, grab a test key, charge a simulated payment. No KYC required for sandbox.