> ## Documentation Index
> Fetch the complete documentation index at: https://docs.meshconnect.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Add Mesh to your withdrawal flow

By the end of this guide, you'll know how to use Mesh to power automated address retrieval in your withdrawal flow — eliminating the risk of user error from manual copy/paste.

<Check>
  **Before you start**

  * Your core Mesh integration is working end-to-end (see [Prepare for go-live](/build/go-live))
  * You have a withdrawal or payout flow in your app
</Check>

## Overview

Most withdrawal or payout flows require users to select an asset/network and then paste an address, just like they do in a deposit flow. And their primary concern is the same: losing funds because they make a mistake (ie. wrong network, wrong address, etc.).

Mesh enables automated address retrieval for user withdrawals or payouts from your platform. After connecting an account, Mesh lets you pull addresses with clear asset/network mapping — eliminating human error and the risk of lost funds. Additionally, after a deposit, "refund addresses" are also available via Mesh SDK events and webhooks. Together, these can form the foundation of an "address book" where users save their preferred withdrawal destinations for future use.

## Register for, and consume Mesh Transfer Status webhooks

**Why?**: Mesh provides real-time updates to transfer statuses which can be used to power several things for your app. But one piece (providing the `RefundAddress` for user transfers from external accounts) can be the underpinning of creating a seamless roundtrip journey.

<Accordion title="Instructions">
  * See the [Transfer status webhooks](/resources/webhooks) guide for more info.
  * Callback URIs can be added in the Mesh dashboard in **Account > API keys > Webhooks**.
</Accordion>

## Save the `RefundAddress` and associated details when the user makes a deposit, and surface it as a withdrawal destination.

**Why?**: Creating a seamless roundtrip journey for the user builds trust. Users often want to withdraw funds back to the same source from where they deposited. This process makes that easy. It feels personalized.

<Accordion title="Instructions">
  * The objects below are in Mesh transfer webhook events. Save this data, and surface it as a possible withdrawal destination in your UX (eg. `Your Binance account (0x31…cF98)`).

  | Parameter | Description |
  | - | - |
  | `SourceAccountProvider` | Where the deposit came from (eg. `Binance`) |
  | `Chain` | The blockchain used for the transfer (eg. `Ethereum`) |
  | `Token` | The token used for the transfer (eg. `USDC`) |
  | `RefundAddress` | Where the user can receive funds back to (eg. a deposit address within that account). |

  * **Important notes**:
    * Take proper care to ensure you associate it with the correct user.
    * That `RefundAddress` is specific to the `Chain` & `Token`. Any transfer of that specific token on that chain to that address is safe, but sending any other token or on any other network to that address may result in lost funds.
      * See [Concepts](/resources/concepts) for more information about `refundAddress`
</Accordion>

## Add a `Connect account` option in the withdrawal flow

**Why?**: Users' number-one fear when transferring crypto is making a mistake — wrong network, wrong address. With Mesh Link, that becomes impossible because it's all automated. Providing an automated address retrieval option adds a layer of trust and certainty to the withdrawal process.

