Accept XAF payments with one REST call.
A single endpoint creates a hosted-checkout payment. Redirect the customer, listen for the webhook, ship. No payment form to build.
- Idempotency keys on payment creation
- HMAC-SHA256 webhook signatures
- Test keys and a simulate call for test payments
- Test → live: swap the key, the path follows its prefix
curl -X POST https://api.quatapay.com/api/v1/gateway/sandbox/payments \
-H "Authorization: Bearer $QUATAPAY_API_KEY" \
-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": "3f2b8c1e-5d7a-4e0b-...",
"status": "requested",
"slug": "Xb3kP0qLm7Rt2VwY9cZa4Hn1"
},
"checkout_url": "https://quatapay.com/checkout/Xb3kP0qLm7Rt2VwY9cZa4Hn1"
},
"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: `{ success, data, error, code }`. No bespoke field names per endpoint.
Idempotency keys
Send a UUID in the `Idempotency-Key` header when you create a payment. Replays return the first response — never a second payment.
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.
Test mode
Test keys run against test data with no real money. Finish a test payment with one simulate call.
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 gateway.payment.succeeded / .failed / .cancelled / .expired. 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.
- Payment events: gateway.payment.succeeded, .failed, .cancelled, .expired
- Register several endpoints — 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 and field, with examples in cURL.
ReadSandbox
Test keys, the simulate call, and a throwaway sandbox wallet in the merchant panel.
ReadCode examples
Drop-in snippets for Node, Python and PHP, with webhook verification.
ReadWebhook guide
Event types, signature verification, retry policy.
ReadBase URL, test and live
One base URL, how test and live are told apart, versioning.
ReadAuth + access tokens
API keys and Bearer tokens, rotation, user access tokens.
ReadBuild today
Test with sandbox keys.
Create a merchant account, grab a test key, run a simulated payment.