> ## Documentation Index
> Fetch the complete documentation index at: https://docs.houdini.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Private Swap

> Integrate multi-hop private swaps using the unified v2 quotes and exchanges API

## Overview

Private swaps route through **multiple CEX hops** to break the transaction trail, providing enhanced anonymity. Optionally routes through Monero (XMR) as an untraceable intermediate layer. In API v2, private swaps use the same `/quotes` and `/exchanges` endpoints as standard and DEX swaps — pass `types=private` to get only private quotes, or filter the response by `type: "private"`.

> [!NOTE]
>
> **Best For**: Users who prioritize privacy and are willing to accept longer completion times (15–45 minutes) for enhanced anonymity.

> [!NOTE]
>
> Looking for the v1 private swap guide? See [API v1 — Private Swap](https://docs.houdini.com/api-v1/swap-flows/private-swap.md).

> [!NOTE]
>
> Private swaps support **fixed rate** and **reverse quotes**. Add `fixed=true` to lock the rate across both hops, and `amountType=receive` to specify what the recipient receives instead of what the user sends. See [Fixed Rate & Reverse Quote](https://docs.houdini.com/developer-hub/swap-flows/fixed-rate-swap.md).

> [!NOTE]
>
> Private swaps can reach **more tokens with an on-chain hop**. When a token has no direct private route, the swap runs privately to a hub token, then an on-chain hop delivers the destination token. This covers almost any token on Solana and high-volume EVM chains. Contact your Houdini representative to turn it on, and send `intermediateRefundAddress` when the quote asks for it. See [Private Routes with an On-chain Hop](https://docs.houdini.com/developer-hub/swap-flows/private-onchain-hop.md).

## Key Features

> [card] Multi-Hop Routing
>
> Routes through 2 exchanges to break the transaction trail

> [card] Optional XMR Privacy Layer
>
> Monero used as an untraceable intermediate when available

> [card] No Wallet Connection
>
> No browser wallet or on-chain approvals required

> [card] Maximum Anonymity
>
> No direct on-chain link between source and destination

> [card] Optional Rate Lock
>
> Add `fixed=true` to guarantee the output amount across both hops

> [card] Optional Reverse Quote
>
> Add `amountType=receive` to specify the amount the recipient gets

## How It Works

**1. Get Tokens**

Bulk fetch CEX-supported tokens and cache to your DB, or search by name/symbol. Note each token's `id`.

**2. Get Quotes**

Call `GET /quotes` with token IDs. Either pass `types=private` to get only private quotes, or filter the response by `type: "private"`.

**3. Create Order**

Call `POST /exchanges` with the selected `quoteId` and destination address.

**4. Send Deposit**

Send exactly `inAmount` to the `depositAddress` returned in the order.

**5. Monitor Status**

Poll `GET /orders/{houdiniId}`. Private swaps pass through `ANONYMIZING` before `FINISHED`.

## Integration Guide

### Step 1: Get Tokens

There are two approaches for getting tokens. Choose the one that fits your integration:

> [tab] Bulk Fetch + Cache
>
> Fetch all CEX-supported tokens once and store them in your backend database.
>
> > [!WARNING]
> >
> > Cache the token list in your backend database. Never call `/tokens` on every user request — load on server startup or via a scheduled job and refresh every 24 hours.
>
> ```javascript JavaScript theme={null}
> async function fetchAllCexTokens() {
>   let page = 1;
>   let allTokens = [];
>
>   while (true) {
>     const response = await fetch(
>       `https://api-partner.houdiniswap.com/v2/tokens?hasCex=true&pageSize=20&page=${page}`,
>       {
>         headers: { 'Authorization': `${API_KEY}:${API_SECRET}` }
>       }
>     );
>
>     const { tokens, totalPages } = await response.json();
>     allTokens = allTokens.concat(tokens);
>
>     if (page >= totalPages) break;
>     page++;
>   }
>
>   return allTokens; // save to your DB
> }
> ```
>
> ```bash cURL theme={null}
> curl -X GET "https://api-partner.houdiniswap.com/v2/tokens?hasCex=true&pageSize=20&page=1" \
>   -H "Authorization: your_api_key:your_api_secret"
> ```

> [tab] Token Search
>
> Search for specific tokens by name or symbol on demand.
>
> ```javascript JavaScript theme={null}
> async function searchTokens(query) {
>   const params = new URLSearchParams({
>     term: query,
>     hasCex: 'true',
>     pageSize: '20',
>     page: '1'
>   });
>
>   const response = await fetch(
>     `https://api-partner.houdiniswap.com/v2/tokens?${params}`,
>     {
>       headers: { 'Authorization': `${API_KEY}:${API_SECRET}` }
>     }
>   );
>
>   const { tokens } = await response.json();
>   return tokens; // use token `id` in /quotes requests
> }
> ```
>
> ```bash cURL theme={null}
> curl -X GET "https://api-partner.houdiniswap.com/v2/tokens?term=monero&hasCex=true&pageSize=20&page=1" \
>   -H "Authorization: your_api_key:your_api_secret"
> ```

### Step 2: Get Private Quote

Call `GET /quotes` with token IDs. Pass `types=private` to receive only private quotes, or omit it to get all types and filter by `type: "private"`.

```javascript JavaScript theme={null}
const params = new URLSearchParams({
  amount: '1',
  from: '6689b73ec90e45f3b3e51566',  // ETH token id
  to:   '6689b73ec90e45f3b3e51577',  // SOL token id
  types: 'private',                  // only return private quotes
});

