curl --request POST \
--url https://sandbox.groundtech.co/v2/wallets/{id}/withdrawals \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"requestId": "f4a5b6c7-0000-4000-8000-000000000001",
"destinationChain": "arbitrum",
"amountUsd": 50,
"token": "usdc",
"destinationAddress": "0x76F8fc6667E239f83a547d4e16225d6a34f6FA22",
"partnerFeeAmountUsd": 0.5,
"partnerFeeRecipientAddress": "0x1111111111111111111111111111111111111111"
}
'import requests
url = "https://sandbox.groundtech.co/v2/wallets/{id}/withdrawals"
payload = {
"requestId": "f4a5b6c7-0000-4000-8000-000000000001",
"destinationChain": "arbitrum",
"amountUsd": 50,
"token": "usdc",
"destinationAddress": "0x76F8fc6667E239f83a547d4e16225d6a34f6FA22",
"partnerFeeAmountUsd": 0.5,
"partnerFeeRecipientAddress": "0x1111111111111111111111111111111111111111"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
requestId: 'f4a5b6c7-0000-4000-8000-000000000001',
destinationChain: 'arbitrum',
amountUsd: 50,
token: 'usdc',
destinationAddress: '0x76F8fc6667E239f83a547d4e16225d6a34f6FA22',
partnerFeeAmountUsd: 0.5,
partnerFeeRecipientAddress: '0x1111111111111111111111111111111111111111'
})
};
fetch('https://sandbox.groundtech.co/v2/wallets/{id}/withdrawals', 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://sandbox.groundtech.co/v2/wallets/{id}/withdrawals",
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([
'requestId' => 'f4a5b6c7-0000-4000-8000-000000000001',
'destinationChain' => 'arbitrum',
'amountUsd' => 50,
'token' => 'usdc',
'destinationAddress' => '0x76F8fc6667E239f83a547d4e16225d6a34f6FA22',
'partnerFeeAmountUsd' => 0.5,
'partnerFeeRecipientAddress' => '0x1111111111111111111111111111111111111111'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"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://sandbox.groundtech.co/v2/wallets/{id}/withdrawals"
payload := strings.NewReader("{\n \"requestId\": \"f4a5b6c7-0000-4000-8000-000000000001\",\n \"destinationChain\": \"arbitrum\",\n \"amountUsd\": 50,\n \"token\": \"usdc\",\n \"destinationAddress\": \"0x76F8fc6667E239f83a547d4e16225d6a34f6FA22\",\n \"partnerFeeAmountUsd\": 0.5,\n \"partnerFeeRecipientAddress\": \"0x1111111111111111111111111111111111111111\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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://sandbox.groundtech.co/v2/wallets/{id}/withdrawals")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"requestId\": \"f4a5b6c7-0000-4000-8000-000000000001\",\n \"destinationChain\": \"arbitrum\",\n \"amountUsd\": 50,\n \"token\": \"usdc\",\n \"destinationAddress\": \"0x76F8fc6667E239f83a547d4e16225d6a34f6FA22\",\n \"partnerFeeAmountUsd\": 0.5,\n \"partnerFeeRecipientAddress\": \"0x1111111111111111111111111111111111111111\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://sandbox.groundtech.co/v2/wallets/{id}/withdrawals")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"requestId\": \"f4a5b6c7-0000-4000-8000-000000000001\",\n \"destinationChain\": \"arbitrum\",\n \"amountUsd\": 50,\n \"token\": \"usdc\",\n \"destinationAddress\": \"0x76F8fc6667E239f83a547d4e16225d6a34f6FA22\",\n \"partnerFeeAmountUsd\": 0.5,\n \"partnerFeeRecipientAddress\": \"0x1111111111111111111111111111111111111111\"\n}"
response = http.request(request)
puts response.read_bodyWithdraw funds
Starts a withdrawal. Reusing requestId returns the same withdrawal. If automatic rebalancing is off, you can choose the source positions.
curl --request POST \
--url https://sandbox.groundtech.co/v2/wallets/{id}/withdrawals \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"requestId": "f4a5b6c7-0000-4000-8000-000000000001",
"destinationChain": "arbitrum",
"amountUsd": 50,
"token": "usdc",
"destinationAddress": "0x76F8fc6667E239f83a547d4e16225d6a34f6FA22",
"partnerFeeAmountUsd": 0.5,
"partnerFeeRecipientAddress": "0x1111111111111111111111111111111111111111"
}
'import requests
url = "https://sandbox.groundtech.co/v2/wallets/{id}/withdrawals"
payload = {
"requestId": "f4a5b6c7-0000-4000-8000-000000000001",
"destinationChain": "arbitrum",
"amountUsd": 50,
"token": "usdc",
"destinationAddress": "0x76F8fc6667E239f83a547d4e16225d6a34f6FA22",
"partnerFeeAmountUsd": 0.5,
"partnerFeeRecipientAddress": "0x1111111111111111111111111111111111111111"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
requestId: 'f4a5b6c7-0000-4000-8000-000000000001',
destinationChain: 'arbitrum',
amountUsd: 50,
token: 'usdc',
destinationAddress: '0x76F8fc6667E239f83a547d4e16225d6a34f6FA22',
partnerFeeAmountUsd: 0.5,
partnerFeeRecipientAddress: '0x1111111111111111111111111111111111111111'
})
};
fetch('https://sandbox.groundtech.co/v2/wallets/{id}/withdrawals', 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://sandbox.groundtech.co/v2/wallets/{id}/withdrawals",
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([
'requestId' => 'f4a5b6c7-0000-4000-8000-000000000001',
'destinationChain' => 'arbitrum',
'amountUsd' => 50,
'token' => 'usdc',
'destinationAddress' => '0x76F8fc6667E239f83a547d4e16225d6a34f6FA22',
'partnerFeeAmountUsd' => 0.5,
'partnerFeeRecipientAddress' => '0x1111111111111111111111111111111111111111'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"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://sandbox.groundtech.co/v2/wallets/{id}/withdrawals"
payload := strings.NewReader("{\n \"requestId\": \"f4a5b6c7-0000-4000-8000-000000000001\",\n \"destinationChain\": \"arbitrum\",\n \"amountUsd\": 50,\n \"token\": \"usdc\",\n \"destinationAddress\": \"0x76F8fc6667E239f83a547d4e16225d6a34f6FA22\",\n \"partnerFeeAmountUsd\": 0.5,\n \"partnerFeeRecipientAddress\": \"0x1111111111111111111111111111111111111111\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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://sandbox.groundtech.co/v2/wallets/{id}/withdrawals")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"requestId\": \"f4a5b6c7-0000-4000-8000-000000000001\",\n \"destinationChain\": \"arbitrum\",\n \"amountUsd\": 50,\n \"token\": \"usdc\",\n \"destinationAddress\": \"0x76F8fc6667E239f83a547d4e16225d6a34f6FA22\",\n \"partnerFeeAmountUsd\": 0.5,\n \"partnerFeeRecipientAddress\": \"0x1111111111111111111111111111111111111111\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://sandbox.groundtech.co/v2/wallets/{id}/withdrawals")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"requestId\": \"f4a5b6c7-0000-4000-8000-000000000001\",\n \"destinationChain\": \"arbitrum\",\n \"amountUsd\": 50,\n \"token\": \"usdc\",\n \"destinationAddress\": \"0x76F8fc6667E239f83a547d4e16225d6a34f6FA22\",\n \"partnerFeeAmountUsd\": 0.5,\n \"partnerFeeRecipientAddress\": \"0x1111111111111111111111111111111111111111\"\n}"
response = http.request(request)
puts response.read_bodyAuthorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Path Parameters
Wallet ID
Body
Client-generated idempotency key (UUID v4).
Stablecoin lane used to validate, fund, rebalance, and withdraw an allocation independently from other token lanes.
usdc, usdt Destination chain for the withdrawal. Production chains are arbitrum, base, ethereum, polygon, and solana; sandbox accepts ethereum_sepolia and solana_devnet.
arbitrum, base, ethereum, ethereum_sepolia, polygon, solana, solana_devnet Gross wallet value to withdraw before execution fees. The destination receives this amount minus reported fees.
On-chain destination address. Use an EVM hex address for EVM chains or a base58 address for solana.
Optional exact gross source split when automatic rebalancing is disabled. Amounts must sum to amountUsd.
1Show child attributes
Show child attributes
Optional partner-calculated fee deducted from the gross EVM USDC or USDT withdrawal. Supports up to 6 decimal places, must be smaller than amountUsd, and must be supplied with partnerFeeRecipientAddress.
x > 0EVM address that receives the partner fee. Must be supplied with partnerFeeAmountUsd and differ from destinationAddress.
Response
Withdrawal initiated (or existing withdrawal returned for idempotent retry)
Requested withdrawal amount in USD as a formatted string.
Completed payout amount in USD as a formatted string. Null until at least one payout completes.
Confirmed amount paid to the partner in USD as a formatted string. Null until at least one partner payout completes.
Execution and protocol fees charged for the withdrawal, as a formatted string.
Destination chain for the withdrawal.
arbitrum, base, ethereum, ethereum_sepolia, polygon, solana, solana_devnet usdc, usdt Simplified withdrawal status. partially_completed means at least one payout leg delivered value and at least one leg failed or was cancelled.
processing, completed, partially_completed, failed, cancelled Source-to-destination payout workflow legs.
Show child attributes
Show child attributes
Human-readable reason for failure (only present when status is failed or partially_completed). insufficient_proceeds_after_partner_fee means realized proceeds could not cover the committed partner fee while leaving a positive customer payout, so no payout or partner fee was sent.