Practical knowledge about the Lighter exchange: two independent deployments (regular zkLighter mainnet and an instance on robinhoodchain, commonly called “Robinhood”), the REST API, signing through the official Python SDK and a sidecar signer for TypeScript, markets and quantization, order responses without status, identifiers above 2^53, the 40/60 s write window, account and leverage, operations, and pitfalls. Facts were verified on the robinhoodchain instance; every rule includes its reason and verification date. There are no addresses, accounts, names, or sizes here—only mechanics, formulas, thresholds, and pitfalls.
Stack used for verification: Node ≥ 20, TypeScript, Node fetch; signing uses Python 3 + lighter-sdk (pip) + aiohttp. Freshness: facts verified through 2026-09-16.
How to read annotations inside the files:
- “verified with a live request ” / “verified with a live order ” / “verified ” / “observed ”—checked against an instance response on the stated date; do not simplify the rule without understanding its reason;
- “according to Lighter documentation”—taken from public documentation or the SDK and not verified live;
- “not verified” / the “Open questions / not verified” section—the last section in each file; summarized at the end of this page.
Files
| File | Covers | Open when |
|---|---|---|
| instances-and-api.md | Two instances and their hosts, where the RH host comes from, public reads (orderBooks, orderBookDetails, account), an expiring auth token and accountActiveOrders without market_id, response shapes, required metadata, and read transport policy | Starting Lighter code, choosing an instance, reading metadata and an account |
| signing-and-sdk.md | Non-EVM key, account_index / api_key_index, Python SDK (SignerClient, calls, constants), the sidecar-signer concept (endpoints, HTTP contract, skeleton, timeouts, one process per key, fail closed), signer client in TS, startup key-binding verification | Signing, connecting a key, starting the signer, “exchange unavailable” |
| markets-and-numbers.md | RH listing (40 perpetuals + 26 */USDG duplicates), market_id, decimals, integer base_amount/price, two minimums, sizing policy, mark price, and spread | Metadata, quantization, minimums, listing checks |
| orders.md | Payload, time in force, reduceOnly (capped by the position—observed), minimums, client_order_index / order_index / order_id (exact identity is the string), tx_hash instead of status, IoC fill by delta, write memory and rollup lag, 21734, cancellations, retries, codes, write budget, dispatch order | Any placement, cancellation, or order reconciliation |
| account-and-leverage.md | account?by=index, positions with the sign stored separately, equity = total_asset_value, two fraction scales, update_leverage, 2x default, changing leverage under an open position, fees (not measured) | Balance, sizing, leverage, margin, protective triggers |
| rate-limits.md | 40/60 s window per L1 address (code 23000), limiter with reserve and seeding, operation costs, window capacity for write sequences, throttling ≠ rejection ≠ minimum, read limits | Load design, 23000, “holding N place(s)” |
| ops.md | Process layout and signer as a separate process, startup preflight, health and instrumentation, failure runbook, micro-cycle before going live | Going live with real funds, incident analysis |
| pitfalls.md | Summary table of pitfalls with dates, error classes, and anti-patterns with reasons | Reviewing Lighter trading code, “strange behavior” |
Quick answers
1. Are Lighter and “Robinhood” the same thing?
One exchange, two independent deployments: zkLighter mainnet at https://mainnet.zklighter.elliot.ai and the robinhoodchain instance at https://api.rh.lighter.xyz (the host comes from the frontend JS bundle and is not in the HTML). They have different market lists, accounts, and account_index values, plus independent write windows. Everything in this knowledge base was verified on RH; mainnet is based on documentation. → instances-and-api.md §1
2. How do I sign from TypeScript?
Not directly: the scheme is proprietary, the 40-byte key is not EVM, and the official SDK supports only Python/Go. Move signing into a Python sidecar (lighter-sdk, with the signer binary inside the pip package) exposing /health, /auth, /order, /cancel, and /leverage; use a fail-closed bearer token, one long-lived SignerClient under one lock, and a 25-second timeout that produces unknown:true. The key lives only in the signer’s environment. → signing-and-sdk.md §3
3. What does placement return?
Only tx_hash. No status and no order_index. A resting order appears in accountActiveOrders after a lag of seconds; measure an IoC fill as the position delta before and after (poll for up to ~4 seconds); if no delta is observed → REJECTED. → orders.md §7
4. How do I cancel an order?
Use the exchange-assigned order_index, but take it from the string order_id: numeric order_index has been rounded by JSON.parse (values around 1e16 > 2^53). Cancellation with the rounded identifier is a valid transaction for a nonexistent order; the exchange responds OK and the order remains. Pass the identifier to the signer as a string. → orders.md §5, §8
5. What are the minimums?
Two independent values: min_quote_amount = $10 and lot-based min_base_amount (code 21706; it can be stricter than $10: SNDK 0.01 ≈ $16). Skip entries and partial reduceOnly orders below either value; for a full reduceOnly close, use ceil and raise above both. → markets-and-numbers.md §4
6. What is the write limit?
40 writes (placements, cancellations, leverage) in a sliding 60-second window per L1 address, code 23000; restarting the process does not reset the window. Configure the local limit below the ceiling and the reserve for cancellations/reduceOnly explicitly: lighter-kit does not choose them for the application. Replacing one order costs 2 writes. Public reads do not count toward the window. → rate-limits.md §1–3
7. How do I read positions and equity?
GET /api/v1/account?by=index&value=<account_index> without a token. Position: sign × position. Equity = total_asset_value; there is no separate free spot balance outside it. A position’s initial_margin_fraction is a percentage ("50.00" = 2x). → account-and-leverage.md §1–3
8. How do I set leverage?
update_leverage(market_index, CROSS_MARGIN_MODE, leverage); leverage is the market’s initial margin fraction, the default is 5000 = 50% = 2x, and the cap is floor(10000 / min_initial_margin_fraction). Under cross margin it is safe to change leverage under an open position (liquidation is based on the maintenance fraction and does not move). Every attempt consumes a write-window slot. → account-and-leverage.md §4
9. Is resting reduceOnly capped by the position? Yes, verified experimentally on 2026-08-20: an RO SELL twice the long position size → the position reached exactly 0 and the exchange canceled the remainder. Therefore, a reduceOnly order larger than the remaining position will either not be placed or will be truncated. → orders.md §3
10. Why does the bot place duplicates and cancel the same order repeatedly? The order list lags behind your own writes (zk-rollup). Keep confirmed-write memory for ~45 seconds: do not send a duplicate, and filter a confirmed cancellation from reads. A memory key can be asset + side + price, without size. → orders.md §7.2
11. What should I do after a timeout?
The outcome is unknown: do not retry placement (deduplication by client_order_index is unconfirmed); treat an unconfirmed cancellation as a live order; after leverage, reread the account. A local-limiter refusal is a known outcome, so retrying on the next cycle is safe. → orders.md §9
12. Which markets exist on RH?
40 base perpetuals + 26 */USDG duplicates (2026-08-23): major crypto, equity perpetuals, and the SPY ETF; some popular altcoins, PAXG, and CL were absent from the checked 2026-08…09 samples. Query the instance rather than relying on memory. → markets-and-numbers.md §1
13. What are the fees? Not measured. Public materials say that standard Lighter accounts trade without fees; this was not verified on RH. Measure them from your own account’s trade history. → account-and-leverage.md §6
Open questions (summary)
Everything below is not verified or contradictory. Details are in each file’s “Open questions” section.
Instances and API
- zkLighter mainnet: market list, minimums, limits, and response shapes were not checked. → instances-and-api.md
- Numeric public-read limit; whether auth-token issuance counts toward the write window;
Bearerprefix for the token. → instances-and-api.md, rate-limits.md - WebSocket, trade history, candles, and funding were not used. → instances-and-api.md
Signing and SDK
- API-key registration, per-account key limit, nonce separation across
api_key_indexvalues. → signing-and-sdk.md - Signer on Windows and macOS; Go SDK. → signing-and-sdk.md
Markets
- 21734 threshold as a percentage; market statuses other than
active; trading*/USDGduplicates. → markets-and-numbers.md
Orders
- Deduplication by
client_order_index; GTT after 28 days; IoC on an empty book and partial-fill price;ORDER_TYPE_MARKET, post-only, stops,modify_order; codes other than 23000/21706/21734; exact reflection lag; dispatch order IoC → GTC RO → GTC (not verified live); reduceOnly IoC larger than the position. → orders.md
Account and leverage
- Isolated margin; liquidation formula from the maintenance fraction; fees;
collateral/available_balancesemantics; reads byl1_address. → account-and-leverage.md
Limits and operations
- Write window across sub-accounts of one address; per-key limit; open-order count limit; window on zkLighter mainnet. → rate-limits.md
- Effects of clock skew (the SDK nonce is a counter, not time); one signer for multiple
account_indexvalues of one address. → ops.md
Disclaimer
This is not financial advice or a recommendation to trade. Measured values describe specific periods and the robinhoodchain instance and do not guarantee any outcome. The Lighter API, limits, minimums, and response shapes can change without notice: before using them, verify the facts against official Lighter documentation and live requests, especially anything marked “not verified.” Run snippet code in dry-run first and with minimal capital. You are responsible for its use.
Code
The tested implementation of these rules is the packages/lighter-kit package (@markpaper/lighter-kit): metadata parsing, quantization and sizing policy, exact order identifiers (order_id > 2^53), write memory, a limiter with reserve and seeding, IoC fill by delta, the signer client, and the Python SDK signer itself. The knowledge-base snippets illustrate the same rules; when moving them into your own code, include tests, with test traps documented in each file’s “Pitfalls” section.
License
The knowledge base and the lighter skill are licensed under CC BY 4.0. You may copy, adapt, and use them, including commercially, but every publication must credit “markpaper — Lighter knowledge base,” link to the original and the license, and indicate changes. See LICENSE.md for the terms.
© markpaper authors. Licensed under CC BY 4.0: when publishing or adapting this material, credit “markpaper — Lighter knowledge base” and link to the original and the license.