---
title: "Lighter API: REST, WebSocket, Python SDK and Rate Limits"
description: "Lighter API base URLs, REST endpoints, WebSocket channels, the Python SDK, API keys and rate limits, tested live in November 2026."
canonical_url: "https://0xarchive.io/resources/market-data-guides/lighter-api"
markdown_url: "https://0xarchive.io/resources/market-data-guides/lighter-api.md"
route: "/resources/market-data-guides/lighter-api"
robots: "index, follow, max-image-preview:large"
generated_from: "prerendered_html"
---

# Lighter API Guide: Endpoints, WebSocket and Rate Limits

Lighter's base URLs, REST endpoints, WebSocket channels, API keys and rate limits, each tested live, plus what its history covers.

By

[0xArchive Team](https://0xarchive.io/authors/0xarchive-team)

November 9, 2026

14 min read

- [Lighter](https://0xarchive.io/resources?topic=lighter)
- [Funding](https://0xarchive.io/resources?topic=funding)
- [API and alerts](https://0xarchive.io/resources?topic=api-and-alerts)

## Key findings

1. [Step 4: funding units](https://0xarchive.io/resources/market-data-guides/lighter-api#article-section-step-4-funding-units) 0.0012 One BTC funding rate, in percent per hour. As a decimal it is 0.000012.
2. [Step 6: rate limits](https://0xarchive.io/resources/market-data-guides/lighter-api#article-section-step-6-rate-limits) 60/min A standard account's REST limit. A 120-request burst hit HTTP 429 on request 58.
3. [Step 7: pull history from Lighter's API](https://0xarchive.io/resources/market-data-guides/lighter-api#article-section-step-7-pull-history-from-lighters-api) 17 Jan 2025 Lighter's own API paged hourly BTC funding back to mainnet launch in 23 requests.
4. [History: what Lighter's API covers and where it stops](https://0xarchive.io/resources/market-data-guides/lighter-api#article-section-history-what-lighters-api-covers-and-where-it-stops) Free Every Lighter trade since launch, as daily Parquet files in a public AWS bucket.

Lighter, an onchain crypto exchange, gives builders a free public API. Below are the parts you need to ship: base URLs, the REST endpoints worth knowing, WebSocket channels, API keys, rate limits and funding units. Every call below ran on 8 November 2026, and every output is what came back. The last section shows where Lighter's own API runs out of history, and what the same jobs return from 0xArchive.

## Short answer

- **What it is:** free public REST and WebSocket APIs for markets, order books, trades, funding and candles, plus signed endpoints for accounts and trading. Official SDKs: Python ( `pip install lighter-sdk` ), Go and TypeScript.
- **REST:** `https://mainnet.zklighter.elliot.ai` . **WebSocket:** `wss://mainnet.zklighter.elliot.ai/stream` . Market data needs no key.
- **Rate limit:** 60 requests per rolling minute for a standard client, with heavier endpoints weighted. Our burst test got its first `429` on request 58.
- **History it publishes:** funding and candles over REST, and every trade since 17 January 2025 as free daily files. We paged BTC hourly funding back to that day in 23 requests.
- **History it does not publish:** past order books. 0xArchive serves those, and trades by market, account and time window in one request.

## Why build on Lighter's API

Lighter runs a public order book where every resting order carries the account that placed it. Markets, books, trades, funding and open interest are open to anyone, over REST and WebSocket. That makes it a good venue for dashboards, scanners and research tools: you can see who is quoting, not only what is quoted. The official reference is at [docs.lighter.xyz/api](https://docs.lighter.xyz/api). The older `apidocs.lighter.xyz` address redirects there.

## Step 1: base URLs and markets

| Exchange | REST | WebSocket |
| --- | --- | --- |
| Lighter mainnet | `https://mainnet.zklighter.elliot.ai` | `wss://mainnet.zklighter.elliot.ai/stream` |
| Lighter testnet | `https://testnet.zklighter.elliot.ai` | `wss://testnet.zklighter.elliot.ai/stream` |
| Lighter on Robinhood Chain | `https://api.rh.lighter.xyz` | `wss://api.rh.lighter.xyz/stream` |
| Lighter on Robinhood Chain testnet | `https://api.rh-testnet.lighter.xyz` | `wss://api.rh-testnet.lighter.xyz/stream` |

Lighter on Robinhood Chain is a separate exchange with its own accounts, keys and markets. This guide uses mainnet.

`GET /api/v1/orderBooks` lists every market. On our run it returned 246: 235 perpetuals (215 active, 20 inactive) and 11 spot markets. Each market has a numeric `market_id` that every other call takes. BTC is 1 and ETH is 0.

The snippets are short prototypes with no retry logic.

## Step 2: the REST endpoints worth knowing

Market data lives under `/api/v1/`. Account reads need an auth token, orders go through `sendTx` and `sendTxBatch`, and chain data (blocks, batches, account logs) has its own Explorer API at `https://explorer.elliot.ai/api` with separate limits. The endpoints we tested:

| Endpoint | Returns | Our result |
| --- | --- | --- |
| `/api/v1/orderBooks` | Markets, fees, tick sizes, open interest | 246 markets, 222 ms |
| `/api/v1/orderBookDetails?market_id=1` | Mark, index and last price, 24h volume, funding clamps | 200, 194 ms |
| `/api/v1/orderBookOrders?market_id=1&limit=5` | Resting orders now, each with `owner_account_index` | 5 asks |
| `/api/v1/recentTrades?market_id=1&limit=100` | Latest trades, 100 at most | 100 rows |
| `/api/v1/fundings` | Funding history at `1h` or `1d` | 750 rows a page |
| `/api/v1/candles` | OHLCV candles | 500 rows a page |
| `/api/v1/funding-rates` | Current funding on Lighter and three other exchanges | 732 rows |

`/api/v1/trades` only accepts `sort_dir=desc`. Sending `asc` returns `400 invalid param`.

### The same call from the Python SDK

Lighter's official Python SDK wraps these endpoints as typed clients. `OrderApi.order_books()` is `/api/v1/orderBooks`, and it needs no key:

```
"""sdk_first_read.py: a first read with Lighter's official Python SDK. Install: pip install lighter-sdk. No key needed."""
import asyncio
import lighter

async def main():
    client = lighter.ApiClient()                      # Lighter mainnet by default
    books = (await lighter.OrderApi(client).order_books()).order_books
    perps = [b for b in books if b.market_type == "perp" and b.status == "active"]
    print(len(perps), "active perpetual markets")
    for b in perps:
        if b.symbol in ("BTC", "ETH"):
            print(f"{b.symbol}: market_id {b.market_id}, min size {b.min_base_amount}, "
                  f"min order ${float(b.min_quote_amount):.0f}, size decimals {b.supported_size_decimals}, "
                  f"price decimals {b.supported_price_decimals}")
    await client.close()

asyncio.run(main())
```

Run on 9 November 2026 with `lighter-sdk` 1.1.8:

```
215 active perpetual markets
BTC: market_id 1, min size 0.00007, min order $10, size decimals 5, price decimals 1
ETH: market_id 0, min size 0.0020, min order $10, size decimals 4, price decimals 2
```

Of the 246 markets in the table above, 215 were active perpetuals, 20 inactive perpetuals and 11 spot markets. Use `min_base_amount` and the size and price decimals to round every order before you sign it.

## Step 3: WebSocket channels

Connect to `/stream`, send `{"type":"subscribe","channel":"..."}`, then read one `subscribed/...` message followed by `update/...` messages. The public channels:

- `order_book/{market_id}` : a full book on subscribe, then changes batched every 50 ms.
- `trade/{market_id}` : new trades.
- `ticker/{market_id}` : best bid and offer on every book change.
- `market_stats/{market_id}` or `market_stats/all` : mark and index price, open interest, `current_funding_rate` (the estimate for the next payment) and `funding_rate` (the last payment).

Account channels (orders, positions, trades, transactions) need an `auth` token in the subscribe message. Send any frame at least every 2 minutes or the server closes the connection. After a disconnect, open a new connection, subscribe again and start from the fresh snapshot it sends, not from your old book.

Over 15 seconds on BTC we received 246 `order_book` updates, 311 `ticker` updates, 28 `trade` messages and 12 `market_stats` updates. From our server, the plain `/stream` URL returned `HTTP 400` with a restricted-jurisdiction message. Lighter documents `?readonly=true` for market data from those regions, and that form connected in 523 ms.

```
import asyncio, json
import websockets

URL = "wss://mainnet.zklighter.elliot.ai/stream?readonly=true"

async def main():
    async with websockets.connect(URL) as ws:
        print(await ws.recv())
        await ws.send(json.dumps({"type": "subscribe", "channel": "market_stats/1"}))
        for _ in range(3):
            msg = json.loads(await ws.recv())
            s = msg["market_stats"]
            print(msg["type"], s["symbol"], "mark", s["mark_price"],
                  "current_funding_rate", s["current_funding_rate"])

asyncio.run(main())
```

```
{"session_id":"e9c468dc-7739-4477-a7a2-8961225c86fc","type":"connected"}
subscribed/market_stats BTC mark 76040.1 current_funding_rate 0.0012
update/market_stats BTC mark 76039.2 current_funding_rate 0.0012
update/market_stats BTC mark 76039.3 current_funding_rate 0.0012
```

That `0.0012` is a percent per hour, not a decimal. Step 4 explains.

## Step 4: funding units

Lighter pays funding every hour. The same BTC hour appears in three scales depending on where you read it:

| Where | Field | BTC value | Unit |
| --- | --- | --- | --- |
| Lighter `/api/v1/fundings` and WebSocket | `rate`, `current_funding_rate` | `0.0012` | Percent per hour |
| Lighter `/api/v1/funding-rates` | `rate` | `9.6e-05` | Decimal per 8 hours |
| 0xArchive `/v1/lighter/funding/BTC` | `funding_rate` | `0.000012` | Decimal per hour |

All three are the same rate: 0.0012% is 0.000012, and 0.000012 times 8 is 0.000096. We checked five consecutive hours on 1 November 2026 and they matched. Lighter's history endpoint rounds to four decimal places of a percent. 0xArchive returns the unrounded value. Convert everything to one scale before you compare markets or venues.

## Step 5: API keys and auth

Market data is open. Trading and private account data need credentials:

- Each account can hold API keys at indexes 0 to 254. Lighter reserves 0 to 3 for its own apps, so use 4 to 254. On Robinhood Chain, 157 is reserved too.
- Lighter's official SDKs do the signing: Python ( `pip install lighter-sdk` ), Go ( `github.com/elliottech/lighter-go` ) and TypeScript with WASM. Each API key has its own nonce. The SDK tracks it for you, or you can read the next one from `nextNonce` .
- Requests are signed with the API private key. The auth token has the form `{expiry_unix}:{account_index}:{api_key_index}:{random_hex}` and lasts up to 8 hours. Send it as the `Authorization` header on REST, or as `"auth"` in a WebSocket subscribe.
- For a dashboard that only reads, create a read token with `tokens/create` . It cannot trade or withdraw and can last up to 10 years. Creating one costs 10,000 request weight, so do it once.
- Authenticated requests count against your L1 address instead of your IP. That is the documented way past IP limits.

The older trade export, `/api/v1/export/historicalTrades`, returned `400` without a token. You do not need it for bulk trade history: Lighter now publishes that as free files, covered below.

## Step 6: rate limits

From [Lighter's rate limit page](https://docs.lighter.xyz/developers/reference/rate-limits):

| Account type | Lighter mainnet | Lighter on Robinhood Chain |
| --- | --- | --- |
| Standard | 60 requests a minute | 60 requests a minute |
| Plus | 24,000 weighted a minute | 120,000 weighted a minute |
| Premium (Advanced on mainnet) | 24,000 weighted a minute | 24,000 weighted a minute |
| Builder (apply through Lighter's Discord) | 240,000 weighted a minute | 150,000 weighted a minute |

All limits are per rolling minute for REST reads. On Plus and Premium accounts, order submission (`sendTx` and `sendTxBatch`) has its own budget, set by the LIT staked; standard accounts send orders out of the same 60. Limits count per IP and per L1 address. Authenticate each request and only the L1 limit applies.

Endpoints carry weights: `recentTrades` 600, `trades` 200 (600 on Robinhood Chain), `accountActiveOrders` 100, most others 300. Weights spend the budgets of the higher tiers: at 600 a call, a 24,000 budget allows 40 `recentTrades` calls a minute. A standard account counts requests instead, 60 a minute whatever the endpoint. WebSocket limits are per IP: 255 connections, 500 subscriptions per connection, 5,000 subscriptions per IP and 200 client messages a minute. Over a limit you get `429`, sometimes `405`. A firewall block lasts a flat 60 seconds, and REST and WebSocket limits trip together.

We tested it. 120 `recentTrades` calls with a different query string each time, sent over 25.9 seconds, returned 67 successes and 53 responses of `429 {"code":23000,"message":"Too Many Requests!"}`. The first `429` came on request 58. Repeating one identical URL 125 times never hit the limit, because a cache in front of the API answered the repeats. Do not size a backfill from a test that repeats one URL.

## Step 7: pull history from Lighter's API

Funding and candles reach the first day of a market. Page backward with `end_timestamp`:

```
import time
import requests

BASE = "https://mainnet.zklighter.elliot.ai"

books = requests.get(f"{BASE}/api/v1/orderBooks", timeout=30).json()["order_books"]
market_id = {b["symbol"]: b["market_id"] for b in books}
print(len(books), "markets; BTC market_id =", market_id["BTC"])

end_ms, rows, calls = int(time.time() * 1000), [], 0
while True:
    page = requests.get(f"{BASE}/api/v1/fundings", timeout=30, params={
        "market_id": market_id["BTC"], "resolution": "1h",
        "start_timestamp": 0, "end_timestamp": end_ms, "count_back": 0,
    }).json()["fundings"]
    calls += 1
    if not page:
        break
    rows = page + rows
    end_ms = (page[0]["timestamp"] - 1) * 1000
    time.sleep(1.1)  # stay under 60 requests a minute

print(calls, "requests,", len(rows), "hourly rows; first:", rows[0])
```

```
246 markets; BTC market_id = 1
23 requests, 15849 hourly rows; first: {'timestamp': 1737100800, 'value': '0.00000000', 'rate': '0.0000', 'direction': 'long'}
```

BTC hourly funding starts on 17 January 2025 at 08:00 UTC. The walk took about 29 seconds. Hourly candles took 33 requests for the same 15,849 hours. For these two datasets, Lighter's free API is enough, and you should use it.

## History: what Lighter's API covers and where it stops

Lighter publishes more history than most exchanges. As of 8 November 2026:

- **Funding and candles** over REST, back to the first hour of each market (Step 7).
- **Every trade** , free, as one Parquet file per UTC day in the public AWS Open Data bucket `s3://aws-public-blockchain/v1.1/lighter/core/mainnet/trades/` , from 17 January 2025. No AWS account or payment is needed ( `--no-sign-request` ). Rows carry both account ids, the position before the fill and PnL. The file for 7 November 2026 was 117.5 MB and covers every market that day.
- **Hourly open interest** for every perpetual, in the same bucket under `open_interest_hourly/` .

Over REST, `/api/v1/trades` answered for a start time one hour back. At 65 minutes back, and at every older point we tried, it returned an empty list. Lighter's [historical data page](https://docs.lighter.xyz/developers/integration-guides/historical-data) covers the bucket and the account endpoints.

What Lighter does not publish is the order book at a past moment. `orderBookOrders` and the `order_book` channel show the book now, and the historical data page lists no book dataset. For every Lighter dataset, its start date and how to pull it, see [Lighter historical market data](https://0xarchive.io/resources/market-data-guides/lighter-historical-market-data).

## Same jobs on 0xArchive

0xArchive serves Lighter at `https://api.0xarchive.io/v1/lighter` with one key in an `X-API-Key` header. Lighter on Robinhood Chain has its own namespace at `/v1/rh-lighter`, with the same routes as mainnet except L3, which it does not capture. Trades, order books, funding, open interest and candles are on every plan. The Free plan covers the last 30 days. Build and above reach the full archive. See [pricing](https://0xarchive.io/pricing).

| Job (BTC) | Lighter | 0xArchive |
| --- | --- | --- |
| Hourly funding history | REST: 23 requests, 15,849 rows, from 17 Jan 2025 | 11 requests, 10,084 rows, from 25 Aug 2025 |
| Hourly candles | REST: 33 requests, 15,849 rows, from 17 Jan 2025 | 2 requests, 11,152 rows, from 1 Aug 2025 |
| BTC trades from 00:00 to 00:05 UTC, 1 Nov 2026 | Download that day's file for every market, then filter | 1 request, 3,594 trades, 0.2 s |
| Order book once a second for a minute | Not published | 1 request, 60 snapshots |
| Order book on 15 Feb 2026 | Not published | 1 request |
| Each resting order, with its account, on 1 Apr 2026 | Live only | 1 request |
| Fill log for one account, with position before and after | Build it from the daily files | Paged by account, from January 2025 |

Read it plainly. For funding, candles and bulk trades, Lighter's own free sources reach as far back as 0xArchive, or further. 0xArchive saves the file pipeline: one market, one account or one time window per request, on the same key as Hyperliquid. The data Lighter does not publish at all is the past order book, by price level and order by order. The full comparison is in [Lighter's native API vs 0xArchive](https://0xarchive.io/resources/comparisons/lighter-native-api-vs-0xarchive).

### Where each 0xArchive dataset starts

From [capabilities](https://docs.0xarchive.io/capabilities) on 8 November 2026, and confirmed in our responses:

- **Trades:** 17 January 2025. The first weeks are thin: a 5-minute window on 1 February 2025 held 98 trades, against 3,594 in November 2026.
- **Account fill log:** January 2025, at `/v1/lighter/accounts/{account_index}/positions/changes` . We pulled rows for 20 January 2025. Each row is a fill with the position before and after, `event_type` , realized PnL and fee.
- **Funding and open interest:** 25 August 2025.
- **Candles:** 1 August 2025.
- **Order book (L2):** 29 January 2026, at `tick` , `1s` , `10s` , `30s` or `checkpoint` granularity.
- **L3, each resting order with its account:** 5 March 2026. Rows carry `order_index` , `owner_account_index` , side, price and size. These are Lighter account indexes, not wallet addresses.

The funding walk from Step 7, on 0xArchive:

```
import os
import requests

H = {"X-API-Key": os.environ["OXARCHIVE_API_KEY"]}
url = "https://api.0xarchive.io/v1/lighter/funding/BTC"
params = {"start": "2025-01-01T00:00:00Z", "end": "2026-11-08T16:00:00Z",
          "interval": "1h", "limit": 1000}

rows, calls = [], 0
while True:
    j = requests.get(url, headers=H, params=params, timeout=60).json()
    calls += 1
    rows += j["data"]
    if not j["meta"].get("has_more"):
        break
    params["cursor"] = j["meta"]["next_cursor"]

print(calls, "requests,", len(rows), "hourly rows; first:", rows[0]["timestamp"], rows[0]["funding_rate"])
```

```
11 requests, 10084 hourly rows; first: 2025-08-25T15:00:00Z 0.000011999999999999434
```

Trades, past order books and L3, one request each:

```
import os
import requests

H = {"X-API-Key": os.environ["OXARCHIVE_API_KEY"]}
API = "https://api.0xarchive.io/v1/lighter"

t = requests.get(f"{API}/trades/BTC", headers=H, timeout=60, params={
    "start": "2026-11-01T00:00:00Z", "end": "2026-11-01T00:05:00Z", "limit": 50000}).json()
print("trades:", len(t["data"]), "first:", t["data"][0]["timestamp"], t["data"][0]["price"], t["data"][0]["size"])

b = requests.get(f"{API}/orderbook/BTC/history", headers=H, timeout=60, params={
    "start": "2026-11-01T12:00:00Z", "end": "2026-11-01T12:01:00Z",
    "granularity": "1s", "depth": 5, "limit": 1000}).json()
print("order book:", len(b["data"]), "snapshots")

l3 = requests.get(f"{API}/l3orderbook/BTC", headers=H, timeout=60, params={
    "timestamp": "2026-04-01T12:00:00Z", "depth": 3}).json()["data"]
o = l3["orders"][0]
print("L3 at", l3["timestamp"], "account", o["owner_account_index"], o["side"], o["price"])
```

```
trades: 3594 first: 2026-11-01T00:00:00.041Z 77531.7 0.00516
order book: 60 snapshots
L3 at 2026-04-01T11:57:49.951Z account 388044 bid 68688.9
```

### Live and replay on 0xArchive

Connect to `wss://api.0xarchive.io/ws` with your key as a bearer token in the `Authorization` header, then send `{"op":"subscribe","channel":"lighter_trades","symbol":"BTC"}`. Live channels are `lighter_orderbook`, `lighter_trades`, `lighter_funding` and `lighter_open_interest`. `lighter_l3_orderbook` and `lighter_candles` are replay only. In 15 seconds on BTC we received 42 trade messages, 16 order book messages and 11 funding messages. Replaying five minutes of BTC trades from the day before delivered 1,638 messages in 4.2 seconds. Channel details are in the [Lighter WebSocket reference](https://docs.0xarchive.io/websocket/lighter).

## Which one to use

- **Live prices, funding estimates or the book right now:** Lighter's WebSocket.
- **Funding or candles back to January 2025:** Lighter's REST. It is free and takes about 30 seconds per market.
- **Every trade for whole days, in bulk:** Lighter's public bucket.
- **One market, account or window without a file pipeline, or Lighter and Hyperliquid on one key:** 0xArchive.
- **Past order books, by price level or order by order:** 0xArchive. Lighter does not publish them.

## What to know before you build

- **Three funding scales.** Percent per hour, decimal per 8 hours and decimal per hour. Convert first.
- **Test limits with varied URLs.** Cached repeats never count, so a naive test overstates your budget.
- **Finalized trades end at the previous UTC day.** On 8 November, 0xArchive's `meta.finalized_through` read `2026-11-07T23:59:59.999Z` , and a window from one hour earlier returned nothing from the history route. Read today's trades from `/v1/lighter/trades/{symbol}/recent` or the live channel. Replay works on finalized days.
- **Inactive markets.** Lighter listed 20 inactive perpetuals and 0xArchive listed 28. Filter on `status` .
- **Regions.** Lighter blocks some jurisdictions. The `?readonly=true` WebSocket is the documented route for market data there.

## FAQ

### What is the Lighter API base URL?

`https://mainnet.zklighter.elliot.ai` for REST and `wss://mainnet.zklighter.elliot.ai/stream` for WebSocket. Testnet and Robinhood Chain use the URLs in Step 1.

### What are the Lighter API rate limits?

On Lighter mainnet: 60 requests per rolling minute on a standard account, 24,000 weighted requests on Plus, Premium and Advanced, and 240,000 on Builder. Lighter on Robinhood Chain allows 120,000 on Plus and 150,000 on Builder. A `429` carries code `23000`.

### Does Lighter have a WebSocket API?

Yes. Public channels are `order_book`, `trade`, `ticker` and `market_stats`. Account channels need an auth token.

### Does Lighter have a testnet API?

Yes. REST is `https://testnet.zklighter.elliot.ai` and WebSocket is `wss://testnet.zklighter.elliot.ai/stream`.

### Is there a Lighter Python SDK?

Yes. `pip install lighter-sdk` installs the official Python SDK, which signs transactions and manages nonces. Lighter also publishes Go and TypeScript SDKs. You do not need any SDK to read market data: plain HTTP and WebSocket calls work.

### Do I need an API key to read Lighter market data?

No. Keys are for trading and private account data.

## Next steps

- [Lighter data on 0xArchive](https://0xarchive.io/lighter) and the [Lighter REST reference](https://docs.0xarchive.io/rest-api/lighter) .
- Data type pages: [trades](https://0xarchive.io/data-types/trades) , [L2 order books](https://0xarchive.io/data-types/l2-order-books) , [L3 order books](https://0xarchive.io/data-types/l3-order-books) , [funding](https://0xarchive.io/data-types/funding) .
- [Lighter native API vs 0xArchive](https://0xarchive.io/resources/comparisons/lighter-native-api-vs-0xarchive) , the full history comparison.
- [Funding rate arbitrage across Hyperliquid and Lighter](https://0xarchive.io/resources/market-data-guides/funding-rate-arbitrage) .
- [Lighter historical market data](https://0xarchive.io/resources/market-data-guides/lighter-historical-market-data) .
- [0xArchive rate limits](https://docs.0xarchive.io/rate-limits) and [pricing](https://0xarchive.io/pricing) .

Tested on 8 November 2026. The code is prototype code.
