Merchant Withdrawals
Merchant Withdrawals
Overview
Withdrawals let you move your own balance held at Mesta out to a wallet you control — refunded amounts, unused deposits, over-deposits, or any other balance sitting against your senders or your pooled account.
There are two distinct halves, and only one of them is available over the API:
| Where | API? | |
|---|---|---|
| Registering a withdrawal wallet | Merchant portal only | No |
| Initiating and tracking withdrawals | API or portal | Yes |
Wallet registration is deliberately portal-only. It is defined by two interactive ceremonies — a step-up authentication and reading a test amount out of your own wallet — that an API credential cannot perform. Once a wallet is registered and verified, withdrawals to it can be automated.
Table of Contents
- Prerequisites
- Registering a withdrawal wallet
- Listing your wallets
- Initiating a withdrawal
- Tracking a withdrawal
- Status reference
- Rules and limits
- Errors
- Permissions
1. Prerequisites
- Withdrawals must be enabled on your account. This is off by default. Contact your Mesta representative to have it enabled; until then every withdrawal endpoint returns
WITHDRAWAL_WALLETS_DISABLED. - One registered, verified wallet per network. You cannot withdraw to an arbitrary address — only to a wallet you registered and verified in advance. This is the core safety property of the flow.
- A balance to withdraw, on a sender or on your pooled account.
2. Registering a withdrawal wallet
Portal only. This cannot be done over the API.
In the merchant portal, go to Withdrawal wallets and add one address per network. The sequence is:
- Enter the address and network. One address per network, not per token — a single Ethereum address receives both USDC and USDT. Double-check it: transfers to a wrong address cannot be reversed.
- Step-up authentication. Passkey, or an authenticator code if you have no passkey enrolled.
- Automatic security screening of the address. If it is flagged, the wallet is held for review rather than rejected, and Mesta will contact you.
- Test deposit. Mesta sends a small random amount, under one dollar, to the address. Enter the exact amount to prove you control the wallet. You get three attempts; after that the registration is rejected and you start again with a new wallet.
- 24-hour waiting period. Once the test passes, the wallet becomes usable 24 hours later. There is no way to shorten this, including via support.
Only a merchant admin can register or verify a wallet. Ordinary users on your account can view the registered wallets but not add one.
You cannot replace a wallet yourself. Contact support, and the replacement runs the full sequence again including the waiting period.
3. Listing your wallets
GET /v1/merchant/withdrawal-wallets
Authorization: Bearer <merchant user token>Returns your registered wallets with their network, address, status and — if it is still within the waiting period — when it becomes usable.
Also available for a single wallet:
GET /v1/merchant/withdrawal-wallets/{id}Note on the status field. A wallet whose waiting period has passed may still report
cooldown. That is expected: readcooldownUntilto decide whether the wallet is usable, not the status string. IfcooldownUntilis in the past, the wallet is withdrawable.
These read endpoints require a merchant user session. They are not available to API keys.
4. Initiating a withdrawal
POST /v1/merchant/withdrawals
Authorization: Bearer <api key or merchant user token>
Content-Type: application/json{
"idempotencyKey": "3f2a1c40-9b7e-4d51-8a62-0c9d4e7b1f88",
"senderId": "c715b301-9654-438a-8893-72c90c8ce467",
"currency": "USDC_ETH",
"amount": "250.00"
}| Field | Required | Notes |
|---|---|---|
idempotencyKey | yes | Must be a UUID. Generate a fresh one per withdrawal attempt. Resubmitting the same key returns the original withdrawal instead of creating a second one. |
senderId | conditional | The sender whose balance to withdraw. Omit and set pooled: true to withdraw from your pooled balance instead. |
pooled | conditional | true to withdraw from your pooled account. Mutually exclusive with senderId. |
currency | yes | e.g. USDC_ETH, USDT_TRX. The network is derived from the currency, and determines which registered wallet receives the funds. |
amount | yes | Decimal string, at most 2 decimal places, greater than zero. Do not send a number — precision matters here. |
You do not supply a destination. It is resolved from your registered wallet for that network. This is intentional: there is no request shape in which a withdrawal can be sent to an address you have not already registered and verified.
No fee is charged. Mesta absorbs the network fee.
Idempotency
The key is enforced by a unique constraint scoped to your merchant, not by a read-then-write, so two concurrent submissions of the same key cannot both create a withdrawal. Reuse the key when retrying a request whose response you did not receive.
5. Tracking a withdrawal
GET /v1/merchant/withdrawals
GET /v1/merchant/withdrawals/{id}Filters on the list endpoint: status, chain, currency, senderId, createdFrom, createdTo.
createdFrom and createdTo must be full ISO-8601 datetimes with a timezone — 2026-06-29T00:00:00Z, not 2026-06-29. A date without an offset is rejected rather than silently interpreted, because a withdrawal audit that is quietly shifted by your timezone is worse than an error.
Poll GET /v1/merchant/withdrawals/{id} until the status is terminal. There are no withdrawal webhooks today.
6. Status reference
| Status | Terminal | Meaning |
|---|---|---|
created | no | Accepted, not yet started. |
screening | no | The destination is being security-screened. Happens before any funds move. |
debiting | no | Your balance is being debited. |
withdrawing | no | The on-chain transfer is in progress. This is the longest stage. |
completed | yes | Funds sent. txHash is populated. |
failed | yes | Did not complete. See failureReason. |
rejected | yes | Refused before any debit — most often the destination failed screening. |
needs_reconciliation | no | The outcome is not yet known. See below. |
needs_reconciliation
needs_reconciliationThis does not mean the withdrawal failed. It means the outcome is genuinely undecided — typically the debit was made and the transfer result is unresolved. A Mesta operator resolves these manually.
While a withdrawal is in this state it holds your one-in-flight slot for that network, so you cannot start another withdrawal on the same network until it is resolved. That is deliberate: an unresolved withdrawal should block the next one rather than be papered over by it.
If you see this status, contact support with the withdrawal ID rather than retrying.
7. Rules and limits
- One withdrawal in flight per network. A second attempt while one is open is refused. Wait for the first to reach a terminal status.
- One registered wallet per network. Per network, not per token.
- Destination is always your registered wallet. Not client-supplied, on any endpoint.
- The destination is screened before every send, not only at registration.
- Amount must exceed zero and carry at most 2 decimal places. Minimum amounts may apply per network — check with your Mesta representative before automating small withdrawals.
- Failed withdrawals are not automatically reversed. If a withdrawal fails after your balance was debited, a Mesta operator posts the correcting entry. No balance is silently lost, but resolution involves a person.
8. Errors
| Code | Meaning |
|---|---|
WITHDRAWAL_WALLETS_DISABLED | Withdrawals are not enabled on your account. |
WITHDRAWAL_NO_ACTIVE_WALLET | No verified wallet is registered for that network, or it is still within its waiting period. |
WITHDRAWAL_CHAIN_NOT_SUPPORTED | Withdrawals are not available on that network yet. |
WITHDRAWAL_WALLET_ADMIN_REQUIRED | Adding or verifying a wallet requires a merchant admin. Viewing does not. |
WITHDRAWAL_WALLET_ALREADY_EXISTS | A wallet is already registered for that network. Contact support to replace it. |
WITHDRAWAL_ADDRESS_INVALID | The address is not valid for the selected network. |
WITHDRAWAL_ADDRESS_NOT_ALLOWED | That address cannot be used as a withdrawal destination. |
WITHDRAWAL_VERIFICATION_AMOUNT_INCORRECT | The test amount did not match. The response includes attempts remaining. |
WITHDRAWAL_VERIFICATION_ATTEMPTS_EXHAUSTED | Too many incorrect attempts. Start again with a new wallet. |
9. Permissions
| Action | Merchant admin | Ordinary user | API key |
|---|---|---|---|
| Register a wallet | ✅ | ❌ | ❌ |
| Verify the test amount | ✅ | ❌ | ❌ |
| View wallets | ✅ | ✅ | ❌ |
| Initiate a withdrawal | ✅ | requires merchant:withdrawal:write | ✅ |
| View withdrawals | ✅ | ✅ | ✅ |
Wallet endpoints require a merchant user session and reject API keys, sender tokens and account-recovery tokens outright — an account-recovery session in particular must never be able to reach a fund destination.
Scope your API keys deliberately. A key that can initiate withdrawals can move your balance to your registered wallet without further authentication. The destination is constrained to an address you already verified, so a leaked key cannot redirect funds elsewhere — but it can move them. If you do not automate withdrawals, do not grant withdrawal permissions to your keys.
Updated about 19 hours ago

