Documentation
The BoundlessPay API
Accounts, collections, payouts, FX, cards, payroll and treasury over one REST API. Version 2026-08-29, 153 endpoints across 21 products.
Quickstart
Your first authenticated call in a few minutes.
API reference
Every endpoint, parameter, response and error code.
Webhooks
Subscribe to events and verify signatures.
Changelog
What changed, and when.
Base URL
https://business.boundlesspay.com/api/public/v1One secure, versioned API over the same services that power the BoundlessPay Business Suite.
- Money is always a decimal string, never a float.
- Timestamps are ISO 8601 UTC.
- Every response carries a
request_id. - Every financial POST requires an
Idempotency-Key. - Errors follow RFC 9457 problem details.
Checkout notifications
Register an endpoint (POST /v1/webhook-endpoints) and BoundlessPay posts a signed JSON body every time a checkout page changes:
| Event | When it fires |
|---|---|
checkout_session.created | The payment request was opened and the payer can pay. |
checkout_session.pending | The first money against this checkout was seen. |
checkout_session.partially_paid | A further amount landed and the total is still short. |
checkout_session.underpaid | The countdown ran out with less than the full amount. |
checkout_session.paid | The total received reached the amount requested. |
checkout_session.expired | The countdown ran out with nothing received. |
checkout_session.cancelled | You cancelled the payment request. |
Every body carries the checkout: id, object, status, method, currency, amount_minor, paid_amount_minor, outstanding_amount_minor, reference, expires_at, paid_at, deposit_id, metadata, and on a settling event surplus_minor and payments (the number of part payments).
Verifying the signature
Each delivery carries BoundlessPay-Signature: t=<unix seconds>,v1=<hex> where v1 is HMAC-SHA256 of `${t}.${rawBody}` using the endpoint secret returned once at creation. Compare with a timing-safe check, and reject anything older than five minutes to stop replays.
import { createHmac, timingSafeEqual } from 'node:crypto'
export function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')))
const age = Math.abs(Date.now() / 1000 - Number(parts.t))
if (!parts.t || !parts.v1 || age > 300) return false
const expected = createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex')
const a = Buffer.from(expected), b = Buffer.from(parts.v1)
return a.length === b.length && timingSafeEqual(a, b)
}
Handle deliveries idempotently on the event id: an endpoint that times out is retried.
Embedding the checkout
Create the session on your server, then either send the payer to checkout_url, or embed it:
<div id="pay"></div>
<script src="https://business.boundlesspay.com/checkout.js"></script>
<script>
BoundlessPayCheckout.mount({
sessionId: 'chk_9f2b1c7a4d',
container: '#pay',
onStatus: (s) => console.log(s.status, s.outstandingAmountMinor),
onSuccess: () => location.assign('/thank-you'),
})
</script>
Omit container for a modal. The widget never sees an API key. The frame shows your business name and logo, and may only be framed by domains you have verified in the Suite — anything else is refused by the browser.
Part payments
A checkout is marked paid only once the total received reaches the amount requested. Anything less stays open and keeps accepting more, each arrival appended to payments. Overpayment is paid with the surplus recorded, never silently swallowed.
Getting access
API access is granted per business through the Suite, not by self-service key creation.
- In the Suite, open Developer → Request API access and complete the intake questionnaire (legal identity, ownership, business model, products, corridors, expected volumes, funds flow, settlement model, licensing, data handling, downstream merchants and risk indicators).
- We score the application, assign a risk tier and generate your agreement pack from versioned templates. You review each document in the app, consent, and sign the pack once.
- Compliance, commercial and legal each approve, then the pack is countersigned and sealed. Executed copies, each with its SHA-256 fingerprint, stay downloadable in the document room.
- Sandbox keys (
bp_test_) are issued once the minimum KYB checks pass and the pack is executed. Live keys (bp_live_) are issued after full approval and integration readiness (a verified webhook endpoint, an IP allowlist, and at least one successful sandbox call per product).
Only the products approved on your application are enabled. Calling a scope outside them returns PRODUCT_NOT_ENABLED; calling a live endpoint with a test key (or the reverse) returns ENVIRONMENT_MISMATCH. Approved products also switch on the matching Suite modules automatically — anything your account team set by hand always wins and is never reversed.
Countries and currencies
We onboard globally. A small list of comprehensively sanctioned countries is refused everywhere — in onboarding, in customer and cardholder records, and in payouts — with COMPLIANCE_BLOCKED. That list is reconciled against the official sanctions register and only changes when a compliance officer approves the change, so treat it as data to read from errors rather than a fixed constant to hard-code.
Balances and accounts can be held in NGN, USD, GBP, EUR, CAD, GHS, KES, ZAR and CDF, plus USDT, USDC and cNGN (cNGN is opt-in per business). Payouts reach considerably further: call GET /v1/transfers/corridors for the live list of destination countries, currencies and rails available to your business — coverage is resolved per corridor at request time, so the corridor list is the only authoritative answer.
Naira virtual accounts are issued in the legal name of the business that owns them.
Cards over the API
POST /v1/cards issues virtual and physical cards. Single-use (disposable) cards are currently available in the Suite only and are not yet exposed here; they will appear as a third card_type value when they are.
Card issuance is never fire-and-forget: if the issuer has accepted the request but not yet confirmed the card, the call fails with PROVIDER_UNAVAILABLE and you retry with the same Idempotency-Key. Retrying that way can never produce a second card.
Guides
AI agents
Connect an agent with scoped tools, revocable access, human approvals, and audit trails.
Quickstart
Make your first authenticated call against the sandbox in a few minutes.
Authentication
Bearer keys, key rotation, IP allowlists and request signing.
Environments
How sandbox and live differ, and how to move between them.
Idempotency
Safe retries for anything that creates or moves value.
Pagination
Cursor paging over list endpoints.
Errors
The problem-details error shape and every error code.
Rate limits
Per-key limits, the headers to watch and how to back off.
Webhooks
Subscribing to events, verifying signatures and handling retries.
Going live
The readiness checklist before live keys are issued.
