Skip to main content

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 CodeReason
401Missing Authorization header
400Malformed 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

// 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;
  }
};

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.
Subscribe to all orders
{ "type": "subscribe" }
Subscribe to specific orders
{
  "type": "subscribe",
  "houdiniIds": ["abc123", "def456"]
}
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.

unsubscribe

Stop receiving updates. Send without houdiniIds to unsubscribe from everything, or specify an array to stop watching specific orders.
Unsubscribe from all
{ "type": "unsubscribe" }
Unsubscribe from specific orders
{
  "type": "unsubscribe",
  "houdiniIds": ["abc123"]
}
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.

ping

Application-level keepalive. The server responds with pong.
{ "type": "ping" }
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.

Server → Client

welcome

Sent immediately after a successful connection.
{
  "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}.
{
  "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.
{
  "type": "subscribed",
  "houdiniIds": ["abc123", "def456"]
}
When subscribed to all orders
{
  "type": "subscribed",
  "houdiniIds": "all"
}

unsubscribed

Confirmation after an unsubscribe message.
When unsubscribed from all
{
  "type": "unsubscribed",
  "houdiniIds": "all"
}
When unsubscribed from specific orders
{
  "type": "unsubscribed",
  "houdiniIds": ["abc123"]
}

error

Sent when the server cannot process a client message.
{
  "type": "error",
  "code": "INVALID_MESSAGE",
  "message": "Invalid JSON"
}
Error CodeDescription
AUTH_FAILEDInvalid credentials — connection will be closed with code 4401
INVALID_MESSAGEMessage is not valid JSON or missing type field
UNKNOWN_MESSAGE_TYPEThe type field is not recognized

Order Status Codes

The status field in order_update is a numeric code:
CodeLabelDescription
-2INITIALIZINGOrder is being initialized
-1NEWOrder initialized, awaiting processing
0WAITINGWaiting for user’s deposit
1CONFIRMINGDeposit is being confirmed on-chain
2EXCHANGINGSwap is in progress
3ANONYMIZINGGoing through privacy routing
4FINISHEDCompleted successfully
5EXPIREDExpired (no deposit within 30 minutes)
6FAILEDFailed
7REFUNDEDRefunded to sender
8DELETEDDeleted (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.
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.