Skip to main content
All ABCMPay API requests are authenticated with two headers, sent on every request:
You’ll find both on your API Keys page in the merchant dashboard.
Your secret key must never be exposed in client-side code (a mobile app, a browser script). Every ABCMPay endpoint is a server-to-server call — make requests from your backend only.

Example request

IP allowlisting (optional)

If you turn on IP allowlisting for your account, requests from any other IP are rejected with IP_NOT_WHITELISTED — even with a valid key and secret. Leave it off if you call the API from infrastructure with unpredictable outbound IPs (most serverless platforms).

Errors

See the full error reference for every code the API can return.

Reference vs. transaction ID

Two different fields show up throughout the API and in webhooks, and what reference means depends on which endpoint or event you’re looking at — it is not always yours, and it is not always unique. transaction_id (also returned as order_no) is the one field that’s always ours, always unique, and always safe to key duplicate-detection off.
string
Always ours, always unique. ABCMPay’s own internal identifier for the transaction, generated server-side on every transaction type. This is the value to store for reconciliation and to use as your idempotency/duplicate-detection key — it never repeats and never changes across webhook retries of the same payment.
string
Depends on the endpoint:
  • Payouts — yours. An optional value you pass when creating a payout; if you don’t pass one, we generate one. Unique either way.
  • Collect Payments (checkout) — ours. We generate this when the payment link is created; you never supply it.
  • Virtual account payments (the payment.received webhook) — the payer’s bank transfer narration, exactly as their bank sent it. Free text, not chosen by you or by us, and not unique — two different payments can carry identical narration text. See the webhook payload for detail.
Because its meaning changes by context, treat reference as a display/lookup convenience only, never as a duplicate-detection key — use transaction_id for that in every case.