const response = await fetch(
  `https://api-partner.houdiniswap.com/v2/quotes?${params}`,
  {
    headers: {
      'Authorization': `${API_KEY}:${API_SECRET}`,
      'x-user-ip': userIp,
      'x-user-agent': userAgent,
      'x-user-timezone': userTimezone
    }
  }
);

const { quotes } = await response.json();

// Select a private (multi-hop) quote
const privateQuote = quotes.find(q => q.type === 'private');
console.log('Amount out:', privateQuote.amountOut);
console.log('ETA:', privateQuote.duration, 'minutes');  // typically 60 min
console.log('Quote ID:', privateQuote.quoteId);         // needed for /exchanges
```

```bash cURL theme={null}
curl -X GET "https://api-partner.houdiniswap.com/v2/quotes?amount=1&from=6689b73ec90e45f3b3e51566&to=6689b73ec90e45f3b3e51577&types=private" \
  -H "Authorization: your_api_key:your_api_secret" \
  -H "x-user-ip: 192.168.1.1" \
  -H "x-user-agent: Mozilla/5.0..." \
  -H "x-user-timezone: America/New_York"
```

### Quotes Response (private quote)

```json theme={null}
{
  "quotes": [
    {
      "quoteId": "69af93b1f9c5affabcaccbdb",
      "type": "private",
      "amountIn": 1,
      "amountOut": 25842.84927999,
      "amountOutUsd": 2007.5759034667433,
      "min": 0.09828,
      "max": 4228.846045,
      "duration": 60,
      "rewardsAvailable": true
    }
  ],
  "total": 5
}
```

**Key Private Quote Fields:**

* `quoteId`: Pass this to `/exchanges` to create the order
* `type`: `"private"` indicates multi-hop routing
* `duration`: Estimated time in minutes — longer due to multi-hop (typically 60 min)

#### Rate options

The quote above is a **floating** rate — `amountOut` is an estimate that can move before settlement. Two options change that:

| Option | Parameter | Effect |
| - | - | - |
| Fixed rate | `fixed=true` | `amountOut` is guaranteed, locked across both hops until `validUntil` |
| Reverse quote | `fixed=true&amountType=receive` | `amount` becomes what the recipient receives; the API computes the deposit |

Both require a `refundAddress` on the source chain when you create the order, and both can return fewer routes — or none — for a pair that floating rate serves. See [Fixed Rate & Reverse Quote](https://docs.houdini.com/developer-hub/swap-flows/fixed-rate-swap.md) for the full flow, response differences, and error codes.

### Step 3: Create Private Order

Pass the `quoteId` and destination address to `POST /exchanges`. No additional parameters are needed to enable private routing — the quote type determines the routing.

> [!WARNING]
>
> If the quote has `requiresIntermediateRefundAddress: true`, it is a [private route with an on-chain hop](https://docs.houdini.com/developer-hub/swap-flows/private-onchain-hop.md). You must also send `intermediateRefundAddress`, or the request fails with `INTERMEDIATE_REFUND_ADDRESS_REQUIRED`.

```javascript JavaScript theme={null}
const response = await fetch('https://api-partner.houdiniswap.com/v2/exchanges', {
  method: 'POST',
  headers: {
    'Authorization': `${API_KEY}:${API_SECRET}`,
    'Content-Type': 'application/json',
    'x-user-ip': userIp,
    'x-user-agent': userAgent,
    'x-user-timezone': userTimezone
  },
  body: JSON.stringify({
    quoteId: '694cd4b5d924391f000561e3',  // private quote from /quotes
    addressTo: '1nc1nerator11111111111111111111111111111111'
  })
});

