Prerequisites
Your program must be configured with theRETAIN routing policy.
The routing policy determines what happens to funds when they arrive in a balance, and it is set during enrollment:
RETAIN— deposited funds stay on the balance until you move them. This is what makes manual withdrawals possible.SWEEP— deposited funds are automatically forwarded to a preconfigured credit instrument. Meridian initiates the withdrawal for you, so there is nothing to trigger manually.
routing_policy entry in the Information Request during onboarding:
- an enrollment in
ACTIVEstatus — see Onboarding your customer - an access token for the program context, with the
transactions:createscope - a funded balance to withdraw from
- the payment instrument IDs for both sides of the movement (see below)
Identifying the two instruments
Every intent moves funds from a debit instrument to a credit instrument, each identified by a payment instrument ID. Both come from a single call toGET /v1/accounts/{accountId}:
GET /v1/accounts/{accountId}
The destination is registered during onboarding. For an external wallet, it comes from the
destination_external_wallet_account_number entry you submit in the Information Request. Reading it from the account means you never have to hardcode it.
Use GET /v1/accounts to list a customer’s accounts first if you need to choose one, then fetch that account for the withdrawal.
Both instruments must be
ACTIVE and belong to the authenticated caller, or the request returns 403. The debit instrument must be a balance. Passing any other instrument type returns 400 with the message Debit instrument must be a balance.creditInstrument is omitted when the account has no withdrawal destination configured. If it is absent on a RETAIN account, that account cannot be withdrawn from. Treat it as a configuration issue and contact your Solutions Engineer.Making a withdrawal
1
Create the transaction intent
Call
POST /v1/transaction-intents with both instruments and the amount. The response is a preview: it returns the exchange rate, the converted amount, and any fees, but no funds move yet.2
Review the quoted rate
Show the customer the quoted
exchangeRate, creditAmount, and fees from the intent so they can confirm before committing.3
Commit the intent
Call
POST /v1/transaction-intents/{transactionIntentId}/commit to execute the movement. This creates the transaction and returns the intent with a relatedTransactionId.4
Track the transaction
Use the returned
relatedTransactionId with GET /v1/transactions/{transactionId}, and consume transaction webhooks, to follow the withdrawal to completion.Step 1: Create the intent
fixedSide tells Meridian which side of the conversion your amount refers to. Use DEBIT to specify how much leaves the balance, or CREDIT to specify how much should arrive at the destination.
Request
CREATED status:
Response (201)
id. You need it to commit.
Step 2: Commit the intent
Commit with the sameidempotencyKey you used to create the intent:
Request
Response (200)
relatedTransactionId is the transaction Meridian created. Committing the same intent again returns the same result rather than creating a second transaction.
Intent status values
An intent holds a quoted exchange rate, so it does not stay valid indefinitely. If a customer takes too long to confirm, the intent reaches
EXPIRED and committing it returns an error. Create a new intent to get a fresh rate.
The intent does not return an expiry timestamp, so treat the quote as short-lived and commit promptly after the customer confirms.
Idempotency
TheidempotencyKey is required on both calls, and the key you commit with must match the key the intent was created with. Use one unique key per withdrawal attempt, generated from your own reference for the withdrawal, and reuse it if you need to retry either call. This makes retries safe: a repeated request returns the original result instead of creating a duplicate withdrawal.
Recommended integration behavior
Your integration should:- confirm the account’s
routingPolicyisRETAINand carries acreditInstrumentbefore exposing withdrawal functionality in your UI - resolve both instrument IDs from the account at withdrawal time rather than hardcoding them, so a destination change is picked up automatically
- show the quoted
exchangeRate,creditAmount, andfeesto the customer before committing - treat the intent as short-lived, and request a new one when an intent reaches
EXPIRED - store the
idempotencyKeywith your own withdrawal record so retries reuse it - track completion through the
relatedTransactionIdand the transaction webhook, not the intent itself