# Hyperlight API — Quick Start Guide

> Complete onboarding guide for the Hyperlight enhanced trading API.
> Last updated: 2026-03-14

**API Base URL:** `https://api.hyperlightapi.xyz`
**WebSocket URL:** `wss://api.hyperlightapi.xyz/ws`
**OpenAPI Spec:** https://hyperlightapi.xyz/openapi.yaml

---

## Getting Your API Key

Create an account and get your API key in under a minute. Every key is prefixed with hlt_ and shown exactly once — save it somewhere safe.

### Register via API

Send a single POST request to create your account. The response includes a JWT token for dashboard access and your first API key.

> **Tip:** Your API key is shown exactly once in the response. Copy it immediately — the server only stores a SHA-256 hash.

> **Tip:** The free tier includes 75K credits/month and 30 requests/minute.

**curl:**
```bash
curl -X POST https://api.hyperlightapi.xyz/api/v1/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "email": "you@example.com",
    "password": "your-secure-password",
    "tos_accepted": true
  }'
```

**Python:**
```python
import requests

resp = requests.post("https://api.hyperlightapi.xyz/api/v1/auth/register", json={
    "email": "you@example.com",
    "password": "your-secure-password",
    "tos_accepted": True,
})
data = resp.json()["data"]
api_key = data["api_key"]   # hlt_... — save this!
jwt     = data["token"]     # for dashboard endpoints
print(f"API Key: {api_key}")
```

**JavaScript:**
```javascript
const resp = await fetch("https://api.hyperlightapi.xyz/api/v1/auth/register", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    email: "you@example.com",
    password: "your-secure-password",
    tos_accepted: true,
  }),
});
const { data } = await resp.json();
const apiKey = data.api_key;  // hlt_... — save this!
const jwt = data.token;       // for dashboard endpoints
console.log("API Key:", apiKey);
```

### Register via Website

Prefer a UI? Visit hyperlightapi.xyz/auth/signup to create your account with email or GitHub OAuth. Your API key appears on the dashboard after signup.

### Understanding Your API Key

All Hyperlight API keys start with the prefix hlt_ followed by 48 hex characters. Example: hlt_7kT9BxQ4mN2pR8vL1wX5yZ3aD6fG9hJ0kS.

The server never stores your full key — only its SHA-256 hash. If you lose your key, you cannot recover it. Create a new one from your dashboard or via the API.

---

## Authentication

Pass your API key via header, bearer token, or query parameter. WebSocket connections authenticate with the first message.

### X-Api-Key Header (Recommended)

The simplest and most secure method for REST calls.

**curl:**
```bash
curl https://api.hyperlightapi.xyz/api/v1/orderbook/0 \
  -H "X-Api-Key: hlt_your_key_here"
```

**Python:**
```python
import requests

resp = requests.get("https://api.hyperlightapi.xyz/api/v1/orderbook/0",
    headers={"X-Api-Key": "hlt_your_key_here"})
print(resp.json())
```

**JavaScript:**
```javascript
const resp = await fetch("https://api.hyperlightapi.xyz/api/v1/orderbook/0", {
  headers: { "X-Api-Key": "hlt_your_key_here" },
});
const data = await resp.json();
console.log(data);
```

### Authorization Bearer

Works with both API keys and JWT tokens. Useful when your HTTP client already sets an Authorization header.

**curl:**
```bash
# With API key
curl https://api.hyperlightapi.xyz/api/v1/orderbook/0 \
  -H "Authorization: Bearer hlt_your_key_here"

# With JWT (from login/register)
curl https://api.hyperlightapi.xyz/api/v1/keys \
  -H "Authorization: Bearer eyJhbG..."
```

### Query Parameter

Pass your key as a query parameter. Convenient for quick testing but avoid in production — URLs can appear in logs and browser history.

**curl:**
```bash
curl "https://api.hyperlightapi.xyz/api/v1/orderbook/0?api_key=hlt_your_key_here"
```

