Prepare a Withdrawal
curl --request POST \
--url https://api.hel.io/v1/withdraw/{withdrawalConfigId}/prepare \
--header 'Content-Type: application/json' \
--data '
{
"ownerAddress": "<string>",
"recipient": "<string>",
"amount": "<string>",
"toCurrencyId": "<string>",
"sourceCurrencyId": "<string>",
"customerId": "<string>"
}
'import requests
url = "https://api.hel.io/v1/withdraw/{withdrawalConfigId}/prepare"
payload = {
"ownerAddress": "<string>",
"recipient": "<string>",
"amount": "<string>",
"toCurrencyId": "<string>",
"sourceCurrencyId": "<string>",
"customerId": "<string>"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
ownerAddress: '<string>',
recipient: '<string>',
amount: '<string>',
toCurrencyId: '<string>',
sourceCurrencyId: '<string>',
customerId: '<string>'
})
};
fetch('https://api.hel.io/v1/withdraw/{withdrawalConfigId}/prepare', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.hel.io/v1/withdraw/{withdrawalConfigId}/prepare",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'ownerAddress' => '<string>',
'recipient' => '<string>',
'amount' => '<string>',
'toCurrencyId' => '<string>',
'sourceCurrencyId' => '<string>',
'customerId' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.hel.io/v1/withdraw/{withdrawalConfigId}/prepare"
payload := strings.NewReader("{\n \"ownerAddress\": \"<string>\",\n \"recipient\": \"<string>\",\n \"amount\": \"<string>\",\n \"toCurrencyId\": \"<string>\",\n \"sourceCurrencyId\": \"<string>\",\n \"customerId\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.hel.io/v1/withdraw/{withdrawalConfigId}/prepare")
.header("Content-Type", "application/json")
.body("{\n \"ownerAddress\": \"<string>\",\n \"recipient\": \"<string>\",\n \"amount\": \"<string>\",\n \"toCurrencyId\": \"<string>\",\n \"sourceCurrencyId\": \"<string>\",\n \"customerId\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.hel.io/v1/withdraw/{withdrawalConfigId}/prepare")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"ownerAddress\": \"<string>\",\n \"recipient\": \"<string>\",\n \"amount\": \"<string>\",\n \"toCurrencyId\": \"<string>\",\n \"sourceCurrencyId\": \"<string>\",\n \"customerId\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"withdrawalDetailId": "<string>",
"token": "<string>",
"prepared": {
"kind": "raw",
"chain": "<string>",
"unsignedTx": "<string>"
},
"summary": {
"sourceToken": "<string>",
"sourceAmount": "<string>",
"destinationToken": "<string>",
"destinationAmount": "<string>",
"destinationAmountMin": "<string>",
"maxSlippageBps": 123,
"estimatedPriceImpact": 123,
"bridgeFee": {
"amount": "<string>",
"currency": {
"blockchain": {
"engine": {
"id": "<string>"
},
"id": "<string>",
"name": "<string>"
},
"id": "<string>",
"symbol": "<string>",
"name": "<string>",
"mintAddress": "<string>",
"coinMarketCapId": 123,
"decimals": 123,
"order": 123,
"minDecimals": 123,
"symbolPrefix": "<string>",
"features": [],
"iconUrl": "<string>"
}
},
"applicationFee": {
"amount": "<string>",
"currency": {
"blockchain": {
"engine": {
"id": "<string>"
},
"id": "<string>",
"name": "<string>"
},
"id": "<string>",
"symbol": "<string>",
"name": "<string>",
"mintAddress": "<string>",
"coinMarketCapId": 123,
"decimals": 123,
"order": 123,
"minDecimals": 123,
"symbolPrefix": "<string>",
"features": [],
"iconUrl": "<string>"
}
},
"protocolFee": {
"amount": "<string>",
"currency": {
"blockchain": {
"engine": {
"id": "<string>"
},
"id": "<string>",
"name": "<string>"
},
"id": "<string>",
"symbol": "<string>",
"name": "<string>",
"mintAddress": "<string>",
"coinMarketCapId": 123,
"decimals": 123,
"order": 123,
"minDecimals": 123,
"symbolPrefix": "<string>",
"features": [],
"iconUrl": "<string>"
}
},
"totalFee": {
"amount": "<string>",
"currency": {
"blockchain": {
"engine": {
"id": "<string>"
},
"id": "<string>",
"name": "<string>"
},
"id": "<string>",
"symbol": "<string>",
"name": "<string>",
"mintAddress": "<string>",
"coinMarketCapId": 123,
"decimals": 123,
"order": 123,
"minDecimals": 123,
"symbolPrefix": "<string>",
"features": [],
"iconUrl": "<string>"
}
},
"expiresAt": "2023-11-07T05:31:56Z"
}
}Runtime Flow
Prepare a Withdrawal
Quotes a withdrawal and returns a lane-specific payload for the holder to sign. No authentication required (rate-limited).
POST
/
v1
/
withdraw
/
{withdrawalConfigId}
/
prepare
Prepare a Withdrawal
curl --request POST \
--url https://api.hel.io/v1/withdraw/{withdrawalConfigId}/prepare \
--header 'Content-Type: application/json' \
--data '
{
"ownerAddress": "<string>",
"recipient": "<string>",
"amount": "<string>",
"toCurrencyId": "<string>",
"sourceCurrencyId": "<string>",
"customerId": "<string>"
}
'import requests
url = "https://api.hel.io/v1/withdraw/{withdrawalConfigId}/prepare"
payload = {
"ownerAddress": "<string>",
"recipient": "<string>",
"amount": "<string>",
"toCurrencyId": "<string>",
"sourceCurrencyId": "<string>",
"customerId": "<string>"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
ownerAddress: '<string>',
recipient: '<string>',
amount: '<string>',
toCurrencyId: '<string>',
sourceCurrencyId: '<string>',
customerId: '<string>'
})
};
fetch('https://api.hel.io/v1/withdraw/{withdrawalConfigId}/prepare', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.hel.io/v1/withdraw/{withdrawalConfigId}/prepare",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'ownerAddress' => '<string>',
'recipient' => '<string>',
'amount' => '<string>',
'toCurrencyId' => '<string>',
'sourceCurrencyId' => '<string>',
'customerId' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.hel.io/v1/withdraw/{withdrawalConfigId}/prepare"
payload := strings.NewReader("{\n \"ownerAddress\": \"<string>\",\n \"recipient\": \"<string>\",\n \"amount\": \"<string>\",\n \"toCurrencyId\": \"<string>\",\n \"sourceCurrencyId\": \"<string>\",\n \"customerId\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.hel.io/v1/withdraw/{withdrawalConfigId}/prepare")
.header("Content-Type", "application/json")
.body("{\n \"ownerAddress\": \"<string>\",\n \"recipient\": \"<string>\",\n \"amount\": \"<string>\",\n \"toCurrencyId\": \"<string>\",\n \"sourceCurrencyId\": \"<string>\",\n \"customerId\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.hel.io/v1/withdraw/{withdrawalConfigId}/prepare")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"ownerAddress\": \"<string>\",\n \"recipient\": \"<string>\",\n \"amount\": \"<string>\",\n \"toCurrencyId\": \"<string>\",\n \"sourceCurrencyId\": \"<string>\",\n \"customerId\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"withdrawalDetailId": "<string>",
"token": "<string>",
"prepared": {
"kind": "raw",
"chain": "<string>",
"unsignedTx": "<string>"
},
"summary": {
"sourceToken": "<string>",
"sourceAmount": "<string>",
"destinationToken": "<string>",
"destinationAmount": "<string>",
"destinationAmountMin": "<string>",
"maxSlippageBps": 123,
"estimatedPriceImpact": 123,
"bridgeFee": {
"amount": "<string>",
"currency": {
"blockchain": {
"engine": {
"id": "<string>"
},
"id": "<string>",
"name": "<string>"
},
"id": "<string>",
"symbol": "<string>",
"name": "<string>",
"mintAddress": "<string>",
"coinMarketCapId": 123,
"decimals": 123,
"order": 123,
"minDecimals": 123,
"symbolPrefix": "<string>",
"features": [],
"iconUrl": "<string>"
}
},
"applicationFee": {
"amount": "<string>",
"currency": {
"blockchain": {
"engine": {
"id": "<string>"
},
"id": "<string>",
"name": "<string>"
},
"id": "<string>",
"symbol": "<string>",
"name": "<string>",
"mintAddress": "<string>",
"coinMarketCapId": 123,
"decimals": 123,
"order": 123,
"minDecimals": 123,
"symbolPrefix": "<string>",
"features": [],
"iconUrl": "<string>"
}
},
"protocolFee": {
"amount": "<string>",
"currency": {
"blockchain": {
"engine": {
"id": "<string>"
},
"id": "<string>",
"name": "<string>"
},
"id": "<string>",
"symbol": "<string>",
"name": "<string>",
"mintAddress": "<string>",
"coinMarketCapId": 123,
"decimals": 123,
"order": 123,
"minDecimals": 123,
"symbolPrefix": "<string>",
"features": [],
"iconUrl": "<string>"
}
},
"totalFee": {
"amount": "<string>",
"currency": {
"blockchain": {
"engine": {
"id": "<string>"
},
"id": "<string>",
"name": "<string>"
},
"id": "<string>",
"symbol": "<string>",
"name": "<string>",
"mintAddress": "<string>",
"coinMarketCapId": 123,
"decimals": 123,
"order": 123,
"minDecimals": 123,
"symbolPrefix": "<string>",
"features": [],
"iconUrl": "<string>"
}
},
"expiresAt": "2023-11-07T05:31:56Z"
}
}Note: When using the production environment at moonpay.hel.io, set your API endpoint to
api.hel.io/v1. For the development environment, use api.dev.hel.io/v1.Display
summary as your confirmation screen. The quote and token expire at summary.expiresAt. sourceCurrencyId is always required. Optionally pass customerId (max 255 characters) to attach a merchant-defined end-user identifier to the quote. Inspect prepared.kind to determine what to sign: raw (Solana unsignedTx), userop (EVM ERC-4337 user operation), or hypercore (Hyperliquid EIP-712 typedData).Path Parameters
The withdrawal config ID.
Body
application/json
Holder's source wallet address. Format is lane-specific (e.g. Solana base58 for Solana raw, EVM checksummed address for EVM raw/hyperliquid).
Destination address on any supported chain.
Amount in atomic units as a decimal-free string (e.g. 1500000 for 1.5 USDC).
Pattern:
^\d+$Destination currency Mongo ID.
Source currency Mongo ID from the withdrawal config.
Optional merchant identifier for the end user (max 255 characters). Persisted on prepare and echoed on the withdrawal detail and webhooks. Not applied on re-quote.
Maximum string length:
255⌘I