const order = await response.json();
console.log('Order ID:', order.houdiniId);
console.log('Deposit to:', order.depositAddress);
console.log('Send amount:', order.inAmount, order.inSymbol);
console.log('Expires:', order.expires);
```

```bash cURL theme={null}
curl -X POST "https://api-partner.houdiniswap.com/v2/exchanges" \
  -H "Authorization: your_api_key:your_api_secret" \
  -H "Content-Type: application/json" \
  -H "x-user-ip: 192.168.1.1" \
  -H "x-user-agent: Mozilla/5.0..." \
  -H "x-user-timezone: America/New_York" \
  -d '{
    "quoteId": "694cd4b5d924391f000561e3",
    "addressTo": "1nc1nerator11111111111111111111111111111111"
  }'
```

### Order Response

```json theme={null}
{
  "houdiniId": "bwc5iKVeeW5GiQpLHCm65w",
  "created": "2025-12-25T06:13:21.293Z",
  "expires": "2025-12-25T06:43:21.293Z",
  "depositAddress": "0xA2fC2BD472aB6FAF3176EBcBCaeeC7f95F563Ada",
  "receiverAddress": "1nc1nerator11111111111111111111111111111111",
  "anonymous": true,
  "status": -1,
  "statusLabel": "NEW",
  "inAmount": 1,
  "inSymbol": "ETH",
  "inStatus": 0,
  "inStatusLabel": "NEW",
  "outAmount": 23.66258493,
  "outSymbol": "SOL",
  "outStatus": 0,
  "outStatusLabel": "NEW",
  "eta": 28,
  "swapName": "Changelly → Quickex"
}
```

> [!WARNING]
>
> Send exactly `inAmount` of `inSymbol` to `depositAddress` before `expires` (typically 30 minutes).

### Step 4: Monitor Order Status

Poll `GET /orders/{houdiniId}` to track multi-hop progress, or subscribe via the [WebSocket API](https://docs.houdini.com/developer-hub/core-concepts/websocket-order-updates.md) for real-time updates:

```javascript JavaScript theme={null}
const response = await fetch(
  `https://api-partner.houdiniswap.com/v2/orders/${order.houdiniId}`,
  {
    headers: {
      'Authorization': `${API_KEY}:${API_SECRET}`,
      'x-user-ip': userIp,
      'x-user-agent': userAgent,
      'x-user-timezone': userTimezone
    }
  }
);