### WebSocket Authentication

The first message on any WebSocket connection must be an auth message. You have 10 seconds to authenticate before the server closes the connection.

**Message:**
```json
// Client sends:
{"type": "auth", "api_key": "hlt_your_key_here"}

// Server responds:
{"type": "authenticated", "tier": "free", "max_subscriptions": 5}
```

---

## Your First API Call

Start with a health check, then fetch live data. Every response follows the same envelope format.

### Health Check (No Auth Required)

Verify the API is reachable. No authentication needed.

**curl:**
```bash
curl https://api.hyperlightapi.xyz/health
```

**Response:**
```json
{
  "status": "ok",
  "version": "0.1.0",
  "uptime_seconds": 86400,
  "checks": {
    "postgres": "ok",
    "redis": "ok",
    "lighter_api": "ok"
  }
}
```

### Get an Orderbook

Fetch the current orderbook for market 0 (ETH-PERP). Data is served from Redis cache with sub-second freshness.

**curl:**
```bash
curl https://api.hyperlightapi.xyz/api/v1/orderbook/0 \
  -H "X-Api-Key: hlt_your_key_here"
```

**Python:**
```python
import requests

resp = requests.get("https://api.hyperlightapi.xyz/api/v1/orderbook/0",
    headers={"X-Api-Key": "hlt_your_key_here"})

book = resp.json()["data"]
print(f"Best bid: {book['best_bid']}")
print(f"Best ask: {book['best_ask']}")
print(f"Spread:   {book['spread']}")
```

**JavaScript:**
```javascript
const resp = await fetch("https://api.hyperlightapi.xyz/api/v1/orderbook/0", {
  headers: { "X-Api-Key": "hlt_your_key_here" },
});
const { data } = await resp.json();
console.log(`Best bid: ${data.best_bid}`);
console.log(`Best ask: ${data.best_ask}`);
console.log(`Spread:   ${data.spread}`);
```

### Batch Query Accounts

Query multiple accounts in a single request — the signature Hyperlight feature. Lighter's native API only supports one account per request.

**curl:**
```bash
curl -X POST https://api.hyperlightapi.xyz/api/v1/accounts/batch \
  -H "X-Api-Key: hlt_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"accounts": [0, 1, 2, 3, 4], "by": "index"}'
```

**Python:**
```python
resp = requests.post("https://api.hyperlightapi.xyz/api/v1/accounts/batch",
    headers={"X-Api-Key": "hlt_your_key_here"},
    json={"accounts": [0, 1, 2, 3, 4], "by": "index"})

data = resp.json()["data"]
for acct in data["accounts"]:
    print(f"Account {acct['account_index']}: "
          f"collateral={acct['collateral']}")
```

### Understanding the Response Envelope

Every response follows the same structure. Check success first, then read data. The meta object includes a unique request_id for tracing.

**Success:**
```json
{
  "success": true,
  "data": { ... },
  "meta": {
    "request_id": "550e8400-e29b-41d4-a716-446655440000",
    "timestamp": 1706745600000,
    "total": 100,
    "limit": 50,
    "offset": 0
  }
}
```

**Error:**
```json
{
  "success": false,
  "data": {
    "code": "unauthorized",
    "message": "missing or invalid API key"
  },
  "meta": {
    "request_id": "...",
    "timestamp": 1706745600000
  }
}
```

---

## REST Endpoints by Category

43 REST endpoints organized by function. All authenticated endpoints require an API key unless noted.

### Accounts & Batch Queries

Batch endpoints accept up to your tier's batch size limit (5 for Free, up to 5,000 for Enterprise).

