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

# Order Status Updates

> Real-time order status updates via WebSocket

# WebSocket: Order Status Updates

Get instant order status updates pushed to your application in real-time instead of polling the REST API.

## Connection

```
wss://partner-api.houdiniswap.com/v2/ws
```

### Authentication

Include your API credentials in the `Authorization` header during the WebSocket handshake:

```
Authorization: {partnerId}:{secret}
```

The server performs a quick format check on the header before upgrading the connection. If the header is missing or malformed, the connection is rejected at the HTTP level:

| HTTP Code | Reason                                        |
| --------- | --------------------------------------------- |
| 401       | Missing `Authorization` header                |
| 400       | Malformed header (must be `partnerId:secret`) |

Once the WebSocket connection is established, the server verifies your credentials asynchronously. On success you receive a `welcome` message. If credentials are invalid, you receive an `error` message with code `AUTH_FAILED` and the connection is closed with WebSocket close code `4401`.

## Quick Start

<CodeGroup>
  ```javascript Node.js theme={null}
  // Note: Custom headers require a Node.js WebSocket client (e.g. 'ws' npm package).
  // Browser-native WebSocket does not support custom headers.
  const WebSocket = require("ws");
  const ws = new WebSocket("wss://partner-api.houdiniswap.com/v2/ws", {
    headers: { Authorization: "your-partner-id:your-secret" },
  });

  ws.onopen = () => {
    // Subscribe to all your orders
    ws.send(JSON.stringify({ type: "subscribe" }));
  };

  ws.onmessage = (event) => {
    const message = JSON.parse(event.data);

    switch (message.type) {
      case "welcome":
        console.log("Connected as", message.partnerId);
        break;
      case "order_update":
        console.log("Order updated:", message.data.houdiniId, "→", message.data.status);
        break;
      case "subscribed":
        console.log("Subscribed to:", message.houdiniIds);
        break;
    }
  };
  ```

  ```python Python theme={null}
  import asyncio
  import json
  import websockets

  async def listen():
      headers = {"Authorization": "your-partner-id:your-secret"}
      async with websockets.connect(
          "wss://partner-api.houdiniswap.com/v2/ws",
          additional_headers=headers,
      ) as ws:
          # Subscribe to all orders
          await ws.send(json.dumps({"type": "subscribe"}))

          async for raw in ws:
              message = json.loads(raw)
              if message["type"] == "order_update":
                  data = message["data"]
                  print(f"Order {data['houdiniId']} → status {data['status']}")

  asyncio.run(listen())
  ```

  ```bash wscat theme={null}
  wscat -H "Authorization: your-partner-id:your-secret" \
    -c wss://partner-api.houdiniswap.com/v2/ws

  # Once connected, subscribe to all orders:
  > {"type":"subscribe"}
  ```
</CodeGroup>

## Message Protocol

All messages are JSON objects with a `type` field.

### Client → Server

#### subscribe

Subscribe to order status updates. Send without `houdiniIds` to receive updates for **all** your orders, or specify an array to watch specific orders.

```json Subscribe to all orders theme={null}
{ "type": "subscribe" }
```

```json Subscribe to specific orders theme={null}
{
  "type": "subscribe",
  "houdiniIds": ["abc123", "def456"]
}
```

<Note>
  Subscriptions are additive. Sending multiple `subscribe` messages with different `houdiniIds` adds to your watch list. Sending a `subscribe` without `houdiniIds` switches to all-orders mode.
</Note>

#### unsubscribe

Stop receiving updates. Send without `houdiniIds` to unsubscribe from everything, or specify an array to stop watching specific orders.

```json Unsubscribe from all theme={null}
{ "type": "unsubscribe" }
```

```json Unsubscribe from specific orders theme={null}
{
  "type": "unsubscribe",
  "houdiniIds": ["abc123"]
}
```

<Note>
  If you are subscribed to all orders and send an `unsubscribe` with specific `houdiniIds`, this resets your subscription to none. To continue receiving updates for other orders, re-subscribe after unsubscribing.
</Note>

#### ping

Application-level keepalive. The server responds with `pong`.

```json theme={null}
{ "type": "ping" }
```