const status = await response.json();
console.log('Overall status:', status.statusLabel);
console.log('First hop:', status.inStatusLabel);   // input leg
console.log('Second hop:', status.outStatusLabel); // output leg
```

```bash cURL theme={null}
curl -X GET "https://api-partner.houdiniswap.com/v2/orders/bwc5iKVeeW5GiQpLHCm65w" \
  -H "Authorization: your_api_key:your_api_secret" \
  -H "x-user-ip: 192.168.1.1" \
  -H "x-user-agent: Mozilla/5.0..." \
  -H "x-user-timezone: America/New_York"
```

### Private Swap Status Progression

Private swaps pass through an additional `ANONYMIZING` stage during the XMR privacy layer:

```
NEW / WAITING
  ↓ Deposit sent and detected
CONFIRMING
  ↓ Blockchain confirmations received
EXCHANGING
  ↓ First CEX hop processing
ANONYMIZING
  ↓ Routing through XMR privacy layer
  ↓ Second CEX hop processing
FINISHED
```

**Status Fields:**

* `statusLabel`: Overall order status
* `inStatusLabel`: First hop status
* `outStatusLabel`: Second hop status (private swaps only)

> [!TIP]
>
> Poll every 30 seconds. Private swaps typically complete in 15–45 minutes due to multi-hop routing. For real-time updates without polling, use the [WebSocket API](https://docs.houdini.com/developer-hub/core-concepts/websocket-order-updates.md).

## Best Practices

> [accordion] Set Proper Expectations
>
> Clearly communicate the 15–45 minute completion time. Users should understand they are trading speed for privacy.

> [accordion] Track Both Hops
>
> Display both `inStatusLabel` and `outStatusLabel` to show users which leg of the swap is processing.

> [accordion] Handle Long Waits
>
> Implement loading states and progress indicators. Multi-hop routing takes significantly longer than standard swaps.

> [accordion] Security
>
> Never expose API keys in frontend code. Validate all destination addresses before submitting. Store `houdiniId` for support lookups.

## Common Issues

> [accordion] Longer Than Expected Completion
>
> **Cause**: Multi-hop routing through 2 exchanges takes longer than a direct swap.
>
> **Solution**: This is expected for private swaps. Monitor `inStatusLabel` and `outStatusLabel` to see which hop is processing.

> [accordion] Privacy Questions
>
> **Question**: "How private is this really?"
>
> **Answer**: Private swaps break the transaction trail by routing through multiple exchanges. When XMR routing is used, it adds an untraceable intermediate step. However, this is not absolute anonymity — compliance checks still apply.

> [accordion] Order Expired
>
> **Cause**: Deposit was not received before the `expires` timestamp.
>
> **Solution**: Fetch a new quote and create a new order.

## Example Repositories

See full working integrations on GitHub:

> [card] [Next.js Example](https://github.com/HoudiniSwap/houdini-api-examples/tree/main/nextjs-example)
>
> Full Next.js integration showing standard, private, and DEX swap flows

> [card] [Node.js Example](https://github.com/HoudiniSwap/houdini-api-examples/tree/main/node-examples)
>
> Backend Node.js integration with token fetching, quoting, and order tracking

## Next Steps

> [card] [Standard Swap](https://docs.houdini.com/developer-hub/swap-flows/standard-swap.md)
>
> Fast single-hop CEX swaps

> [card] [DEX Swap](https://docs.houdini.com/developer-hub/swap-flows/dex-swap.md)
>
> On-chain decentralized swaps

> [card] [Fixed Rate & Reverse Quote](https://docs.houdini.com/developer-hub/swap-flows/fixed-rate-swap.md)
>
> Guarantee the output amount, or specify what the recipient receives

> [card] [Private Routes with an On-chain Hop](https://docs.houdini.com/developer-hub/swap-flows/private-onchain-hop.md)
>
> Reach tokens that have no direct private route

> [card] [Order Lifecycle](https://docs.houdini.com/developer-hub/core-concepts/order-lifecycle.md)
>
> Understand all order statuses


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.