Skip to main content
POST
Create a payment
Collects money into your own business balance. Where an onramp or offramp order moves value on behalf of one of your end users, a payment is you getting paid — a checkout, a subscription charge, a top-up. Paj hands you somewhere to be paid into, watches it, and credits your balance once the money lands. Nothing in the request names your business: the x-api-key header already does, and the payment is opened for whichever business the key belongs to.

Being paid on-chain

method defaults to TOKEN, so the common case is a short request:
amount is in whole units of the token — 25 means 25 USDC, not 25 base units. The response comes back with a token object holding the address to pay, which is reserved for this payment and no other. Token payments open on SOLANA and the five EVM chains — ETHEREUM, BASE, BSC, MONAD and ARC. TON is not supported for payments yet, even though it appears in the chain enum — a TOKEN payment on TON is a 400. Use TON for onramp and offramp orders only. Supported chains lists the USDC contract on each. Your balance is held in USDC. A payment in USDC is credited as it lands; a payment in any other token is swapped to USDC first, and the swap’s output is what is credited.
Send the token named in mint, on the chain named in chain, to that address and nothing else. A different token arriving at the address is not recognised as paying the payment, and recovering it is a manual process.

Being paid in fiat

Set method to FIAT and supply a currency, and the response carries a fiat object instead: a virtual account number, the account name, and the bank it sits with. Your payer transfers into it exactly as they would for an onramp order.
Fiat payments are collected but are not yet added to your business balance, which is denominated in USDC. Until the conversion is settled, use TOKEN for anything that needs to reach your balance automatically.

The platform fee

Paj charges a fee on each payment, currently 1% of amount, and adds it on top rather than taking it out. The response shows the split:
  • amount — what you asked for, and the share that reaches your balance.
  • fee — Paj’s share, in the same units. Absent when no fee applies.
  • totalAmount — amount plus fee, and what the payer must actually send.
Show your payer totalAmount, not amount. A payer who sends only amount has underpaid, and the payment settles for less than you asked — the fee is taken proportionally from whatever arrives, so a 25 USDC payment funded with exactly 25 credits you about 24.75.

The payment window

Every payment carries an expiresAt, 30 minutes out. Money that arrives inside that window settles normally; a payment that reaches its expiry unpaid moves to EXPIRED, and for on-chain payments the deposit address is released. That release is the reason the deadline matters. An address belonging to an expired payment is no longer being watched on that payment’s behalf, so tokens sent late are not credited automatically. Show the countdown to whoever is paying, and open a fresh payment rather than reusing an address once the first one lapses.

Following the payment

status starts at AWAITING. When a deposit is seen it becomes PROCESSING while the funds are swept into Paj’s pool, then SUCCESSFUL once that completes and your balance has been credited. EXPIRED and ERROR are terminal. You do not have to poll for that. Set a paymentWebhookURL on your API key and Paj POSTs the settled payment to it — the same body this endpoint returned, with status now SUCCESSFUL, so you can match it to the payment you opened by id. It is separate from the rampWebhookURL that carries onramp and offramp order updates, because the two payloads differ; a key can have one, both, or neither. If several of your keys name a payment webhook, each distinct URL is called. Any 2xx from your endpoint counts as delivered. Anything else — a 4xx, a 5xx, or a connection that never opens — is retried every 30 seconds, up to five attempts in total, after which the payment is left settled and the delivery is abandoned. Return a 2xx as soon as you have durably recorded the payment and do the rest of your work afterwards; a slow handler that eventually answers 500 costs you the next two minutes of retries. Retries live in the process that saw the settlement, so a deploy mid-window ends them. Treat the webhook as a prompt rather than a ledger, and let your own records be the authority. The credited amount follows what actually arrived, not what you asked for. If a payer sends 24.5 USDC against a payment whose totalAmount is 25.25, the payment settles for 24.5 and your balance is credited that less the fee — reconcile against the settled amount rather than assuming the requested one. Your balance accumulates across payments and is withdrawn from the Paj dashboard, not through this API.

Authorizations

x-api-key
string
header
required

Body

application/json
amount
number
required

Amount to collect, in whole units. Must be positive.

Example:

100

currency
enum<string>

Fiat currency to charge. Required when method=FIAT; ignored for TOKEN.

Available options:
NGN,
GHS,
TZS,
KES,
ZAR,
USD
chain
enum<string>

Chain to receive the token on. Required when method=TOKEN; ignored for FIAT.

Available options:
SOLANA,
MONAD,
ETHEREUM,
BSC,
BASE,
ARC,
ZCASH,
TON
mint
string

Mint/contract address of the token on the selected chain. Required when method=TOKEN.

Example:

"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"

method
enum<string>
default:TOKEN

How the payment is funded. Defaults to TOKEN, which issues a deposit address and requires chain and mint. FIAT issues a virtual account and requires currency.

Available options:
FIAT,
TOKEN

Response

The pending payment with funding instructions (fiat or token).

id
string
required

Payment id. Subscribe to live updates with it.

Example:

"507f1f77bcf86cd799439011"

method
enum<string>
required
Available options:
FIAT,
TOKEN
status
enum<string>
required
Available options:
INIT,
AWAITING,
PROCESSING,
SUCCESSFUL,
EXPIRED,
ERROR
amount
string
required

Requested amount, in whole units of the currency or token (the stored base units scaled back down by details.decimals).

Example:

100

totalAmount
string
required

What the payer must fund: amount plus any fee. Equal to amount when no fee was charged.

Example:

101

fee
number

Platform fee charged on top of amount, in the same units. Absent when the payment carries no fee.

Example:

1

expiresAt
string<date-time>

When the payment window closes.

fiat
object

Fiat funding details. Present when method=FIAT.

token
object

On-chain funding details. Present when method=TOKEN.