Skip to main content
A withdrawal moves funds out of a customer’s Meridian balance to a destination instrument, such as an external wallet. Withdrawals use the Transaction Intent API, a two-step flow. You first create an intent, which returns a preview with the exchange rate and fees but moves no money. You then commit that intent, which creates the actual transaction.

Prerequisites

Your program must be configured with the RETAIN 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.
The policy is submitted as a routing_policy entry in the Information Request during onboarding:
The withdrawal destination is also established during onboarding. For an external wallet destination, submit it alongside the routing policy:
If your program is configured with SWEEP, funds leave the balance automatically and this flow does not apply. Contact your Solutions Engineer if you need a RETAIN program configured.
You also need:
  • an enrollment in ACTIVE status — see Onboarding your customer
  • an access token for the program context, with the transactions:create scope
  • 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 to GET /v1/accounts/{accountId}:
GET /v1/accounts/{accountId}
Map the two values straight onto the intent: 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
The response is the intent preview, in CREATED status:
Response (201)
No funds have moved at this point. Keep the returned id. You need it to commit.

Step 2: Commit the intent

Commit with the same idempotencyKey you used to create the intent:
Request
Response (200)
The 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

The idempotencyKey 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. Your integration should:
  • confirm the account’s routingPolicy is RETAIN and carries a creditInstrument before 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, and fees to the customer before committing
  • treat the intent as short-lived, and request a new one when an intent reaches EXPIRED
  • store the idempotencyKey with your own withdrawal record so retries reuse it
  • track completion through the relatedTransactionId and the transaction webhook, not the intent itself