Status values
| Status | Meaning | Terminal? |
|---|---|---|
requested | Created, awaiting the customer | No |
processing | The customer started paying; a Mobile Money prompt or wallet approval is pending | No |
succeeded | Paid; the money is in your QuataPay wallet | Yes |
failed | The payment failed for good (for example the Mobile Money prompt was refused) | Yes |
cancelled | The customer or you cancelled it | Yes |
expired | Reached expires_at unpaid. If MTN confirms a Mobile Money payment after expiry, it becomes succeeded | Yes, with that one exception |
There is no pending or refunded payment status.
GET a single payment
Use the payment's id (data.payment.id from creation), not its slug. A test key reads test payments on the sandbox path; a live key reads live payments.
GET https://api.quatapay.com/api/v1/gateway/payments/3f2b8c1e-5d7a-4e0b-9a61-2c4d8e7f9a10
Authorization: Bearer qpay_live_xxx
(test key: /gateway/sandbox/payments/{id})
→ 200
{
"success": true,
"data": {
"id": "3f2b8c1e-5d7a-4e0b-9a61-2c4d8e7f9a10",
"slug": "Xb3kP0qLm7Rt2VwY9cZa4Hn1",
"mode": "live",
"status": "succeeded",
"amount": 1500,
"currency": "XAF",
"customer_reference": "order_12345",
"payment_method": "momo",
"completed_at": "2026-10-28T13:24:09Z",
"completed_transaction_id": "b81e…",
"metadata_json": { "cart_id": "c_981" },
...
},
"error": null
}You send metadata when you create a payment and read it back as metadata_json. A payment that is not yours, or is in the other mode, is 404.
List recent payments
GET /api/v1/gateway/payments?status=succeeded&limit=50 returns your newest payments first (limit 1 to 200; sandbox: /gateway/sandbox/payments). It filters by status only.
Polling vs. webhooks
Webhooks are the recommended pattern. Poll only for a status screen the customer opens, or as a safety net for orders still unpaid after a while, and never faster than the rate limit allows (60 requests per 60 seconds per key and endpoint).