| Method | Path | Description |
| --- | --- | --- |
| POST | /api/v1/accounts/batch | Batch query accounts (positions, orders, fills) |
| POST | /api/v1/accounts/batch/fills | Batch fills across accounts |
| POST | /api/v1/accounts/batch/positions | Batch positions across accounts |
| POST | /api/v1/accounts/batch/liquidations | Batch liquidation events |
| GET | /api/v1/accounts/:id/positions | Single account positions |
| GET | /api/v1/accounts/:id/fills | Single account fill history |
| GET | /api/v1/accounts/:id/pnl | PnL snapshot history |
| GET | /api/v1/accounts/:id/liquidation-risk | Liquidation risk estimate |

### Orderbook

| Method | Path | Description |
| --- | --- | --- |
| GET | /api/v1/orderbook/:market_id | Current orderbook (Redis-cached, sub-second) |
| GET | /api/v1/orderbook/:market_id/depth | Aggregated depth at custom price levels |
| GET | /api/v1/orderbook/:market_id/snapshots | Historical orderbook at any point in time |

### Trades & Candles

| Method | Path | Description |
| --- | --- | --- |
| GET | /api/v1/trades/by-time | Trades within arbitrary time ranges |
| GET | /api/v1/trades/aggregate | VWAP + volume aggregation at custom intervals |
| GET | /api/v1/candles | OHLCV candles (1m to 1w resolution) |

### Liquidations

| Method | Path | Description |
| --- | --- | --- |
| GET | /api/v1/liquidations/by-time | Liquidation events in a time range |
| GET | /api/v1/liquidations/recent | Recent liquidations across all markets |
| GET | /api/v1/liquidation-heatmap/:market_id | Liquidation level heatmap |
| GET | /api/v1/liquidation-heatmap/:market_id/cascade | Cascade effect analysis |

### Funding Rates

| Method | Path | Description |
| --- | --- | --- |
| GET | /api/v1/funding-rates | Current funding rates for all markets |
| GET | /api/v1/funding-rates/history | Historical funding rate data |

### Exchange Analytics

| Method | Path | Description |
| --- | --- | --- |
| GET | /api/v1/exchange/stats | 24h volume, open interest, price changes |
| GET | /api/v1/exchange/metrics | Historical exchange-level metrics |
| GET | /api/v1/markets/:market_id/top-accounts | Top accounts by position size (tier-limited) |
| GET | /api/v1/exchange/top-accounts | Top accounts exchange-wide by total notional (tier-limited) |

### Data Lake

Parquet exports for backtesting and analytics. Available on paid tiers.

| Method | Path | Description |
| --- | --- | --- |
| GET | /api/v1/data-lake/exports | List available Parquet exports |
| GET | /api/v1/data-lake/download/:export_id | Pre-signed S3 download URL |

### Signal Engine (Custom Alerts)

Create rules that trigger webhooks based on market conditions. See the Signal Engine section below for full details.

| Method | Path | Description |
| --- | --- | --- |
| POST | /api/v1/signals | Create alert rule (JSON DSL) |
| GET | /api/v1/signals | List your alerts |
| GET | /api/v1/signals/:signal_id | Get alert details |
| PATCH | /api/v1/signals/:signal_id | Update alert rule |
| DELETE | /api/v1/signals/:signal_id | Delete alert |
| GET | /api/v1/signals/:signal_id/backtest | Backtest against historical data |

### API Key Management

| Method | Path | Description |
| --- | --- | --- |
| POST | /api/v1/keys | Create new API key |
| GET | /api/v1/keys | List your keys (prefix only) |
| PATCH | /api/v1/keys/:key_id | Update key (name, IP allowlist) |
| DELETE | /api/v1/keys/:key_id | Revoke key |
| GET | /api/v1/keys/:key_id/usage | Hourly usage breakdown |

### Auth, Billing & Health

| Method | Path | Auth | Description |
| --- | --- | --- | --- |
| GET | /health | No | Service health check |
| GET | /status | No | Lighter network status |
| POST | /api/v1/auth/register | No | Register and get API key + JWT |
| POST | /api/v1/auth/login | No | Login and get JWT token |
| POST | /api/v1/billing/checkout | JWT | Create Stripe checkout session |
| POST | /api/v1/billing/portal | JWT | Create Stripe customer portal |

