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

# DEX Swap Integration API v1

> Complete guide to integrating on-chain DEX swaps with wallet signatures and approvals

<Danger>
  Deprecation of the REST v1 swap endpoints begins on September 30, 2026. Please migrate to the Partner API v2. Dashboard and authentication endpoints remain on v1 GraphQL and are not affected. [Read the migration guide](https://docs.houdiniswap.com/migration/v1-to-v2)
</Danger>

## Overview

DEX (Decentralized Exchange) swaps execute on-chain through smart contracts. Unlike CEX swaps that use deposit addresses, DEX swaps require users to connect their wallet, sign transactions, and broadcast them directly to the blockchain.

<Info>
  **Best For**: Users who want true decentralized swaps, keep custody of their funds, and interact directly with on-chain liquidity sources like Uniswap, Cowswap, and 1inch.
</Info>

### Supported Networks

DEX swaps are currently supported on the following networks:

* **EVM** (Ethereum, BSC, Polygon, etc.)
* **Solana**
* **SUI**
* **TRON**
* **TON**
* **Stellar**

<Warning>
  **Stellar Trustline Requirement**: For swaps involving Stellar assets, the integrator is responsible for ensuring that the destination account has the required [trustlines](https://developers.stellar.org/docs/learn/fundamentals/stellar-data-structures/accounts#trustlines) established before initiating the swap. Houdini does not handle trustline creation automatically. If the trustline is missing, the swap will fail.
</Warning>

## Key Characteristics

| Feature       | DEX                                    | CEX (Private/Standard)        |
| ------------- | -------------------------------------- | ----------------------------- |
| **Execution** | On-chain via smart contracts           | Off-chain via exchanges       |
| **Wallet**    | Required (MetaMask, etc.)              | Not required                  |
| **Custody**   | User keeps custody                     | User sends to deposit address |
| **Speed**     | Varies by network (seconds to minutes) | 3-45 minutes                  |
| **Approvals** | May require token approvals            | Not required                  |

## How It Works

DEX swaps follow this flow:

```mermaid theme={null}
sequenceDiagram
    participant User
    participant YourApp
    participant Wallet
    participant DEX
    participant Blockchain

    User->>YourApp: Request swap
    YourApp->>API: Get quote
    API-->>YourApp: Return route
    YourApp->>API: Check approvals
    API-->>YourApp: Return approval/signature requirements
    User->>Wallet: Send approval transactions (if needed)
    Wallet->>Blockchain: Submit approval
    User->>Wallet: Sign signatures (if needed)
    Wallet->>DEX: Execute swap
    DEX->>Blockchain: Process on-chain
    Blockchain-->>YourApp: Transaction confirmed
```

## Technical Flow Diagram

This diagram shows the complete integration flow with conditional logic:

```mermaid theme={null}
flowchart TD
    Start([Start Integration]) --> Step1[Step 1: Get Supported Assets<br/>/dexTokens, /networks]
    Step1 --> Step2[Step 2: Get DEX Quote<br/>/dexQuote]
    Step2 --> Step3[Step 3: Check Approvals & Signatures<br/>/dexApprove]

    Step3 --> CheckArrays{What's needed?}

    CheckArrays -->|Has approvals| Step4[Step 4: Send Approval Transactions<br/>Broadcast via wallet]
    CheckArrays -->|Has signatures only| Step5[Step 5: Process Signatures<br/>User signs with wallet]
    CheckArrays -->|Has both| Step4
    CheckArrays -->|Neither| Step7[Step 7: Execute Swap<br/>/dexExchange]

    Step4 --> CheckSig{Has signatures?}
    CheckSig -->|Yes| Step5
    CheckSig -->|No| Step6[Step 6: Check Allowance<br/>/dexHasEnoughAllowance]

    Step5 --> CheckSigType{Signature type?}
    CheckSigType -->|SINGLE| CollectSig[Collect signature]
    CheckSigType -->|CHAINED| ChainLoop[Loop: Sign → /chainSignatures<br/>Until isComplete = true]

    CollectSig --> CheckApproval{Sent approvals?}
    ChainLoop --> CheckApproval

    CheckApproval -->|Yes| Step6
    CheckApproval -->|No| Step7

    Step6 --> PollAllowance{hasEnoughAllowance?}
    PollAllowance -->|No| Wait[Wait 30 seconds]
    Wait --> PollAllowance
    PollAllowance -->|Yes| Step7

    Step7 --> CheckOffChain{offChain?}

    CheckOffChain -->|false| BroadcastTx[Broadcast transaction<br/>via wallet]
    CheckOffChain -->|true| ConfirmOffChain[Call /dexConfirmTx<br/>with txHash: undefined]

    BroadcastTx --> ConfirmTx[Call /dexConfirmTx<br/>with txHash]
    ConfirmTx --> Step8[Step 8: Track Status<br/>/status]
    ConfirmOffChain --> Step8

    Step8 --> PollStatus{Status?}
    PollStatus -->|0-2| WaitStatus[Wait 30 seconds]
    WaitStatus --> Step8
    PollStatus -->|4 COMPLETED| Success([✅ Swap Complete])
    PollStatus -->|6 FAILED| Failed([❌ Swap Failed])

    style Step1 fill:#e1f5ff,color:#000
    style Step2 fill:#e1f5ff,color:#000
    style Step3 fill:#fff4e1,color:#000
    style Step4 fill:#ffe1e1,color:#000
    style Step5 fill:#ffe1e1,color:#000
    style Step6 fill:#ffe1e1,color:#000
    style Step7 fill:#e1ffe1,color:#000
    style Step8 fill:#f0e1ff,color:#000
    style Success fill:#90EE90,color:#000
    style Failed fill:#FFB6C1,color:#000
```

## Integration Steps

### Step 1: Get Supported Assets

Discover which tokens and networks are available for DEX swaps. Learn more about [DEX tokens](/developer-hub/core-concepts/tokens-networks#dex-tokens) and [network identifiers](/developer-hub/core-concepts/tokens-networks#network-identifiers).

<Warning>
  **Performance Note**: The `/tokens` endpoint can take several seconds to minute to respond due to the large token list.

  * Save tokens in your backend database
  * Load tokens on server startup or via scheduled job
  * Serve token list from your database to frontend
  * Refresh cache periodically (e.g., every 24 hours)
</Warning>

<CodeGroup>
  ```javascript JavaScript theme={null}
  const tokens = await fetchFromHoudini('/dexTokens');

  // Get supported networks
  const networks = await fetchFromHoudini('/networks');
  ```

  ```bash cURL theme={null}
  # Get tokens
  curl -X GET "https://api-partner.houdiniswap.com/dexTokens" \
    -H "Authorization: your_api_key:your_api_secret"

  # Get networks
  curl -X GET "https://api-partner.houdiniswap.com/networks" \
    -H "Authorization: your_api_key:your_api_secret"
  ```
</CodeGroup>

### Step 2: Get DEX Quote

Request a quote for the DEX swap using token IDs from [`/dexTokens`](/developer-hub/core-concepts/tokens-networks#fetch-dex-tokens):

<CodeGroup>
  ```javascript JavaScript theme={null}
  const quotes = await fetchFromHoudini('/dexQuote', {
    tokenIdFrom: '6689b73ec90e45f3b3e51566',  // ETH token _id from /dexTokens
    tokenIdTo: '6689b73ec90e45f3b3e51553',    // USDT token _id from /dexTokens
    amount: 1,
  });

  // Select the best quote (first in array)
  const selectedQuote = quotes[0];
  ```

  ```bash cURL theme={null}
  curl -X GET "https://api-partner.houdiniswap.com/dexQuote?tokenIdFrom=6689b73ec90e45f3b3e51558&tokenIdTo=6689b73ec90e45f3b3e51553&amount=1&address=0x742d35Cc6634C0532925a3b844Bc454e4438f44e" \
    -H "Authorization: your_api_key:your_api_secret"
  ```
</CodeGroup>

**Quote Parameters:**

* `tokenIdFrom`: Source token `_id` from [`/dexTokens`](/developer-hub/core-concepts/tokens-networks#fetch-dex-tokens) endpoint
* `tokenIdTo`: Destination token `_id` from [`/dexTokens`](/developer-hub/core-concepts/tokens-networks#fetch-dex-tokens) endpoint
* `amount`: Amount to swap (float: `1` = 1 token)
* `slippage` (optional): Slippage percentage (e.g., `0.5` for 0.5%)
* `fromAddress` (optional): Specific source address for the swap
* `toAddress` (optional): Specific destination address for receiving tokens

<Tip>
  Remember to use the `_id` field from DEX tokens, not the `id` field. Learn more about [token identifiers](/developer-hub/core-concepts/tokens-networks#token-identifiers).
</Tip>

#### Quote Response

The response is an **array of quote options** from different DEX aggregators, sorted by best rate (highest output first). Each quote object contains:

| Field                | Type    | Description                                                                                                                  |
| -------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `swap`               | string  | DEX identifier code used in subsequent API calls                                                                             |
| `swapName`           | string  | Human-readable DEX name (e.g., "CowSwap", "Uniswap")                                                                         |
| `quoteId`            | string  | Unique quote ID - pass this to `/dexExchange`                                                                                |
| `amountOut`          | number  | Expected output amount (human-readable)                                                                                      |
| `amountOutUsd`       | number  | USD value of output amount                                                                                                   |
| `netAmountOut`       | number  | Net output after fees                                                                                                        |
| `feeUsd`             | number  | Fee amount in USD                                                                                                            |
| `duration`           | number  | Estimated swap duration in minutes                                                                                           |
| `type`               | string  | Always `"dex"` for DEX swaps                                                                                                 |
| `logoUrl`            | string  | DEX logo image URL for UI display                                                                                            |
| `raw`                | object  | Full route data - **pass this as `route` to subsequent endpoints**                                                           |
| `supportsSignatures` | boolean | Whether this DEX supports gasless signatures                                                                                 |
| `markupSupported`    | boolean | Whether partner markup is supported                                                                                          |
| `rewardsAvailable`   | boolean | Whether rewards are available for this route                                                                                 |
| `filtered`           | boolean | If `true` and sender/receiver addresses differ on same-chain swaps, this route is not supported and should be disabled in UI |

<Warning>
  **Filtering Routes**: When `filtered: true`, the route does not support different sender and receiver addresses for same-chain swaps. You must either:

  * Filter out these routes from the UI when `addressFrom !== addressTo`
  * Disable the route option and show a message explaining it's not available for this configuration
</Warning>

### Step 3: Check Approvals and Signatures

Before executing a swap, check what's needed from the user:

<CodeGroup>
  ```javascript JavaScript theme={null}
  const approvalCheck = await fetch(`${API_BASE_URL}/dexApprove`, {
    method: 'POST',
    headers: {
      'Authorization': `${API_KEY}:${API_SECRET}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      tokenIdFrom: '6689b73ec90e45f3b3e51566',
      tokenIdTo: '6689b73ec90e45f3b3e51553',
      amount: 1,
      addressFrom: '0x45CF73349a4895fabA18c0f51f06D79f0794898D', // user's address
      swap: selectedQuote.swap, // From step 2
      route: selectedQuote.raw  // From step 2
    })
  });

  const { approvals, signatures } = await approvalCheck.json();
  ```

  ```bash cURL theme={null}
  curl -X POST "https://api-partner.houdiniswap.com/dexApprove" \
    -H "Authorization: your_api_key:your_api_secret" \
    -H "Content-Type: application/json" \
    -d '{
      "tokenIdFrom": "6689b73ec90e45f3b3e51566",
      "tokenIdTo": "6689b73ec90e45f3b3e51553",
      "amount": 1,
      "swap": "cs",
      "addressFrom": "0x45CF73349a4895fabA18c0f51f06D79f0794898D",
      "route": {...}
    }'
  ```
</CodeGroup>

**Response Contains:**

* `approvals`: Array of on-chain approval transactions (may be empty)
* `signatures`: Array of signatures needed (may be empty)

<Note>
  **Both Arrays Can Exist**: You may receive both approvals AND signatures. Handle approvals first, then signatures.
</Note>

#### Understanding Approvals

If the `approvals` array is not empty, the user must approve the DEX to spend their tokens. See more in Step 4.

#### Understanding Signatures

The `signatures` array can contain two types:

**1. SINGLE Type** - Simple one-time signature: **Action:** User signs once, add to results, done.

**2. CHAINED Type** - Multi-step signature (currently only for Cowswap): **Action:** User signs, call `/chainSignatures`, repeat until `isComplete: true`.

See more in Step 5.

### Step 4: Send Approval Transactions (if needed)

If the `approvals` array is not empty, broadcast approval transactions:

<CodeGroup>
  ```javascript JavaScript theme={null}
  // Send each approval transaction
  if (approvals && approvals.length > 0) {
    for (const approval of approvals) {
      // Send approval transaction through user's wallet
      const approvalTx = await walletProvider.sendTransaction({
        to: approval.to,      // Token contract address
        data: approval.data   // Encoded approve() call
      });

      // Wait for transaction to be mined
      await approvalTx.wait();
      console.log('Approval confirmed:', approvalTx.hash);
    }
  }
  ```

  ```bash Example theme={null}
  # User broadcasts approval transaction via wallet
  # Example: Approving USDC to be spent by Uniswap router
  to: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"  # USDC token
  data: "0x095ea7b3..."  # approve(spender, amount) encoded
  ```
</CodeGroup>

<Warning>
  **Skip This Step If**: No approvals were required (empty `approvals` array in Step 3).
</Warning>

### Step 5: Process Signatures (if needed)

Handle signature requests from Step 3:

<CodeGroup>
  ```javascript JavaScript theme={null}
  // Helper function to process all signatures
  async function processSignatures(signatures) {
    if (!signatures || signatures.length === 0) return [];

    const results = [];

    for (const sig of signatures) {
      // Prompt user to sign
      const signatureResult = await walletProvider.signTypedData({
        domain: sig.data.domain,
        types: sig.data.types,
        primaryType: sig.data.primaryType,
        message: sig.data.message
      });

      const signatureObject = {
        signature: signatureResult,
        key: sig.key,
        swapRequiredMetadata: sig.swapRequiredMetadata
      };

      // If CHAINED and not complete, get next signature
      if (sig.type === 'CHAINED' && !sig.isComplete) {
        const nextSigResponse = await fetch(`${API_BASE_URL}/chainSignatures`, {
          method: 'POST',
          headers: {
            'Authorization': `${API_KEY}:${API_SECRET}`,
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            tokenIdFrom,
            tokenIdTo,
            addressFrom: userWalletAddress,
            route: quote.route,
            swap: quote.swap,
            previousSignature: signatureObject,
            signatureKey: sig.key,
            signatureStep: sig.step
          })
        });

        const { chainSignatures } = await nextSigResponse.json();

        // Recursively process next signature
        if (chainSignatures?.length > 0) {
          const chainResults = await processSignatures(chainSignatures);
          if (chainResults.length > 0) {
            results.push(chainResults[chainResults.length - 1]); // Only add final
          }
        }
      } else {
        // SINGLE type or final CHAINED signature
        results.push(signatureObject);
      }
    }

    return results;
  }

  // Usage
  const collectedSignatures = await processSignatures(signatures);
  ```
</CodeGroup>

**Key Points:**

* **SINGLE**: User signs once, done
* **CHAINED**: User signs → API call → User signs again → Repeat until complete
* Only keep the **final** signature from CHAINED sequences

<Warning>
  **Skip This Step If**: No signatures were required (empty `signatures` array in Step 3).
</Warning>

### Step 6: Check Allowance (if approvals were sent)

If you sent approval transactions in Step 4, verify they are confirmed on-chain:

<CodeGroup>
  ```javascript JavaScript theme={null}
  // Poll until approval is confirmed on-chain
  if (approvals && approvals.length > 0) {
    let hasAllowance = false;
    while (!hasAllowance) {
      const allowanceCheck = await fetchFromHoudini('/dexHasEnoughAllowance', {
        tokenIdFrom: '6689b73ec90e45f3b3e51566',
        tokenIdTo: '6689b73ec90e45f3b3e51553',
        amount: 1,
        addressFrom: "0x45CF73349a4895fabA18c0f51f06D79f0794898D",
        swap: quote.swap,
        route: quote.raw
      });

      hasAllowance = allowanceCheck.hasEnoughAllowance;

      if (!hasAllowance) {
        await sleep(30000); // Wait 30 seconds before checking again
      }
    }
    console.log('Allowance confirmed!');
  }
  ```

  ```bash cURL theme={null}
  curl -X GET "https://api-partner.houdiniswap.com/dexHasEnoughAllowance?tokenIdFrom=6689b73ec90e45f3b3e51566&tokenIdTo=6689b73ec90e45f3b3e51553&amount=1&addressFrom=0x45CF73349a4895fabA18c0f51f06D79f0794898D&swap=cs&route=..." \
    -H "Authorization: your_api_key:your_api_secret"
  ```
</CodeGroup>

<Warning>
  **Skip This Step If**: No approvals were sent in Step 4.
</Warning>

### Step 7: Execute the Swap

Now execute the swap with any collected signatures:

<CodeGroup>
  ```javascript JavaScript theme={null}
  const swapResponse = await fetch(`${API_BASE_URL}/dexExchange`, {
    method: 'POST',
    headers: {
      'Authorization': `${API_KEY}:${API_SECRET}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      tokenIdFrom: '6689b73ec90e45f3b3e51566',
      tokenIdTo: '6689b73ec90e45f3b3e51553',
      amount: 26.2244,
      addressFrom: userWalletAddress,  // User's wallet address
      addressTo: destination address,    // Destination address to receive fund
      route: quote.raw,                // Route object from quote response
      swap: quote.swap,                // DEX identifier (e.g., "zx", "cs", "un")
      quoteId: quote.quoteId,          // Quote ID from quote response
      signatures: collectedSignatures, // From Step 5 (can be empty array)
      destinationTag: '',              // For chains that require memo/tag
      deviceInfo: 'web',               // Device type: 'web', 'ios', 'android'
      isMobile: false,                 // Boolean indicating mobile device
      walletInfo: 'MetaMask',          // Wallet name being used (e.g., "MetaMask", "Rabby Wallet")
      slippage: null                   // Custom slippage percentage (null = use default) 0.5 = 0.5%
    })
  });

  const { order } = await swapResponse.json();
  console.log('Swap created:', order.houdiniId);
  console.log('Off-chain?', order.metadata.offChain);
  ```

  ```bash cURL theme={null}
  curl -X POST "https://api-partner.houdiniswap.com/dexExchange" \
    -H "Authorization: your_api_key:your_api_secret" \
    -H "Content-Type: application/json" \
    -d '{
      "tokenIdFrom": "6689b73ec90e45f3b3e51566",
      "tokenIdTo": "6689b73ec90e45f3b3e51553",
      "amount": 26.2244,
      "addressFrom": "0xb7dE6b6eEBF7401aFea5a49D6405C9048fEf2d40",
      "addressTo": "0xb7dE6b6eEBF7401aFea5a49D6405C9048fEf2d40",
      "route": {...},
      "swap": "zx",
      "quoteId": "69155e0bdb5ab0cbe27e2709",
      "signatures": [],
      "destinationTag": "",
      "deviceInfo": "web",
      "isMobile": false,
      "walletInfo": "MetaMask",
      "slippage": null
    }'
  ```
</CodeGroup>

**Request Parameters:**

* `tokenIdFrom`: Source token ID
* `tokenIdTo`: Destination token ID
* `amount`: Amount to swap (float)
* `addressFrom`: User's wallet address (source)
* `addressTo`: Destination address for receiving tokens
* `route`: Complete route object from quote response (`quote.raw`)
* `swap`: DEX identifier from quote (e.g., "zx" for 0x, "cs" for Cowswap)
* `quoteId`: Quote ID from quote response
* `signatures`: Array of signature objects from Step 5 (empty if none required)
* `destinationTag`: Memo/tag for chains that require it (empty string if not needed)
* `deviceInfo`: Device type - "web", "ios", "android", or custom identifier
* `isMobile`: Boolean indicating if request is from mobile device
* `walletInfo`: Name of wallet being used (e.g., "MetaMask", "Rabby Wallet")
* `slippage`: Custom slippage tolerance (null to use default from quote)

**Response Contains:**

* `order.houdiniId`: Unique swap identifier for tracking
* `order.metadata.offChain`: Boolean indicating if user transaction is needed
* `order.metadata.to`: DEX router address (if offChain: false)
* `order.metadata.data`: Encoded swap call (if offChain: false)
* `order.metadata.value`: ETH value for native swaps (if offChain: false)

#### Broadcast Transaction and Confirm

After receiving the swap order, you need to:

1. Have the user broadcast the transaction (if `offChain: false`)
2. Call `/dexConfirmTx` to notify Houdini of the transaction hash

<Tabs>
  <Tab title="On-Chain Swap (offChain: false)">
    User must broadcast the transaction, then confirm with Houdini:

    ```javascript theme={null}
    if (!order.metadata.offChain) {
      // Step 1: User sends transaction via wallet
      const tx = await walletProvider.sendTransaction({
        to: order.metadata.to,
        data: order.metadata.data,
        value: order.metadata.value || '0'
      });

      const receipt = await tx.wait();
      const txHash = receipt.hash;

      console.log('Transaction broadcast:', txHash);

      // Step 2: Confirm with Houdini API
      await fetch(`${API_BASE_URL}/dexConfirmTx`, {
        method: 'POST',
        headers: {
          'Authorization': `${API_KEY}:${API_SECRET}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          houdiniId: order.houdiniId,
          txHash: txHash
        })
      });

      console.log('Transaction confirmed with Houdini');
    }
    ```
  </Tab>

  <Tab title="Off-Chain Swap (offChain: true)">
    Backend handles execution (e.g., Cowswap), but you still need to confirm:

    ```javascript theme={null}
    if (order.metadata.offChain) {
      // No user transaction needed - Houdini backend will execute the swap
      // But still need to call dexConfirmTx to start processing

      await fetch(`${API_BASE_URL}/dexConfirmTx`, {
        method: 'POST',
        headers: {
          'Authorization': `${API_KEY}:${API_SECRET}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          houdiniId: order.houdiniId,
          txHash: undefined  // No transaction hash for off-chain swaps
        })
      });

      console.log('Off-chain swap confirmed with Houdini');
    }
    ```
  </Tab>
</Tabs>

<Warning>
  **Critical Step**: You MUST call `/dexConfirmTx` after creating the swap order:

  * **On-chain swaps**: Pass the transaction hash after user broadcasts
  * **Off-chain swaps**: Pass `txHash: undefined` to start backend processing

  Without this call, the swap will not be processed and status tracking will not work.
</Warning>

### Step 8: Track Swap Status

Monitor the swap progress:

<CodeGroup>
  ```javascript JavaScript theme={null}
  const status = await fetchFromHoudini('/status', {
    id: order.houdiniId
  });

  console.log('Status:', status.status);
  console.log('Transaction hash:', status.txHash);
  ```

  ```bash cURL theme={null}
  curl -X GET "https://api-partner.houdiniswap.com/status?id=xyz123" \
    -H "Authorization: your_api_key:your_api_secret"
  ```
</CodeGroup>

**Status Codes:**

* `0` = WAITING - Awaiting transaction
* `1` = CONFIRMING - Transaction submitted, waiting for confirmations
* `2` = EXCHANGING - Processing swap
* `4` = COMPLETED - Swap complete ✅
* `6` = FAILED - Swap failed ❌

<Tip>
  **Polling**: Check status every 30 seconds for on-chain swaps. They typically complete in seconds to a few minutes depending on network congestion.
</Tip>

## Complete Example

For a complete, runnable Node.js example:

<Card title="DEX Swap Example" icon="github" href="https://github.com/HoudiniSwap/houdini-api-examples/blob/main/examples/dex-swap-example.ts">
  Complete DEX swap script with approval handling and wallet simulation
</Card>

## Next Steps

<CardGroup cols={2}>
  <Card title="Private Swaps" icon="lock" href="/developer-hub/swap-flows/private-swap">
    Learn about CEX-based private swaps
  </Card>

  <Card title="Standard Swaps" icon="gauge" href="/developer-hub/swap-flows/standard-swap">
    Integrate fast single-hop CEX swaps
  </Card>

  <Card title="Order Lifecycle" icon="rotate" href="/developer-hub/core-concepts/order-lifecycle">
    Understand swap status progression
  </Card>

  <Card title="Error Handling" icon="triangle-exclamation" href="/developer-hub/troubleshooting/errors">
    Handle errors and edge cases
  </Card>
</CardGroup>
