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>",
"slippageBps": 500
}
'import requests
url = "https://api.hel.io/v1/withdraw/{withdrawalConfigId}/prepare"
payload = {
"ownerAddress": "<string>",
"recipient": "<string>",
"amount": "<string>",
"toCurrencyId": "<string>",
"sourceCurrencyId": "<string>",
"customerId": "<string>",
"slippageBps": 500
}
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>',
slippageBps: 500
})
};
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>',
'slippageBps' => 500
]),
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 \"slippageBps\": 500\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 \"slippageBps\": 500\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 \"slippageBps\": 500\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>",
"destinationAmountUsd": "<string>",
"destinationAmountMinUsd": "<string>",
"maxSlippageBps": 123,
"estimatedPriceImpact": 123,
"routerAddresses": [
"<string>"
],
"bridgeIds": [
"<string>"
],
"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"
}
}Prepare a Withdrawal
Quotes a withdrawal and returns a lane-specific payload for the holder to sign. No authentication required (rate-limited).
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>",
"slippageBps": 500
}
'import requests
url = "https://api.hel.io/v1/withdraw/{withdrawalConfigId}/prepare"
payload = {
"ownerAddress": "<string>",
"recipient": "<string>",
"amount": "<string>",
"toCurrencyId": "<string>",
"sourceCurrencyId": "<string>",
"customerId": "<string>",
"slippageBps": 500
}
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>',
slippageBps: 500
})
};
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>',
'slippageBps' => 500
]),
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 \"slippageBps\": 500\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 \"slippageBps\": 500\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 \"slippageBps\": 500\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>",
"destinationAmountUsd": "<string>",
"destinationAmountMinUsd": "<string>",
"maxSlippageBps": 123,
"estimatedPriceImpact": 123,
"routerAddresses": [
"<string>"
],
"bridgeIds": [
"<string>"
],
"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"
}
}api.hel.io/v1. For the development environment, use api.dev.hel.io/v1.summary as your confirmation screen. When available, summary.destinationAmountUsd and summary.destinationAmountMinUsd provide the USD value of the destination amounts for display (both optional — omit them from your UI when absent). 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).Amount precision: amount must be in the source currency’s atomic units. Resolve sourceCurrencyId to its decimals value (via Get Withdrawal Currencies) and compute humanAmount × 10^decimals. USDC on HyperCore uses 8 decimals — e.g. 1.5 USDC = "150000000", not "1500000".Path Parameters
The withdrawal config ID.
Body
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. Scale using the source currency's decimals value (e.g. 1500000 for 1.5 USDC at 6 decimals; 150000000 for 1.5 USDC at 8 decimals on HyperCore).
^\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.
255Optional slippage tolerance in basis points (0–10000) forwarded to the swap/bridge provider. Defaults to 500 (5%) when omitted.
0 <= x <= 10000