---

## WebSocket Streaming

Connect to the WebSocket endpoint for real-time orderbook updates, enriched trades, whale alerts, and liquidation heatmaps.

### Connecting & Authenticating

Connect to the WebSocket endpoint and send an auth message as your first message. The server responds with your tier and subscription limit.

**wscat:**
```bash
# Install: npm install -g wscat
wscat -c wss://api.hyperlightapi.xyz/ws

# Once connected, send:
{"type": "auth", "api_key": "hlt_your_key_here"}
```

**Python:**
```python
import asyncio
import websockets
import json

async def stream():
    async with websockets.connect("wss://api.hyperlightapi.xyz/ws") as ws:
        # Authenticate
        await ws.send(json.dumps({
            "type": "auth",
            "api_key": "hlt_your_key_here"
        }))
        auth_resp = json.loads(await ws.recv())
        print(f"Authenticated: tier={auth_resp['tier']}")

        # Subscribe to ETH-PERP orderbook
        await ws.send(json.dumps({
            "type": "subscribe",
            "channel": "order_book/0"
        }))

        # Listen for updates
        async for msg in ws:
            data = json.loads(msg)
            if data.get("type") == "data":
                print(f"[{data['channel']}]", data["data"])

asyncio.run(stream())
```

**JavaScript:**
```javascript
const ws = new WebSocket("wss://api.hyperlightapi.xyz/ws");

ws.onopen = () => {
  ws.send(JSON.stringify({
    type: "auth",
    api_key: "hlt_your_key_here",
  }));
};

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

  if (msg.type === "authenticated") {
    console.log("Tier:", msg.tier);
    // Subscribe to ETH-PERP orderbook
    ws.send(JSON.stringify({
      type: "subscribe",
      channel: "order_book/0",
    }));
  } else if (msg.type === "data") {
    console.log(`[${msg.channel}]`, msg.data);
  }
};
```

### Available Channels

Subscribe and unsubscribe to channels by sending JSON messages. Replace {market_id} with the numeric market ID (0 = ETH-PERP).

| Channel | Description |
| --- | --- |
| order_book/{market_id} | Live orderbook updates (direct upstream proxy) |
| enriched_order_book/{market_id} | Orderbook with account attribution and whale flags |
| enriched_trade/{market_id} | Trades with account attribution |
| trade/{market_id} | Raw trade updates |
| alert/{market_id} | Large order and whale activity alerts |
| liquidation_heatmap/{market_id} | Liquidation level heatmap updates |

**Subscribe/Unsubscribe:**
```json
// Subscribe
{"type": "subscribe", "channel": "trade/0"}
// → {"type": "subscribed", "channel": "trade/0"}

// Unsubscribe
{"type": "unsubscribe", "channel": "trade/0"}
// → {"type": "unsubscribed", "channel": "trade/0"}
```

### Data Message Format

Channel data arrives in a standard envelope with the channel name and a server timestamp.

**Trade update:**
```json
{
  "type": "trade_update",
  "channel": "trade/0",
  "trade": {
    "trade_id": 12345,
    "price": "3200.50",
    "size": "2.5",
    "is_maker_ask": true,
    "ask_account_id": 42,
    "bid_account_id": 99,
    "market_id": 0,
    "timestamp": 1706700000123
  }
}
```

**Orderbook update:**
```json
{
  "type": "order_book_update",
  "channel": "order_book/0",
  "order_book": {
    "code": 0,
    "asks": [{"price": "3200.00", "size": "18.2"}],
    "bids": [{"price": "3199.50", "size": "25.5"}],
    "nonce": 999999
  }
}
```

### Connection Limits

WebSocket connections are rate-limited to 30 messages/second (burst of 60). After 3 consecutive violations, the connection is closed. The server sends a ping every 30 seconds — your client must respond with a pong within 10 seconds.

