Confirm Off-Ramp Checkout
Confirm a pending off-ramp by selecting a payout account (called by the checkout UI).
Confirms a PENDING off-ramp created via Initiate Off-Ramp Checkout by attaching the customer's chosen payout account. On success the transaction moves to INITIATED and the response contains the receiver crypto address the customer sends funds to.
You usually do not call this endpoint. The IvoryPay hosted checkout calls it on the customer's behalf after they authenticate and pick a payout account. It's documented here so you understand the lifecycle, and for the case where you build your own checkout UI on top of the API.
Endpoint
POST /v1/offramp/:reference/checkout/confirm:reference is the reference returned by checkout/initiate.
Authentication
Protected by HybridCheckoutHTTPAuthGuard — accepts customer JWT (standard), business-user JWT, or merchant API key. Under a customer JWT the off-ramp is scoped to that customer. See Customer authentication.
Prerequisite — a saved payout account
The customer must have a saved bank / mobile-money account whose type and currency match the off-ramp. Accounts are created via Customer Bank Accounts:
Off-ramp fiatCurrency
Required account type
Required fields when adding
NGN, ZAR, USD
BANK_TRANSFER
accountNumber, bankCode, accountName
UGX, GHS, KES, …
MOBILE_MONEY
accountNumber (E.164 phone), operator
The bankAccountId passed below is the id of one of those saved accounts.
Request body
bankAccountId
string (UUID)
Yes
ID of one of the customer's saved bank / mobile-money accounts. Its currency must match the off-ramp's fiatCurrency.
Example request
Example response
Returns 200 OK. The transferDetails now include the receiver address and session.
For mobile-money payout accounts, accountNumber is the E.164 phone number and bankCode carries the mobile-money operator (e.g. MTN_MOMO_UGA). For bank-transfer accounts these are the bank account number and bank code.
Response fields
firstName, lastName, email
string
Customer identity
refCode
string
IvoryPay's customer reference
reference
string
Your transaction reference
transferDetails.token
string
Token the customer sends
transferDetails.blockchain
string
Source blockchain
transferDetails.amountPayable
number
Crypto the customer must send
transferDetails.walletAddress
string
Receiver address — the customer sends crypto here
transferDetails.expiresAt
string
ISO 8601 expiry of the send window
transferDetails.sessionId
string
Settlement session id
transferDetails.duration
number
Session duration in seconds
transferDetails.businessFee / platformFee
number
Fees
transferDetails.fiatAmount
number
Fiat the customer receives
transferDetails.fiatCurrency
string
Payout currency
transferDetails.accountName
string
Payout account holder name
transferDetails.accountNumber
string
Bank account number, or E.164 phone for mobile money
transferDetails.bankCode
string
Bank code, or mobile-money operator
transferDetails.bankName
string
Bank / mobile-money provider name
transferDetails.status
string
INITIATED after a successful confirm
transferDetails.receivedToken / receivedCryptoAmount
nullable
Populated once the customer's crypto is received
transferDetails.failureReason
nullable
Set if the transaction later fails
Getting a customer JWT
Same flow as on-ramp:
POST /v1/auth/customer-twofactor— body{ "email": "...", "context": "LIVE" }.POST /v1/auth/customer-twofactor/verify— body{ "token": "123456" }→data.jwt.accessToken.
Send it as Authorization: Bearer <accessToken>.
Errors
401 CUSTOMER_CONTEXT_REQUIRED
No customer context on the confirm call
404 OFFRAMP_NOT_FOUND_OR_CONFIRMED
No PENDING off-ramp matches this reference for the caller
404
bankAccountId doesn't belong to the customer or isn't active
400 BANK_ACCOUNT_CURRENCY_MISMATCH
Saved account currency ≠ off-ramp fiatCurrency
403 CUSTOMER_KYC_REQUIRED
KYC re-check failed
Related
Last updated