Error handling
Understand error responses and how to react to them.
Errors share one shape, and the HTTP status tells you what kind of problem occurred:
{
"status": "error",
"message": "Could not find the account.",
"timestamp": 1793404800000
}Show message to developers, not end users, and don't match on its exact wording because it can change.
Status codes
| Status | Meaning | What to do |
|---|---|---|
200, 201 | Success | Read data |
400 | The request could not be completed, or a record was not found | Read message and fix the request |
401 | The key is missing, invalid, or expired | Check your key |
403 | The key is not allowed | Check message, your IP allowlist, and your modules |
404 | The record or route does not exist | Check the ID and the environment |
409 | The merchant_reference was already used with different data | Use a new reference, or resend the original request |
422 | One or more fields are invalid | Fix the fields listed in errors |
429 | You hit the rate limit | Wait for Retry-After, then retry |
500 | Payinto or a provider failed | Query the status, then retry if it's safe |
A status to watch
Several lookups, such as GET /customers/{id}, return 400 rather than 404 when a record doesn't exist.
Validation errors
A 422 lists each invalid field under errors:
{
"status": "error",
"message": "One or more of the given data has an error.",
"errors": {
"account_number": ["The account number field must be 10 digits."]
},
"timestamp": 1793404800000
}Retrying money movement safely
A timeout or a 500 doesn't tell you whether the money moved. Never retry a payment blindly.
Send a merchant_reference with every transfer and bill payment.
If the request fails with a timeout or a 500, call GET /transactions/tsq/{reference} with your merchant_reference.
If the transaction exists, use its status. If you get 404, retry with the same merchant_reference and the same payload.
Repeating a merchant_reference is safe because Payinto returns the original result instead of paying twice.
Transaction statuses
GET /transactions/tsq/{reference} returns one of these in data.status:
| Status | Meaning |
|---|---|
pending | Still processing. Check again later, or wait for a webhook. |
successful | Complete. |
failed | Did not complete. |
reversed | Completed and later reversed. |