Sequence/docs

Rate Limits

Sequence enforces per-client API rate limiting with a token-bucket model.


REST API Limit Model

  • Limits are applied per authenticated client.
  • The configured limit comes from your account profile (rate_limit_qps).
  • If no profile-specific value is set, default behavior is low-QPS safe mode.
  • Exceeding limit returns 429 Too Many Requests with:
json
{
  "error": "Rate limit exceeded"
}
Note

Docs examples should not hardcode one global QPS number. Your effective limit depends on your account profile and environment configuration.


SSE Streams

SSE endpoints are long-lived authenticated HTTP connections:

  • GET /v1/parent_orders/stream
  • GET /v1/fills/stream
  • GET /v1/tca/stream
  • GET /v1/algo_orders/stream

Practical guidance:

  • Run one consumer per stream type per application instance.
  • Reconnect with backoff on disconnect.
  • Filter server-side where supported (parent_id, edge_id) to reduce client load.

WebSocket Market Data

GET /v1/ws/market_data provides real-time market updates.

Recommended auth flow:

  1. GET /v1/ws/ticket with bearer auth
  2. Connect with ?ticket=<short-lived-ticket>

This avoids putting long-lived API keys in URLs.


Headers and Retry Behavior

Current API behavior to rely on:

  • 429 indicates throttling.
  • Error body includes a structured envelope with error.code = "RATE_LIMITED" and a request_id for correlation.
json
{
  "error": {
    "code": "RATE_LIMITED",
    "message": "rate limit exceeded",
    "request_id": "550e8400-..."
  }
}

Do not assume standardized rate-limit headers (such as X-RateLimit-*) are always present.


Client Best Practices

  1. Prefer streaming (SSE/WebSocket) over polling hot endpoints.
  2. Use exponential backoff on 429, 503, and disconnects.
  3. Batch reads where possible (/v1/nbbo, paginated /v1/parent_orders).
  4. Use separate API keys per service to isolate load.

Minimal retry template:

javascript
async function withBackoff(requestFn, retries = 4) {
  for (let i = 0; i <= retries; i++) {
    const res = await requestFn();
    if (![429, 503].includes(res.status)) return res;
    const delayMs = Math.min(1000 * 2 ** i, 8000);
    await new Promise((r) => setTimeout(r, delayMs));
  }
  throw new Error('request failed after retries');
}