Lighter L3 provides order-level snapshots of up to 250 resting orders per side, with owner attribution. Where L2 shows how much size sits at a price, L3 disaggregates the served depth into individual resting-order rows: its order ID, the account that placed it, the side, the price, and how much of it is left. 0xArchive serves this for Lighter over REST and historical WebSocket replay across 200+ markets, with L3 history going back to March 2026. Use L3 to study individual resting orders and attribute orders to accounts.
L2 vs L3: what actually changes
Most order-book data is L2. L2 is aggregated by price level. Every resting order at 1567.79 gets summed into a single number, and you see one row: price, total size, and an order count. That is enough to draw a depth chart. It is not enough to know what happens to your order when you join that price.
L3 is the disaggregated book. Each served resting order is its own row. Two traders resting 2 ETH each at the same price show up as two records, not one 4-ETH level. This is the data shape quants call market-by-order: each order carries a stable ID, and you can follow it while it remains inside the served, bounded view. Disappearance alone does not prove that it filled or canceled.
Every level from the best bid to the wallet, shown on one order book, is in level 1 vs level 2 vs level 3 market data.
Here is the same price level in both views.
| L2 (aggregated) | L3 (per order) |
|---|---|
{ px: "1567.79", sz: "3.807", n: 3 } |
{ price: 1567.79, remaining_size: 1.500, owner_account_index: 476270 }{ price: 1567.79, remaining_size: 1.807, owner_account_index: 708287 }{ price: 1567.79, remaining_size: 0.500, owner_account_index: 713041 }
|

