Skip to main content
Corridors and limits may change. Use the quote endpoint to validate amounts before confirming payouts.

Overview

LOCAL_BANK and LOCAL_MOMO let you settle to a local bank account or mobile money wallet in a supported corridor. Your payout is funded from your business USDC balance using a locked FX quote (quote → confirm). Jump to:

Supported corridors

19 destination countries are supported. LOCAL_BANK is available where we have local bank-transfer coverage; LOCAL_MOMO is available where the corridor has active mobile-money payout channels. Always confirm an amount with the quote endpoint before paying out — corridor and rail availability can change.
The West Africa (XOF), additional Central Africa (XAF), and DR Congo (CDF) corridors are mobile-money only — pay out with LOCAL_MOMO. Use GET /v1/business/payouts/networks?country=&rail=LOCAL_MOMO to list the available carriers/networks for the recipient before confirming.

Recipient shapes per rail

You can pay out in one of two ways. Both are fully supported — pick per payout, not per integration.
  • Saved recipient (3 calls): create a recipient with POST /v1/business/payouts/recipients, then reference it by recipientId on every payout. Best when you pay the same payee repeatedly. The create call is idempotent on the destination — sending the same rail and account details returns the existing recipient rather than a duplicate — so it is safe to call before every payout.
  • Inline recipient (2 calls): pass a recipient (or destination) object directly on POST /v1/business/payouts — no pre-created recipient needed. Best at high destination cardinality, where a saved recipient per payout is address-book noise.
Provide exactly one of recipientId, recipient, or destination on confirm; sending two is rejected with RECIPIENT_AMBIGUOUS. The inline recipient uses the same fields as the saved-recipient details object (shown below).
What happens to an inline recipient depends on how you authenticate.
  • Merchant API (x-api-key) — the inline recipient or destination is paid as an ad-hoc destination: Axra does not sanctions-screen it and does not save it, so the payout comes back with recipientId: null and there is nothing to reuse by id. Under your merchant agreement you are the obligated party for beneficiary screening. If you want a reusable id, call POST /v1/business/payouts/recipients first — the two-step flow works exactly as before.
  • Dashboard (user JWT) — the inline recipient is created, sanctions-screened, and saved to your recipient book, and a screening match is refused with 403.
A destination object on LOCAL_BANK / LOCAL_MOMO is accepted only on the x-api-key channel.

Get the network / bank list first

For LOCAL_BANK and LOCAL_MOMO, you must select an opaque upstream network identifier using: GET /v1/business/payouts/networks?country=NG&rail=LOCAL_BANK That endpoint returns a list of supported banks or mobile-money networks for the corridor. Use the returned id as:
  • bankCode for LOCAL_BANK
  • networkId for LOCAL_MOMO
Recipients are created with POST /v1/business/payouts/recipients. Use label to identify the payee in your dashboard.

Local bank (LOCAL_BANK)

bankCode is the id returned by GET /v1/business/payouts/networks?country=NG&rail=LOCAL_BANK.

Local mobile money (LOCAL_MOMO)

phoneNumber must be E.164 (e.g. +254712345678). networkId is the id returned by GET /v1/business/payouts/networks?country=CM&rail=LOCAL_MOMO.

Cross-currency quote → confirm flow

Local-rail payouts use a two-step flow to lock FX and fees:
  1. POST /v1/business/payouts/quote returns a signed quoteToken (valid for 60 seconds).
  2. POST /v1/business/payouts confirms the payout by passing quoteToken back, along with exactly one of a saved recipientId, an inline recipient object, or an inline destination.
If the quote is expired, invalid, or issued for a different business workspace, the create call fails. The quote is scoped to corridor + amount + business and carries no recipient, so a single quoteToken confirms any of the three destination shapes. Quoting first and only then deciding whether to use a saved or an inline destination is supported.

Quote and confirm (Node + Python)

Single-call payout with an inline recipient

Skip the separate recipient-creation call by passing the recipient inline on confirm. Exactly one of recipientId, recipient, or destination is required. On the x-api-key channel the inline recipient is paid as an ad-hoc destination — not screened by Axra, not saved, and the payout returns recipientId: null. See the note under Recipient shapes per rail.