<Accordion title="Instructions">
  * Call for a Link Token using the request structure below, and launch the Mesh Link SDK for the user.

  <div className="parameter-reference">
    <Accordion title="Parameter reference">
      <div className="param-list">
        <div className="param-row">
          <div className="param-name"><code>X-Client-Id</code> <span className="param-tag param-tag-required">required</span></div>
          <div className="param-body">Your Mesh Client ID.</div>
        </div>

        <div className="param-row">
          <div className="param-name"><code>X-Client-Secret</code> <span className="param-tag param-tag-required">required</span></div>
          <div className="param-body">Your Mesh API Key.</div>
        </div>

        <div className="param-row">
          <div className="param-name"><code>userId</code> <span className="param-tag param-tag-required">required</span></div>
          <div className="param-body">A unique, persistent user identifier. Personally identifiable information such as an email address or phone number should not be used. 300 characters length maximum.</div>
        </div>

        <div className="param-row">
          <div className="param-name"><code>restrictMultipleAccounts</code> <span className="param-tag param-tag-optional">optional</span></div>

          <div className="param-body">
            <p>Defaults to `false` if omitted. Pass `true` for transfer-style Link (hides "Link another account").</p>
            <p>Set `false` if you want users to connect multiple accounts for an address book.</p>
          </div>
        </div>

        <div className="param-row">
          <div className="param-name"><code>integrationId</code> <span className="param-tag param-tag-optional">optional</span></div>

          <div className="param-body">
            <p>A unique Mesh identifier representing a specific integration.</p>
            <p>Use the **Get integrations** endpoint ([/api/v1/transfers/managed/integrations](https://docs.meshconnect.com/api-reference/managed-transfers/get-integrations)) to pull a list of integrations and the corresponding Mesh `integrationId`. These values won't change, so you do not have to hit this endpoint before each Link Token request.</p>
            <p>To be used if the user selects the integration in your UX before launching Mesh (most commonly in an `onramp` flow).</p>
          </div>
        </div>
      </div>
    </Accordion>
  </div>

  ```bash theme={null}
  # This example points to sandbox. The address-list example further down points to prod.
  # Replace YOUR_CLIENT_ID, YOUR_API_KEY and UNIQUE_USER_ID with your own values.
  # integrationId is optional. 47624467-e52e-4938-a41a-7926b6c27acf is Coinbase.
  curl --request POST \
    --url https://sandbox-integration-api.meshconnect.com/api/v1/linktoken \
    --header 'Content-Type: application/json' \
    --header 'X-Client-Id: YOUR_CLIENT_ID' \
    --header 'X-Client-Secret: YOUR_API_KEY' \
    --data '
  {
    "userId": "UNIQUE_USER_ID",
    "restrictMultipleAccounts": true,
    "integrationId": "47624467-e52e-4938-a41a-7926b6c27acf"
  }
  '
  ```

  * The user will select an account, authenticate / provide access, and then their session will end.
  * You will receive an SDK event called `integrationConnected`. You should use the `onIntegrationConnected()` callback function to save the `tokenId` & `brokerType` values, associated with that `userId`.
    * See the [Supercharge return-users](/build/return-users) guide for more information about this step.
  * Call the Mesh **Get deposit addresses** endpoint ([/api/v1/transfers/managed/address/list](https://docs.meshconnect.com/api-reference/managed-transfers/get-list-of-deposit-addresses)), supplying the `authToken` (`accessToken.accountTokens[].tokenId` from `integrationConnected`) & `type` (`accessToken.brokerType`, e.g. `coinbase`, `uphold`, `deFiWallet`).
    * The response will return all addresses for each network on which the user can receive the specified crypto token. It will also have other helpful data to build you UX like a `networkName` for displaying the network and a `logoUrl` for that network.
    * Important note: Be sure to capture the `memo` for deposits of relevant assets (eg. XRP) into any custodial platform.

  <div className="parameter-reference">
    <Accordion title="Parameter reference">
      <div className="param-list">
        <div className="param-row">
          <div className="param-name"><code>X-Client-Id</code> <span className="param-tag param-tag-required">required</span></div>
          <div className="param-body">Your Mesh Client ID.</div>
        </div>

        <div className="param-row">
          <div className="param-name"><code>X-Client-Secret</code> <span className="param-tag param-tag-required">required</span></div>
          <div className="param-body">Your Mesh API Key.</div>
        </div>

        <div className="param-row">
          <div className="param-name"><code>type</code> <span className="param-tag param-tag-required">required</span></div>

          <div className="param-body">
            <p>The type of integration from which your pulling the user's deposit addresses.</p>
            <p>This is `deFiWallet` for self-hosted wallets, or a name of an exchange account (eg. `uphold`).</p>
          </div>
        </div>

        <div className="param-row">
          <div className="param-name"><code>authToken</code> <span className="param-tag param-tag-required">required</span></div>

          <div className="param-body">
            <p>The `tokenId` returned to you in the `integrationConnected` event when the user connected this account.</p>
            <p>This provides access to read data from the account.</p>
          </div>
        </div>

        <div className="param-row">
          <div className="param-name"><code>symbol</code> <span className="param-tag param-tag-required">required</span></div>
          <div className="param-body">The symbol of the asset for which you want the user's deposit address(es) at the linked account.</div>
        </div>

        <div className="param-row">
          <div className="param-name"><code>networks.<strong>networkId</strong></code> <span className="param-tag param-tag-optional">optional</span></div>

          <div className="param-body">
            <p>Mesh's unique identifier for a specific network for which you would like to pull the user's deposit address for `symbol` at the specified integration.</p>
            <p>Use the **Get networks** endpoint ([/api/v1/transfers/managed/networks](https://docs.meshconnect.com/api-reference/managed-transfers/get-networks)) to pull a list of all supported networks and the corresponding Mesh `networkId`. These values won't change, so you do not have to hit this endpoint before each Link Token request.</p>
            <p>This should not be used with `caipId`. Use one or the other. If both are left blank, this endpoint will return addresses for all eligible networks for the specified `symbol`.</p>
          </div>
        </div>

        <div className="param-row">
          <div className="param-name"><code>networks.<strong>caipId</strong></code> <span className="param-tag param-tag-optional">optional</span></div>

          <div className="param-body">
            <p>A standardized identifier for blockchain networks/assets (e.g. `eip155:1` is Ethereum mainnet).</p>
            <p>This should not be used with `networkId`. Use one or the other. If both are left blank, this endpoint will return addresses for all eligible networks for the specified `symbol`.</p>
          </div>
        </div>
      </div>
    </Accordion>
  </div>

  ```bash theme={null}
  # This example points to production.
  # Replace YOUR_CLIENT_ID, YOUR_API_KEY, ACCOUNT_TYPE, USER_TOKEN_ID and symbol.
  # networks is optional. The ids below are:
  #   0291810a-5947-424d-9a59-e88bb33e999d  Solana
  #   e3c7fdd8-b1fc-4e51-85ae-bb276e075611  Ethereum
  #   aa883b03-120d-477c-a588-37c2afd3ca71  Base
  curl --request POST \
    --url https://integration-api.meshconnect.com/api/v1/transfers/managed/address/list \
    --header 'Content-Type: application/json' \
    --header 'X-Client-Id: YOUR_CLIENT_ID' \
    --header 'X-Client-Secret: YOUR_API_KEY' \
    --data '
  {
    "type": "ACCOUNT_TYPE",
    "authToken": "USER_TOKEN_ID",
    "symbol": "USDC",
    "networks": [
      {
        "networkId": "0291810a-5947-424d-9a59-e88bb33e999d"
      },
      {
        "networkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611"
      },
      {
        "networkId": "aa883b03-120d-477c-a588-37c2afd3ca71"
      }
    ]
  }
  '
  ```
</Accordion>

## Expand withdrawal destinations with bridging

**Why?**: The account-connection flow above returns the addresses a user *natively* holds. With Mesh **headless bridging**, you can offer additional withdrawal destinations you don't natively settle in — Mesh bridges from an asset/network you *do* send from into the asset/network the user chooses, and returns an address for you to send to. It's a pure API (no Mesh UI), so you keep your own withdrawal experience.

<Accordion title="Instructions">
  * Call **Discover withdrawal routes** (`POST /api/v1/bridging/routes/withdrawal`) with the asset/network pairs your platform can pay out from (your settlement / omnibus legs). Mesh returns the **bridged** destinations it can reach from those sources. Mesh does not know which pairs the user already holds natively, so de-duplicate against the native addresses from the connection flow above before showing options.
  * When the user picks a **native** pair, send it as you do today — no extra Mesh call. When they pick a **bridged** pair, optionally call `POST /api/v1/bridging/quote` with the withdrawal amount to show the user an estimated receive amount, then call **Create bridged address** (`POST /api/v1/bridging/address`) with the selected route and the user's destination address, and send your settlement funds to the returned bridging address before its `constraints.expirationTime` (6 hours). Mesh bridges them to the user's chosen pair.
  * Each bridged transfer returns a Mesh `transferId`. Mesh sends a `Succeeded` or `Failed` webhook for it (no `Pending`), and you can poll `GET /api/v1/transfers/managed/mesh` by `Id` or `ClientTransactionId` at any point; the transfer is listed immediately as `pending`.
  * **Important**: Headless bridging is gated per-client, and its routes are configured on Mesh's side. Contact your Mesh representative to enable it and to set up the routes for your settlement pairs.
  * See the full [Headless bridging](/resources/headless-bridging) guide for request/response details, parameter tables, and status tracking.
</Accordion>

## What's next

Explore the other **Extend** guides:

* [Add Mesh onramp integrations to your "Buy" lineup](/extend/onramp) — add exchange-based onramps to your "Buy" flow.
* [Verify self-hosted wallets](/extend/verify-wallets) — add wallet ownership verification for compliance or security.

***

<Accordion title="AI coding reference (llms.txt)">
  *AI coding reference — a compact summary of this page's APIs, parameters, and patterns for use by AI coding assistants (following the [llms.txt standard](https://llmstxt.org/)). Human readers can safely ignore this.*

  **llms.txt — Add Mesh to your withdrawal flow**

  Automated address retrieval for withdrawal/payout flows: consume transfer webhooks for `RefundAddress`, retrieve deposit addresses via API, offer "Connect account" in your withdrawal UI.

  **RefundAddress from transfer webhooks**: Save `RefundAddress` + `Chain` + `Token` + `SourceAccountProvider` per userId. Surface as a withdrawal destination (e.g. "Your Binance account (0x31…cF98)"). Note: `RefundAddress` is specific to that chain+token combination.

  **Deposit address retrieval**: `POST /api/v1/transfers/managed/address/list`
  Params: `type` (broker type, e.g. "uphold", or "deFiWallet" for self-custody) | `authToken` (= `accessToken.accountTokens[].tokenId` from onIntegrationConnected) | `symbol` | `networks[].networkId` or `networks[].caipId` (optional — omit for all networks)
  Response includes: address per network, `networkName`, `logoUrl`, `memo` (important for XRP, XLM)

  **Get networkIds**: Use GET /api/v1/transfers/managed/networks to fetch the full list of supported networks and their networkId values. These values don't change — safe to cache permanently, no need to call this endpoint before every Link Token request.

  **Withdrawal Link Token**: No `transferOptions` needed — user just connects account. Receive `integrationConnected` → save `accessToken.accountTokens[].tokenId` + `accessToken.brokerType` → call address list endpoint.

  **Optional**: Pass `integrationId` to pre-select the exchange. `restrictMultipleAccounts` defaults to `false` when omitted; pass `true` for transfer-style Link, or leave it `false` to let users build an "address book" across multiple accounts.

  **Expand destinations with headless bridging**: To offer withdrawal destinations you don't natively settle in, use Mesh headless bridging (pure API, no UI). Discover bridged destinations with `POST /api/v1/bridging/routes/withdrawal` (send your settlement pairs as `sources`; de-duplicate against the user's native addresses, since Mesh does not know them), optionally quote the amount with `POST /api/v1/bridging/quote`, then when the user picks a bridged pair call `POST /api/v1/bridging/address` and send your settlement funds to the returned address before `constraints.expirationTime` (6h); track via the returned `transferId` (`Succeeded`/`Failed` webhooks, no `Pending`; list API shows it as `pending` immediately). Gated per-client. See the Headless bridging guide for full details.

  **Withdrawal Link Token — minimal request** (no `transferOptions` — user just connects account):

  ```bash theme={null}
  # Sandbox endpoint. Replace YOUR_CLIENT_ID, YOUR_API_KEY and UNIQUE_USER_ID.
  curl --request POST \
    --url https://sandbox-integration-api.meshconnect.com/api/v1/linktoken \
    --header 'Content-Type: application/json' \
    --header 'X-Client-Id: YOUR_CLIENT_ID' \
    --header 'X-Client-Secret: YOUR_API_KEY' \
    --data '
  {
    "userId": "UNIQUE_USER_ID",
    "restrictMultipleAccounts": true
  }
  '
  ```

  **Deposit address list — canonical request body** (call after `onIntegrationConnected`):

  ```bash theme={null}
  # Production endpoint. Replace the credentials, ACCOUNT_TYPE, USER_TOKEN_ID and symbol.
  # networks is optional. Ids below: Solana, Ethereum, Base.
  curl --request POST \
    --url https://integration-api.meshconnect.com/api/v1/transfers/managed/address/list \
    --header 'Content-Type: application/json' \
    --header 'X-Client-Id: YOUR_CLIENT_ID' \
    --header 'X-Client-Secret: YOUR_API_KEY' \
    --data '
  {
    "type": "ACCOUNT_TYPE",
    "authToken": "USER_TOKEN_ID",
    "symbol": "USDC",
    "networks": [
      {
        "networkId": "0291810a-5947-424d-9a59-e88bb33e999d"
      },
      {
        "networkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611"
      },
      {
        "networkId": "aa883b03-120d-477c-a588-37c2afd3ca71"
      }
    ]
  }
  '
  ```
</Accordion>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.