The L2 row tells you 3.807 ETH is bid at that price across three orders. The L3 rows show the three accounts and their individual sizes: the difference between a histogram and an attributed ledger.
What L3 carries on Lighter
Lighter is the only venue on 0xArchive that exposes L3. Hyperliquid exposes L4 resting-order book data, while order-lifecycle records are available through separate order routes. On Lighter, an L3 snapshot returns an array of resting orders, each with the fields below, plus book-level counts.
| Field | What it is |
|---|---|
order_index | Stable identifier for the resting order. Track it across snapshots to follow a single order's life. |
owner_account_index | The account index that placed the order. This is the attribution key. |
side | bid or ask. |
price | Limit price of the order. |
remaining_size | Size still resting. Falls as the order gets partially filled. |
original_size | Size the order was placed with. Compare to remaining_size to see fill progress. |
The response also carries bid_count and ask_count (orders per side), totals, mid price, and spread. A real ETH snapshot looks like this:
{
"data": {
"coin": "ETH",
"timestamp": "2026-06-28T21:07:16.492Z",
"mid_price": "1571.12",
"spread": "0.14",
"bid_count": 250,
"ask_count": 250,
"orders": [
{ "order_index": 562947490139185, "owner_account_index": 476270, "side": "bid",
"price": 1568.36, "remaining_size": 0.485, "original_size": 0.485 },
{ "order_index": 562947490009211, "owner_account_index": 708287, "side": "bid",
"price": 1570.85, "remaining_size": 0.400, "original_size": 0.400 },
{ "order_index": 281477344539214, "owner_account_index": 713041, "side": "ask",
"price": 1573.27, "remaining_size": 3.2233, "original_size": 3.2233 }
]
}
}Coverage you can build on today: Lighter trades from the observed global floor of January 17, 2025, with exact starts varying by market; native L2 tick order book since January 2026; and L3 order-level since March 2026, across 200+ markets. Every one of those orders is keyed to the account that placed it, which is what turns the archive from a price series into a behavioral dataset.
Download the fixed Parquet sample and verify its published size and SHA-256 in the sample manifest.
What you can do with it
Reconstruct queue position
Study individual resting orders and account behavior with L3 snapshots and trades. Snapshots support sampled book-state research; event-by-event queue replay and passive-fill simulation need an ordered change stream and a queue model.
Attribute behavior to Lighter accounts
Each served resting order carries its owner_account_index. Group by owner and the book stops being anonymous. You can see which accounts post the tightest quotes, who only ever rests on one side, and which handful of accounts set the top of book. This is the join key for market-participant studies, flow-toxicity models, and account-level analysis. The numeric account index is not a wallet address.
Separate makers from takers
Finalized Lighter trades carry maker/taker attribution on every fill, including is_maker and order_id. Join those fills to the L3 order indexes and accounts you observed in the book. Doing this per account, over time, gives you a maker/taker profile per account instead of only a venue-wide ratio.
Spot concentrated accounts and replenishment
Because you have original_size and remaining_size per order, refills become visible. An order that keeps reappearing at the same price in similar size after observed fills is a potential replenishment pattern that aggregated data can hide. Repetition alone does not prove hidden-size intent. The same fields let you size real resting interest from a single account and flag the orders large enough to move the book.
Build reproducible backtests
Study individual resting orders and account behavior with L3 snapshots and trades. Snapshots support sampled book-state research; event-by-event queue replay and passive-fill simulation need an ordered change stream and a queue model. Simulated fills still depend on queue and execution-model assumptions.
Worked example: who is really at the top of book
Take the ETH snapshot above. The best bid sits at 1570.85 from owner 708287 for 0.4 ETH. Rank accounts by the bid size visible in each snapshot. Across distinct snapshots, track which order indexes remain visible and how their displayed sizes change. For maker/taker attribution, use the finalized fill's attribution fields. Now group every bid by owner_account_index across the window: if three accounts account for most of the size inside two ticks of mid, the book is thinner than the depth chart suggests, because L2 would have shown you the summed size and hidden the concentration. That is a signal you can only get from per-order rows with an owner attached.
How to pull it
Authenticate with the X-API-Key header. L3 is available on every tier, including Free. Start with a single snapshot:
curl -H "X-API-Key: $OXARCHIVE_API_KEY" \
"https://api.0xarchive.io/v1/lighter/l3orderbook/ETH?depth=50"For comparison, the L2 book is the aggregated route, and trades are their own feed:
# L2 aggregated book: bids/asks of { px, sz, n }
curl -H "X-API-Key: $OXARCHIVE_API_KEY" \
"https://api.0xarchive.io/v1/lighter/orderbook/ETH?depth=50"
# Trades: price, size, side, account
curl -H "X-API-Key: $OXARCHIVE_API_KEY" \
"https://api.0xarchive.io/v1/lighter/trades/ETH"Displayed ETH bid size by Lighter account index at one snapshot
Group the returned bids once. The result is displayed ETH size inside this snapshot's depth bound, not traded volume or cumulative liquidity. Repeating the request must not add the same resting size again. The script prints the requested depth, the snapshot timestamp, the returned bid and ask counts, the truncated flag and the number of orders it processed beside the ranking.
# Read one bounded snapshot; do not accumulate repeated polls.
import json
import os
import urllib.request
from collections import defaultdict
from decimal import Decimal
DEPTH = 50
url = f"https://api.0xarchive.io/v1/lighter/l3orderbook/ETH?depth={DEPTH}"
request = urllib.request.Request(
url, headers={"X-API-Key": os.environ["OXARCHIVE_API_KEY"]}
)
with urllib.request.urlopen(request, timeout=30) as response:
envelope = json.load(response, parse_float=Decimal)
if envelope.get("success") is not True:
raise RuntimeError("L3 request was not successful")
book = envelope["data"]
size_by_account = defaultdict(Decimal)
seen_orders = set()
for order in book["orders"]:
index = order["order_index"]
if index in seen_orders:
raise RuntimeError("Duplicate order_index in one snapshot")
seen_orders.add(index)
if order["side"] == "bid":
size = Decimal(str(order["remaining_size"]))
if not size.is_finite() or size < 0:
raise RuntimeError("Invalid remaining_size")
size_by_account[order["owner_account_index"]] += size
print("Requested depth:", DEPTH)
print("Snapshot:", book["timestamp"])
print("Returned counts: bids", book.get("bid_count"), "asks", book.get("ask_count"),
"truncated", book.get("truncated"))
print("Orders processed:", len(seen_orders))
for account, size in sorted(size_by_account.items(), key=lambda x: (-x[1], x[0]))[:5]:
print(f"account index {account}: {size} ETH displayed bid size")The numeric owner_account_index is a Lighter account index, not a wallet address. order_index identifies a resting order. Keep the returned timestamp, depth, counts and truncated flag with the result.
To run the same grouping without a key, read the fixed BTC L3 Parquet sample: ten snapshots of 500 captured orders each (250 bids and 250 asks). Its JSON preview shows 40 orders per row, so use the Parquet for the full captured view.
Studying behavior over time
For an over-time study, deduplicate observations by their actual stored timestamp and sequence where provided. Compute a fresh per-account total inside each distinct snapshot. Declare whether the statistic is an observation-weighted average or a time-weighted average, the maximum staleness allowed between observations and the treatment of missing intervals. Never sum repeated stock measurements and call the result volume.
Use REST for bounded L3 snapshots and history. The lighter_l3_orderbook WebSocket channel supports historical replay, not continuous live updates. For live Lighter market reads, use the order book, trades, funding and open-interest channels.
Lighter mainnet and Lighter on Robinhood Chain
| Contract | Lighter mainnet | Lighter on Robinhood Chain |
|---|---|---|
| Managed REST namespace | /v1/lighter/* | /v1/rh-lighter/* |
| Export exchange key | lighter | rh-lighter |
| Account identity | Mainnet account index | Robinhood Chain account index |
| L3 snapshot | /v1/lighter/l3orderbook/{symbol} | No L3 capture in current docs |
| Market discovery | /v1/lighter/instruments | /v1/rh-lighter/instruments |
Account indexes are local to each deployment. Equal numbers do not establish a shared account. A matching ticker does not make these the same market. Keep deployment, market identity and UTC window in every query, file and join. Check schema-specific coverage before comparing retained history. Live, replay and export availability is a per-dataset question, not a property inherited from the deployment.
Where to get Lighter L3
0xArchive carries Lighter L3 across 200+ markets over REST and historical WebSocket replay. Each resting order is keyed to the account that placed it, with order-level history since March 2026, alongside L2 tick data since January 2026 and trades from the observed global floor of January 17, 2025, with exact starts varying by market.
FAQ
What is the difference between L2 and L3 on Lighter?
L2 is aggregated: one row per price level with total size and an order count. L3 is per order: one row per resting order with its ID, owner, price, and remaining size. L3 attributes individual resting orders to accounts; L2 aggregates size by price.
Does Lighter L3 identify the account that placed each order?
Yes. Each order carries a numeric owner_account_index for the Lighter account that placed it. It is not a wallet address. Use it for account-level maker/taker and flow analysis.
How far back does Lighter L3 history go?
L3 order-level data goes back to March 2026. Native L2 tick order book goes back to January 2026. The observed global trade floor is January 17, 2025, with exact starts varying by market; funding and open-interest coverage must be checked separately by market.
Is L3 available for Hyperliquid?
No. L3 is Lighter only. Hyperliquid exposes L4 resting-order book data; separate order routes provide lifecycle records. If you need per-order owner data on Lighter, that is L3.
Which plan do I need for L3?
L3 is available on every tier, including Free. Every plan gets full venue and depth coverage; plans differ on limits like credits, rate, WebSocket subscriptions, replay, export, and history window: Free covers the most recent rolling 30 days with a maximum 30-day span per request, and Build and above keep the full retained archive. See pricing for current limits.
Can I use L3 for reproducible backtests?
Yes, with a stated model. The archived L3 records and trades are repeatable, but simulated fills depend on queue, latency, and execution assumptions. Record those assumptions beside the result.
REST or WebSocket?
Use REST for bounded L3 snapshots and history. The lighter_l3_orderbook WebSocket channel supports historical replay, not continuous live updates. For live Lighter market reads, use the order book, trades, funding and open-interest channels.
For current Lighter data, start with the Lighter live and historical data API, then use the overview and REST reference below for implementation details.
Start here
Pull one ETH snapshot, group the bids by owner_account_index, and see how few accounts hold the top of book. From there you can study resting-order concentration and run model-based research against the same historical window. Read the Lighter historical data overview, the Lighter REST reference, and check pricing for the plan that fits your usage.