curl --request GET \
--url https://api.pay.aptahq.com/v1/capabilities \
--header 'X-AptaPay-Signature: <api-key>'const options = {method: 'GET', headers: {'X-AptaPay-Signature': '<api-key>'}};
fetch('https://api.pay.aptahq.com/v1/capabilities', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.pay.aptahq.com/v1/capabilities"
headers = {"X-AptaPay-Signature": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text){
"code": 200,
"message": "OK",
"data": [
{
"capability": "collections",
"provider": "eversend",
"supported": true
},
{
"capability": "refunds",
"provider": "eversend",
"supported": false,
"reason": "Eversend exposes no refund endpoint; refunds are automatic on failed transactions only."
}
]
}{
"code": 200,
"message": "OK",
"data": "<unknown>",
"error": {
"code": "payout_rejected_by_provider",
"message": "<string>",
"terminal": true,
"retriable": true,
"ambiguous": true,
"details": {}
}
}What this tenant's providers can actually do
Ask what YOUR tenant can actually do before you build against it. Returns one row per capability — collections, payouts, refunds, fx, balances, reference data, bank resolution — naming the provider it routes to and whether it works.
The integration-time contract. Call it once at integration, not on every request: it tells you to build a refund button or not, whether FX is enabled for your account, which provider your traffic lands on. Ask BEFORE promising a user a refund, rather than discovering a 501 at the worst moment.
Each entry carries supported and, when false, a reason in plain language — “Eversend exposes no refund endpoint” rather than a bare false. Two different things make a capability unsupported: the provider genuinely lacks it, or your tenant is not permitted to use it. Both are reported here, so a 403 capability_not_allowed at runtime should never be a surprise.
curl --request GET \
--url https://api.pay.aptahq.com/v1/capabilities \
--header 'X-AptaPay-Signature: <api-key>'const options = {method: 'GET', headers: {'X-AptaPay-Signature': '<api-key>'}};
fetch('https://api.pay.aptahq.com/v1/capabilities', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.pay.aptahq.com/v1/capabilities"
headers = {"X-AptaPay-Signature": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text){
"code": 200,
"message": "OK",
"data": [
{
"capability": "collections",
"provider": "eversend",
"supported": true
},
{
"capability": "refunds",
"provider": "eversend",
"supported": false,
"reason": "Eversend exposes no refund endpoint; refunds are automatic on failed transactions only."
}
]
}{
"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
The capability matrix for this tenant.
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