Sell Flow
The sell flow aka offramping is how users can trade their crypto back for fiat currency.
If you would like to use Meld's UI for the entire flow, Meld recommends using the All in One Wizard which follows the below standard flow. If you use the wizard you do not need to read any of the information below.
The below information applies only if you are planning to use the Meld White Label Widget.
Prerequisites
Before a user can sell crypto, you should know the following information:
-
The payment method the user intends to pay with
-
The amount of crypto the user wants to exchange for fiat
-
The fiat currency the user will receive the fiat in (for example USD)
-
The cryptocurrency and network the user wants to sell (for example ETH_ARBITRUM aka Ethereum on the Arbitrum network)
-
The country the user's billing address is in
You can either collect this information through your own UI, or use the Meld Crypto Wizard for an all-in-one UI that collects this information then allows the user to make purchase.
Steps to Users Selling Crypto
If you are using your own UI to collect this information, you should use Meld's service provider endpoints to know which countries / payment methods / fiat currencies / tokens the onramps you have enabled support.
Once you have the above information, there are 2 possible flows, depending on what the offramp supports.
Standard Flow
Complete the following steps, in order:
- Get a crypto quote from Meld for each provider. This involves gathering the parameters for what kind of quote the user wants and passing them in to the crypto quote endpoint. Meld recommends sorting by the highest
destinationAmount(which is the amount of fiat the user will receive). - The user will select an offramp based on the quotes (or you can select one for them) and launch the onramp's widget. The user completes the transaction using the widget. This entails the user sending crypto to the offramp and the offramp sending the fiat currency to the payment method they provided (typically bank account or card). You can pass in a redirectUrl so that the user gets redirected to it after they submit a transaction on the onramp.
- Wait and listen for webhooks, and use them as triggers to fetch transaction data. For more information on how to do this see here. Once you have transaction data, you can choose how you would like to display it to the user.
Preferred Flow
This flow is similar to the one above, however leads to a smoother user experience and therefore higher conversion. Meld recommends using this flow as more offramps start to support it.
- Get a crypto quote from Meld for each provider. This involves gathering the parameters for what kind of quote the user wants and passing them in to the crypto quote endpoint. Meld recommends sorting by the highest
destinationAmount(which is the amount of fiat the user will receive). - The user will select an offramp based on the quotes (or you can select one for them) and launch the onramp's widget. To trigger the preferred flow, make sure you pass in
"redirectFlow": truein the body of the request (withinsessionData). The user completes KYC and confirms the quote in the widget, however they don't complete the transaction there. Instead they are redirected back to your UI. - Using the redirection to your UI as a trigger, call meld's /transactions endpoint to fetch the token (
sourceCurrencyCode), amount (sourceAmount), and the wallet address for the user to send crypto to (cryptoDetails.offrampDestinationWalletAddress). Using these, queue up a transfer of that amount of that token to that wallet address, and simply ask the user to confirm the transfer. Once they do, commence the transfer. - Once the offramp receives the token, they will send the fiat currency to the payment method they provided (typically bank account or card). You can show the user a transaction status page while they wait for the transaction to complete.
- Wait and listen for webhooks, and use them as triggers to fetch transaction data. For more information on how to do this see here. Once you have transaction data, you can choose how you would like to display it to the user.
Note that in both flows while Step 1, getting a quote, will lead to the best user experience, it is not a required step. You can just launch an offramp's widget without asking for a quote beforehand.
How to Sell Crypto
API Calls
Quote
Here is an example of a call to /quotes when selling cryptocurrency (note that passing in serviceProviders is optional here):
{
"countryCode": "US",
"sourceCurrencyCode": "ETH",
"sourceAmount": "0.01",
"destinationCurrencyCode": "USD"
// "serviceProviders": ["TRANSAK", "KOYWE"]
}And here's a sample response:
{
"quotes": [
{
"transactionType": "CRYPTO_SELL",
"sourceAmount": 0.01,
"sourceAmountWithoutFees": null,
"fiatAmountWithoutFees": 30.75,
"destinationAmountWithoutFees": 30.75,
"sourceCurrencyCode": "ETH",
"countryCode": "US",
"totalFee": 4.43,
"networkFee": null,
"transactionFee": 3.99,
"destinationAmount": 26.32,
"destinationCurrencyCode": "USD",
"exchangeRate": 3075,
"paymentMethodType": "VISA_DIRECT",
"customerScore": null,
"serviceProvider": "TRANSAK"
},
{
"transactionType": "CRYPTO_SELL",
"sourceAmount": 0.01,
"sourceAmountWithoutFees": null,
"fiatAmountWithoutFees": 30.25,
"destinationAmountWithoutFees": 30.25,
"sourceCurrencyCode": "ETH",
"countryCode": "US",
"totalFee": 4.93,
"networkFee": null,
"transactionFee": 3.99,
"destinationAmount": 27.04,
"destinationCurrencyCode": "USD",
"exchangeRate": 2986,
"paymentMethodType": "CREDIT_DEBIT_CARD",
"customerScore": null,
"serviceProvider": "TRANSFI"
},
],
"message": null,
"error": null
}Unlike the Buy flow, currently there are no customerScore values returned for the Sell flow.
Widget
Here is an example of the corresponding call to /widget when selling cryptocurrency (note that unlike the Buy call, the wallet address shouldn't be passed here):
{
"sessionData": {
"countryCode": "US",
"sourceCurrencyCode": "ETH",
"sourceAmount": "0.01",
"destinationCurrencyCode": "USD",
"serviceProvider": "TRANSAK"
},
"sessionType": "SELL",
"externalCustomerId": "customer1",
"externalSessionId": "sellsession1"
}And here's a sample response:
{
"id": "WQ4xsQLPnY1yFWvT1eEYgU",
"externalSessionId": "sellsession1",
"externalCustomerId": "customer1",
"customerId": "WQ5BicuTRkM5BCQAFCY3Qs",
"widgetUrl": "https://meldcrypto.com/?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJjcnlwdG8iLCJtZXJjaGFudElkIjoiVzlrZzlpUDFzYnB5WnB0UURjQ01KdSIsImlzcyI6Im1lbGQuaW8iLCJzZXNzaW9uSWQiOiJXUTR4c1FMUG5ZMXlGV3ZUMWVFWWdVIiwiZXhwIjoxNzEzNTYzMDI1LCJpYXQiOjE3MTM1NjEyMjV9.SAZjeTQxCTgPFkjITBqT4Hx-sSPqao7bQa9ClMt-EOs",
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJjcnlwdG8iLCJtZXJjaGFudElkIjoiVzlrZzlpUDFzYnB5WnB0UURjQ01KdSIsImlzcyI6Im1lbGQuaW8iLCJzZXNzaW9uSWQiOiJXUTR4c1FMUG5ZMXlGV3ZUMWVFWWdVIiwiZXhwIjoxNzEzNTYzMDI1LCJpYXQiOjE3MTM1NjEyMjV9.SAZjeTQxCTgPFkjITBqT4Hx-sSPqao7bQa9ClMt-EOs"
}Webhooks
Here is a sample of a TRANSACTION_CRYPTO_PENDING webhook, which is the first webhook you will receive for any transaction. See more about the various webhooks here.
{
"eventType": "TRANSACTION_CRYPTO_PENDING",
"eventId": "AAsuLXHXD3mS1cjNBuHHab",
"timestamp": "2024-02-24T16:36:41.717262Z",
"accountId": "W2aRZnYGPwhBWB94iFsZus",
"version": "2024-02-02",
"payload": {
"accountId": "W2aRZnYGPwhBWB94iFsZus",
"paymentTransactionId": "W9k9Tg12BFk1i68WpQYQY9",
"customerId": "WQ4toL6ECKWc96PZ8HufDU",
"externalCustomerId": "customer1",
"externalSessionId": "sellsession1",
"paymentTransactionStatus": "PENDING"
}
}Transaction Data
Once you call the /transactions with a transactionId (the paymentTransactionId in the webhook above), this is a sample response:
{
"key": "LYoQeP31CEkFxmsZvBKqy2EcRvgHiKdSqdsLQNA9C23DAg4ahRPdaSWeL7esWooQb9tMZaEdd7SLukWCSD95zzciDE",
"id": "W9k9Tg12BFk1i68WpQYQY9",
"parentPaymentTransactionId": null,
"accountId": "W9kg9iP1sbpyZptQDcCMJu",
"isPassthrough": false,
"passthroughReference": null,
"isImported": false,
"customer": {
"id": "WQ4toL6ECKWc96PZ8HufDU",
"accountId": "W2aRZnYGPwhBWB94iFsZus",
"name": {
"firstName": null,
"lastName": null
},
"addresses": []
},
"transactionType": "CRYPTO_SELL",
"status": "SETTLED",
"sourceAmount": 0.01,
"sourceCurrencyCode": "ETH",
"destinationAmount": 26.18,
"destinationCurrencyCode": "USD",
"paymentMethodType": "CREDIT_DEBIT_CARD",
"serviceProvider": "TRANSAK",
"serviceTransactionId": "transak-2332238o32uo3iu2",
"description": null,
"externalReferenceId": null,
"serviceProviderDetails": {
"networkFee": 0.77,
"type": "transak",
"quoteId": "edff5599-3999-46d5-a887-9dc340323234",
"processingFee": 1.50,
"cryptoCurrency": "ETH",
"txnHash": "6E54FC71179F741EEE63569A4BA554FEF5A9FDDEDBDF23r23rewfsdfewfw32f3f",
"totalFee": 3.27,
"requestId": "fa0f7454-0f6d-4e71-b274-3232ewf33f33",
"cryptoCurrencyAmount": 0.01,
"partnerUserId": "WQ4wmNrDmELekUBRFJZg7K",
"walletAddress": "0x23rewFEWKJNEWN3313EFEFKNKN33qx3f3k3k3f3J2",
"status": "completed",
"partnerFee": 1
},
"multiFactorAuthorizationStatus": null,
"createdAt": "2024-04-19T20:47:36.578875Z",
"updatedAt": "2024-04-19T20:49:04.616555Z",
"countryCode": "NO",
"sessionId": "WQ4wQ4w475pjaRrNfT8KE9",
"externalSessionId": null,
"paymentDetails": null,
"cryptoDetails": {
"offrampDestinationWalletAddress": "0x23rewFEWKJNEWN3313EFEFKNKN33qx3f3k3k3f3J2",
"walletAddress": "0x23rewFEWKJNEWN3313EFEFKNKN33qx3f3k3k3f3J2",
"networkFee": 0.77,
"transactionFee": 1.50,
"partnerFee": 1,
"totalFee": 3.27,
"networkFeeInUsd": null,
"transactionFeeInUsd": null,
"partnerFeeInUsd": null,
"totalFeeInUsd": null,
"blockchainTransactionId": "6E54FC71179F741EEE63569A4BA554FEF5A9FDDEDBDF23r23rewfsdfewfw32f3f",
"institution": null,
"chainId": 1
},
"externalCustomerId": null,
"fiatAmountInUsd": 96.73,
"sessionClientTags": null,
"apiAccessProfileId": "WGuwgsCEsfyyrzmZfb4y2t"
}The serviceProviderDetails are directly the fields from the offramp's own transactions endpoint so the specific field and field names will vary per offramp.
Updated 2 months ago