> ## 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.

# Fetch a Link Token

By the end of this guide, you'll know how to request a Link Token for any use case: deposits, payments, onramps, withdrawals, and wallet verification.

<Check>
  **Before you start**

  * You have a Mesh dashboard account with a sandbox API key (see [Prepare to build](/build/prepare-to-build))
  * You know which use case(s) you're building for
</Check>

## Overview

A Link token, as the name implies, is an access key for a session of Link, Mesh's SDK. You'll request it with an API call to Mesh, and the parameters you include will configure the user session. This is how you'll start every user session. This guide will walk you through how to request a Link token, including code snippets for specific use cases.

## How to request a Link token

### General information

**Endpoint**: **Get Link token with parameters** ([/api/v1/linktoken](https://docs.meshconnect.com/api-reference/managed-account-authentication/get-link-token-with-parameters))

You will start every user session with this request. Its parameters configure the user's experience within Link.

* Tokens are short-lived (must be used within 10mins).
* Tokens are one-time use.

### Use-case-specific example requests

<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 `true`, which is standard used for any transfer flow.</p>
          <p>On some non-transfer flows (ie. "read" use cases), a user could connect multiple accounts in a row if this value were `false`. Sometimes valuable for withdrawal use cases to let the user create an external "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 className="param-row">
        <div className="param-name"><code>transferOptions.<strong>transactionId</strong></code> <span className="param-tag param-tag-optional">optional</span> <span className="param-tag param-tag-required">required for PayLinks transfers</span></div>
        <div className="param-body">A unique transaction identifier used to tie back to your data or track this transaction in future calls to Mesh.</div>
      </div>

      <div className="param-row">
        <div className="param-name"><code>transferOptions.<strong>transferType</strong></code> <span className="param-tag param-tag-optional">optional</span></div>
        <div className="param-body">Ensures the language and flow matches your user's mental model for the type of transfer they're doing. Defaults to `deposit`.</div>
      </div>

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

        <div className="param-body">
          <p>Specifies if fees should be included in the amount to transfer.</p>
          <p>`false` is standard for `deposit` and `payment`, meaning any applicable fees are on top of the deposit/payment amount. `true` is standard for `onramp`, meaning the amount the user receives is the amount specified minus applicable fees.</p>
        </div>
      </div>

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

        <div className="param-body">
          <p>When `true`, this request will return a url in addition to the Link token that can be used to launch Mesh Link in a separate web page.</p>
          <p>This should only be used if you're launching Mesh in a separate webpage (see more about "PayLinks" in the [Launch the Mesh SDK](/build/launch-sdk) guide).</p>
        </div>
      </div>

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

        <div className="param-body">
          <p>The fiat-equivalent amount of the symbol to be purchased.</p>
          <p>To be used if the user enters an amount in your UX before launching Mesh (most commonly in an `onramp` flow).</p>
        </div>
      </div>

      <div className="param-row">
        <div className="param-name"><code>transferOptions.toAddresses.<strong>networkId</strong></code> <span className="param-tag param-tag-optional">optional</span> <span className="param-tag param-tag-required">required for transfers</span></div>

        <div className="param-body">
          <p>Mesh's unique identifier for the network to be used for this `toAddress`.</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>
        </div>
      </div>

      <div className="param-row">
        <div className="param-name"><code>transferOptions.toAddresses.<strong>symbol</strong></code> <span className="param-tag param-tag-optional">optional</span> <span className="param-tag param-tag-required">required for transfers</span></div>
        <div className="param-body">The symbol of the asset that can be transferred to this `toAddress`.</div>
      </div>

      <div className="param-row">
        <div className="param-name"><code>transferOptions.toAddresses.<strong>address</strong></code> <span className="param-tag param-tag-optional">optional</span> <span className="param-tag param-tag-required">required for transfers</span></div>
        <div className="param-body">The destination to which the specified `symbol` can be sent on the specified `networkId`.</div>
      </div>

      <div className="param-row">
        <div className="param-name"><code>transferOptions.toAddresses.<strong>amount</strong></code> <span className="param-tag param-tag-optional">optional</span> <span className="param-tag param-tag-required">required for payments</span></div>

        <div className="param-body">
          <p>Exact amount of the asset that should be transferred.</p>
          <p>This parameter is optional for `deposit` and `onramp`, but required when transferType: `payment`. Not to be used in combination with the `amountInFiat` field.</p>
        </div>
      </div>

      <div className="param-row">
        <div className="param-name"><code>transferOptions.toAddresses.<strong>displayAmountInFiat</strong></code> <span className="param-tag param-tag-optional">optional</span></div>

        <div className="param-body">
          <p>A fiat-equivalent amount that will be shown to the user in the Mesh UI.</p>
          <p>This ensures a consistent experience from your checkout experience to Mesh. It will only be used if it is within 1% of the `amountInFiat` Mesh determines based on its pricing data. This is generally used for non-stablecoin payments, as Mesh maps stablecoins to a 1:1 price with USD for display purposes.</p>
        </div>
      </div>

      <div className="param-row">
        <div className="param-name"><code>verifyWalletOptions.<strong>verificationMethods</strong></code> <span className="param-tag param-tag-optional">optional</span> <span className="param-tag param-tag-required">required for verifications</span></div>

        <div className="param-body">
          <p>Method by which the user must verify their self-hosted wallet.</p>
          <p>Enum to support future verification methods, but only one option for now.</p>
        </div>
      </div>

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

        <div className="param-body">
          <p>The message the user should sign in their wallet.</p>
          <p>The exact language isn't important. Mesh has standard language if this isn't provided.</p>
        </div>
      </div>

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

        <div className="param-body">
          <p>A unique Mesh identifier for the network on which the user must verify their self-hosted address.</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>To be used if you need your user to verify an address on a specific network. Should not be used in combination with `networkType`.</p>
        </div>
      </div>

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

        <div className="param-body">
          <p>The network type on which the user must verify their self-hosted address.</p>
          <p>To be used if you need your user to verify an address on a particular network type (eg. EVM). Should not be used in combination with `networkId`.</p>
        </div>
      </div>

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

        <div className="param-body">
          <p>A list of address from which the user can verify ownership. User is not allowed to verify an address outside this list.</p>
          <p>Used if you need your user to verify ownership of a specific address. If not provided, user can verify ownership of any self-hosted address they connect.</p>
        </div>
      </div>
    </div>
  </Accordion>
</div>

<AccordionGroup>
  <Accordion title="Use case: Deposits">
    ```javascript theme={null}
    curl --request POST \
      --url https://sandbox-integration-api.meshconnect.com/api/v1/linktoken \ // This is pointing to sandbox
      --header 'Content-Type: application/json' \
      --header 'X-Client-Id: YOUR_CLIENT_ID' \ // Replace
      --header 'X-Client-Secret: YOUR_API_KEY' \ // Replace
      --data '
    {
      "userId": "UNIQUE_USER_ID", // Replace
      "restrictMultipleAccounts": true,
      "transferOptions": {
        "transactionId": "UNIQUE_TRANSACTION_ID", // Replace
        "transferType": "deposit",
        "isInclusiveFeeEnabled": false,
        "generatePayLink": false,
        "toAddresses": [ // Replace (example array below)
          {
            "networkId": "0291810a-5947-424d-9a59-e88bb33e999d", // Solana
            "symbol": "USDC", // Replace
            "address": "xxx", // Replace
          },
          {
            "networkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611", // Ethereum
            "symbol": "USDC", // Replace
            "address": "xxx", // Replace
          },
          {
            "networkId": "aa883b03-120d-477c-a588-37c2afd3ca71", // Base
            "symbol": "USDC", // Replace
            "address": "xxx", // Replace
          }
        ],
      }
    }
    '
    ```

    * The `toAddresses` are the possible destinations at which user deposits can be received. This object is an array. The example request shows 3 possible destination addresses (USDC.sol, USDC.eth, USDC.base), but you should **provide all possible destination addresses** to maximize the chances that Mesh can make a transaction happen.

          <Info>
            **Want more help?** Use our [toAddress generator](https://mesh-address-generator.vercel.app/?section=link). This tool helps you quickly construct your toAddress array.
          </Info>
    * There is an additional parameter for `addressTag` within the `toAddress` object. Be sure to include that for assets like XRP or XLM if necessary for proper attribution to your user accounts.
    * There are additional parameters for `minAmount` & `minAmountInFiat` within the `toAddress` object. Be sure to include this if you have deposit minimums.
  </Accordion>

  <Accordion title="Use case: Payments">
    ```javascript theme={null}
    curl --request POST \
      --url https://sandbox-integration-api.meshconnect.com/api/v1/linktoken \ // This is pointing to sandbox
      --header 'Content-Type: application/json' \
      --header 'X-Client-Id: YOUR_CLIENT_ID' \ // Replace
      --header 'X-Client-Secret: YOUR_API_KEY' \ // Replace
      --data '
    {
      "userId": "UNIQUE_USER_ID", // Replace
      "restrictMultipleAccounts": true,
      "transferOptions": {
        "transactionId": "UNIQUE_TRANSACTION_ID", // Replace
        "transferType": "payment",
        "isInclusiveFeeEnabled": false,
        "generatePayLink": false,
        "toAddresses": [ // Replace (example array below)
          {
            "networkId": "0291810a-5947-424d-9a59-e88bb33e999d", // Solana
            "symbol": "USDC", // Replace
            "address": "xxx", // Replace
            "amount": 99.99 // Replace
          },
          {
            "networkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611", // Ethereum
            "symbol": "USDC", // Replace
            "address": "xxx", // Replace
            "amount": 99.99 // Replace
          },
          {
            "networkId": "aa883b03-120d-477c-a588-37c2afd3ca71", // Base
            "symbol": "USDC", // Replace
            "address": "xxx", // Replace
            "amount": 99.99 // Replace
          },
          {
            "networkId": "03dee5da-7398-428f-9ec2-ab41bcb271da", // Bitcoin
            "symbol": "BTC", // Replace
            "address": "xxx", // Replace
            "amount": 0.00141, // Replace
            "displayAmountInFiat": 99.99 // Replace
          }
        ],
      }
    }
    '
    ```

    * The `toAddresses` are the possible destinations at which user payments can be received. This object is an array. The example request shows 4 possible destination addresses (USDC.sol, USDC.eth, USDC.base, BTC.btc), but you should **provide all possible destination addresses** to maximize the chances that Mesh can make a transaction happen.

          <Info>
            **Want more help?** Use our [toAddress generator](https://mesh-address-generator.vercel.app/?section=link). This tool helps you quickly construct your toAddress array.
          </Info>
    * The `amount` parameter is the amount of the `symbol` specified in this object that must be transferred (ie. the total payment amount, in crypto). Do not use the `amountInFiat` parameter, as Mesh cannot guarantee exchange rates.
    * There is an additional parameter for `addressTag` within the `toAddress` object. Be sure to include that for assets like XRP or XLM if necessary for proper attribution on your end.
  </Accordion>

  <Accordion title="Use case: Onramps">
    ```javascript theme={null}
    curl --request POST \
      --url https://sandbox-integration-api.meshconnect.com/api/v1/linktoken \ // This is pointing to sandbox
      --header 'Content-Type: application/json' \
      --header 'X-Client-Id: YOUR_CLIENT_ID' \ // Replace
      --header 'X-Client-Secret: YOUR_API_KEY' \ // Replace
      --data '
    {
      "userId": "UNIQUE_USER_ID", // Replace
      "restrictMultipleAccounts": true,
      "integrationId": "5620bf49-3240-4f85-8b4f-9dd6261597e2", // Binance Connect (Replace)
      "transferOptions": {
        "transactionId": "UNIQUE_TRANSACTION_ID", // Replace
        "transferType": "onramp",
        "amountInFiat": 100.00, // Replace
        "isInclusiveFeeEnabled": true,
        "generatePayLink": false,
        "toAddresses": [ // Replace (this could be a full array, or only one destination if the user selects a token/network in your UX before launching Mesh)
          {
            "networkId": "0291810a-5947-424d-9a59-e88bb33e999d", // Solana
            "symbol": "USDC", // Replace
            "address": "xxx", // Replace
          }
        ],
      }
    }
    '
    ```

    * There is an additional parameter for `addressTag` within the `toAddress` object. Be sure to include that for assets like XRP or XLM if necessary for proper attribution to your user accounts.

          <Info>
            **Want more help?** If you're passing an array of multiple possible destinations for your user's purchase, use our [toAddress generator](https://mesh-address-generator.vercel.app/?section=link). This tool helps you quickly construct your toAddress array.
          </Info>
    * There are additional parameters for `minAmount` & `minAmountInFiat` within the `toAddress` object. Be sure to include this if you have deposit minimums.
    * Read more about this in [Add Mesh onramp integrations to your "Buy" lineup](/extend/onramp).
  </Accordion>

  <Accordion title="Use case: Withdrawals">
    ```javascript theme={null}
    curl --request POST \
      --url https://sandbox-integration-api.meshconnect.com/api/v1/linktoken \ // This is pointing to sandbox
      --header 'Content-Type: application/json' \
      --header 'X-Client-Id: YOUR_CLIENT_ID' \ // Replace
      --header 'X-Client-Secret: YOUR_API_KEY' \ // Replace
      --data '
    {
      "userId": "UNIQUE_USER_ID", // Replace
      "restrictMultipleAccounts": true,
    }
    '
    ```

    * This user flow will end immediately after they connect their account.
    * At that point, you will receive an accessToken for the user's account, which you can use to hit Mesh's **Get deposit addresses** endpoint ([/api/v1/transfers/managed/address/list](https://docs.meshconnect.com/api-reference/managed-transfers/get-list-of-deposit-addresses)).
    * Read more about this in the [Add Mesh to your withdrawal flow](/extend/withdrawal) guide.
  </Accordion>

  <Accordion title="Use case: Verify (self-hosted wallets)">
    ```javascript theme={null}
    curl --request POST \
      --url https://sandbox-integration-api.meshconnect.com/api/v1/linktoken \ // This is pointing to sandbox
      --header 'Content-Type: application/json' \
      --header 'X-Client-Id: YOUR_CLIENT_ID' \ // Replace
      --header 'X-Client-Secret: YOUR_API_KEY' \ // Replace
      --data '
    {
      "userId": "UNIQUE_USER_ID", // Replace
      "restrictMultipleAccounts": true,
      "integrationId": "757e703f-a8fe-4dc4-d0ec-08dc6737ad96", // Phantom, replace, optional
      "verifyWalletOptions": {
        "verificationMethods": [
          "signedMessage"
        ],
        "message": "MESSAGE_TO_BE_SIGNED", // Replace
        "networkId": "0291810a-5947-424d-9a59-e88bb33e999d", // Solana, replace, optional
        "networkType": "solana", // Replace, optional
        "addresses": [ // Optional
          "xxx" // Replace
        ],
      }
    }
    '
    ```

    * Wallet verification is fully compatible with the deposit & payment use cases. If you require users to verify that they own a self-custody wallet before initiating a deposit or payment from that wallet, you can add these configurations into the same Link Token request.
    * Read more about this in [Verify self-hosted wallets](/extend/verify-wallets).
  </Accordion>
</AccordionGroup>

## What's next

Next up: [Launch the Mesh SDK](/build/launch-sdk) — use the Link Token you just requested to initialize and launch a user-facing SDK session.

***

<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 — Fetch a Link Token**

  Every Mesh session starts server-side with a Link Token request. Tokens are short-lived (10 min) and single-use.

  **Endpoint**: `POST /api/v1/linktoken`

  **Required params**: `userId` (unique, persistent, non-PII, ≤300 chars) — the only universally required body param.

  **Conditionally required**: `transferOptions.toAddresses[].networkId`, `.symbol`, `.address` — required for any transfer flow | `transferOptions.toAddresses[].amount` — required for payment flows (not for deposit/onramp) | `verifyWalletOptions.verificationMethods` — required when using wallet verification

  **Key optional params**: `transferOptions.transferType` (deposit/payment/onramp — defaults to deposit) | `integrationId` (deep-link to specific provider) | `accessTokens` (MMT return-user array) | `restrictMultipleAccounts` (default true) | `generatePayLink` (true returns `paymentLink` URL) | `transferOptions.isInclusiveFeeEnabled` (false for deposit/payment; true for onramp) | `transferOptions.amountInFiat` | `transferOptions.toAddresses[].addressTag` (for XRP, XLM) | `transferOptions.toAddresses[].minAmount` / `minAmountInFiat`

  **verifyWalletOptions** (wallet ownership): `verificationMethods: ["signedMessage"]` | `message` | `networkId` or `networkType` (not both) | `addresses[]`

  **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.

  **Key networkIds**: Solana `0291810a-5947-424d-9a59-e88bb33e999d` | Ethereum `e3c7fdd8-b1fc-4e51-85ae-bb276e075611` | Base `aa883b03-120d-477c-a588-37c2afd3ca71` | Bitcoin `03dee5da-7398-428f-9ec2-ab41bcb271da`

  **Tool**: [toAddress generator](https://mesh-address-generator.vercel.app/?section=link) — quickly construct your toAddresses array.

  **Deposit use case — canonical request body**:

  ```javascript theme={null}
  curl --request POST \
    --url https://sandbox-integration-api.meshconnect.com/api/v1/linktoken \ // This is pointing to sandbox
    --header 'Content-Type: application/json' \
    --header 'X-Client-Id: YOUR_CLIENT_ID' \ // Replace
    --header 'X-Client-Secret: YOUR_API_KEY' \ // Replace
    --data '
  {
    "userId": "UNIQUE_USER_ID", // Replace
    "restrictMultipleAccounts": true,
    "transferOptions": {
      "transactionId": "UNIQUE_TRANSACTION_ID", // Replace
      "transferType": "deposit",
      "isInclusiveFeeEnabled": false,
      "generatePayLink": false,
      "toAddresses": [ // Replace (example array below)
        {
          "networkId": "0291810a-5947-424d-9a59-e88bb33e999d", // Solana
          "symbol": "USDC", // Replace
          "address": "xxx", // Replace
        },
        {
          "networkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611", // Ethereum
          "symbol": "USDC", // Replace
          "address": "xxx", // Replace
        },
        {
          "networkId": "aa883b03-120d-477c-a588-37c2afd3ca71", // Base
          "symbol": "USDC", // Replace
          "address": "xxx", // Replace
        }
      ],
    }
  }
  '
  ```

  **Payment use case** — same as deposit but add `"amount": 99.99` to each `toAddress` entry and set `"transferType": "payment"`.

  **Onramp use case** — add `"integrationId": "...", "amountInFiat": 100.00, "isInclusiveFeeEnabled": true` and set `"transferType": "onramp"`.

  **Verify use case** — replace `transferOptions` with `"verifyWalletOptions": { "verificationMethods": ["signedMessage"], "message": "...", "networkId": "..." }`.
</Accordion>
