curl --request GET \
--url https://api.pay.aptahq.com/v1/reference/corridors \
--header 'X-AptaPay-Signature: <api-key>'const options = {method: 'GET', headers: {'X-AptaPay-Signature': '<api-key>'}};
fetch('https://api.pay.aptahq.com/v1/reference/corridors', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.pay.aptahq.com/v1/reference/corridors"
headers = {"X-AptaPay-Signature": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text){
"code": 200,
"message": "OK",
"data": "<unknown>",
"error": {
"code": "payout_rejected_by_provider",
"message": "<string>",
"terminal": true,
"retriable": true,
"ambiguous": true,
"details": {}
}
}{
"code": 200,
"message": "OK",
"data": "<unknown>",
"error": {
"code": "payout_rejected_by_provider",
"message": "<string>",
"terminal": true,
"retriable": true,
"ambiguous": true,
"details": {}
}
}The full country x currency x direction x method matrix
The lookup your UI renders its country and method pickers from. Returns every route the gateway supports as (country, currency, direction, method) rows — so you can grey out “bank transfer” for Rwanda instead of letting a user fill in a form that was always going to be refused.
Render only what actually works. Capability is per corridor, NEVER per country: Nigeria supports bank payouts but no momo; Rwanda momo but no bank; Tanzania neither, only wallet-to-wallet. Collection and payout coverage differ for the same country too — hence direction.
Served from the gateway’s own config, so it is fast and needs no provider capability. Contrast with GET /v1/reference/countries, which asks the provider live and covers payout delivery only. This endpoint is the broader, authoritative one for building a UI against; cache it and refresh on deploy.
FILTER ON active. This returns gated corridors too. A corridor with active: false is known to the gateway but refuses every charge, and several ship that way: Eversend documents its collection footprint in three places that disagree, so corridors named by one source and contradicted by another (CM, CI, TZ, BF) are seeded complete and gated off rather than guessed at. Rendering this list unfiltered puts countries in your picker that will fail with corridor_unsupported at charge time.
They are returned rather than hidden because active is a live config flag: a corridor can be enabled without a deploy, and a client that caches only the active subset would not notice. Read the flag, do not infer it from presence.
curl --request GET \
--url https://api.pay.aptahq.com/v1/reference/corridors \
--header 'X-AptaPay-Signature: <api-key>'const options = {method: 'GET', headers: {'X-AptaPay-Signature': '<api-key>'}};
fetch('https://api.pay.aptahq.com/v1/reference/corridors', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.pay.aptahq.com/v1/reference/corridors"
headers = {"X-AptaPay-Signature": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text){
"code": 200,
"message": "OK",
"data": "<unknown>",
"error": {
"code": "payout_rejected_by_provider",
"message": "<string>",
"terminal": true,
"retriable": true,
"ambiguous": true,
"details": {}
}
}{
"code": 200,
"message": "OK",
"data": "<unknown>",
"error": {
"code": "payout_rejected_by_provider",
"message": "<string>",
"terminal": true,
"retriable": true,
"ambiguous": true,
"details": {}
}
}Authorizations
v1={hex HMAC-SHA256} over the ten-field canonical string. Sent alongside X-AptaPay-Key, X-AptaPay-Timestamp and X-AptaPay-Nonce — all four are required. OpenAPI can only model one header per scheme, so the other three are described in the Authentication section above.
Response
Every known corridor, gated ones included — read active on each row rather than assuming presence means usable.
The single response envelope, used by EVERY endpoint so a consuming app parses one shape everywhere.
200
"OK"
Present on success. Shape varies per endpoint.
Machine-readable error classification. EXACTLY ONE of terminal/retriable/ ambiguous is true. laces_api inferred this from the HTTP status and got it wrong, stranding real money twice (2026-08-15, 2026-08-16). Branch on these booleans, never on the status code:
terminal -> the provider refused. Reverse the debit and tell the user. retriable -> safe to retry with the SAME Idempotency-Key. ambiguous -> the outcome is UNKNOWN. Do NOT reverse. Poll instead.
Show child attributes
Show child attributes