---

## Backtesting Replay

Replay historical orderbook snapshots and trades via WebSocket at 0.1x–100x speed. Point your trading bot at the replay endpoint and test strategies against real market data.

### Starting a Replay

Connect to the /ws/replay endpoint, authenticate, then send a replay command with your desired market, time range, and playback speed.

**Python:**
```python
import asyncio, websockets, json

async def replay():
    async with websockets.connect("wss://api.hyperlightapi.xyz/ws/replay") as ws:
        # Authenticate
        await ws.send(json.dumps({
            "type": "auth",
            "api_key": "hlt_your_key_here"
        }))
        print(json.loads(await ws.recv()))  # authenticated

        # Start replay: ETH-PERP, 1 hour, 10x speed
        await ws.send(json.dumps({
            "type": "replay",
            "market_id": 0,
            "start": "2026-01-01T00:00:00Z",
            "end": "2026-01-01T01:00:00Z",
            "speed": 10.0
        }))

        async for msg in ws:
            event = json.loads(msg)
            if event["type"] == "replay_event":
                print(f"[{event['event_type']}] {event['data']}")
            elif event["type"] == "replay_complete":
                print(f"Done! {event['events_sent']} events")
                break

asyncio.run(replay())
```

### Playback Controls

Pause, resume, or stop a replay at any time. Only one replay can be active per connection — send stop before starting another.

**Commands:**
```json
{"type": "pause"}    // → {"type": "replay_paused"}
{"type": "resume"}   // → {"type": "replay_resumed"}
{"type": "stop"}     // → {"type": "replay_stopped"}
```

### Replay Event Types

Events arrive in chronological order, interleaving trades and orderbook snapshots. Each event has the original timestamp (ts) and the wall-clock replay timestamp (replay_ts).

**Trade event:**
```json
{
  "type": "replay_event",
  "event_type": "trade",
  "data": {
    "market_id": 0,
    "trade_id": 12345,
    "price": "3200.50",
    "size": "2.5",
    "side": "buy"
  },
  "ts": 1717200330000,
  "replay_ts": 1706700050000
}
```

**Orderbook snapshot:**
```json
{
  "type": "replay_event",
  "event_type": "orderbook_snapshot",
  "data": {
    "market_id": 0,
    "bids": [["3199.50", "25.5"]],
    "asks": [["3200.00", "18.2"]],
    "best_bid": "3199.50",
    "best_ask": "3200.00",
    "spread": "0.50"
  },
  "ts": 1717200330000,
  "replay_ts": 1706700050000
}
```

### Replay Tier Limits

The maximum replay window and number of concurrent replays depend on your tier.

| Tier | Max Replay Window | Concurrent Replays |
| --- | --- | --- |
| Free | Disabled | 0 |
| Starter | 7 days | 2 |
| Growth | 30 days | 5 |
| Scale | 90 days | 10 |
| Enterprise | Unlimited | Unlimited |

---

## Signal Engine (Custom Alerts)

Define alert rules using a JSON DSL. When market conditions match, Hyperlight sends a webhook to your endpoint with HMAC-SHA256 signing.

### Creating a Signal

Define a rule, a delivery channel (webhook URL + secret), and optional cooldown. The rule evaluates in real-time against live market data.

**curl:**
```bash
curl -X POST https://api.hyperlightapi.xyz/api/v1/signals \
  -H "Authorization: Bearer <your_jwt_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "ETH price alert",
    "market_id": 0,
    "rule_definition": {
      "conditions": [
        {"field": "trade_price", "op": "gt", "value": 4000}
      ],
      "logic": "AND"
    },
    "delivery_channels": [
      {
        "type": "webhook",
        "url": "https://your-app.com/webhook",
        "secret": "your-hmac-secret-min-16-chars"
      }
    ],
    "cooldown_secs": 300
  }'
```

