Skip to main content
POST
Create a payout
The fields above are what you encrypt, not what goes on the wire. The body is always { "data": "<aes-256-gcm ciphertext>" } — see Authentication.
The recipient is identified one of two ways, never both: pass beneficiary_id for a saved recipient, or the full corridor plus recipient_details inline. Sending both is a validation error, not a merge.

Example request

All examples assume you’ve already encrypted the body and signed the request — see the Quickstart for the full helper in Node and Python.

Recipient details

The shape of recipient_details depends on payment_method. Every method requires name (the recipient’s full name, max 200 chars). Additional fields per method are listed below.

imps / rtgs / neft — India bank transfer (INR)

For payment_method: "imps", send the following inside recipient_details. The API picks the underlying rail (IMPS, RTGS, or NEFT) automatically based on the amount and bank availability. Decrypted request body:
If any required field is missing or malformed, the API responds with HTTP 400 and a structured validation_error pointing at the offending field — for example:

Reading the outcome

pending_approval is not a failure. It means the amount exceeds your auto-approval limit and a human on your account has to release it. The payout proceeds normally once they do. A 422 means a business rule refused the payout, and the code tells you which: Of these, only rate_moved is worth retrying automatically. The rest need something to change first. A 404 is no_route — that country/currency/method combination is not enabled on your account. Full code list in Errors.

Sandbox tip

In sandbox, the trailing cents of source_amount decide the eventual status — see Sandbox.

Authorizations

x-api-key
string
header
required

Identifies your account. Issued from Developer Tools in the dashboard.

Authorization
string
header
required

Short-lived token from /api/v1/user/login, bound to your account and mode. Expires in 900 seconds.

Headers

x-timestamp
integer<int64>
required

Unix epoch in seconds — not milliseconds. Must be within ±5 minutes of our clock, which is what makes a captured request unusable later. Keep your client's clock NTP-synced.

Example:

1748023400

x-signature
string
required

HMAC-SHA256 over the signing string, hex encoded. The timestamp is part of what is signed, so a replayed body cannot be re-dated. See https://docs.pontisglobe.com/authentication for how it is built.

Example:

"2f8a9b4c1d7e0a3f6b8c2d5e9f1a4b7c0d3e6f9a2b5c8d1e4f7a0b3c6d9e2f5a"

Body

application/json
idempotency_key
string<uuid>
required
source_amount
string
required

A positive decimal string. Never send a float — precision is the whole point, and a JSON number cannot hold these exactly.

Pattern: ^\d+(\.\d+)?$
Example:

"250.00"

source_currency
string
default:USDT

Send this explicitly rather than relying on the default. The supported set grows; code written against it keeps working.

Required string length: 2 - 8
purpose_of_payment
string
Maximum string length: 200
source_of_funds
string
Maximum string length: 200
beneficiary_id
string<uuid>

Beneficiary mode. Mutually exclusive with the fields below.

country_code
string
Required string length: 2
Example:

"NG"

currency_code
string
Required string length: 2 - 8
Example:

"NGN"

payment_method
string
Required string length: 1 - 32
Example:

"bank_local"

payment_network
string
Maximum string length: 32
recipient_details
object

Per-corridor fields, plus name. Required fields vary by corridor — do not assume a fixed recipient shape.

Response

Payout accepted.

ok
enum<boolean>
Available options:
true
data
object