curl --request POST \
--url https://api-partner.houdiniswap.com/v2/exchanges \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"addressTo": "<string>",
"quoteId": "<string>",
"markup": 0.5,
"refundAddress": "<string>",
"refundExtraId": "<string>",
"intermediateRefundAddress": "<string>",
"destinationTag": "<string>",
"addressFrom": "<string>",
"signatures": [
{
"signature": "<string>",
"key": "<string>",
"swapRequiredMetadata": {}
}
],
"walletInfo": "<string>"
}
'import requests
url = "https://api-partner.houdiniswap.com/v2/exchanges"
payload = {
"addressTo": "<string>",
"quoteId": "<string>",
"markup": 0.5,
"refundAddress": "<string>",
"refundExtraId": "<string>",
"intermediateRefundAddress": "<string>",
"destinationTag": "<string>",
"addressFrom": "<string>",
"signatures": [
{
"signature": "<string>",
"key": "<string>",
"swapRequiredMetadata": {}
}
],
"walletInfo": "<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>',
intermediateRefundAddress: '<string>',
destinationTag: '<string>',
addressFrom: '<string>',
signatures: [{signature: '<string>', key: '<string>', swapRequiredMetadata: {}}],
walletInfo: '<string>'
})
};
fetch('https://api-partner.houdiniswap.com/v2/exchanges', 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",
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>',
'intermediateRefundAddress' => '<string>',
'destinationTag' => '<string>',
'addressFrom' => '<string>',
'signatures' => [
[
'signature' => '<string>',
'key' => '<string>',
'swapRequiredMetadata' => [
]
]
],
'walletInfo' => '<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"
payload := strings.NewReader("{\n \"addressTo\": \"<string>\",\n \"quoteId\": \"<string>\",\n \"markup\": 0.5,\n \"refundAddress\": \"<string>\",\n \"refundExtraId\": \"<string>\",\n \"intermediateRefundAddress\": \"<string>\",\n \"destinationTag\": \"<string>\",\n \"addressFrom\": \"<string>\",\n \"signatures\": [\n {\n \"signature\": \"<string>\",\n \"key\": \"<string>\",\n \"swapRequiredMetadata\": {}\n }\n ],\n \"walletInfo\": \"<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")
.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 \"intermediateRefundAddress\": \"<string>\",\n \"destinationTag\": \"<string>\",\n \"addressFrom\": \"<string>\",\n \"signatures\": [\n {\n \"signature\": \"<string>\",\n \"key\": \"<string>\",\n \"swapRequiredMetadata\": {}\n }\n ],\n \"walletInfo\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-partner.houdiniswap.com/v2/exchanges")
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 \"intermediateRefundAddress\": \"<string>\",\n \"destinationTag\": \"<string>\",\n \"addressFrom\": \"<string>\",\n \"signatures\": [\n {\n \"signature\": \"<string>\",\n \"key\": \"<string>\",\n \"swapRequiredMetadata\": {}\n }\n ],\n \"walletInfo\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"houdiniId": "example-houdini-id",
"created": "2026-01-01T12:00:00.000Z",
"depositAddress": "bc1qexampledepositaddress000000000000000000",
"receiverAddress": "0x9f1f9a5c0f1d9a5c0f1d9a5c0f1d9a5c0f1d9a5c",
"anonymous": false,
"expires": "2026-01-01T12:30:00.000Z",
"status": 0,
"inAmount": 0.25,
"inSymbol": "BTC",
"outAmount": 3.52,
"outSymbol": "ETH",
"displayStatus": "WAITING_FOR_DEPOSIT"
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}{
"message": "<string>",
"code": "<string>",
"fields": {},
"requestId": "<string>"
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}Create exchange
Create a new exchange (swap). Use type: "private" or type: "standard" for centralized exchanges or type: "dex" for decentralized exchanges.
For a private same-token send you can use Create private send order, or stay on this endpoint with a private same-token quoteId — see the Private send guide.
curl --request POST \
--url https://api-partner.houdiniswap.com/v2/exchanges \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"addressTo": "<string>",
"quoteId": "<string>",
"markup": 0.5,
"refundAddress": "<string>",
"refundExtraId": "<string>",
"intermediateRefundAddress": "<string>",
"destinationTag": "<string>",
"addressFrom": "<string>",
"signatures": [
{
"signature": "<string>",
"key": "<string>",
"swapRequiredMetadata": {}
}
],
"walletInfo": "<string>"
}
'import requests
url = "https://api-partner.houdiniswap.com/v2/exchanges"
payload = {
"addressTo": "<string>",
"quoteId": "<string>",
"markup": 0.5,
"refundAddress": "<string>",
"refundExtraId": "<string>",
"intermediateRefundAddress": "<string>",
"destinationTag": "<string>",
"addressFrom": "<string>",
"signatures": [
{
"signature": "<string>",
"key": "<string>",
"swapRequiredMetadata": {}
}
],
"walletInfo": "<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>',
intermediateRefundAddress: '<string>',
destinationTag: '<string>',
addressFrom: '<string>',
signatures: [{signature: '<string>', key: '<string>', swapRequiredMetadata: {}}],
walletInfo: '<string>'
})
};
fetch('https://api-partner.houdiniswap.com/v2/exchanges', 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",
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>',
'intermediateRefundAddress' => '<string>',
'destinationTag' => '<string>',
'addressFrom' => '<string>',
'signatures' => [
[
'signature' => '<string>',
'key' => '<string>',
'swapRequiredMetadata' => [
]
]
],
'walletInfo' => '<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"
payload := strings.NewReader("{\n \"addressTo\": \"<string>\",\n \"quoteId\": \"<string>\",\n \"markup\": 0.5,\n \"refundAddress\": \"<string>\",\n \"refundExtraId\": \"<string>\",\n \"intermediateRefundAddress\": \"<string>\",\n \"destinationTag\": \"<string>\",\n \"addressFrom\": \"<string>\",\n \"signatures\": [\n {\n \"signature\": \"<string>\",\n \"key\": \"<string>\",\n \"swapRequiredMetadata\": {}\n }\n ],\n \"walletInfo\": \"<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")
.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 \"intermediateRefundAddress\": \"<string>\",\n \"destinationTag\": \"<string>\",\n \"addressFrom\": \"<string>\",\n \"signatures\": [\n {\n \"signature\": \"<string>\",\n \"key\": \"<string>\",\n \"swapRequiredMetadata\": {}\n }\n ],\n \"walletInfo\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-partner.houdiniswap.com/v2/exchanges")
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 \"intermediateRefundAddress\": \"<string>\",\n \"destinationTag\": \"<string>\",\n \"addressFrom\": \"<string>\",\n \"signatures\": [\n {\n \"signature\": \"<string>\",\n \"key\": \"<string>\",\n \"swapRequiredMetadata\": {}\n }\n ],\n \"walletInfo\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"houdiniId": "example-houdini-id",
"created": "2026-01-01T12:00:00.000Z",
"depositAddress": "bc1qexampledepositaddress000000000000000000",
"receiverAddress": "0x9f1f9a5c0f1d9a5c0f1d9a5c0f1d9a5c0f1d9a5c",
"anonymous": false,
"expires": "2026-01-01T12:30:00.000Z",
"status": 0,
"inAmount": 0.25,
"inSymbol": "BTC",
"outAmount": 3.52,
"outSymbol": "ETH",
"displayStatus": "WAITING_FOR_DEPOSIT"
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}{
"message": "<string>",
"code": "<string>",
"fields": {},
"requestId": "<string>"
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}Authorizations
Body
Request body for creating a new exchange
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.
64HS-2178: refund target for the intermediate (USDC) hop on a private
onchain-leg route — required only when the quote's
requiresIntermediateRefundAddress flag is set. Ignored otherwise.
200Destination tag / memo (e.g. for XRP, XLM)
64Source wallet address (required for DEX, ignored for CEX)
EIP-712 signatures for permit-based approvals (DEX only)
Show child attributes
Show child attributes
Wallet info string
256Response
Exchange created
- -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.