Phoenix Pay
API Reference

Status Codes

Complete reference for HTTP status codes, payment statuses, and error responses.

HTTP Status Codes

Success Codes

StatusNameWhen Used
200 OKSuccessGET requests, step submissions
201 CreatedResource CreatedPOST requests that create a new deposit or withdrawal

Client Error Codes

StatusNameDescription
400 Bad RequestInvalid RequestMissing or invalid parameters. The error field describes what's wrong.
401 UnauthorizedAuthentication FailedMissing headers, invalid signature, unknown key ID, or stale timestamp (> 5 minutes).
403 ForbiddenInsufficient PermissionsValid signature but the API key doesn't have permission for this operation.
404 Not FoundResource Not FoundThe resource doesn't exist or belongs to a different tenant. Phoenix Pay doesn't distinguish these to prevent information leakage.
409 ConflictDuplicate ReferenceThe reference_id already exists for your tenant. The response includes the existing intent_id.
422 Unprocessable EntityProcessing ErrorThe PSP rejected the request. Response includes error code and message.
429 Too Many RequestsRate LimitedWait for the Retry-After header duration before retrying.

Server Error Codes

StatusNameDescription
500 Internal Server ErrorServer ErrorUnexpected error. Response: {"error": "internal_error"}.

Error Response Format

Standard errors:

Validation error
{
  "error": "missing required parameter: channel"
}

Duplicate reference (includes the existing intent for idempotent handling):

409 Conflict
{
  "error": "duplicate_reference",
  "intent_id": "01912e4a-7b3c-7def-8a90-1234567890ab"
}

PSP errors (includes a human-readable message):

422 PSP error
{
  "error": "insufficient_liquidity",
  "message": "PSP does not support this currency in your region"
}

Common Error Messages

Authentication Errors (401)

ErrorCauseResolution
"unauthorized"Missing X-Key-Id, X-Timestamp, or X-Signature headerInclude all three headers
"unauthorized"Invalid signatureVerify signing payload format: "{timestamp}.{body}"
"unauthorized"Stale timestampEnsure X-Timestamp is within 5 minutes of server time
"unauthorized"Unrecognized key IDUse a valid key ID from the admin dashboard

Validation Errors (400)

ErrorCause
"missing required parameter: reference_id"The reference_id field is missing or empty
"missing required parameter: amount"The amount field is missing or empty
"missing required parameter: currency"The currency field is missing or empty
"missing required parameter: channel"The channel field is missing or empty

Step Errors (409)

ErrorCause
"attempt_not_awaiting_input"Tried to submit a step for an attempt that isn't waiting for input

Payment Status Values

These are the possible values for the status field on intents (payments):

StatusDescriptionTerminal?
createdIntent recorded, first attempt may be in progressNo
pendingAt least one attempt active with PSPNo
completedPayment successfulYes
failedPayment failed or rejectedYes
expiredPayment window expiredYes

Terminal means no further status changes are possible. All subsequent update attempts are silently ignored.

Attempt Status Values

These appear in the timeline and represent individual PSP interaction states:

StatusDescription
initiatedAttempt created, PSP request in progress
awaiting_inputWaiting for user input (e.g., OTP)
pendingPSP accepted, awaiting confirmation
completedPSP confirmed success
failedPSP reported failure
expiredPayment window expired

Payment Types

ValueDescriptionAPI Route
depositInbound payment (customer pays you)/api/deposits
withdrawalOutbound payment (you pay a recipient)/api/payouts

The API route is /api/payouts but the type field in responses is "withdrawal".

PSP Identifiers

ValuePSPCapabilities
nowpaymentsNOWPaymentsCrypto deposits (crypto_address)
chapaChapaFiat deposits (checkout, ussd_push, otp) + withdrawals (direct_payout)

Channels

ChannelTypePSPDescription
crypto_addressDepositNOWPaymentsSend crypto to generated address
checkoutDepositChapaRedirect to hosted checkout page
ussd_pushDepositChapaUSSD push to mobile phone (Telebirr)
otpDepositChapaDirect charge with OTP verification (Telebirr)
direct_payoutWithdrawalChapaBank transfer or mobile money payout