Quote-token error codes

These codes can be returned when confirming a payout (POST /v1/business/payouts) with a quoteToken:
  • INVALID_QUOTE_TOKEN: Token is malformed or signature validation failed.
  • QUOTE_EXPIRED: Token is older than the 60-second TTL.
  • QUOTE_BUSINESS_MISMATCH: Token was issued for a different business workspace.
  • INSUFFICIENT_PAYOUT_LIQUIDITY: Liquidity is temporarily unavailable to settle the corridor.
  • TREASURY_FROZEN: Payouts are temporarily disabled for treasury safety checks.
  • PAYOUT_CORRIDOR_NOT_ENABLED: Your business is not enabled for this corridor.

Recipient error codes

  • RECIPIENT_REQUIRED: Neither recipientId nor an inline recipient / destination was provided.
  • RECIPIENT_AMBIGUOUS: More than one of recipientId, recipient, destination was provided. Send exactly one.
  • RECIPIENT_RAIL_MISMATCH: The inline recipient.rail does not match the payout rail.
  • RECIPIENT_NOT_FOUND: No recipient with that recipientId in this business workspace, or its rail differs from the payout rail.
  • QUOTE_RECIPIENT_COUNTRY_MISMATCH: The destination country does not match the country the quote was issued for.
  • 403 Recipient failed sanctions screening: Returned on the dashboard (JWT) channel only, for a recipient that matched a sanctions/PEP list. x-api-key requests are not screened by Axra and never receive this.

NG bank-name resolve (Nigeria only)

To validate an NG NUBAN and resolve the account-holder name: POST /v1/business/payouts/resolve-account Request:
Response:
This endpoint validates country="NG" and rejects other countries. Mobile money has no equivalent “name resolve” API.

Idempotency

idempotencyKey is required on POST /v1/business/payouts.
  • Reusing the same key returns the original payout record for that key.
  • Use a new key for every user-initiated payout attempt to avoid accidental deduping.

2FA threshold

The $10,000 USD-equivalent TOTP requirement applies only to interactive dashboard payouts. When a human initiates a payout at or above this amount from the Axra dashboard, a fresh TOTP code (twoFactorCode) is required, and a missing code returns 401 with code: "TWO_FACTOR_REQUIRED".
Server-to-server payouts (API key) are exempt from the 2FA gate. For programmatic payouts there is no interactive TOTP step at any amount — the controls are your secret API key and per-corridor velocity caps. You never need to send twoFactorCode from a server integration. Axra does not sanctions-screen destinations on this channel; under your merchant agreement beneficiary screening is your obligation.

Settlement webhooks

Local-rail payouts emit the same business payout events as other rails. Subscribe via Webhooks. Event types:
  • payout.initiated — payout accepted and ledger-debited (status CREATED).
  • payout.submitted — dispatched to the payout provider (status SUBMITTED).
  • payout.settled — funds delivered to the recipient (status SETTLED).
  • payout.failed — dispatch or settlement failed; the debit is reversed (status FAILED).
  • payout.cancelled — a CREATED payout was cancelled before dispatch (status CANCELLED).
  • payout.review — payout held for compliance/admin review (status PENDING_REVIEW).
The data.object of each event is the same shape as GET /v1/business/payouts/{id}.

Fee model

Merchants see only the aggregated total via GET /v1/business/psp-pricing. Rates are set per-merchant (your SLA), and the quote response includes the total Axra fee for the corridor.

Confirm payout (raw API)

After quoting, confirm with either a saved recipientId or an inline recipient object (exactly one). Saved recipient:
Inline recipient. Note the nested { label, rail, details } shape on the raw API — the SDKs accept the flat form shown above and map it for you, so copying the SDK shape into a raw request returns 400. On the x-api-key channel this is paid ad hoc: not screened by Axra, not saved, recipientId: null on the payout.
Full integration guides and webhook event reference will be expanded in a later docs release. For OpenAPI field-level detail, see the API Reference tab.