# Add new Registered company info
Source: https://docs.meshconnect.com/api-reference/account-management/subclient/add-new-registered-company-info
https://admin-api.meshconnect.com/swagger/AdminAPI/swagger.json post /admin/api/v1/SubClient
# Delete Registered Company info
Source: https://docs.meshconnect.com/api-reference/account-management/subclient/delete-registered-company-info
https://admin-api.meshconnect.com/swagger/AdminAPI/swagger.json delete /admin/api/v1/SubClient/{id}
# Get all registered clients
Source: https://docs.meshconnect.com/api-reference/account-management/subclient/get-all-registered-clients
https://admin-api.meshconnect.com/swagger/AdminAPI/swagger.json get /admin/api/v1/SubClient
# Get Registered Client
Source: https://docs.meshconnect.com/api-reference/account-management/subclient/get-registered-client
https://admin-api.meshconnect.com/swagger/AdminAPI/swagger.json get /admin/api/v1/SubClient/{id}
# Remove Registered Client Logo
Source: https://docs.meshconnect.com/api-reference/account-management/subclient/remove-registered-client-logo
https://admin-api.meshconnect.com/swagger/AdminAPI/swagger.json delete /admin/api/v1/SubClient/{id}/logo
# Update Registered Client Logo
Source: https://docs.meshconnect.com/api-reference/account-management/subclient/update-registered-client-logo
https://admin-api.meshconnect.com/swagger/AdminAPI/swagger.json post /admin/api/v1/SubClient/{id}/logo
# Update Registered company info
Source: https://docs.meshconnect.com/api-reference/account-management/subclient/update-registered-company-info
https://admin-api.meshconnect.com/swagger/AdminAPI/swagger.json put /admin/api/v1/SubClient/{id}
# Post adminapiv1token
Source: https://docs.meshconnect.com/api-reference/account-management/token/post-adminapiv1token
https://admin-api.meshconnect.com/swagger/AdminAPI/swagger.json post /admin/api/v1/Token
# Get account balance
Source: https://docs.meshconnect.com/api-reference/balance/get-account-balance
post /api/v1/balance/get
Get real-time account fiat balances.
# Get aggregated portfolio fiat balances
Source: https://docs.meshconnect.com/api-reference/balance/get-aggregated-portfolio-fiat-balances
get /api/v1/balance/portfolio
Get cached aggregated fiat balances from all connected integrations.
# Get health status
Source: https://docs.meshconnect.com/api-reference/managed-account-authentication/get-health-status
get /api/v1/status
Get the list of supported institutions and their health statuses.
# Get Link token with parameters
Source: https://docs.meshconnect.com/api-reference/managed-account-authentication/get-link-token-with-parameters
post /api/v1/linktoken
Get a short lived, one-time use token for initializing a Link session using the client-side SDKs
# Refresh auth token
Source: https://docs.meshconnect.com/api-reference/managed-account-authentication/refresh-auth-token
post /api/v1/token/refresh
Refresh auth token of the connected institution.
Some institutions do not require tokens to be refreshed.
The following institutions require custom flows:
WeBull: AuthToken should be provided along with the RefreshToken
Vanguard: security settings may activate MFA, requiring user action.
If MFA is triggered, a second refresh request should be sent.
Second request should contain MFA code and access token obtained from initial response
# Remove connection
Source: https://docs.meshconnect.com/api-reference/managed-account-authentication/remove-connection
delete /api/v1/account
Remove connection to the financial institution and erase all related data completely.
# Retrieve the list of all available integrations.
Source: https://docs.meshconnect.com/api-reference/managed-account-authentication/retrieve-the-list-of-all-available-integrations
get /api/v1/integrations
Returns a list of integrations with details including the integration ID, name, type,
DeFi wallet provider ID, and categories.
# Get deposit address
Source: https://docs.meshconnect.com/api-reference/managed-transfers/get-deposit-address
post /api/v1/transfers/managed/address/get
Get or generate a cryptocurrency deposit address that can be used to transfer assets to the financial institution
# Get integrations
Source: https://docs.meshconnect.com/api-reference/managed-transfers/get-integrations
get /api/v1/transfers/managed/integrations
**Get supported integrations list.**
---
Get the list of all integrations supported by Mesh to perform transfers, including which tokens and networks are supported.
# Get networks
Source: https://docs.meshconnect.com/api-reference/managed-transfers/get-networks
get /api/v1/transfers/managed/networks
**Get supported networks list.**
---
Get the list of all networks supported by Mesh to perform transfers, including which tokens and integrations are supported.
# Get supported tokens list
Source: https://docs.meshconnect.com/api-reference/managed-transfers/get-supported-tokens-list
get /api/v1/transfers/managed/tokens
Get the list of all tokens supported by Mesh to perform transfers, including which networks and integrations are supported.
# Get transfers initiated by Mesh
Source: https://docs.meshconnect.com/api-reference/managed-transfers/get-transfers-initiated-by-mesh
get /api/v1/transfers/managed/mesh
Get cryptocurrency transfers initiated by Mesh on exchanges or self-custody wallets.
# Get aggregated portfolio
Source: https://docs.meshconnect.com/api-reference/portfolio/get-aggregated-portfolio
get /api/v1/holdings/portfolio
Get the aggregated portfolio of the user containing market values.
# Get holdings.
Source: https://docs.meshconnect.com/api-reference/portfolio/get-holdings
post /api/v1/holdings/get
Obtain assets from the connected investment account. Performs realtime API call to the underlying integration.
# Get holdings values.
Source: https://docs.meshconnect.com/api-reference/portfolio/get-holdings-values
post /api/v1/holdings/value
Obtain assets from the connected investment account and return total value and performance.
Performs realtime API call to the underlying integration.
# Get deposit address
Source: https://docs.meshconnect.com/api-reference/transfers/get-deposit-address
post /api/v1/transfers/address/get
Get or generate a cryptocurrency deposit address that can be used to transfer assets to the financial institution
# Get details of asset
Source: https://docs.meshconnect.com/api-reference/transfers/get-details-of-asset
post /api/v1/transfers/symbol/details
Get details of the asset for deposit or withdrawal. For example, several exchanges support same tokens over multiple
blockchains, and thus require the name of chain to be supplied for transfers. This endpoint allows getting such details.
# Get transfer details
Source: https://docs.meshconnect.com/api-reference/transfers/get-transfer-details
post /api/v1/transfers/details
Get details of a specific transfer (withdrawals or deposits) executed from an exchange.
Only supports Exchange integrations.
# Get transfer history
Source: https://docs.meshconnect.com/api-reference/transfers/get-transfer-history
post /api/v1/transfers/list
Get entire history of cryptocurrency transfers (withdrawals or deposits) executed from an exchange.
Only supports Exchange integrations.
# Verify account identity.
Source: https://docs.meshconnect.com/api-reference/verify/verify
post /api/v1/exchange/verify
Returns basic profile data of the user's exchange account.
Available data varies by exchange and linked account.
# Get wallet verifications for user and address.
Source: https://docs.meshconnect.com/api-reference/verify/wallet
get /api/v1/wallets/verify
# Android SDK
Source: https://docs.meshconnect.com/guides/android-sdk
# Mesh Connect Android SDK
Android library for integrating with Mesh Connect.
[](https://central.sonatype.com/artifact/com.meshconnect/link)
## Installation
Add dependency to your `build.gradle`:
```gradle
dependencies {
implementation 'com.meshconnect:link:$linkVersion'
}
```
## Getting Link token
The `linkToken` should be obtained from
the [`/api/v1/linktoken`](https://docs.meshconnect.com/reference/post_api-v1-linktoken) endpoint.
The request must be performed from the server side as it risks exposing your API secret.
You will get the response in the following format:
```json
{
"content": {
"linkToken": "{linkToken}"
},
"status": "ok",
"message": ""
}
```
## Launching Link
### Create a LinkConfiguration
Each time you launch Link, you have to get a new `linkToken` from your backend and build a new
`LinkConfiguration` object:
```kotlin
val configuration = LinkConfiguration(
token = "linkToken"
)
```
Additional `LinkConfiguration` object parameters:
* `accessTokens` to initialize crypto transfers flow at the 'Select asset step’ using previously obtained integration `auth_token`.
It can be used if you have a valid `auth_token` and want to bypass authentication to jump right into a transfer.
* `transferDestinationTokens` for crypto transfers flow.
It is an alternative way of providing target addresses for crypto transfers by using previously obtained integration `auth_tokens`.
* `disableDomainWhiteList` is a flag that allows to disable origin whitelisting.
By default, it's enabled with the predefined [domains](link/src/main/java/com/meshconnect/link/utils/WhitelistedvOrigins.kt).
### Register an Activity Result callback
The Link UI runs in a separate Activity within your app.
To return the result you can use [Activity Result APIs](https://developer.android.com/training/basics/intents/result).
```kotlin
private val linkLauncher = registerForActivityResult(LaunchLink()) { result ->
when (result) {
is LinkSuccess -> /* handle success */
is LinkExit -> /* handle exit */
}
}
```
### Launch Link
```kotlin
linkLauncher.launch(configuration)
```
At this point, Link UI will open and return the `LinkSuccess` object if the user successfully
completes the flow.
### LinkSuccess
When a user successfully links an account or completes the transfer, the `LinkSuccess` object is
received. It contains a list of payloads that represent the linked items:
```kotlin
private fun onLinkSuccess(result: LinkSuccess) {
result.payloads.forEach { payload ->
when (payload) {
is AccessTokenPayload -> /* broker connected */
is DelayedAuthPayload -> /* delayed authentication */
is TransferFinishedSuccessPayload -> /* transfer succeed */
is TransferFinishedErrorPayload -> /* transfer failed */
}
}
}
```
### LinkExit
When a user exits Link without successfully linking an account or an error occurs,
the `LinkExit` object is received:
```kotlin
private fun onLinkExit(result: LinkExit) {
if (result.errorMessage != null) {
/* use error message */
}
}
```
### LinkPayloads
A `SharedFlow` emits payloads immediately:
```kotlin
lifecycleScope.launch {
LinkPayloads.collect { /* use payloads */ }
}
```
### LinkEvents
A `SharedFlow` emits events that happen at certain points in the Link flow:
```kotlin
lifecycleScope.launch {
LinkEvents.collect { /* use event */ }
}
```
## Deeplink navigation (recommended solution)
Standard deep links always create a new task or activity, unless you handle the back stack yourself.
To resume the previous state, consider these steps:
1. Define a custom URI scheme that is handled by a "No-op" activity.
2. No-op activity checks if the app is already running. If so, it finishes itself.
AndroidManifest.xml:
```xml
```
DeepLinkEntryActivity.kt:
```kotlin
class DeepLinkEntryActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Check if app is already running
packageManager.getLaunchIntentForPackage(packageName)?.run {
addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
startActivity(this)
}
finish()
}
}
```
Test deeplink:
```shell
adb shell am start -a android.intent.action.VIEW -d "myapp://"
```
When triggered:
* If your app is in the background: it’s brought to the foreground.
* If it’s not running: the default launcher activity is opened.
# API Key Permissions
Source: https://docs.meshconnect.com/guides/api-key-permissions
# Overview
Scoped access enables you to set permissions for your production Mesh API keys. Rather than granting unrestricted access, you can define whether each key has **Read-only** or **Read & Write** permissions. By managing access to specific API endpoints, you can reduce security risks by ensuring users only have access to necessary resources and nothing more. This is inline with the principles of zero trust and least privilege.
# Scope of current implementation
* Permissions are set at the client API key level.
* Permissions can only be set for production API keys, not sandbox keys.
* Permissions cannot be set at the broker-level (ie. clients cannot configure different permissions for Binance vs. Coinbase for the same API key).
* All keys allow for Read access.
* Clients can assign a key **Read-only** permissions or **Read & Write** permissions.
* Permissions can only be assigned at the time of key creation, not afterwards. API keys cannot be edited after they’ve been created. Only deleted.
* **Read** permission enables you to receive successful responses to all read calls to the Mesh API when using this key (eg. Get holdings, Get transfer history, etc.). A production API key always has read access. Even for write functionality, Mesh must read account data like balances as part of transfer configuration.
* **Write** permission enables you to receive successful responses to all write calls (eg. Execute order, Execute transfer, etc.) to the Mesh API when using this key. If **Write** permission is not enabled, a call to write data to a linked user account will return a `403` error from the Mesh API.
* When connecting their account, users will see a permissions screen that reflects the permissions granted to the API key, as shown below (Read & Write on the left, Read-only on the right).
* When connecting to Coinbase via OAuth, the Mesh API key permissions have been mapped to the OAuth permissions. Therefore, the permissions shown to the user in Coinbase's Oauth window will also reflect there properly.
* However, Mesh API key permissions are not currently mapped to other broker integrations beyond Coinbase. For example, if a Read-only Mesh API key is used to link a user’s Binance account to a client app, that Binance authentication still provides both Read & Write capabilities.
* Rest assured, even though the Binance connection to the client-app does support both Read & Write permissions, any calls to the Mesh API will respect the Mesh API key permissions (in this example, a trade or transfer call to the linked Binance account would return a `403` response from the Mesh API).
* This mapping is also not yet in place for other OAuth integrations beyond Coinbase. To discuss this further, please email [support@meshconnect.com](mailto:support@meshconnect.com).
# How to view & configure API key access scopes
* You can create Mesh API keys by going to Accounts —> [API keys](https://dashboard.meshconnect.com/company/keys).
* When creating a new production API key, you will have the option to enable permissions as shown below.
* We strongly recommend naming keys in a meaningful and logical way. For example, you can use the format: `--` (eg. Mesh-ReadOnly-MeshAggregate)
* After a key exists, you can view whether it has Read or Read & Write permissions as shown below.
# null
Source: https://docs.meshconnect.com/guides/error-dictionary
## Possible Ineligibility Reasons
Here are the reasons why holdings cannot be transferred in some cases.
## Configure Transfer Errors
| Error Code | Description | Level Found |
| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| NoEligibleNetworks | None of the networks supported by Source and Target accounts can be used for the transfer. Individual reasons specifying why a particular network cannot be used may vary. | Holdings |
| SymbolDoesNotMatch | The symbol that was requested for the transfer is different from the holding’s symbol | Holdings |
| NotSupportedForTransferByTarget | None of the networks for that token are eligible to transfer TO the source. This is often due to the **client** not supporting the token for transfer. | Holdings |
| NotSupportedForTransferBySource | None of the networks for that token are eligible to transfer FROM the source. This is often due to **Mesh or the integration** not supporting the token for transfer. | Holdings |
| AmountNotSufficient | The (amount to be transferred + the gas fee) is more than the available balance | Network |
| NoTargetNetworkFound | Target addresses/institution do not contain the corresponding network, so this network cannot be used for the transfer | Network |
| GasFeeAssetBalanceNotEnough | The amount of the asset is sufficient, but there’s not enough balance of the gas fee’s asset (e.g. not enough ETH to send USDC) | Network |
## Preview Transfer Errors
Statuses:
* Succeeded
* Failed
### Error messages (when status = failed)
| Error Code | Error Message |
| -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| NetworkIdMissing | (TransferToAddress.NetworkId) field was not provided. |
| AddressMissing | (TransferToAddress.Address) field was not provided. |
| SymbolMissing | (TransferToAddress.Symbol) field was not provided. |
| UnsupportedSymbolByNetwork | Network does not currently support the requested symbol. |
| InvalidAddressPattern | Target address does not match network '{0}' address pattern. |
| NetworkNotFound | Network not found. |
| NetworkDisabled | Network '{0}' is currently disabled and cannot be used. |
| InsufficientFunds | Insufficient '{0}' funds. |
| InsufficientFeeFunds | Insufficient '{0}' funds for transfer fees. |
| EmptyWalletSymbolBalance | Source wallet '{0}' balance is empty. |
| KycRequired | The provided '{0}' account requires KYC to be completed to perform transfers. |
| DepositAmountTooLow | The requested amount is lower than the minimum amount that can be accepted by the target institution. |
| WrongPreviewRequestFromAuthTokenMissing | (PreviewTransferRequest.FromAuthToken) is a mandatory field and should be provided. |
| WrongPreviewRequestNoSymbol | (PreviewTransferRequest.Symbol) is a mandatory field and should be provided. |
| WrongPreviewRequestInvalidToAuthToken | (PreviewTransferRequest.ToAuthToken) is invalid. |
| WrongPreviewRequestToData | Either (PreviewTransferRequest.ToAuthToken) with (PreviewTransferRequest.ToType) or (PreviewTransferRequest.ToAddress) should be provided. |
| WrongPreviewRequestAmount | Both (PreviewTransferRequest.AmountInFiat) and (PreviewTransferRequest.Amount) can not be provided. |
| WrongPreviewRequestNoAmount | Either (PreviewTransferRequest.AmountInFiat) or (PreviewTransferRequest.Amount) should be provided. |
| WrongPreviewRequestUnsupportedSymbolBySourceWallet | Symbol to transfer not supported by the source wallet over the requested network. |
| WrongPreviewRequestUnsupportedSymbolByTargetWallet | Symbol to transfer not supported by the target wallet over the requested network. |
| WrongPreviewRequestNetwork | Requested network is not supported by the source wallet. |
| PriceNotFound | Could not fetch '{0}' price. |
| AmountMoreThanWithdrawMaximum | Could not preview the transfer. The requested amount (previewRequest.Amount) (requestDto.Request.Symbol) is greater than the maximum allowed amount (minimumMaximumAmount.WithdrawMaximumAmount requestDto.Request.Symbol). |
| AmountLessThanWithdrawMinimum | Could not preview the transfer. The requested amount (previewRequest.Amount) (requestDto.Request.Symbol) is below the minimum allowable threshold (minimumMaximumAmount.WithdrawMinimumAmount requestDto.Request.Symbol). |
## Execute Transfer Errors
Statuses:
* Succeeded
* Failed
* MfaRequired
* EmailConfirmationRequired
* DeviceConfirmationRequired
* MfaFailed
* AddressWhitelistRequired
### Error messages (when status = failed)
| Error Code | Error Message |
| -------------------- | ------------------------------------- |
| PreviewExpired | The preview is expired. |
| TransferIsRequested | The transfer is already requested. |
| PreviewNotFound | Could not find the preview. |
| AddressNotRegistered | The target address is not registered. |
# Getting Started
Source: https://docs.meshconnect.com/guides/getting-started
We’re building fintech’s modern connection layer and are excited to help you on your journey toward a single, unified API.
###
Check out our guides to learn how to build on Mesh
Leverage our interactive workshop to get a 201 understanding on how Mesh works
Explore our API endpoints
We've built some beatiful experiences on top of our API/SDK- check em out
The simplest and most secure way to deposit crypto
Let your customers pay from their existing accounts on Coinbase, Binance, Metamask and 300+ others, with a single integration
On-ramp directly from stored payment methods in your customers’ exchange accounts with no additional KYC
Automated, secure collection of payout wallet addresses
### Requirements
The Mesh API program is built for scaling and self-service. In order to get started, we require:
* [Mesh Dashboard account](https://dashboard.meshconnect.com/login)
* A registered business account (for production keys)
### Grabbing Your API Keys
* [Generate API Keys](https://dashboard.meshconnect.com/company/keys)
* Choose to create Sandbox or Production API Keys. ***Be sure to store key in a secure place (i.e., .env file ) and you only get one chance to copy from dashboard***
## Start Building on Mesh
You're ready to begin building on our MeshConnect platform! Be sure to check out our guides and [interactive workshop](https://workshop.meshconnect.com)
# Handling Auth Tokens
Source: https://docs.meshconnect.com/guides/handling-auth-tokens
This guide explains the integration tokens system within Mesh API, encompassing the processes of token generation, renewal, and storage. It can be used to better understand the system so that developers can follow best practices when integrating with Mesh APIs.
# What is a “token”
`AccessToken` or `AuthToken` is a generated secret (sequence of symbols) that is returned by Mesh API upon successful account authentication and used in subsequent requests to access the user’s data.
Each token represents a connection between a particular user (typically, an end user of a client) and the user’s brokerage/exchange/wallet account.
The token grants access to the user's data and enables the execution of read and (based on the integration) write operations. Therefore, it is essential to store the token with **utmost security measures** in place.
## Types of tokens
There are 2 types of tokens provided by the Mesh API:
### `AccessToken`
A token that allows performing read and write operations with the connected account.
Can be obtained in the following ways:
* in a [Link JS](/api-reference/managed-account-authentication/get-link-token-with-parameters) callback upon **successful** authentication [managed authentication](/api-reference/managed-account-authentication/get-link-token-with-parameters) - recommended
* by calling [/api/v1/linkToken](/api-reference/managed-account-authentication/get-link-token-with-parameters)
* by refreshing the token using the refreshToken in the following request - [/api/v1/token/refresh](/api-reference/managed-account-authentication/refresh-auth-token)
### `RefreshToken`
A token that is returned by some integrations and needs to be used to refresh the access token before it expires.
Provided typically by OAuth and username password integrations, it is critical that it is handled correctly in order to ensure continued connections to accounts.
Can be obtained in the following ways:
\-- in a [Link JS](/api-reference/managed-account-authentication/get-link-token-with-parameters) callback upon **successful** authentication [managed authentication](/api-reference/managed-account-authentication/get-link-token-with-parameters) - recommended
* by calling [/api/v1/authenticate](/api-reference/managed-account-authentication/get-link-token-with-parameters)
* by refreshing the token using the refreshToken in the following request - [/api/v1/token/refresh](/api-reference/managed-account-authentication/refresh-auth-token)
* by refreshing the refresh token using the refreshToken in the following request - [/api/v1/token/refresh](/api-reference/managed-account-authentication/refresh-auth-token) and providing `CreateNewRefreshToken` parameter
***
# Walkthrough
## Step 1: Get tokens
You can use the SDK callback function `onIntegrationConnected()` to capture the accessTokenPayload after the user successfully connects an account. In particular, the elements you'll need are:
* `accessToken`
* `refreshToken`
* `expiresInSeconds`
* `refreshTokenExpiresInSeconds`
* `brokerType`
* `brokerName`
## Step 2: Associate tokens with a user
You can use any unique identifier you have to associate this with one user.\
This step is very important to ensure you don't load one user's account for a different user.
## Step 3: Store tokens securely
Store tokens in a secure and encrypted storage layer such as a key management system.
## Step 4: Add in logic to refresh tokens as necessary
Check if `expiresInSeconds` value is present. If so, it means that the `accessToken` should be refreshed before it expires.\
Create logic that registers the timestamp when the accessToken is obtained, records the `expiresInSeconds`, and uses the `refreshToken` in a POST to the endpoint [/api/v1/token/refresh](https://docs.meshconnect.com/api-reference/managed-account-authentication/refresh-auth-token) before `timestamp` + `expiresInSeconds` occurs.\
If `refreshTokenExpiresInSeconds` is also provided, create the same logic for the `refreshToken` to refresh it with a call to the same endpoint with `CreateNewRefreshToken: true` parameter before timestamp +`refreshTokenExpiresInSeconds` occurs.
Note: it is a bad practice to rely on 401 responses to update tokens after they have expired.
## Step 5: Pass this data when initializing the Mesh SDK for a specific user
Method to load SDK: `createLink()`...\
Within the `IntegrationAccessToken` interface...\
Pass the following for the object `accessTokens`...
* `accessToken`
* `brokerType`
* `brokerName`
* `accountId` can be empty
* `accountName` can be empty
This can be an array (ie. different access tokens for each integration that the user has previously linked).
***
## A note on UX considerations for implementation
If you would like the user to go directly to a specific integration when launching Mesh's SDK (for example if you have a "Deposit from Coinbase" button in your UX), then you can additionally include an `integrationId` in the `linkToken` request. This will skip the catalog and would normally bring the user to that integrations authentication flow. But if an `accessToken` is supplied for this integration when initializing the SDK, then the user will go right into the transfer flow when Link launches (ie. they will skip catalog and skip auth).
If you would like the user to see the catalog (ie. maybe there's a general "Deposit directly from your exchange or wallet" button in your UX), then you can simply follow the steps above to pass any `accessTokens` available for the user (one or an array). If the user selects an integration from the catalog for which there is an available `accessToken`, they will skip auth and go right to transfer.
# iOS SDK
Source: https://docs.meshconnect.com/guides/ios-sdk
## Installation
Add package [LinkSDK](https://github.com/FrontFin/mesh-ios-sdk) in your project's Package Dependencies or download [LinkSDK.xcframework](https://github.com/FrontFin/mesh-ios-sdk/tree/main/LinkSDK.xcframework).
## Get Link token
Link token should be obtained from the POST `/api/v1/linktoken endpoint`. API reference for this request is available [here](/api-reference/managed-account-authentication/get-link-token-with-parameters). The request must be performed from the server side because it requires the client's secret. You will get the response in the following format:
Set up `GetFrontLinkSDK` with the `linkToken`
```json
{
"content": {
"linkToken": "{linkToken}"
},
"status": "ok",
"message": ""
}
```
## Launch Link
Create a `LinkConfiguration` instance with the `linkToken` and the callbacks:
```swift
let configuration = LinkConfiguration(
linkToken: linkToken,
settings: LinkSettings?,
onIntegrationConnected: onIntegrationConnected,
onTransferFinished: onTransferFinished,
onEvent: onEvent,
onExit: onExit)
```
The callback `onIntegrationConnected` is called with `LinkPayload` once an integration has been connected.
```swift
let onIntegrationConnected: (LinkPayload)->() = { linkPayload in
switch linkPayload {
case .accessToken(let accessTokenPayload):
print(accessTokenPayload)
case .delayedAuth(let delayedAuthPayload):
print(delayedAuthPayload)
}
}
```
The callback `onTransferFinished` callback is called once a crypto transfer has been executed or failed. The parameter is either `success(TransferFinishedSuccessPayload)` or `error(TransferFinishedErrorPayload)`.
The callback `onEvent` is called to provide more details on the user's progress while interacting with the Link. This is a list of possible event types, some of them may have additional parameters:
* `loaded`
* `integrationConnectionError`
* `integrationSelected`
* `credentialsEntered`
* `transferStarted`
* `transferPreviewed`
* `transferPreviewError`
* `transferExecutionError`
The callback `onExit` is called once a user exits the Link flow. It might be used to dismiss the Link view controller in case the app manages its life cycle (see `LinkHandler.create()`)
Callback closures are optional, but either `onIntegrationConnected` or `onTransferFinished` must be provided.
Create a `LinkHandler` instance by calling `createHandler()` function, or handle an error. The following errors can be returned:
* Invalid `linkToken`
* Either `onIntegrationConnected` or `onTransferFinished` callback must be provided
```swift
let result = configuration.createHandler()
switch result {
case .failure(let error):
print(error)
case .success(let handler):
handler.present(in: self)
}
```
In case of success, you can call `LinkHandler.present` (in `viewController`) function to let `LinkSDK` modally present the Link view controller and dismiss it on exit, or get the reference to a view controller by calling `LinkHandler.create()` if you prefer your app to manage its life cycle.
### Adding URL Schemes to Info.plist
To enable our SDK to interact with specific apps, please add the following URL schemes to your info plist file
* Open your info.plist located in the 'ios' directory of your React Native project
* Add the following XML snippet within the `` tag.
```xml
LSApplicationQueriesSchemestrustrobinhoodmetamaskrainbowuniswapexodusrobinhood-walletblockchain-wallet1inchcryptowalletokxbitkeep
```
# Launch Checklist
Source: https://docs.meshconnect.com/guides/launch
### Getting Started:
* [Generate API](https://dashboard.meshconnect.com/company/keys) keys for sandbox and production environments.
* Production access requires going through our KYB process. But don’t worry, our Sandbox environment allows you to develop end to end while you await KYB approval.
* [Define](https://dashboard.meshconnect.com/company/keys) Specific Domains for Mesh Access Across All Production and Pre-Production Environments (i.e., [https://localhost:3000](https://localhost:3000)). Wildcards are supported (i.e., https\://\*.westus2.5.azurestaticapps.net/).
* \[Optional] Familiarize yourself with [Interactive Demo](https://dashboard.meshconnect.com/docs/interactive-demo) to see how Mesh Link Modal handles different use cases and integrations.
### Dashboard Configuration:
* [Upload](https://dashboard.meshconnect.com/company/link/branding) your icon and Company Name to be displayed in Mesh modal
* [Create](https://dashboard.meshconnect.com/company/link/restrictions) either a “Deny List” or an “Allow List” to manage the countries from which your users will be able to use Mesh Link to connect accounts or initiate transfers (based on IP address).
* [Configure](https://dashboard.meshconnect.com/company/link/configurations) the Mesh modal to your Branding guidelines.
* [Exclude](https://dashboard.meshconnect.com/company/link/configurations) wallets/exchanges/brokerages that aren’t popular to your user demographic. Typically our customers use custom buttons for their top few exchanges and wallets and a ‘catch all button’ that opens the Mesh catalogue
* [Customize](https://dashboard.meshconnect.com/company/link/customizations) the branding elements of the Link modal. You can adjust the modal overlay opacity, corner radii, button radii, and also add button backup colors to match your app for lesser-used integrations.
### Development
* \[Optional] Before starting development, we recommend completing the [Mesh Workshop](https://workshop.meshconnect.com/). This workshop provides a comprehensive introduction to:
* Connecting to our integrations, networks, and tokens
* Authenticating users through the Mesh Modal
* Fetching data from connected wallets or exchanges
* Exploring various workflows transferring data
* Since Mesh is a client-side SDK, ensure that your front-end application running the Mesh SDK does not make direct API calls or store Mesh API credentials. The best practice is to have your front end communicate with a middleware service layer that securely handles access to Mesh API credentials.
* \[Optional] Pass fundingOptions object in linkToken to ensure users can buy more crypto or convert existing crypto in a
transfer flow. This extends Transfer options when a user is paying for a good or
service but doesn’t have enough of the request token. Refer to Account
* Pass a unique transactionId with every transfer initiated in Link Modal
* Pass a transferType key value pay for every linkToken transfer request. Values are: deposit | onramp | payment
* \[Optional] Allow users to send assets over L2’s to save on gas
* \[Recommended] Listen for Mesh transfer webhooks to receive real-time updates
on the transfer lifecycle, including statuses such as pending, succeeded, or failed.
* Completed transfers will include a transaction hash in the response object of the GET Mesh transfers endpoint.
* Mesh monitors transactions on the blockchain for up to 2 hours to obtain a transaction hash. If the hash is not received within this timeframe, an alert is triggered for our on-call team to investigate.
* \[Recommended]
Listen to Client side SDK events: Each SDK provides client-side events to help you
understand the workflow behavior of every Link session. This allows you to push real-time
user experience data to your observability and business intelligence tools (e.g.,
Mixpanel). - \[Optional] Leverage our guides for [handling access tokens](https://docs.meshconnect.com/guides/handling-auth-tokens)
* \[Optional] Error Handling: familiarize yourself with [Mesh Error types](https://docs.meshconnect.com/guides/error-dictionary)
and add retry logic and error handling as necessary
### **Testing**
* Conduct end-to-end testing in the sandbox environment. Please note, Mesh does not support testnets for self-custody wallets. All API and Modal behavior is simulated
* Test webhook data connectivity to your endpoint
* \[Recommnded] Share application build with Mesh to provide any final guidance and feedback
### **Pre-Launch:**
* Notify Mesh team of planned launch
* Upgrade to the latest SDK build and perform functional and UAT testing
### Post-launch
* Notify your Mesh Account Executive and Implementation Specialist
* [Subscribe](https://status.meshconnect.com/) to Mesh status page
### Links
* [Mesh API Docs](https://docs.meshconnect.com/guides/getting-started)
* [Interactive Demo](https://dashboard.getfront.com/docs/interactive-demo)
* [Mesh Workshop](https://workshop.meshconnect.com)
# Link Utilization and Use cases
Source: https://docs.meshconnect.com/guides/link-initialization
## Overview
Mesh Link SDK allow client applications to connect users to their accounts across brokerages, centralized exchanges, and self-custody wallets. Mesh Link UI handles credential validation, multi-factor authentication, and error handling when connecting to each account.
After an end user authenticates with their account credentials, clients will be passed authentication tokens to provide access to the account which allows client applications to read account information such as holdings, transactions, and balances, and initiate trades and transfers on behalf of the end user.
## Getting Your API Keys
You can generate two different API keys (one for Sandbox and another for Production) on the [Mesh Dashboard](https://dashboard.meshconnect.com/company/keys), you should **store the API keys immediately** after generating them as they will no longer be viewable after leaving the page.
> ❗️ These API keys should never be stored on your client-side application, always store them securely on your applications backend, following security best practices.
## LinkToken Endpoint
This [endpoint](/api-reference/managed-account-authentication/get-link-token-with-parameters) provides a short-lived, one-time-use token for initializing a Link session, when passed to one of the client side SDKs. Depending on the payload of the API call, the Link UI will load into different workflows, such as user authentication, or asset transfer.
The LinkToken endpoint should always be called from your backend, since it requires an API secret.
## Link UI Use Cases
In the next section we will go trough the different ways Link UI can be initialized:
## Account Authentication
### Basic Account Authentication
The most basic way to initialize Link is to simply pass the `UserId` body param. The `UserId` is a unique ID representing the end user. This identifier is a map to reference which customers you are logging in through Mesh Link.
```json
{
"UserId": "EndUserId",
}
```
POST /api/v1/linktoken body
### Direct to Exchange or Brokerage Integration
Many of our customers and UI/UX designers want to launch link directly to a specific integration (eg. Binance or Coinbase) and skip our Full Catalogue. This is easily achieved by including the `IntegrationId` param.
The `IntegrationId` of the integration you wish to connect can be obtained by calling the **[Retrieve the list of all available integrations.](/api-reference/managed-transfers/get-integrations)** endpoint and referencing the `id` field.
```json
{
"UserId": "EndUserId",
"IntegrationId": "9226e5c2-ebc3-4fdd-94f6-ed52cdce1420"
}
```
POST /api/v1/linktoken body
### Direct to Self Custody Wallet
Many of our customers and UI/UX designers want to load up Link directly to a specific wallet (eg. Metamask) and skip our Full Catalogue. This is easily achieved by including the `IntegrationId` param.
The `IntegrationId` of the integration you wish to connect can be obtained by calling the **[Retrieve the list of all available integrations.](/api-reference/managed-transfers/get-integrations)** endpoint and referencing the `id` field.
```json
{
"UserId": "EndUserId",
"IntegrationId": "34aeb688-decb-485f-9d80-b66466783394"
}
```
POST /api/v1/linktoken body
### Restricting User to Connect only One Account
By default, Link UI lets users authenticate with more than one provider in one session. This is great for portfolio management use cases or when a user wants to transfer from one provider to another within your application. To limit the authentication to one provider, set the RestrictMultipleAccounts param to true.
```json
{
"UserId": "EndUserId",
"RestrictMultipleAccounts": true
}
```
POST /api/v1/linktoken body
## Deposits
### Sending Assets to a Single Crypto Address
You can include as many `toAddresses` object items, but the most streamlined way for users to transfer assets is to include a single token/network/address combo. Please remember that for each item in the 'toAddresses' array, you must provide the Mesh UID for the network to which you are sending the supported token. The comprehensive list of tokens, networks and integrations that can Mesh supports can be found here: [Tokens](/api-reference/managed-transfers/get-supported-tokens-list) | [Networks](/api-reference/managed-transfers/get-networks) | [Integrations](/api-reference/managed-transfers/get-integrations)
> 👍 If only one destination address is provided, the Link UI skips the ‘Select asset’ and ‘Select network’ screens to streamline the user experience.
```json
{
"UserId": "EndUserId",
"TransferOptions": {
"ToAddresses": [
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "ETH",
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
}
]
}
}
```
POST /api/v1/linktoken body - single network and token
### Configuring for Multiple Crypto Tokens or Networks
You can include as many `toAddresses` object items as needed to enable your users to perform transfers. Each item, represents the symbol they can transfer and the network it could be sent over. Please remember that for each item in the 'toAddresses' array, you must provide the Mesh UID for the network to which you are sending the supported token. The comprehensive list of tokens, networks and integrations that can Mesh supports can be found here: [Tokens](/api-reference/managed-transfers/get-supported-tokens-list) | [Networks](/api-reference/managed-transfers/get-networks) | [Integrations](/api-reference/managed-transfers/get-integrations)
```json
{
"UserId": "EndUserId",
"TransferOptions": {
"ToAddresses": [
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "ETH",
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
},
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "USDC",
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
},
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "USDT",
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
},
{
"NetworkId": "7436e9d0-ba42-4d2b-b4c0-8e4e606b2c12",
"Symbol": "MATIC",
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
}
]
}
}
```
POST /api/v1/linktoken body - multiple networks/tokens
### Sending Assets to a Previously Connected User Account
In the case if the end user has an already connected integration, and you want to move some funds between the users accounts, you can pass the `auth_token` when initializing the SDK.
#### `accessTokens` Code Example
`transferDestinationTokens`
The `transferDestinationTokens` are used for crypto transfers flow. It is an alternative way of providing target addresses for crypto transfers by using previously obtained integration `auth_tokens`.
The type of the `transferDestinationTokens` parameter is an array of `IntegrationAccessToken`.
See the type definition on our [GitHub](https://github.com/FrontFin/mesh-web-sdk/blob/main/packages/link/src/utils/types.ts).
```json
const transferDestinationTokens =
[
{
accountId: 'accountId',
accountName: 'accountName',
accessToken: 'accessToken',
brokerType: 'brokerType',
brokerName: 'brokerName',
},
]
const meshLink =
createLink({
clientId: 'clientId',
onIntegrationConnected: (payload) => {},
onExit: (error) => {},
onTransferFinished: (transferData) => {},
onEvent: (ev) => {},
accessTokens: [],
transferDestinationTokens: transferDestinationTokens // Provide a previously obtained integration auth_tokens to use as destination address
})
```
In this case you need to provide an **empty** `toAddresses` array to the LinkToken endpoint, to indicate that you wish to use the transfers workflow.
```json
{
"UserId": "EndUserId",
"TransferOptions": {
"ToAddresses": []
}
}
```
POST /api/v1/linktoken body
## Payments
### Transferring for a Specific Amount
If you’d like to initialize Mesh Link with the transfer amount pre-populated with a supplied destination address, include the assets you want to let the user pay with, plus the destination addresses of those tokens. In the example below, the user can pay with Solana or USDC over Ethereum networks (notice how the network IDs are different).
You can achieve this by providing the `AmountInFiat` parameter when calling the LinkToken endpoint
By providing a unique `TransactionID`, you'll be to map a payments to a specific identifier, similar to an order number.
```json
{
"UserId": "EndUserId",
"TransferOptions": {
"ToAddresses": [
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "ETH",
"Amount": 0.0032,
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
},
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "USDC",
"Amount": 10,
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
},
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "USDT",
"Amount": 10,
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
},
{
"NetworkId": "7436e9d0-ba42-4d2b-b4c0-8e4e606b2c12",
"Symbol": "MATIC",
"Amount": 22.8,
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
}
],
"TransactionId": "TransactionId"
}
}
```
POST /api/v1/linktoken body - multiple networks/tokens
> 👍 If `AmountInFiat` is included and only a single network/token/address combo is included, Link will skip directly to the preview page, making even more streamlined for a user to complete their transfer.
```json
{
"UserId": "EndUserId",
"TransferOptions": {
"ToAddresses": [
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "ETH",
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
}
],
"AmountInFiat": 10,
"TransactionId": "TransactionId"
}
}
```
POST /api/v1/linktoken body - single network and token
#### Adding a Fee for a Payment
If you’d like to charge a client fee for processing a transfer, you can append the `ClientFee` field to the above JSON object examples. This fee should only be used for **Payments** (when the transfer destination is an address owned by your company), and not for Deposits (when the transfer destination is an address owned by the end-user).
A percentage fee (input as a ratio, eg. 0.02500 = 2.500%) added onto your users' gross transfer to your company.
This will override any default fee entered in your Mesh dashboard for an individual transaction.
```json
{
"UserId": "EndUserId",
"TransferOptions": {
"ToAddresses": [
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "ETH",
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
},
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "USDC",
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
},
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "USDT",
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
},
{
"NetworkId": "7436e9d0-ba42-4d2b-b4c0-8e4e606b2c12",
"Symbol": "MATIC",
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
}
],
"AmountInFiat": 10,
"ClientFee": 0.025
}
}
```
POST /api/v1/linktoken body - multiple networks/tokens
```json
{
"UserId": "EndUserId",
"TransferOptions": {
"ToAddresses": [
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "ETH",
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
}
],
"AmountInFiat": 10,
"TransactionId": "TransactionId"
"ClientFee": 0.025
}
}
```
POST /api/v1/linktoken body - single network and token
# Mesh Link SDK Events
Source: https://docs.meshconnect.com/guides/link-ui-events
## Overview
Mesh Link UI offers an event tracking system, allowing you to gain insights into user interactions within the Link UI. These events can be used for analytics and understanding user behavior. The event data can be obtained directly from the SDKs and includes various user actions, such as initiating a connection, completing authentication, completing an asset transfer, or encountering errors.
The way in which these events are captured and transmitted varies slightly across different platforms (Web, iOS, Android, and React Native). For detailed instructions, see the page for your specific platform.
# SDK Callback Functions
| **SDK callback function** | **Description of callback function** | **Payload details** |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`onIntegrationConnected()`** | A callback function that allows you (Mesh client) to run specific business logic when the user has successfully completed connecting an account. | • **`accessToken`**: the access and refresh tokens to the connected account with some basic metadata about the account and tokens. • **`brokerBrandInfo`**: links to icons and logos for the connected integration |
| **`onTransferFinished()`** | A callback function that allows you (Mesh client) to run specific business logic when the user has successfully completed a transfer. | • **`status`**: pending / succeeded / failed • **`txId`**: A unique client identifier • **`transferId`**: A unique Mesh identifier • **`txHash?`**: A unique blockchain identifier • **`fromAddress`**: Address transfer is sent from • **`toAddress`**: Address transfer is sent to • **`symbol`**: Symbol of asset being transferred • **`amount`**: Amount being transferred • **`amountInFiat`**: Fiat equivalent of transfer amount • **`totalAmountInFiat`**: Total amount transferred, including transfer-related fees • **`networkId`**: Selected network identifier • **`networkName`**: Selected network name • **`refundAddress`**: The address that the user can receive back to |
| **`onExit()`** | A callback function that allows you (Mesh client) to run specific business logic when the user has exited Link at some point. | • **`errorMessage`**: Descriptive error message, if applicable • **`summary`**: // optional • **`page`**: the page the user was on when they exited • **`selectedIntegration`**: Name and Id of integration • **`transfer`**: previewId and other details about the transfer preview |
| **`onEvent()`** | A general callback function that allows you (Mesh client) to run specific business logic in more granular scenarios, like when the user exits Link from specific parts in the user journey. The events that can be used in this callback function are listed below. | Different payload structure for different events |
# SDK Events
| **SDK Event Type** | **Description of Occurrence** | **Payload Details** |
| ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`pageLoaded`** | Triggered when the first page is fully loaded. The first page the user sees may differ based on use case. | No additional payload. |
| **`close`** | Triggered when the user exits the Mesh Link modal. | • **`page`**: the page the user was on when they exited. • Note: In the context of a transfer flow, `page: 'transferExecutedPage’` would indicate the full flow was successful because the user exited from the Success page. And if the page is anything else, then the flow was not successfully completed. |
| **`integrationSelected`** | Triggered when a user selects an integration from the catalog list. | • **`integrationType`**: For exchanges, this is the same as the name. For wallets, this is ‘deFiWallet’. • **`integrationName`**: Name of the selected integration. • **`userSearched?`**: true/false if the user searched selected this integration from search results or not. |
| **`legalTermsViewed`** | Triggered if a user views the terms of use page in Link. | No additional payload. |
| **`credentialsEntered`** | Triggered when a user submits exchange login credentials. | No additional payload. |
| **`integrationMfaRequired`** | Triggered when the user is prompted to enter MFA in an exchange authentication flow. | No additional payload. |
| **`integrationMfaEntered`** | Triggered when the user enters their MFA code in an exchange authentication flow. | No additional payload. |
| **`integrationOAuthStarted`** | Triggered when an exchange’s OAuth window is launched in authentication flow. | No additional payload. |
| **`integrationAccountSelectionRequired`** | Triggered if user is prompted to select a specific account within linked exchange. | No additional payload. |
| **`integrationConnected`** | Triggered when a user successfully connects to an integration. | • **`integrationType`**: For exchanges, this is the same as the name. For wallets, this is ‘deFiWallet’. • **`integrationName`**: Name of the selected integration. • \*\*`accessToken`\*\*payload: The access token to the user account and relevant metadata about the integration |
| **`integrationConnectionError`** | Triggered when there is an error in connecting to an integration. | • **`errorMessage`**: Descriptive error message. |
| **`transferStarted`** | Triggered when the user begins the transfer flow. This means they have successfully connected an account and have moved on to either configuring or previewing their transfer. It does NOT mean they have initiated a transfer of assets. | • **`integrationType`**: For exchanges, this is the same as the name. For wallets, this is ‘deFiWallet’. • **`integrationName`**: Name of the selected integration. |
| **`transferAssetSelected`** | Triggered when the user selects an asset to transfer. This does not relate to assets used for funding operations. This is about the asset being transferred. | • **`integrationType`**: For exchanges, this is the same as the name. For wallets, this is ‘deFiWallet’. • **`integrationName`**: Name of the selected integration. • **`symbol`**: Currency symbol |
| **`transferNetworkSelected`** | Triggered when the user selects a network to transfer on. | • **`integrationType`**: For exchanges, this is the same as the name. For wallets, this is ‘deFiWallet’. • **`integrationName`**: Name of the selected integration. • **`symbol`**: Currency symbol • **`networkId`**: Selected network identifier • **`networkName`**: Selected network name |
| **`transferAmountEntered`** | Triggered when the user enters an amount to transfer. | • **`integrationType`**: For exchanges, this is the same as the name. For wallets, this is ‘deFiWallet’. • **`integrationName`**: Name of the selected integration. • **`symbol`**: Currency symbol • **`networkId`**: Selected network identifier • **`networkName`**: Selected network name • **`amount`**: Amount the user enters for transfer |
| **`transferNoEligibleAssets`** | Triggered when there are no assets in the user’s account eligible for the transfer, or Mesh cannot use the assets in the account to fund the transfer. | • **`arrayOfTokensHeld`**: A list of tokens held in the user’s account • **`symbol`**: Currency symbol • **`amount`**: Amount of holding • **`amountInFiat`**: Amount of holding in fiat • **`ineligibilityReason`**: Why the token is ineligible. • **`integrationType`**: For exchanges, this is the same as the name. For wallets, this is ‘deFiWallet’. • **`integrationName`**: Name of the selected integration. • **`noAssetsType`**: |
| **`transferConfigureError`** | This may happen if the session linkToken expires during the configuration flow of a transfer. Very rare. | • **`errorMessage`**: Descriptive error message. • **`requestId`**: |
| **`transferPreviewed`** | Triggered when a user previews the details of a pending transfer. | • **`integrationType`**: For exchanges, this is the same as the name. For wallets, this is ‘deFiWallet’. • **`integrationName`**: Name of the selected integration. • **`symbol`**: Currency symbol • **`networkId`**: Selected network identifier • **`networkName`**: Selected network name • **`amount`**: Crypto amount of the transfer • **`amountInFiat`** (optional): Amount in fiat currency • **`fiatCurrency`**: fiat currency symbol for the **`amountInFiat`** value. • **`toAddress`**: Destination address • **`fees`**: • `institutionTransferFee` • `estimatedNetworkGasFee` • `customClientFee` • **`fiatPurchaseStrategy`**: an enumeration of a fiat funding option used to fund this transaction plus any applicable `tradingFee`. • **`cryptocurrencyFundingOptionType`**: an enumeration of any funding options used to fund this transactionplus any applicable `cryptocurrencyConversionFee` or `depositFee`. • **`previewId`**: Unique ID for the preview |
| **`transferPreviewError`** | Triggered when there is an error in building a transfer preview. | • **`errorMessage`**: Descriptive error message. |
| **`fundingOptionsViewed`** | Triggered when the user views the funding options page. | No additional payload. |
| **`fundingOptionsUpdated`** | Triggered when the user makes updates to the selected funding options and clicks save (ie. saves a new funding strategy). | No additional payload. When a user saves a new funding strategy, it would build a new Preview, which would fire a new **`transferPreviewed`** event with new funding options enumerated. |
| **`transferInitiated`** | Triggered when the user clicks to Proceed from the Preview screen. This will send a request to transfer to the exchange or wallet, which the user then needs to approve (via 2FA for exchange, or signing for wallet). | • **`integrationType`**: For exchanges, this is the same as the name. For wallets, this is ‘deFiWallet’. • **`integrationName`**: Name of the selected integration. • **`symbol`**: Currency symbol • **`networkId`**: Selected network identifier • **`networkName`**: Selected network name • **`amount`**: Crypto amount of the transfer • **`amountInFiat`** (optional): Amount in fiat currency • **`fiatCurrency`**: fiat currency symbol for the **`amountInFiat`** value. • **`toAddress`**: Destination address • **`fees`**: • `institutionTransferFee` • `estimatedNetworkGasFee` • `customClientFee` • **`fiatPurchaseStrategy`**: an enumeration of a fiat funding option used to fund this transaction plus any applicable `tradingFee`. • **`cryptocurrencyFundingOptionType`**: an enumeration of any funding options used to fund this transactionplus any applicable `cryptocurrencyConversionFee` or `depositFee`. |
| **`executeFundingStep`** | Triggered when there is a success or error on a funding operation before a transfer. | • **`fundingOptionType`**: The operation that has completed or failed. • **`status`**: Outcome of the funding operation. • **`errorMessage`**: Descriptive error message. |
| **`gasIncreaseWarning`** | Triggered after funding operations and before initiation of transfer if the cost of gas has gone higher than the buffered estimate shown to the user on the Preview page. | No additional payload. |
| **`transferMfaRequired`** | Triggered when the user is prompted to enter an MFA code to perform an exchange transfer. | No additional payload. |
| **`transferMfaEntered`** | Triggered when the user submits their MFA code to perform an exchange transfer. | No additional payload. |
| **`transferKycRequired`** | Triggered when the user has not completed KYC in the linked account, is prompted to do so before being able to transfer assets. | No additional payload. |
| **`transferExecuted`** | Do not use. Obsolete. | Do not use. Obsolete. |
| **`transferCompleted`** | Triggered when the user views the Success page at the conclusion of the transfer flow. It is recommended to use the **`onTransferFinished()`** callback function to properly handle the user experience returning to your app after a successful transfer. | **`transferFinished`** payload: • **`status`**: pending / succeeded / failed • **`txId`**: A unique client identifier • **`transferId`**: A unique Mesh identifier • **`txHash?`**: A unique blockchain identifier • **`fromAddress`**: Address transfer is sent from • **`toAddress`**: Address transfer is sent to • **`symbol`**: Symbol of asset being transferred • **`amount`**: Amount being transferred • **`amountInFiat`**: Fiat equivalent of transfer amount • **`totalAmountInFiat`**: Total amount transferred, including transfer-related fees • **`networkId`**: Selected network identifier • **`networkName`**: Selected network name • **`refundAddress`**: The address that the user can receive back to |
| **`transferExecutionError`** | Triggered when there is an error in executing a transfer. | • **`errorMessage`**: Descriptive error message. |
| **`seeWhatHappenedClicked`** | Triggered when the user clicks the See what happened link on the Transfer Success screen | No additional payload. |
| **`connectionUnavailable`** | Triggered when a timeout occurs when attempting to open a wallet on mobile, most likely because the DeFi wallet app is not installed on the device. | • **`integrationType`**: For exchanges, this is the same as the name. For wallets, this is ‘deFiWallet’. • **`integrationName`**: Name of the selected integration. • **`reason`**: string |
| **`connectionDeclined`** | Triggered when the user rejects a connection request in their wallet, or some error causes an auto-rejection. | • **`integrationType`**: For exchanges, this is the same as the name. For wallets, this is ‘deFiWallet’. • **`integrationName`**: Name of the selected integration. • **`reason`**: string. • **`networkId`**: Selected network identifier • **`networkName`**: Selected network name • **`toAddress`**: Address transfer is sent to. • **`errorMessage`**: Descriptive error message. |
| **`transferDeclined`** | Triggered when the user rejects the transfer request in their wallet, or some error causes an auto-rejection. | • **`integrationType`**: For exchanges, this is the same as the name. For wallets, this is ‘deFiWallet’. • **`integrationName`**: Name of the selected integration. • **`reason`**: string • **`networkId`**: Selected network identifier • **`networkName`**: Selected network name • **`toAddress`**: Address transfer is sent to • **`symbol`**: Symbol of asset being transferred • **`amount`**: Amount being transferred • **`status`**: pending / succeeded / failed |
| **`walletMessageSigned`** | Triggered when a user signs a message in their wallet to verify ownership. | • **`address`**: wallet address that signed the message • **`isVerified`**: true / false indicator of whether the user has signed the exact message sent for signature from this address • **`message`**: Message that was signed • **`signedMessageHash`**: The hash of the message signed by the wallet • **`timeStamp`**: Time stamp of when the signature happened |
| **`verifyDonePage`** | Triggered when the user views the Success page after successfully completing the wallet verification flow. | No additional payload. |
| **`verifyWalletRejected`** | Triggered when the user rejects the message signature request in their wallet, or some error causes an auto-rejection. | No additional payload. |
| **`done`** | Triggered when the user exits Link after successfully completing a read-only account connection flow (ie. for Mesh Verify) or after successfully completing the wallet verification flow (ie. for Mesh Verify). | • **`page`**: the page the user was on when they exited. • Note: In wallet verification (ie. Mesh Verify) flow, `page: verifyDonePage` would indicate successful completion of the flow. And in a read-only (ie Mesh Portfolio) flow, `page: integrationConnectedPage` would indicate successful completion of the flow. |
| **`registerTransferError`** | Shown when we are unable to receive the transfer hash from a self-custody wallet at the conclusion of a transfer flow. | • **`errorMessage`**: Descriptive error message. |
# Account Authentication
Source: https://docs.meshconnect.com/guides/quickstart-auth
# Authenticating Accounts via Link
This guide details the various methods for authenticating users with Link, enabling secure connections to their external accounts. We will cover basic user identification and advanced routing for streamlined integration experiences.
## Basic User Identification via `UserId`
The fundamental approach to initiating a Link flow involves simply providing the `UserId`. This method allows the user to navigate the full Link integration catalog.
**Request Body:**
```json
{
"UserId": "unique_end_user_identifier"
}
```
* **`UserId`**: A string representing the unique identifier for the end user within your application.
## Direct Integration Launch via `IntegrationId`
For optimized user flows targeting specific platforms, Link supports direct launch into a designated integration (e.g., Binance, Coinbase). This bypasses the full integration catalog, improving user experience for focused connection scenarios.
**Implementation:**
1. **Retrieve `IntegrationId`**: Obtain the unique identifier for the target integration by querying the [Retrieve the list of all available integrations](https://docs.meshconnect.com/api-reference/managed-account-authentication/retrieve-the-list-of-all-available-integrations) endpoint. The `id` field within the integration object represents the `IntegrationId`.
2. **Include `IntegrationId` in Link Token Request:**
```json
{
"UserId": "unique_end_user_identifier",
"IntegrationId": "specific_integration_uuid"
}
```
* **`IntegrationId`**: The `uuid` of the target integration.
## Direct Self-Custody Wallet Launch via `IntegrationId`
Similar to direct exchange/brokerage launch, you can route users directly to the connection flow for a specific self-custody wallet (e.g., MetaMask) using the `IntegrationId`.
**Implementation:**
The process mirrors direct exchange/brokerage launch:
1. **Retrieve `IntegrationId`**: Utilize the "Retrieve the list of all available integrations" endpoint to identify the `id` of the desired self-custody wallet integration.
2. **Include `IntegrationId` in Link Token Request:**
```json
{
"UserId": "unique_end_user_identifier",
"IntegrationId": "specific_wallet_integration_uuid"
}
```
* **`IntegrationId`**: The `uuid` of the target self-custody wallet integration.
## Enforcing Single Account Connection via `RestrictMultipleAccounts`
By default, Link allows users to connect multiple provider accounts within a single session. To enforce a single account connection, the `RestrictMultipleAccounts` parameter can be set to `true`.
**Implementation:**
```json
{
"UserId": "unique_end_user_identifier",
"RestrictMultipleAccounts": true
}
```
* **`RestrictMultipleAccounts`**: A boolean flag. When set to `true`, the Link UI will prevent the user from connecting additional provider accounts after a successful connection.
## Request Structure
All the above configurations are passed within the JSON body of a `POST` request to the `/api/v1/linktoken` endpoint. Ensure that your `X-Client-Id` and `X-Client-Secret` are correctly included in the request headers for API authentication.
# Deposits
Source: https://docs.meshconnect.com/guides/quickstart-deposits
# Configuring Crypto Deposits with Link
This guide explains how to configure Link to enable your users to deposit cryptocurrency assets into specified addresses. You'll learn how to define the destination addresses and streamline the deposit experience.
## Understanding Deposit Configuration via `toAddresses`
The `toAddresses` array within the `TransferOptions` object of your link token request is the primary mechanism for configuring where users can deposit their cryptocurrency assets. Each object in this array defines a specific cryptocurrency, the network it resides on, and the receiving address.
**Key Requirement:** For each item in the `toAddresses` array, you **must** provide the Mesh-specific Unique Identifier (UID) for the target network. You can find a comprehensive list of supported tokens, networks, and their corresponding Mesh UIDs here: [Tokens](/api-reference/managed-transfers/get-supported-tokens-list) | [Networks](/api-reference/managed-transfers/get-networks) | [Integrations](/api-reference/managed-transfers/get-integrations).
## Streamlined Deposits to a Single Crypto Address
For the most direct user experience, especially when you intend users to deposit a specific asset to a specific address, configure a single entry in the `toAddresses` array. This will instruct the Link UI to skip the asset and network selection screens, taking the user directly to the connection and authorization steps.
**Link Token Request Body:**
```json
{
"UserId": "unique_end_user_identifier",
"TransferOptions": {
"ToAddresses": [
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "ETH",
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
}
]
}
}
```
* **`NetworkId`**: The Mesh UID of the target network (e.g., Ethereum Mainnet in this case).
* **`Symbol`**: The symbol of the cryptocurrency being deposited (e.g., ETH).
* **`Address`**: The receiving cryptocurrency address.
## Offering Deposits for Multiple Crypto Tokens or Networks
To provide users with more flexibility in their deposit options, you can include multiple objects within the `toAddresses` array. Each object will represent a specific token and the network it can be deposited over.
**Link Token Request Body:**
```json
{
"UserId": "unique_end_user_identifier",
"TransferOptions": {
"ToAddresses": [
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "ETH",
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
},
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "USDC",
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
},
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "USDT",
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
},
{
"NetworkId": "7436e9d0-ba42-4d2b-b4c0-8e4e606b2c12",
"Symbol": "MATIC",
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
}
]
}
}
```
* Each object in the `ToAddresses` array defines a specific deposit option (Network and Symbol).
## Seamless Return Customer Experience
**Step 1: Retrieving the Access Token**
During the initial connection, you'll use the `onIntegrationConnected` SDK event (more information about UI Events can be found [here](/guides/link-ui-events)) to capture and save the `accessToken`. You will need to construct the `accessToken` object prior to sending it back to Mesh for the reconnection. Here's how:
```jsx
const meshLink = await createLink({
clientId: clientId,
linkToken: linkToken,
onIntegrationConnected: async (payload) => {
var accessToken = [
{
"accessToken": payload.accessToken.accountTokens[0].accessToken,
"brokerType": payload.accessToken.brokerType,
"accountId": payload.accessToken.accountTokens[0].account.accountId,
"accountName": payload.accessToken.accountTokens[0].account.accountName,
"brokerName": payload.accessToken.brokerName
}
] // Store the accessToken
// IMPORTANT: Store the accessToken securely on your server or in a secure storage location.
},
// ... other options
});
```
**Key Points:**
* **Saving the Access Token:** The most crucial step is to securely save the `accessToken`. Never store it directly in client-side code (e.g., local storage) for production applications.
* **User Association:** Associate the `accessToken` with the corresponding user in your application's database.
**Step 2: Using the Access Token for Reconnections**
The next time you initialize `createLink` for the same user, include the stored `accessToken` in the `accessTokens` property:
```jsx
const meshLink = await createLink({
clientId: clientId,
linkToken: linkToken,
accessTokens: accessToken, // Use the stored accessToken
// ... other options
});
```
**Connecting Multiple Accounts**
If a user has connected multiple accounts, you can store an array of `accessTokens` and pass them to the `accessTokens` property:
```jsx
const meshLink = await createLink({
clientId: clientId,
linkToken: linkToken,
accessTokens: [accessToken1, accessToken2, ...], // Array of accessTokens
// ... other options
});
```
🚨 **IMPORTANT** — You will need a feature flag enabled on your backend to enable your user to select their desired account from the catalog. Please speak with your Mesh team to enable the feature.
```jsx
const fetchLinkToken = async () => {
const response = await fetch(baseUrl + "/api/v1/linktoken", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Client-Id": clientId,
"X-Client-Secret": apiSecret,
},
body: JSON.stringify({
userId: "Mesh",
transferOptions: {
toAddresses: [],
}
// ... other options
}),
});
};
```
**Important Reminders:**
* **Integration ID**: Be sure to not include the **integrationId** when creating the linkToken for the reconnection. This will cause the Link UI to ignore the `accessTokens` provided.
* **Expiration:** Access tokens have an expiration time (`expiresInSeconds`). You'll need to handle token refreshes or re-authentication before the tokens expire.
* **Security:** Always prioritize security when storing and handling access tokens.
**Workflow:**
1. The user initiates a deposit within your application.
2. You fetch a link token with an empty `ToAddresses` array.
3. On the client-side, you initialize `createLink` .
4. When the user goes through the Link flow, they will be presented with their previously connected accounts as potential deposit destinations.
# SDK Overview
Source: https://docs.meshconnect.com/guides/quickstart-guide-with-link-sdks
This page will help you get started using Mesh SDKs to authenticate and make server side calls.
## What is Link SDK?
Mesh Link is a collection of client side SDKs, that allows your users to connect to their financial institutions and perform transactions using a user interface provided by Mesh.
Link will handle credential validation, multi-factor authentication, and error handling for each institution that Mesh supports. Link can also provide a user interface for asset transfers, deposits or payment methods. You can read more about Link use cases in [this document](/guides/link-initialization).
Mesh provides client side SDKs for all modern platforms:
1. [Web Link SDK](/guides/web-sdk)
2. [iOS Link SDK](/guides/ios-sdk)
3. [Android Link SDK](/guides/android-sdk)
4. [React Native SDK](/guides/react-native-sdk)
## Authentication + Call Flow Overview
The starting point for any integration with Mesh is with an account connection, which using the fastest way to get started is by using Link SDKs or cloning the [Quickstart React app](https://github.com/FrontFin/mesh-web-sdk/tree/main/examples/react-example).
After generating Sandbox and Production [API keys](https://dashboard.meshconnect.com/company/keys), you’ll start by leveraging Link SDKs to facilitate end user authentication.
1. Call [/api/v1/linktoken](/api-reference/managed-account-authentication/get-link-token-with-parameters) to create a `linktoken`. This endpoint provides a short-lived, one-time-use token for initializing a Link session
2. Pass the `linktoken` to the appropriate Link SDK. The exact implementation details for passing the `linktoken` will vary by platform. For detailed instructions, see the page for your specific platform
3. Your user will be able to filter and search for the account they want to connect. Mesh will manage the authentication flow and handle MFAs for all supported integrations.
4. After successful authentication on the Link UI, `auth_token` will be passed to the SDK.
1. 🚨 You should **securely store** the `auth_token` (and `refresh_token`) for use in subsequent server requests
The diagram below shows the model of how Link is used to obtain the `auth_token` and `refresh_token` which can be used for subsequent server requests.
Here is a more detailed call flow diagram for user authentication using Link SDK:
### Link Initialization and Use Cases
Depending on the `linktoken` API call payload, Link's functionality can be tailored to suit various user flows. From Authentication, Transfers to Deposits, the primary use cases can be [found here](/docs/link-initialization-and-use-cases).
* [Account Authentication](/docs/link-initialization-and-use-cases#account-authentication)
* [Deposit Use Cases](/docs/link-initialization-and-use-cases#deposits)
* [Payment Use Cases](/docs/link-initialization-and-use-cases#payments)
### Troubleshooting
For details on dealing with common problems, see the [Troubleshooting section](/docs/link-troubleshooting).
### Security Measures for Handling Authentication Tokens
**Secure Storage of Authentication Tokens**
* **Backend Storage:** It is **highly recommended** that `auth_token` and `refresh_token` obtained through Mesh Link should be securely stored on your backend server. Storing tokens on the server side enhances security by reducing the exposure of sensitive data to client-side vulnerabilities.
* **Mobile SDK Secure Storage:** For mobile applications, Mesh provides secure storage solutions within the iOS and Android SDKs. The iOS SDK leverages the Secure Enclave, a hardware-based key manager, and for Android devices, Mesh SDK utilizes secure storage mechanisms provided by the Android Keystore system. Utilizing these secure storage options ensures that tokens are stored in a manner compliant with the best practices of each platform.
**Handling User Credentials**
* **No Storage of User Credentials:** Mesh's backend infrastructure is designed to never store user credentials. This approach aligns with best practices in data security, ensuring that sensitive user information remains confidential and reducing the risk of data breaches.
Learn more about about [Security at Mesh](https://www.meshconnect.com/security)
### Event Tracking in UI
Mesh Link UI offers an event tracking system, allowing you to gain insights into user interactions within the Link UI. These events can be used for analytics and understanding user behavior. The event data can be obtained directly from the SDKs and includes various user actions, such as initiating a connection, completing authentication, completing an asset transfer, or encountering errors.
The way in which these events are captured and transmitted varies slightly across different platforms (Web, iOS, Android, and React Native). For detailed instructions, see the page for your specific platform.
The following document [list of UI Events](/guides/link-ui-events#list-of-events) details all of the events supported by Mesh SDKs.
# Paylinks
Source: https://docs.meshconnect.com/guides/quickstart-paylinks
# Introduction
This document explains how to use Paylinks, which allows merchants to redirect customers to a pre-built page for completing payments or asset transfers. This approach simplifies the payment process by eliminating the need for merchants to integrate the Mesh SDK directly into their systems.
Paylinks is a feature that enables clients to externalize the Link functionality to a Mesh-hosted webpage. Instead of integrating the Mesh SDK directly into their application, merchants can generate a Paylink URL and redirect their customers to this URL. The customer can then complete the payment or transfer process on the Mesh-hosted page.
This approach is particularly useful in several scenarios:
* **Simplified Integration:** For merchants who want to quickly enable payment functionality without extensive development work.
* **Third-Party Platforms:** When integrating with platforms where direct SDK integration is not feasible or desirable.
* **Specific Use Cases:** Situations where a simple redirect-based payment flow is preferred.
# Prerequisites
Before using Paylinks, ensure you have the following:
* Mesh Client ID and Client Secret
# Implementation
## 1. Generate a Paylink URL
To create a Paylink, send a `linkToken` request to the Mesh API. This will generate a URL that you can then provide to your customer.
* **Method:** `POST`
* **URL:** `https://integration-api.meshconnect.com/api/v1/linkToken`
* **Headers:**
* `X-Client-Id`: Your Mesh Client ID. This identifies your application to the Mesh API.
* `X-Client-Secret`: Your Mesh Client Secret. This is a secret key used to authenticate your requests to the Mesh API.
Include these headers in your request to authorize it.
* **Body:** The request body needs to be in JSON format and include the following information:
* `userId`: A unique identifier for the user making the payment or transfer. This should be a value that identifies the user in your system.
* `transferOptions`: This object contains the details of the transaction:
* `toAddresses`: An array of one or more recipient addresses. For each recipient, provide:
* `symbol`: The symbol of the asset being transferred (e.g., "ETH", "BTC").
* `networkId`: The ID of the blockchain network being used for the transfer.
* `address`: The blockchain address of the recipient.
* `isInclusiveFeeEnabled`: A boolean value that specifies whether the transaction fee is included in the transfer amount. Set to `true` if the amount your user enters includes the fee, `false` otherwise.
* `transferType`: The type of transfer. Use "deposit" if the user is sending funds to your platform, "payment" if the user is paying for something.
* `transactionId`: A unique identifier for this transaction in your system. This allows you to track the transaction and reconcile it later.
* `fundingOptions`: An object indicating if SmartFunding is enabled
* `generatePayLink`: Set this value to `true`. This tells the Mesh API to generate a Paylink URL in the response. **This is required to ensure Paylinks works.**
**Important:** You **must** provide a `transactionId` in your request body when `generatePayLink` is set to `true`. If it is not provided, the API will return an error. The `transactionId` should be a unique string generated by your system for each transaction. This ID is used to correlate the Paylink transaction with your internal records. For example, you could use an order ID, a payment ID, or a unique hash. This value should be unique and persistent so you can reliably look up the transaction in your database.
**Example Request (JSON):**
```json
{
"userId": "USER_IDENTIFIER_123",
"transferOptions": {
"amountInFiat": "100.00",
"toAddresses": [
{
"symbol": "ETH",
"networkId": "NETWORK_ID_GOES_HERE",
"address": "0xRecipientAddressGoesHere"
}
],
"generatePayLink": true,
"isInclusiveFeeEnabled": false,
"transferType": "payment",
"transactionId": "YOUR_TRANSACTION_ID",
"fundingOptions": {
"enabled": true
}
}
}
```
Replace the placeholder values (e.g., `USER_IDENTIFIER_123`, `NETWORK_ID_GOES_HERE`) with actual data
## 2. Retrieve the Paylink URL from the Response
After sending the `linkToken` request, the API will respond with a JSON object. If the request was successful, the response will contain a `paymentLink` field.
**Example Response (JSON):**
```json
{
"content": {},
"linkToken": "aHR0cHM6Ly93ZWlubWVzaGNvbm5lY3QuY29tL2lyYi1pZnJhk...",
"paymentLink": "https://paylink.meshconnect.com?linkToken=aHR0cHM6Ly...",
"status": "ok",
"message": "",
"errorType": ""
}
```
The `paymentLink` value is the URL that you will provide to your customer.
## 3. Redirect Your Customer to the Paylink URL
Redirect your customer to the URL provided in the `paymentLink` field. This can be done in several ways, depending on your application (e.g., using a redirect in your web server code, or providing the link in an email or message).
Once the user clicks the link, they will be taken to a Mesh-hosted page where they can complete the payment or transfer.
# Error States
This section describes potential errors that your customers may encounter when using Paylinks, and how to handle them:
* **Paylink was already used**: This error occurs when a user attempts to use the same Paylink URL more than once. Paylinks are designed to be used only once for security reasons.
* **Merchant Action**: When this happens, your user will need to initiate a new payment or transfer and obtain a new Paylink. You should provide clear messaging to the user explaining that the Paylink can only be used once and that they need to generate a new one.
* **Previous Paylink was unused, but expired**: This error occurs when a user tries to use a Paylink that has expired. Paylinks are typically valid for a limited time (e.g., 30 minutes).
* **Merchant Action**: Similar to the previous error, your user will need to generate a new Paylink. Inform them that the previous link has expired and they should start the payment or transfer process again.
**Recommended User Experience**: In both cases, it is strongly recommended that you redirect the user back to the payment initiation page on your site where they can click a button (e.g., "Pay" or "Transfer") to generate a new Paylink. This will provide a seamless experience for the user and allow them to complete their transaction.
# Payments
Source: https://docs.meshconnect.com/guides/quickstart-payments
# Configuring Payments with Mesh Link
This guide explains how to configure Link to facilitate cryptocurrency payments within your application. You'll learn how to define accepted payment assets, amounts, and how to apply fees.
**Understanding Payment Configuration**
When using Link to process payments, you'll utilize the `TransferOptions` object within your link token request to specify the parameters of the payment transaction. This includes defining the acceptable cryptocurrencies, their respective destination addresses, and the payment amount.
## Specifying Payment Assets and Destination Addresses
The `ToAddresses` array within `TransferOptions` allows you to define the cryptocurrencies users can pay with and the corresponding receiving addresses. Each object in this array represents a payment option.
**Important:** For each entry in the `ToAddresses` array, you must provide the Mesh-specific Unique Identifier (UID) for the network on which the supported token resides. Refer to the Mesh Connect documentation for a comprehensive list of supported tokens, networks, and their Mesh UIDs: [Tokens](/api-reference/managed-transfers/get-supported-tokens-list) | [Networks](/api-reference/managed-transfers/get-networks) | [Integrations](/api-reference/managed-transfers/get-integrations)
## Accepting Payments with Multiple Cryptocurrencies
To allow users to pay with a variety of cryptocurrencies, include multiple objects within the `ToAddresses` array. For each object, specify the network, symbol, and destination address.
**Link Token Request Body:**
```json
{
"UserId": "unique_end_user_identifier",
"TransferOptions": {
"ToAddresses": [
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "ETH",
"Amount": 0.0032,
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
},
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "USDC",
"Amount": 10,
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
},
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "USDT",
"Amount": 10,
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
},
{
"NetworkId": "7436e9d0-ba42-4d2b-b4c0-8e4e606b2c12",
"Symbol": "MATIC",
"Amount": 22.8,
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
}
],
"TransactionId": "unique_transaction_identifier"
}
}
```
* `NetworkId`: The Mesh UID of the network.
* `Symbol`: The cryptocurrency symbol.
* `Amount`: The amount the user is expected to pay, in the cryptocurrency specified by the Symbol.
* `Address`: The recipient's cryptocurrency address.
* `TransactionId`: A unique identifier for this payment transaction. This is crucial for mapping payments to orders or other internal systems.
## Streamlined Payments with a Single Asset and Amount
If you want to pre-define a single payment option (one cryptocurrency and amount), Link can streamline the user flow. When you provide `AmountInFiat` and a single network/token/address combination, Link will bypass asset and network selection, taking the user directly to the payment preview.
**Link Token Request Body:**
```json
{
"UserId": "unique_end_user_identifier",
"TransferOptions": {
"ToAddresses": [
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "ETH",
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
}
],
"AmountInFiat": 10,
"TransactionId": "unique_transaction_identifier"
}
}
```
* `AmountInFiat`: The payment amount in fiat currency (e.g., USD).
* Other parameters are the same as in Scenario 1.
## Adding Payment Processing Fees
You can apply a client fee to payment transactions using the `ClientFee` parameter in the link token request.
**Important:**
* The `ClientFee` will override any default fee configured in your Mesh dashboard for the transaction.
**Link Token Request Body (with Client Fee):**
```json
// Multiple Payment Options with Fee
{
"UserId": "unique_end_user_identifier",
"TransferOptions": {
"ToAddresses": [
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "ETH",
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
},
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "USDC",
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
},
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "USDT",
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
},
{
"NetworkId": "7436e9d0-ba42-4d2b-b4c0-8e4e606b2c12",
"Symbol": "MATIC",
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
}
],
"AmountInFiat": 10,
"ClientFee": 0.025 // 2.5% fee (represented as a ratio)
}
}
// Single Payment Option with Fee
{
"UserId": "unique_end_user_identifier",
"TransferOptions": {
"ToAddresses": [
{
"NetworkId": "e3c7fdd8-b1fc-4e51-85ae-bb276e075611",
"Symbol": "ETH",
"Address": "0x9Bf6207f8A3f4278E0C989527015deFe10e5D7c6"
}
],
"AmountInFiat": 10,
"TransactionId": "unique_transaction_identifier",
"ClientFee": 0.025 // 2.5% fee (represented as a ratio)
}
}
```
* `ClientFee`: A decimal representing the fee percentage (e.g., `0.025` for 2.5%).
## Enabling SmartFunding
Sometimes your user doesn’t have enough of the token you want to get paid in. And sometimes your user doesn’t have any of it. SmartFunding enables auto-top-ups of / auto-conversions to the payment token within in the user’s account before initiating the transfer.
To give your users the flexibility to fund their transfers using cryptocurrency, you need to include `"FundingOptions": { "Enabled": true }` during the initial setup of the Link UI. You do this by including the following setting in your Link initialization code:
```json
"userId": "example_user123",
"restrictMultipleAccounts": true,
"transferOptions": {
"transactionId": "example_tx123",
"transferType": "payment", // payment or onRamp
// Enable SmartFunding
"fundingOptions": {
"enabled": true
},
"isInclusiveFeeEnabled": false,
"toAddresses": [
{
"symbol": "USDT",
"address": "0x314838D6783865908456257c0b07Ea4Bc272cF98",
"networkId": "18fa36b0-88a8-43ca-83db-9a874e0a2288",
"amount": 99.99 // pass an amount when enabling SmartFunding
}
]
},
"integrationId": "9226e5c2-ebc3-4fdd-94f6-ed52cdce1420"
```
> 👍 This is best suited for `payment` or `onRamp` transfer types and operate best with a single token and a passed amount parameter
With this option enabled, if a user doesn't have enough balance for a transfer, Mesh can guide them through using the balances in their account, and payment methods linked to their account to top up their balance.
# Testnets for Wallets (Sandbox)
Source: https://docs.meshconnect.com/guides/quickstart-testnet-sandbox
# What It Is
Mesh now supports testnet transactions in our sandbox environment, allowing developers to validate on-chain transactions without risking real funds.
# Why It's Important
Previously, our sandbox environment did not support wallet transactions, requiring customers to use real funds for testing. With testnets, developers can now configure transfers using Sepolia testnet and obtain test tokens from a [faucet](https://cloud.google.com/application/web3/faucet/ethereum/sepolia), ensuring a risk-free and seamless integration experience.
## What Are Testnets and Test Tokens?
* **Testnets** are blockchain networks used for testing purposes, replicating mainnet functionality without real economic consequences.
* **Test Tokens** are tokens issued on testnets that simulate real assets, allowing developers to conduct transactions, test smart contracts, and validate integrations before deploying on the mainnet.
By enabling testnet support, we remove a major barrier to integration, speeding up contract signing and reducing implementation friction for prospective PSP clients.
# How to Use It
1. Reference our updated sandbox documentation: [Sandbox Documentation](https://docs.meshconnect.com/guides/sandbox)
2. Access our demo environment: [Mesh Demo Environment](https://dashboard.meshconnect.com/demos/mesh-deposit)
3. Configure a transfer using the following:
* **Token:** Sepolia ETH
* **Network:** Sepolia
4. **Obtaining testnet tokens:** There are two ways in which customers can obtain testnet tokens:
**Acquire test tokens from a faucet**: Customers can obtain Sepolia ETH from a public faucet for testing. e.g. [https://cloud.google.com/application/web3/faucet/ethereum/sepolia](https://cloud.google.com/application/web3/faucet/ethereum/sepolia)
## Additional Notes
* Expanding testnet coverage is part of our future roadmap.
* Please reach out to product with any additional testnet expansion request.
* Currently, only MetaMask and Rainbow wallets are supported
* Please reach out to product to enable additional wallet support
* Sales and CS teams should proactively inform customers about this feature to accelerate integration timelines.
* For further assistance, customers should reach out to their assigned CS representative.
## Reference Docs
[https://docs.meshconnect.com/guides/sandbox](https://docs.meshconnect.com/guides/sandbox)
# React Native SDK
Source: https://docs.meshconnect.com/guides/react-native-sdk
## Installation
With `npm`:
`npm install --save @meshconnect/react-native-link-sdk`
With `yarn`:
`yarn add @meshconnect/react-native-link-sdk`
💡 This package requires `react-native-webview` to be installed in your project. Although it is listed as direct dependency, some times it is not installed automatically (This is a known [npm issue](https://stackoverflow.com/questions/18401606/npm-doesnt-install-module-dependencies)). You should install it manually via following command in this case:
```
npm install --save react-native-webview
# or with yarn
yarn add react-native-webview
```
## Get Link token
Link token should be obtained from the POST `/api/v1/linktoken` endpoint. API reference for this request is available here. The request must be performed from the server side because it requires the client's secret. You will get the response in the following format:
```json
{
"content": {
"linkToken": "{linkToken}"
},
"status": "ok",
"message": ""
}
```
## Launch Link
```javascript
import React from 'react';
import {
LinkConnect,
LinkPayload,
TransferFinishedPayload,
TransferFinishedSuccessPayload,
TransferFinishedErrorPayload
} from '@meshconnect/react-native-link-sdk';
export const App = () => {
return (
{
// use broker account data
}}
onTransferFinished={(payload: TransferFinishedPayload) => {
if (payload.status === 'success') {
const successPayload = payload as TransferFinishedSuccessPayload
// use transfer finished data
} else {
const errorPayload = payload as TransferFinishedErrorPayload
// handle transfer error
}
}}
onExit={(err?: string) => {
// use error message
}}
onEvent={(event: string, payload: LinkPayload) => {
// use event
}}
/>
)
}
export default App;
```
ℹ️ See full source code example at [examples/](https://github.com/FrontFin/mesh-react-native-sdk/tree/main/examples).
### `LinkConnect` component arguments
| Key | Type | Required/Optional |
| ---------------------- | ------------------------------------------ | ----------------- |
| linkToken | string | required |
| onIntegrationConnected | (payload: LinkPayload) => void | optional |
| onTransferFinished | (payload: TransferFinishedPayload) => void | optional |
| onExit | (err: string) => void) | optional |
### Typescript support
Typescript definitions for `@meshconnect/react-native-link-sdk` are built into the npm package.
### Adding URL Schemes to Info.plist
To enable our SDK to interact with specific apps, please add the following URL schemes to your info plist file
* Open your info.plist located in the 'ios' directory of your React Native project
* Add the following XML snippet within the `` tag.
```xml
LSApplicationQueriesSchemestrustrobinhoodmetamaskrainbowuniswapexodusrobinhood-walletblockchain-wallet1inchcryptowalletokxbitkeep
```
# Sandbox Environment
Source: https://docs.meshconnect.com/guides/sandbox
Learn about the Sandbox environment, its features, limitations, and how to use it for API testing.
## What is the Sandbox?
The **Sandbox** is a dedicated testing environment that allows clients to integrate and interact with our APIs in a safe and controlled manner. It is designed to mirror the **Production** environment as closely as possible, providing a realistic experience without real-world consequences.
This environment enables developers and testers to explore our platform, validate their integrations, and troubleshoot issues **without relying on live third-party services**. Instead, the Sandbox uses **mocked data** to simulate real-world responses.
### Key Features of the Sandbox
* **Isolated Execution** – Runs in a separate application to prevent interference with Production.
* **Mocked Data** – Simulated responses replace real third-party integrations.
* **Dedicated Endpoint** – Access the Sandbox API at: **`https://sandbox-integration-api.meshconnect.com`**
* **Safe Testing Environment** – Ideal for testing API integrations and workflows before moving to Production.
***
## Limitations of the Sandbox
#### **Mocked Third-Party Integrations**
* All third-party integrations (e.g., payment providers, asset pricing, etc.) return **simulated** responses rather than real-time data.
* Asset prices are **hardcoded** and do not reflect real market values.
#### **Self-Custody Wallets Not Available**
* Sandbox does not support **self-custody wallets** yet.
#### **No Real Transactions**
* Since the environment does not interact with actual third-party services, any financial transactions, API calls, or data exchanges are **simulated**.
#### **Performance Differences**
* Performance may vary slightly compared to Prod, due to testing loads and mocked data responses.
***
## Who Should Use the Sandbox?
✅ **Developers & Engineers** – Validating API integrations and troubleshooting issues.\
✅ **Quality Assurance Teams** – Testing workflows before Production deployment.\
✅ **Product Teams** – Understanding platform behavior and testing use cases.
***
## Getting Started
The easiest and quickest way to get started is through our [Interactive Demos](https://dashboard.meshconnect.com/demos/). Try various Mesh products without any set up or touching “real” assets as shown below,
Alternatively, you can start interacting with various Sandbox endpoints following the [API reference](https://docs.meshconnect.com/api-reference/)
1. **Create Sandbox API keys:**
* Create a new key in your [Dashboard](https://dashboard.meshconnect.com/company/keys)
2. **Use the Dedicated API Endpoint:**
* `https://sandbox-integration-api.meshconnect.com`
3. **Authenticate Using API Credentials:**
* Use the newly created Sandbox API keys, separate from your Production credentials.
4. **Test Your Integration:**
* Execute API calls, validate responses, and ensure your application behaves as expected.
5. **Move to Production:**
* Once testing is complete, update your integration to point to the Production API.
***
## Frequently Asked Questions
No, the Sandbox does not process real transactions. All payments, asset movements, and third-party API calls return mocked responses for testing purposes.
Yes, the Sandbox API follows the same structure and endpoints as the Production API, but the responses are simulated.
Currently, Sepolia network is supported for Metamask and Rainbow. Please read more about how to set them up in your sandbox in this [Guide](/guides/quickstart-testnet-sandbox).
No, the Sandbox API supports the following exchange integrations:
| Exchanges |
| ----------- |
| Binance |
| Binance API |
| Coinbase |
| Bybit |
| OKX API |
| Gemini |
| KuCoin API |
| Kraken API |
* To enable a seamless return experience without prompting users to authenticate again, you can pass a valid `accessToken` into the `createLink()` function when connecting an account via the Mesh Web SDK.
* If you provide a valid `accessToken`, users will not need to reauthenticate.
* If you pass **no `integrationId` and no `accessToken`**, the catalog will open, but users will be required to authenticate again when selecting an already linked integration.
* **Important:** You must securely store and manage the `accessToken` on your side. For best practices on handling authentication tokens, refer to our guide: [Handling Auth Tokens](https://docs.meshconnect.com/guides/handling-auth-tokens#handling-auth-tokens).
# Enabling Multi-Language Support for Link
Source: https://docs.meshconnect.com/guides/sdk-linklanguage
This guide explains how to configure Mesh Link to support multiple languages, allowing you to provide a localized experience for your users.
This guide explains how to configure Mesh Link to support multiple languages, allowing you to provide a localized experience for your users.
# Understanding Language Configuration with `language`
The `language` parameter, which you set during Mesh Link initialization, is the key to displaying Link in your user's preferred language. This parameter allows you to:
* **Automatically match the user's device/browser language**, or
* **Specify a particular language.**
# Key Parameter: `language`
You'll use the `language` parameter when initializing Mesh Link via your SDK (Web, iOS, Android, or React Native).
## **Possible Values:**
* **``**: A specific language code enumerated as the 2 digit language identifier (eg. “**`fr-`**” for French) and the 2 digit region identifier (eg. “**`-CA`**” for Canada), combined as “**`fr-CA`**". Alternatively, the SDK will accept an input of only the language (eg. “**`fr`**”).
* If the indicated language (eg. “**`fr-`**”) is followed by a region code (eg. “**`-CA`**”) that is not recognized or supported for that language, Link will fall back to the default translation for that language, if available (eg. “**`fr-FR`**”). If no translation for the language is available, Link will default to "**`en-US`**" (English, US).
* If you do not provide a value for the parameter, or if you provide a value for a language that is not supported, Link will default to "**`en-US`**" (English, US).
* **`system`**: Link will detect the default language on the user’s browser and/or device and display Link in that language. If it is an unsupported value, it will fallback to another locale for that language, or it will fallback to the global default of **`en-US`**.
# Implementation
## **Initialize Link with `language`**
When you initialize Link in your application, use the **`language`** parameter to specify the desired language behavior.
### **Web SDK**
```jsx
const connection = createLink({
...
language: 'en-US'
...
})
```
### **Android SDK**
```kotlin
val configuration = LinkConfiguration(
token = "linkToken",
language = "en-US")
```
### **iOS SDK**
```swift
let settings = LinkSettings(language: "en-US")
let configuration = LinkConfiguration(
linkToken: linkToken,
settings: settings,
...
)
```
### **React native SDK**
```jsx
```
# Testing Your Implementation
Thoroughly test your implementation to ensure a seamless experience for your users:
* Verify that Link displays correctly in the languages you intend to support.
* Please notify your Mesh support person if you see any words or phrases that you believe are incorrectly translated if you see any layout issues (for example with right-to-left languages or character-based languages).
# Currently supported languages
| **Status** | **Language** | **Region** | **Locale code** |
| ------------------------------------------------------ | ------------------------------ | --------------------------------------------------------------------------- | --------------- |
| **live** | English | United States **global default** | **`en-US`** |
| **live** | Spanish | United States **es default** | **`es-US`** |
| **live** | Russian | Russia | **`ru-RU`** |
| **live** | French | France **fr default** | **`fr-FR`** |
| **live** | Chinese/Mandarin (Simplified) | China **zh default** | **`zh-CN`** |
| **live** | Turkish | Turkey | **`tr-TR`** |
| **live** | Polish | Poland | **`pl-PL`** |
| **live** | Japanese | Japan | **`ja-JP`** |
| **live** | German | Germany | **`de-DE`** |
| **live** | Finnish | Finland | **`fi-FI`** |
| **live** | Hindi | India | **`hi-IN`** |
| **live** | Portuguese | Portugal **pt default** | **`pt-PT`** |
| **live** | Vietnamese | Vietnam | **`vi-VN`** |
| **live** | system | | **`system`** |
| **backlog** | Arabic | Egypt | **`ar-EG`** |
| **backlog** | Chinese/Mandarin (Traditional) | United States | **`zh-US`** |
| **backlog** | Chinese | Hong Kong | **`zh-HK`** |
| **backlog** | Chinese | Taiwan | **`zh-TW`** |
| **backlog** | Czech | Czech Republic | **`cs-CZ`** |
| **backlog** | Danish | Denmark | **`da-DK`** |
| **backlog** | Dutch, Flemish | Belgium | **`nl-NL`** |
| **backlog** | English | Australia | **`en-AU`** |
| **backlog** | English | India | **`en-IN`** |
| **backlog** | English | United Kingdom | **`en-GB`** |
| **backlog** | French | Canada | **`fr-CA`** |
| **backlog** | Greek, Modern (1453–) | Greece | **`el-GR`** |
| **backlog** | Hebrew | Israel | **`he-IL`** |
| **backlog** | Hungarian | Hungary | **`hu-HU`** |
| **backlog** | Indonesian | Indonesia | **`id-ID`** |
| **backlog** | Italian | Italy | **`it-IT`** |
| **backlog** | Korean | South Korea | **`ko-KR`** |
| **backlog** | Norwegian | Norway | **`no-NO`** |
| **backlog** | Portuguese | Brazil | **`pt-BR`** |
| **backlog** | Slovak | Slovakia | **`sk-SK`** |
| **backlog** | Spanish, Castilian | Spain | **`es-ES`** |
| **backlog** | Swedish | Sweden | **`sv-SE`** |
| **backlog** | Thai | Thailand | **`th-TH`** |
# Status Page
Source: https://docs.meshconnect.com/guides/status
# Sub-Client Branding
Source: https://docs.meshconnect.com/guides/sub-client-branding
[Sub-Client Branding](https://meshconnect.notion.site/Sub-Client-Functionality-142f862e950a80c695bdd108c37de78b)
# Supported Transfer Integrations
Source: https://docs.meshconnect.com/guides/supported-transfer-integrations
## Centralized Exchanges
* Binance International
* Binance US
* ByBit
* Coinbase
* Coinbase Prime
* Huobi
* Kraken
* KuCoin
* OKX
* Paxos
* Robinhood
* BTC Turk (new)
## Exchanges Coming Soon
* Paribu
* Bitso
* ByBit
## Self-Custody Wallets
* Metamask
* Coinbase Wallet
* Trust Wallet
* Blockchain.com
* ZenGo
* Robinhood Wallet
* Argent Wallet
* [Full Integration List](https://www.meshconnect.com/integrations)
## Supported Chains
* Arbitrum
* Avalanche
* AvalancheC
* AvalancheX
* Base
* Binance Smart Chain
* Bitcoin
* Cardano
* Doge
* Dogecoin
* Ethereum
* Litecoin
* Optimism
* Polygon
* Ripple
* Solana
* Stellar
* Stellar
* Sui
* Tron
## COMING SOON
* Aptos
* Bitcoin Lightning
* Ton
# null
Source: https://docs.meshconnect.com/guides/troubleshooting-link
## Link UI is not displaying in your webpage
**Symptoms:**
* When initializing the Link UI, you see a grey box instead of the Link UI
* An error in the browser's console that says `Refused to frame 'https://web.meshconnect.com/' because an ancestor violates the following Content Security Policy directive...`

**Causes:**
* When using the Link Web SDK in your page, Mesh SDK loads the Link UI using an iFrame component. Due to security reasons, we allow loading the Link UI only on a predefined set of URLs.
* If you are using a Content Security Policy (CSP) directives on your website, they might block loading an external iFrame into your page.
**Troubleshooting:**
* [ ] Add your website's URL to the list of **Allowed Link URLs** in our [dashboard](https://dashboard.meshconnect.com/company/keys).
* [ ] Add the following CSP directives to your site:\
`frame-src: *.meshconnect.com`
# Unable to connect an OAuth integration
**Symptoms:**
* When authenticating on a third party integration's side (e.g., Coinbase or Gemini), the user gets stuck on a page displaying a loading spinner
**Causes:**
* Ad-blocking software is not officially supported with Link UI, and some ad-blockers have been known to cause issues with Link.
* Some browsers have built-in ad-blocking service (Brave Browser) which prevents Link UI from using the browser's storage.
**Troubleshooting:**
* [ ] Disable all ad-blockers in your browser
# Verifying Self-Hosted Wallets
Source: https://docs.meshconnect.com/guides/verifying-self-hosted-wallets
[Verifying Self-Hosted Wallets](https://meshconnect.notion.site/Using-Mesh-Verify-for-wallet-verification-142f862e950a80b78595f7e90409ad36)
# Web SDK
Source: https://docs.meshconnect.com/guides/web-sdk
## Installation
To get started with Web Link SDK, clone the [GitHub repository](https://github.com/FrontFin/mesh-web-sdk), and review the example application.
Next, you will need to install the **[@meshconnect/web-link-sdk](https://www.npmjs.com/package/@meshconnect/web-link-sdk)** package.
```
npm install --save @meshconnect/web-link-sdk
```
With `yarn`:
```
yarn add @meshconnect/web-link-sdk
```
Then import the necessary components and types:
```jsx JSX
import {
Link,
LinkPayload,
TransferFinishedPayload,
createLink,
} from "@meshconnect/web-link-sdk";
```
## Creating Link Connection
The `createLink` function accepts one argument, a configuration Object typed `LinkOptions` and returns an Object with two functions, `openLink` and `closeLink`.
Calling `openLink` will display the Link UI in an iframe, and the overlay around it.\
Calling the `closeLink` will close the already displayed Link UI. Please note, that the Link UI will close itself once the user finishes their workflow in Link UI.
#### `createLink` arguments
| Key | Type | Description |
| ------------------------------------ | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| clientId | string | A Client ID, unique to your company, which can be obtained at [https://dashboard.meshconnect.com/company/keys](https://dashboard.meshconnect.com/company/keys) |
| onIntegrationConnected | callback | A callback function that is called when an integration is successfully connected.The function should expect an argument typed LinkPayload. |
| onExit (optional) | callback | A callback function, that is called, when the Link UI is closed.The function should expect two arguments:1. Nullable error string as an argument.2. Nullable summary object. |
| onTransferFinished (optional) | callback | A callback function that is called when an asset transfer is finished.The function should expect an argument typed TransferFinishedPayload. |
| onEvent (optional) | callback | A callback function that is called when various events occur within the Link UI.The function should expect an argument typed LinkEventType.See [Link UI Events](/guides/link-ui-events) for more details on event types. |
| accessTokens (optional) | Array of IntegrationAccessToken | These access tokens are used to initialize crypto transfers flow at 'Select asset step’ using previously obtained integration auth\_tokens .See [Link Initialization and Use Cases](/guides/link-initialization) for more details. |
| transferDestinationTokens (optional) | Array of IntegrationAccessToken | These access tokens are used to initialize crypto transfers flow at 'Select asset step’ using previously obtained integration auth\_tokens .See [Link Initialization and Use Cases](/guides/link-initialization) for more details. |
#### createLink code example
```JSX JSX
const meshLink =
createLink({
clientId: 'clientId',
onIntegrationConnected: (payload) => {},
onExit: (error) => {},
onTransferFinished: (transferData) => {},
onEvent: (ev) => {},
accessTokens: [],
transferDestinationTokens: []
})
```
### onIntegrationConnected
The `onIntegrationConnected` callback is called when an integration is successfully connected. It takes one argument called `payload` with the type of `LinkPayload`
#### `LinkPayload` properties
| Key | Type | Description |
| ---------------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| accessToken (nullable) | Object of type AccessTokenPayload | The an accessToken payload is returned, when a user successfully connects an integration.It contains all the necessary data to interact with the users connected account via the Mesh API.Make sure, that you handle this data securely and you follow our recommended [best practices](/guides/handling-auth-tokens). See the type definition on our [GitHub](https://github.com/FrontFin/mesh-web-sdk/blob/963dfe9820ec634c8d68f45e7df9b8c30d8402b7/packages/link/src/utils/types.ts#L48C24-L48C24). |
| delayedAuth (nullable) | Object of type DelayedAuthPayload | The a delayedAuth payload is returned, when a user successfully connects an Interactive Brokers account for the first time.It contains a refresh\_token that can be exchanged into an auth\_token in 24 hours, using the Mesh API. See the type definition on our [GitHub](https://github.com/FrontFin/mesh-web-sdk/blob/963dfe9820ec634c8d68f45e7df9b8c30d8402b7/packages/link/src/utils/types.ts#L57). |
### onExit
The `onExit` callback is called, when the Link UI is closed. This can be due to an error, or the user can close the Link UI by choosing so.\
It takes two arguments:
1. `error` with the type of `string`, which is the reason, why the Link UI was closed in an user friendly message.
2. `summary` object that contains session summary in following format
```jsx JSX
{
/**
* Current page of application. Possible values:
* `startPage`
* `integrationsCatalogPage`
* `integrationLoginPage`
* `integrationMfaPage`
* `integrationAccountSelectPage`
* `integrationConnectedPage`
* `errorPage`
* `transferKycPage`
* `transferHoldingSelectionPage`
* `transferNetworkSelectionPage`
* `transferAmountSelectionPage`
* `transferPreviewPage`
* `transferMfaPage`
* `transferFundingPage`
* `transferExecutedPage`
* `termsAndConditionPage`
*
* This list may change in future.
*/
page: string
/** Selected integration */
selectedIntegration?: {
id?: string
name?: string
}
/** Transfer information */
transfer?: {
previewId?: string
symbol?: string
amount?: number
amountInFiat?: number
transactionId?: string
networkId?: string
}
errorMessage?: string
}
```
### onTransferFinished
The `onTransferFinished` callback is called, when an asset transfer is finished successfully or unsuccessfully.\
It takes one argument called `payload` with the type of `TransferFinishedSuccessPayload` or `TransferFinishedErrorPayload`.
#### `TransferFinishedSuccessPayload` properties
See the type definition on our [GitHub](https://github.com/FrontFin/mesh-web-sdk/blob/main/packages/link/src/utils/types.ts).
| Key | Type | Description |
| ----------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| status | string | The status of the transfer in case of TransferFinishedSuccessPayload it will be always success |
| txId | string | The identifier of the executed transaction, received from the integration |
| fromAddress | string | Address where the crypto funds were sent from |
| toAddress | string | Address where the crypto funds were sent to |
| symbol | string | The symbol of the crypto asset |
| amount | string | The amount in the given cryptocurrency that was sent |
| networkId | string | Id of the network over which the transaction was executed.See more about network IDs in our [API reference](/api-reference/managed-transfers/get-networks) |
#### `TransferFinishedErrorPayload` properties
See the type definition on our [GitHub](https://github.com/FrontFin/mesh-web-sdk/blob/main/packages/link/src/utils/types.ts).
| Key | Type | Description |
| ------------ | ------ | ------------------------------------------------------------------------------------------ |
| status | string | The status of the transfer in case of TransferFinishedErrorPayload it will be always error |
| errorMessage | string | A user friendly message on why the transaction failed. |
### onEvent
The `onEvent` callback is called, when various events occur within the Link UI.\
It takes one argument, called `event` with the type of `LinkEventType`.
See [Link UI Events](/guides/link-ui-events) for more details on events and their type definitions.
### accessTokens
The `accessTokens` parameter is used to initialize crypto transfers flow at the 'Select asset step’ using previously obtained integration `auth_token`. It can be used if you have a valid `auth_token` and want to bypass authentication to jump right into a transfer.
The type of the `accessTokens` parameter is an array of `IntegrationAccessToken`, however, please note, only the first item in the array will be taken into account.
See the type definition on our [GitHub](https://github.com/FrontFin/mesh-web-sdk/blob/main/packages/link/src/utils/types.ts).
#### `accessTokens` code example
```JSX JSX
const accessTokens =
[
{
accountId: 'accountId',
accountName: 'accountName',
accessToken: 'accessToken',
brokerType: 'brokerType',
brokerName: 'brokerName',
},
]
const meshLink =
createLink({
clientId: 'clientId',
onIntegrationConnected: (payload) => {},
onExit: (error) => {},
onTransferFinished: (transferData) => {},
onEvent: (ev) => {},
accessTokens: accessTokens, // Provide a previously obtained integration auth_token
transferDestinationTokens: []
})
```
### transferDestinationTokens
The `transferDestinationTokens` are used for crypto transfers flow. It is an alternative way of providing target addresses for crypto transfers by using previously obtained integration `auth_tokens`.
See [Link initialization and use cases](/guides/link-initialization) for more details.
The type of the `transferDestinationTokens` parameter is an array of `IntegrationAccessToken`.
See the type definition on our [GitHub](https://github.com/FrontFin/mesh-web-sdk/blob/main/packages/link/src/utils/types.ts).
#### `transferDestinationTokens` code example
```jsx JSX
const transferDestinationTokens = [
{
accountId: "accountId",
accountName: "accountName",
accessToken: "accessToken",
brokerType: "brokerType",
brokerName: "brokerName",
},
];
const meshLink = createLink({
clientId: "clientId",
onIntegrationConnected: (payload) => {},
onExit: (error) => {},
onTransferFinished: (transferData) => {},
onEvent: (ev) => {},
accessTokens: [],
transferDestinationTokens: transferDestinationTokens, // Provide a previously obtained integration auth_tokens to use as destination address
});
```
### openLink()
Calling `openLink` will display the Link UI in an iframe, and the overlay around it.
It takes `linkToken` as an argument, which can be obtained from the POST `/api/v1/linktoken` endpoint. Request must be preformed from the server side because it requires the client secret and ID.
See more about obtaining the `linkToken` and [initialization use cases](/guides/link-initialization)
#### `openLink` code example
```jsx JSX
const meshLink = createLink({
clientId: "clientId",
onIntegrationConnected: (payload) => {},
onExit: (error) => {},
onTransferFinished: (transferData) => {},
onEvent: (ev) => {},
accessTokens: [],
transferDestinationTokens: [],
});
meshLink.openLink("linktoken"); // Open the Link UI popup
```
### closeLink()
Calling the `closeLink` will close the already displayed Link UI. Please note, that the Link UI will close itself once the user finishes their workflow in Link UI.
### Typescript support
TypeScript definitions for `@meshconnect/web-link-sdk` are built into the NPM package.
# Transfer Webhooks
Source: https://docs.meshconnect.com/guides/webhooks
If your business relies on transfer status updates to make business decisions (releasing inventory, dispersing funds, etc.), then polling Mesh’s managed transfers endpoint is an inefficient and ineffective solution. Mesh offers webhooks to solve this problem. A webhook is a callback function that allows lightweight, event-driven communication between 2 systems. The events that trigger communications from Mesh’s webhooks are updates to transfer statuses. Instead of polling a Mesh endpoint, you can provide Mesh (via the Dashboard) with a unique callback URL which will automatically receive transfer status updates as Mesh learns about them.
## Secure Data Transmission
* Mesh uses HMAC (Hash-based Message Authentication Code)
* When clients register their Webhook URI, they receive a Secret from Mesh which will be used in signing the request.
* Mesh signs each webhook request using a secret key. The receiver can verify the signature using the same secret key to ensure the data has not been tampered with.
* Mesh will include a signature header (e.g., **`X-Mesh-Signature-256`**) that the receiver can use to validate the integrity and authenticity of the payload.
This is the function we use for creating HMAC signature that is used in the request header:
```csharp
public string GenerateHmacSignature(string payload, string webhookSecret)
{
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(webhookSecret));
byte[] hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(payload));
return Convert.ToBase64String(hash);
}
```
# Whitelist IP
All the webhook calls from Mesh side will come from this static IP:
```bash
20.22.113.37
```
## Webhook Event Model
The webhook payload contains the core information related to a transfer update, and also includes additional fields specific to the webhook event.
### Transfer data
* **`TransferId`** (`Guid`): The unique identifier of the transfer related to this event.
* **`Timestamp`** (`long`): The timestamp indicating when the event occurred.
* **`TransferStatus`** (`string`): The status of the transfer at the time of the event. This is an enumeration representing various possible states of the transfer.
* **`TransactionId`** (`string`): The unique identifier for the transaction associated with the transfer.
* **`TxHash`** (`string`): The unique identifier for the blockchain transaction associated with the transfer.
* **`UserId`** (`string`): The unique identifier of the user associated with the transfer.
* **`Token`** (`string`): The token associated with the transfer.
* **`Chain`** (`string`): The chain associated with the transfer.
* **`SourceAmount`** (`decimal?`): The amount of token that has left the source account.
* **`SourceAccountProvider`** (`string`): The account provider that has been used to send the token.
* **`DestinationAmount`** (`decimal?`): The amount of token that has received by the destination account.
* **`DestinationAddress`** (`string`): The destination account address.
* **`RefundAddress`** (`string`): The refund address (optional).
### Webhook call data
* **`EventId`** (`Guid`): A unique identifier for the event. This event identifies each message sent to clients. This ID will remain same even in case of retries.
* **`Id`** (`Guid`): A unique identifier for the webhook event. This is considered as SentID, there maybe multiple retries for any event pushed into the queue. For each try for sending a specific event there is a different Id.
* **`SentTimestamp`** (`long`): The timestamp indicating when the webhook event was sent.
### Payload
The payload format is JSON. Here is an example of payload.
```json
{
"Id": "358c6ab7-4518-416b-9266-c680fda3a8dd",
"EventId": "56713e70-be74-4a37-0036-08da97f5941a",
"SentTimestamp": 1720532648,
"UserId": "user_id_provided_by_client",
"TransactionId": "transaction_id_provided_by_client",
"TransferId": "dd4063e5-f317-441c-3f07-08dc7353b6f8",
"TransferStatus": "Pending",
"TxHash": "0x7d4ec1ce50952a377452c95fdf5a787ff551f08c0343093f866c84f57c473495",
"Chain":"Ethereum",
"Token":"ETH",
"DestinationAddress":"0x0Ff0000f0A0f0000F0F000000000ffFf00f0F0f0",
"SourceAccountProvider" :"Binance",
"SourceAmount":0.004786046226555188,
"DestinationAmount":0.004786046226555188,
"RefundAddress": "0x0Ff0000f0A0f0000F0F000000000ffFf00f0F0f0",
"Timestamp": 1715175519038
}
```
### Transfer Status Values
* **`pending`**: The transfer has been initiated via Mesh, but has not yet reached a final state. Mesh does not yet have a Transfer Hash for this transfer.
* **`succeeded`**: A final state that indicates the transfer was successfully delivered to the destination address. Mesh has a Transfer Hash for this transfer.
* **`failed`**: A final state that indicates the transfer has failed. No transfer hash available.
### Create and register your callback URI
* Create an endpoint that can receive a POST request with application/json content.
* Go to [Account —> API Keys](https://dashboard.meshconnect.com/company/keys) in your Mesh Dashboard.
* Scroll down to “Production Transfer Webhook URI” and “Sandbox Transfer Webhook URI”
* When registering an endpoint, you’ll be prompted to store your secret key, as you won’t be able to view it again.
* You can only save one production URI and one Sandbox URI, but you can deactivate one and save a new one at any time.
### How to respond to a Mesh webhook event
* Please respond with a **`200`** response in \< 200ms to confirm receipt of the event.
* If Mesh does not receive a **`200`** response in \< 200ms, the webhook will retry (you will receive the event again with all duplicate information except for a different **`Id`**).