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

# Private Swap Integration

> 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"`.

<Info>
  **Best For**: Users who prioritize privacy and are willing to accept longer completion times (15–45 minutes) for enhanced anonymity.
</Info>

<Note>
  Looking for the v1 private swap guide? See [API v1 — Private Swap](/api-v1/swap-flows/private-swap).
</Note>

<Note>
  Fixed rate is not available for private swaps. To guarantee the output amount, use a [Fixed Rate Standard Swap](/developer-hub/swap-flows/fixed-rate-swap) instead.
</Note>

## Key Features

<CardGroup cols={2}>
  <Card title="Multi-Hop Routing" icon="route">
    Routes through 2 exchanges to break the transaction trail
  </Card>

  <Card title="Optional XMR Privacy Layer" icon="lock">
    Monero used as an untraceable intermediate when available
  </Card>

  <Card title="No Wallet Connection" icon="shield">
    No browser wallet or on-chain approvals required
  </Card>

  <Card title="Maximum Anonymity" icon="user-secret">
    No direct on-chain link between source and destination
  </Card>
</CardGroup>

## How It Works

<Steps>
  <Step title="Get Tokens">
    Bulk fetch CEX-supported tokens and cache to your DB, or search by name/symbol. Note each token's `id`.
  </Step>

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

  <Step title="Create Order">
    Call `POST /exchanges` with the selected `quoteId` and destination address.
  </Step>

  <Step title="Send Deposit">
    Send exactly `inAmount` to the `depositAddress` returned in the order.
  </Step>

  <Step title="Monitor Status">
    Poll `GET /orders/{houdiniId}`. Private swaps pass through `ANONYMIZING` before `FINISHED`.
  </Step>
</Steps>

## Integration Guide

### Step 1: Get Tokens

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

<Tabs>
  <Tab title="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.
    </Warning>

    <CodeGroup>
      ```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"
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Token Search">
    Search for specific tokens by name or symbol on demand.

    <CodeGroup>
      ```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"
      ```
    </CodeGroup>
  </Tab>
</Tabs>

### 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"`.

<CodeGroup>
  ```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"
  ```
</CodeGroup>

### 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)

### 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.

<CodeGroup>
  ```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"
    }'
  ```
</CodeGroup>

### 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).
</Warning>

### Step 4: Monitor Order Status

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

<CodeGroup>
  ```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"
  ```
</CodeGroup>

### 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](/developer-hub/core-concepts/websocket-order-updates).
</Tip>

## Best Practices

<AccordionGroup>
  <Accordion title="Set Proper Expectations" icon="info">
    Clearly communicate the 15–45 minute completion time. Users should understand they are trading speed for privacy.
  </Accordion>

  <Accordion title="Track Both Hops" icon="chart-line">
    Display both `inStatusLabel` and `outStatusLabel` to show users which leg of the swap is processing.
  </Accordion>

  <Accordion title="Handle Long Waits" icon="clock">
    Implement loading states and progress indicators. Multi-hop routing takes significantly longer than standard swaps.
  </Accordion>

  <Accordion title="Security" icon="shield">
    Never expose API keys in frontend code. Validate all destination addresses before submitting. Store `houdiniId` for support lookups.
  </Accordion>
</AccordionGroup>

## Common Issues

<AccordionGroup>
  <Accordion title="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>

  <Accordion title="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>

  <Accordion title="Order Expired">
    **Cause**: Deposit was not received before the `expires` timestamp.

    **Solution**: Fetch a new quote and create a new order.
  </Accordion>
</AccordionGroup>

## Example Repositories

See full working integrations on GitHub:

<CardGroup cols={2}>
  <Card title="Next.js Example" icon="react" href="https://github.com/HoudiniSwap/houdini-api-examples/tree/main/nextjs-example">
    Full Next.js integration showing standard, private, and DEX swap flows
  </Card>

  <Card title="Node.js Example" icon="node-js" href="https://github.com/HoudiniSwap/houdini-api-examples/tree/main/node-examples">
    Backend Node.js integration with token fetching, quoting, and order tracking
  </Card>
</CardGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Standard Swaps" icon="bolt" href="/developer-hub/swap-flows/standard-swap">
    Fast single-hop CEX swaps
  </Card>

  <Card title="DEX Swaps" icon="arrows-rotate" href="/developer-hub/swap-flows/dex-swap">
    On-chain decentralized swaps
  </Card>

  <Card title="Order Lifecycle" icon="rotate" href="/developer-hub/core-concepts/order-lifecycle">
    Understand all order statuses
  </Card>
</CardGroup>
