Get started
Authentication
Send your API token on every request. The header form is preferred, because a token in a query string ends up in proxy and web-server access logs:
curl -H "X-Api-Token: <your-token>" \
"https://apipe.in/api/corp/v1/balance"Two transports are accepted, in this order of preference:
X-Api-Token: <token>— recommendedAuthorization: Bearer <token>
IP allowlist
Your account is restricted to the source IP addresses you register with us (individual addresses or CIDR ranges). A call from anywhere else is refused with result code 2428. Tell us before you change egress addresses, or your traffic stops.
Rate limit
Requests are capped per minute per account, in two budgets: every GET (status checks, balance, lists) has its own, never larger than your account's limit, so checking statuses never uses up the budget of your money calls. Exceeding a budget returns 429 with result code 123; retry after a short pause.
To follow a pending transaction, check it first about 30 seconds after the reply, then once a minute — or let the callback tell you.
Request signing
Not needed: every recharge call works with your API token alone. If you would rather sign your requests, the Full API docs show how; a signature you send is checked.
Errors
A refusal of your credentials — the token, the signature or the source IP — carries a real HTTP status plus a body like:
{
"status": "rejected",
"error": "ip_not_allowed",
"code": 2428,
"message": "IP Validation failed."
}A new recharge, bill payment, bus booking or money transfer refused for an account or service reason — the service is not switched on for your account; the account is paused, inactive, or waiting on KYC or the service agreement; your wallet is suspended; the service or the recharge operator is switched off; or the service is closed for the night — answers HTTP 200 with "ok":false, "status":"failed", the reason in error and message, and an empty order_id. It has the same fields on every service. Nothing was created and nothing was charged: file it with your other failures. Your own urid or request_id is echoed back.
{
"ok": false,
"status": "failed",
"code": 331,
"order_id": "",
"urid": "ABC123",
"operator_ref": null,
"amount": "100",
"account": "9876543210",
"balance": null,
"message": "Your KYC is not verified yet. Complete it in the client portal before transacting.",
"error": "kyc_not_verified"
}On POST /recharge, the refusals the recharge endpoint gives itself — recharge not switched on for your account, your wallet suspended, the operator or recharge switched off, a daily limit — come back as an ordinary failed recharge: the same fields as any recharge reply (no ok or error), "status":"failed", an empty order_id and the reason in message.
These requests do not get "status":"failed", because it would describe a transaction that already exists:
- A
GET(a status check) and aPOSTto/complaints. For an account reason they getHTTP 403with"status":"rejected", as before. - A retry of a reference that already has a transaction (a
urid,request_id, transferref,block_refor billfetch_refwe have already acted on). On recharge, a retry with the same details gets that transaction's own result, like any retry: when recharge is switched off for your account, and also while your account is paused, inactive, or waiting on KYC or the service agreement (then withbalancenull). Otherwise an account reason, or a service not switched on for your account, answersHTTP 403with"status":"rejected". On bill payments, bus and money transfer, any other refusal of a retry comes back as that service's own error reply, with a4xxor503HTTP status anderrorandmessage. Look the transaction up by its reference. Status checks stay open when a service is switched off for your account; while the account itself is refused they are refused too, until it is restored.
Any other refusal — a mistake in the request, a duplicate, not enough balance — keeps its 4xx status: "status":"rejected" on recharge, the service's own error reply elsewhere.