### Rule DSL Reference

Rules are JSON objects with conditions (each having a field, op, and value), combined with AND/OR logic. Available fields: trade_price, trade_size, trade_notional, orderbook_spread, bid_depth, ask_depth, funding_rate, heatmap_long_at_risk, heatmap_short_at_risk.

| Operator | Description | Example |
| --- | --- | --- |
| gt | Field > value | {"field": "trade_price", "op": "gt", "value": 4000} |
| lt | Field < value | {"field": "trade_price", "op": "lt", "value": 3000} |
| gte | Field >= value | {"field": "trade_size", "op": "gte", "value": 100} |
| lte | Field <= value | {"field": "orderbook_spread", "op": "lte", "value": 0.01} |
| eq | Field == value | {"field": "funding_rate", "op": "eq", "value": 0} |
| ne | Field != value | {"field": "funding_rate", "op": "ne", "value": 0} |
| crosses_above | Field crosses above value | {"field": "trade_price", "op": "crosses_above", "value": 4000} |
| crosses_below | Field crosses below value | {"field": "trade_price", "op": "crosses_below", "value": 3000} |

**Compound rule:**
```json
{
  "conditions": [
    {"field": "trade_price", "op": "gt", "value": 4000},
    {"field": "trade_size", "op": "gt", "value": 50}
  ],
  "logic": "AND"
}
```

### Backtesting a Signal

Test your rule against historical data before activating it. The backtest endpoint returns how many times the rule would have triggered.

**curl:**
```bash
curl "https://api.hyperlightapi.xyz/api/v1/signals/{signal_id}/backtest?start=1767225600000&end=1767312000000" \
  -H "Authorization: Bearer <your_jwt_token>"
```

---

## Rate Limiting & Tiers

Rate limits are enforced per API key. Every response includes rate limit headers so you can track your usage.

### Rate Limit Headers

Every response includes these headers:

| Header | Description |
| --- | --- |
| X-RateLimit-Limit | Your tier's max requests per minute |
| X-RateLimit-Remaining | Requests remaining in current window |
| X-RateLimit-Reset | UNIX timestamp when the window resets |
| Retry-After | Seconds to wait (only on 429 responses) |

### Tier Comparison

| Tier | Price | Rate Limit | Batch Size | Credits/Month | WS Connections |
| --- | --- | --- | --- | --- | --- |
| Free | Free | 30/min | 5 | 75K | 1 |
| Starter | $199 | 300/min | 200 | 750K | 50 |
| Growth | $849 | 3,000/min | 1,000 | 5M | 500 |
| Scale | $1,799 | 30,000/min | 2,500 | 25M | 1,000 |
| Enterprise | Custom | Unlimited | 5,000 | Unlimited | Unlimited |

### Handling 429 Responses

When you exceed your rate limit, the API returns HTTP 429. Use the Retry-After header to know how long to wait.

**Python:**
```python
import time, requests

def api_call(url, headers):
    resp = requests.get(url, headers=headers)
    if resp.status_code == 429:
        wait = int(resp.headers.get("Retry-After", 60))
        print(f"Rate limited. Waiting {wait}s...")
        time.sleep(wait)
        return api_call(url, headers)  # retry
    return resp.json()
```

---

## Verification Checklist

Run through these steps to confirm your integration is working correctly.

### Step-by-Step Verification

Run each command and verify you get the expected response. Replace hlt_your_key_here with your actual API key.