<Tip>
  The server also sends WebSocket-level pings every 30 seconds. Most WebSocket libraries handle these automatically. The application-level `ping`/`pong` is optional — use it if you want to measure round-trip latency.
</Tip>

### Server → Client

#### welcome

Sent immediately after a successful connection.

```json theme={null}
{
  "type": "welcome",
  "partnerId": "your-partner-id"
}
```

#### order\_update

Pushed whenever an order's status changes. The `data` field contains the full order object — the same shape as `GET /v2/orders/{houdiniId}`.

```json theme={null}
{
  "type": "order_update",
  "data": {
    "houdiniId": "abc123",
    "status": 2,
    "inStatus": 3,
    "outStatus": null,
    "amount": "0.5",
    "amountTo": "150.25",
    "inToken": {
      "symbol": "ETH",
      "network": "ethereum"
    },
    "outToken": {
      "symbol": "USDC",
      "network": "ethereum"
    },
    "receiverAddress": "0x...",
    "created": "2026-01-15T10:30:00.000Z",
    "expires": "2026-01-15T11:00:00.000Z"
  }
}
```

#### subscribed

Confirmation after a `subscribe` message.

```json theme={null}
{
  "type": "subscribed",
  "houdiniIds": ["abc123", "def456"]
}
```

```json When subscribed to all orders theme={null}
{
  "type": "subscribed",
  "houdiniIds": "all"
}
```

#### unsubscribed

Confirmation after an `unsubscribe` message.

```json When unsubscribed from all theme={null}
{
  "type": "unsubscribed",
  "houdiniIds": "all"
}
```

```json When unsubscribed from specific orders theme={null}
{
  "type": "unsubscribed",
  "houdiniIds": ["abc123"]
}
```

#### error

Sent when the server cannot process a client message.

```json theme={null}
{
  "type": "error",
  "code": "INVALID_MESSAGE",
  "message": "Invalid JSON"
}
```

| Error Code             | Description                                                      |
| ---------------------- | ---------------------------------------------------------------- |
| `AUTH_FAILED`          | Invalid credentials — connection will be closed with code `4401` |
| `INVALID_MESSAGE`      | Message is not valid JSON or missing `type` field                |
| `UNKNOWN_MESSAGE_TYPE` | The `type` field is not recognized                               |

## Order Status Codes

The `status` field in `order_update` is a numeric code:

| Code | Label        | Description                            |
| ---- | ------------ | -------------------------------------- |
| -2   | INITIALIZING | Order is being initialized             |
| -1   | NEW          | Order initialized, awaiting processing |
| 0    | WAITING      | Waiting for user's deposit             |
| 1    | CONFIRMING   | Deposit is being confirmed on-chain    |
| 2    | EXCHANGING   | Swap is in progress                    |
| 3    | ANONYMIZING  | Going through privacy routing          |
| 4    | FINISHED     | Completed successfully                 |
| 5    | EXPIRED      | Expired (no deposit within 30 minutes) |
| 6    | FAILED       | Failed                                 |
| 7    | REFUNDED     | Refunded to sender                     |
| 8    | DELETED      | Deleted (order older than 48 hours)    |

**Terminal statuses** (no further updates): `FINISHED`, `EXPIRED`, `FAILED`, `REFUNDED`, `DELETED`.

## Reconnection

The server does not persist subscriptions across disconnects. If your connection drops:

1. Reconnect with credentials
2. Re-send your `subscribe` message
3. Optionally call `GET /v2/orders` to catch any updates you missed

**Recommended strategy**: exponential backoff starting at 1 second, capped at 30 seconds.

```javascript theme={null}
let reconnectDelay = 1000;

const connect = () => {
  const ws = new WebSocket(url, { headers });

  ws.onopen = () => {
    reconnectDelay = 1000; // Reset on successful connection
    ws.send(JSON.stringify({ type: "subscribe" }));
  };

  ws.onclose = () => {
    setTimeout(connect, reconnectDelay);
    reconnectDelay = Math.min(reconnectDelay * 2, 30000);
  };
};

connect();
```

## Security Notes

* Only orders belonging to your partner account are delivered. You cannot receive updates for other partners' orders.
* The `Authorization` header format is validated during the HTTP upgrade. Credentials are verified immediately after the WebSocket connection is established.
* Anonymous/private swap orders have their routing path censored from the response.
