curl --request POST \
--url https://api-partner.houdiniswap.com/v2/exchanges/private-send \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"addressTo": "<string>",
"quoteId": "<string>",
"markup": 0.5,
"refundAddress": "<string>",
"refundExtraId": "<string>",
"destinationTag": "<string>"
}
'import requests
url = "https://api-partner.houdiniswap.com/v2/exchanges/private-send"
payload = {
"addressTo": "<string>",
"quoteId": "<string>",
"markup": 0.5,
"refundAddress": "<string>",
"refundExtraId": "<string>",
"destinationTag": "<string>"
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
addressTo: '<string>',
quoteId: '<string>',
markup: 0.5,
refundAddress: '<string>',
refundExtraId: '<string>',
destinationTag: '<string>'
})
};
fetch('https://api-partner.houdiniswap.com/v2/exchanges/private-send', 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-partner.houdiniswap.com/v2/exchanges/private-send",
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([
'addressTo' => '<string>',
'quoteId' => '<string>',
'markup' => 0.5,
'refundAddress' => '<string>',
'refundExtraId' => '<string>',
'destinationTag' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"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-partner.houdiniswap.com/v2/exchanges/private-send"
payload := strings.NewReader("{\n \"addressTo\": \"<string>\",\n \"quoteId\": \"<string>\",\n \"markup\": 0.5,\n \"refundAddress\": \"<string>\",\n \"refundExtraId\": \"<string>\",\n \"destinationTag\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<api-key>")
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-partner.houdiniswap.com/v2/exchanges/private-send")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"addressTo\": \"<string>\",\n \"quoteId\": \"<string>\",\n \"markup\": 0.5,\n \"refundAddress\": \"<string>\",\n \"refundExtraId\": \"<string>\",\n \"destinationTag\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-partner.houdiniswap.com/v2/exchanges/private-send")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"addressTo\": \"<string>\",\n \"quoteId\": \"<string>\",\n \"markup\": 0.5,\n \"refundAddress\": \"<string>\",\n \"refundExtraId\": \"<string>\",\n \"destinationTag\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"houdiniId": "hxK7mQp2",
"created": "2026-01-01T12:00:00.000Z",
"depositAddress": "bc1qexampledepositaddress000000000000000000",
"receiverAddress": "bc1qexampledestinationaddress000000000000",
"anonymous": true,
"expires": "2026-01-01T12:30:00.000Z",
"status": 0,
"inAmount": 0.1,
"inSymbol": "BTC",
"outAmount": 0.095,
"outSymbol": "BTC",
"displayStatus": "WAITING_FOR_DEPOSIT"
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}Create private send order
Send funds to another wallet via a private (two-hop) route. Same token in and out.
Pass a quoteId from Get private send quote.
Quote first, then create the order right away — a stale quoteId is rejected with 422.
Send the deposit to depositAddress before expires.
See the Private send guide.
This endpoint only supports private same-token routes. If you want to keep one integration for every exchange type, use Create exchange with a private same-token quoteId from Get quotes instead.
curl --request POST \
--url https://api-partner.houdiniswap.com/v2/exchanges/private-send \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"addressTo": "<string>",
"quoteId": "<string>",
"markup": 0.5,
"refundAddress": "<string>",
"refundExtraId": "<string>",
"destinationTag": "<string>"
}
'import requests
url = "https://api-partner.houdiniswap.com/v2/exchanges/private-send"
payload = {
"addressTo": "<string>",
"quoteId": "<string>",
"markup": 0.5,
"refundAddress": "<string>",
"refundExtraId": "<string>",
"destinationTag": "<string>"
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
addressTo: '<string>',
quoteId: '<string>',
markup: 0.5,
refundAddress: '<string>',
refundExtraId: '<string>',
destinationTag: '<string>'
})
};
fetch('https://api-partner.houdiniswap.com/v2/exchanges/private-send', 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-partner.houdiniswap.com/v2/exchanges/private-send",
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([
'addressTo' => '<string>',
'quoteId' => '<string>',
'markup' => 0.5,
'refundAddress' => '<string>',
'refundExtraId' => '<string>',
'destinationTag' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"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-partner.houdiniswap.com/v2/exchanges/private-send"
payload := strings.NewReader("{\n \"addressTo\": \"<string>\",\n \"quoteId\": \"<string>\",\n \"markup\": 0.5,\n \"refundAddress\": \"<string>\",\n \"refundExtraId\": \"<string>\",\n \"destinationTag\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<api-key>")
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-partner.houdiniswap.com/v2/exchanges/private-send")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"addressTo\": \"<string>\",\n \"quoteId\": \"<string>\",\n \"markup\": 0.5,\n \"refundAddress\": \"<string>\",\n \"refundExtraId\": \"<string>\",\n \"destinationTag\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-partner.houdiniswap.com/v2/exchanges/private-send")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"addressTo\": \"<string>\",\n \"quoteId\": \"<string>\",\n \"markup\": 0.5,\n \"refundAddress\": \"<string>\",\n \"refundExtraId\": \"<string>\",\n \"destinationTag\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"houdiniId": "hxK7mQp2",
"created": "2026-01-01T12:00:00.000Z",
"depositAddress": "bc1qexampledepositaddress000000000000000000",
"receiverAddress": "bc1qexampledestinationaddress000000000000",
"anonymous": true,
"expires": "2026-01-01T12:30:00.000Z",
"status": 0,
"inAmount": 0.1,
"inSymbol": "BTC",
"outAmount": 0.095,
"outSymbol": "BTC",
"displayStatus": "WAITING_FOR_DEPOSIT"
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}Authorizations
Body
Create a private same-token order from a prior private-send quote.
Destination wallet address where funds will be sent
1 - 200Quote ID from a prior quote response. Amount, from token, to token, and swap provider are retrieved from the provided quote. For CEX exchanges, if the exchange fails with the chosen swap provider, it will fallback to the next best route.
Partner markup for this request, as a percentage (0.5 = 0.5%). Accepted range: 0–4. This value overrides your account’s default markup for this trade. Send 0 to apply no markup, or leave the field empty / set it to null if no markup is requested. Providers that do not support the requested markup will be excluded.
0 <= x <= 40.5
Sender's wallet address for refunds if a fixed-rate swap fails. Required when the quote was created with fixed: true.
200Memo/tag for refundAddress on memo-bearing chains (e.g. XRP DestinationTag, Stellar memo, TON comment). Ignored when the destination chain has no memo concept.
64Destination tag / memo (e.g. for XRP, XLM)
64Response
Success
- -2 Order is being initialized (label: INITIALIZING)
- -1 Order initialized (label: NEW)
- 0 Waiting for deposit confirmation (label: WAITING)
- 1 Deposit is being confirmed (label: CONFIRMING)
- 2 Exchange is in progress (label: EXCHANGING)
- 3 Order is going through anonymization (label: ANONYMIZING)
- 4 Order completed successfully (label: FINISHED)
- 5 Order has expired (label: EXPIRED)
- 6 Order failed (label: FAILED)
- 7 Order was refunded (label: REFUNDED)
- 8 Order was deleted (label: DELETED)
-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8 ETA time, depending on swap
USD value of the input amount at order creation time.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
- 0 New swap
- 1 Waiting for confirmation
- 2 Being confirmed
- 3 Exchange in progress
- 4 Sending to destination
- 5 Swap completed
- 6 Swap failed
- 7 Swap refunded
- 8 Verifying swap
- 9 Swap expired
- 10 Fallback mode
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 WAITING_FOR_DEPOSIT, DEPOSIT_DETECTED, EXCHANGE_IN_PROGRESS, SENDING_TO_INTERMEDIARY, REACHED_INTERMEDIARY, INITIATING_SECOND_EXCHANGE, SECOND_EXCHANGE_IN_PROGRESS, SENDING_TO_RECEIVER, SWAP_COMPLETED, EXPIRED, FAILED, REFUNDED, DELETED Memo/tag required when depositing funds for assets that use one
True when the route that executed is not the one that was quoted,
because the quoted route failed and a fallback was used. The amounts may
differ from the quote — compare inAmount against quotedInAmount and
outAmount against quotedOutAmount.
The deposit amount originally quoted, present only when the order was
rerouted. inAmount is what the fallback route actually asks for; on an
exact-out order this is the side that moves.
The payout originally quoted, present only when the order was rerouted.
outAmount is what the fallback route will actually pay; on an exact-in
order this is the side that moves.
Memo/tag required when receiving funds for assets that use one
Name of the exchange handling the deposit leg. Omitted on private orders, which withhold the provider, and on multiswap orders that have not yet been assigned one.
Multi ID. Present only on orders created as part of a batch.
Status of the payout leg. Present only on private orders — public orders settle in a single leg and never carry one.
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 Payout transaction hash of the second leg. Present only on private orders,
and only once that leg has paid out. Public orders report their payout
hash on inTransactionOutHash instead.
Date and time when the order received status 4. Stamped only when an order finishes; orders that expire, fail or refund never receive one.
The CEX deposit address where the user must send funds. Omitted on multiswap orders whose per-order initialization did not complete.