**Full checklist:**
```bash
# 1. Health check (no auth)
curl -s https://api.hyperlightapi.xyz/health | jq .status
# Expected: "ok"

# 2. Orderbook (auth required)
curl -s https://api.hyperlightapi.xyz/api/v1/orderbook/0 \
  -H "X-Api-Key: hlt_your_key_here" | jq .success
# Expected: true

# 3. Trades in time range
curl -s "https://api.hyperlightapi.xyz/api/v1/trades/by-time?market_id=0&start=2026-01-01T00:00:00Z&end=2026-01-02T00:00:00Z&limit=5" \
  -H "X-Api-Key: hlt_your_key_here" | jq '.data.trades | length'
# Expected: > 0

# 4. Batch query 5 accounts
curl -s -X POST https://api.hyperlightapi.xyz/api/v1/accounts/batch \
  -H "X-Api-Key: hlt_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"accounts": [0,1,2,3,4], "by": "index"}' | jq '.data.accounts | length'
# Expected: up to 5

# 5. Current funding rates
curl -s https://api.hyperlightapi.xyz/api/v1/funding-rates \
  -H "X-Api-Key: hlt_your_key_here" | jq '.data.rates | length'
# Expected: > 0

# 6. Exchange stats
curl -s https://api.hyperlightapi.xyz/api/v1/exchange/stats \
  -H "X-Api-Key: hlt_your_key_here" | jq .success
# Expected: true

# 7. Check rate limit headers
curl -sI https://api.hyperlightapi.xyz/api/v1/orderbook/0 \
  -H "X-Api-Key: hlt_your_key_here" | grep -i x-ratelimit
# Expected: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset

# 8. WebSocket (requires wscat: npm i -g wscat)
# wscat -c wss://api.hyperlightapi.xyz/ws
# > {"type":"auth","api_key":"hlt_your_key_here"}
# < {"type":"authenticated",...}
# > {"type":"subscribe","channel":"order_book/0"}
# < {"type":"subscribed","channel":"order_book/0"}
```

---

## Error Handling

All errors follow the standard response envelope with a code and human-readable message.

### Error Codes

| Code | HTTP Status | Description |
| --- | --- | --- |
| unauthorized | 401 | Missing or invalid API key |
| forbidden | 403 | Key expired, disabled, or IP not allowed |
| bad_request | 400 | Invalid query parameters |
| not_found | 404 | Resource not found |
| rate_limit_exceeded | 429 | Tier rate limit exceeded |
| batch_too_large | 400 | Batch size exceeds tier limit |
| internal_error | 500 | Server error |
| upstream_error | 502 | Lighter API unavailable |

### Error Response Example

**429 Response:**
```json
{
  "success": false,
  "data": {
    "code": "rate_limit_exceeded",
    "message": "rate limit exceeded"
  },
  "meta": {
    "request_id": "550e8400-e29b-41d4-a716-446655440000",
    "timestamp": 1706745600000
  }
}
```

---

## Production Best Practices

Tips for building reliable integrations.

### Recommendations

Use batch endpoints instead of looping: A single POST /api/v1/accounts/batch replaces hundreds of individual requests and costs only 25 credits regardless of batch size.

Monitor rate limit headers: Track X-RateLimit-Remaining and back off before you hit 429. This is more efficient than retrying after the fact.

Implement WebSocket reconnection: Connections can drop due to network issues or server restarts. Use exponential backoff (1s, 2s, 4s, 8s, max 30s) when reconnecting.

Rotate API keys periodically: Create a new key, update your services, then delete the old one. Hyperlight supports multiple active keys per account.

Use IP allowlists: Lock your production keys to specific IP addresses via PATCH /api/v1/keys/:key_id with an allowed_ips array.

Cache responses where appropriate: Orderbook and funding rate data is cached server-side with sub-second freshness. For lower-frequency use cases, cache locally to avoid unnecessary requests.

Use the health endpoint for monitoring: Add GET /health to your uptime monitoring. It checks all dependencies (PostgreSQL, Redis, Lighter API).

---

## Next Steps

- Browse the full [OpenAPI Spec](https://hyperlightapi.xyz/openapi.yaml)
- See [all endpoints](https://hyperlightapi.xyz/llm/endpoints.json)
- Check [pricing details](https://hyperlightapi.xyz/llm/pricing.json)
- Read about [all features](https://hyperlightapi.xyz/llm/features.md)