# Table of Contents - [Get Started](#get-started) - [API keys](#api-keys) - [Rate Limits](#rate-limits) - [Account Types](#account-types) - [SDK](#sdk) - [Signing Transactions](#signing-transactions) - [WebSocket](#websocket) - [Volume Quota](#volume-quota) - [Historical Data](#historical-data) - [Partner Integration](#partner-integration) - [Manage Referrals](#manage-referrals) - [Priority Transactions](#priority-transactions) - [Manage Public Pools](#manage-public-pools) - [Multi-signature and smart wallets](#multi-signature-and-smart-wallets) - [Data Structures, Constants and Errors](#data-structures-constants-and-errors) - [Create accounts programmatically](#create-accounts-programmatically) - [Deposits, Transfers and Withdrawals](#deposits-transfers-and-withdrawals) --- # Get Started Welcome to the Lighter SDK and API Introduction. Here, we will go through everything from the system setup, to creating and cancelling all types of orders, to fetching exchange data. To keep up to date with Lighter's API, join this [Telegram Channel](https://t.me/+4OylVDvI0z9lZDFk) or #api-updates on our [Discord](https://discord.gg/lighterxyz) . For best colocation, use AWS Tokyo ap-northeast-1. Install the SDK [](https://apidocs.lighter.xyz/docs/get-started#install-the-sdk) ------------------------------------------------------------------------------------ **Python:** Shell pip install lighter-sdk **Go:** Shell go get https://github.com/elliottech/lighter-go Find Your Account Index [](https://apidocs.lighter.xyz/docs/get-started#find-your-account-index) ---------------------------------------------------------------------------------------------------- Your account index is Lighter's integer identifier for your account. If you use sub-accounts, there will be multiple account indexes tied to the same L1 wallet. Query it using your L1 (Ethereum) address: Python import asyncio import lighter BASE_URL = "https://mainnet.zklighter.elliot.ai" L1_ADDRESS = "0x123" async def main(): client = lighter.ApiClient(lighter.Configuration(host=BASE_URL)) resp = await lighter.AccountApi(client).accounts_by_l1_address(l1_address=L1_ADDRESS) print(resp.sub_accounts[0].index) await client.close() if __name__ == "__main__": asyncio.run(main()) Create an API Key [](https://apidocs.lighter.xyz/docs/get-started#create-an-api-key) ---------------------------------------------------------------------------------------- API keys enable SDK signing and authenticated API requests; each is tied to a single account index and has its own nonce. You can create up to 253 keys (indices 2-254). Indices 0-1 are reserved for the web/mobile interfaces. Finally, the 255 index can be used as a value for the _api\_key\_index_ parameter of the **apikeys** method of the **AccountApi** for getting the data about all the API keys. See this page for [more details](https://apidocs.lighter.xyz/docs/api-keys) . Initialize the Signer Client [](https://apidocs.lighter.xyz/docs/get-started#initialize-the-signer-client) -------------------------------------------------------------------------------------------------------------- In order to create a transaction (create/cancel/modify order), you need to use the SignerClient. Initialize with the following code: Python client = lighter.SignerClient( url=BASE_URL, api_private_keys={API_KEY_INDEX:PRIVATE_KEY}, account_index=ACCOUNT_INDEX ) The code for the signer can be found in the same repo, in the [signer\_client.py](https://github.com/elliottech/lighter-python/blob/main/lighter/signer_client.py) file. You may notice that it uses a binary for the signer: the code for it can be found in the [lighter-go](https://github.com/elliottech/lighter-go) public repo, and you can compile it yourself using the [justfile](https://github.com/elliottech/lighter-go/blob/main/justfile) . Nonce [](https://apidocs.lighter.xyz/docs/get-started#nonce) ---------------------------------------------------------------- When signing a transaction, you may need to provide a nonce (number used once). A nonce needs to be incremented each time you sign something. You can get the next nonce that you need to use using the **TransactionApi’s** _next\_nonce_ method or take care of incrementing it yourself. Note that each nonce is handled per **API\_KEY**. If you'd like to skip nonces, you can set the `SkipNonce` (`skip_nonce` in the Python SDK) attribute (4th in `L2TxAttributes`) to `1`. If this attribute is not specified, we require `new_nonce = old_nonce + 1`. In any case, the following must hold true when skipping nonces: `2^47-1 > new_nonce > old_nonce`. Otherwise, nonces are capped at `2^48-1`. Signing a transaction [](https://apidocs.lighter.xyz/docs/get-started#signing-a-transaction) ------------------------------------------------------------------------------------------------ One can sign a transaction using the **SignerClient’s** _sign\_create\_order_, _sign\_modify\_order_, _sign\_cancel\_order_ and its other similar methods. For actually pushing the transaction, you need to call _send\_tx_ or _send\_tx\_batch_ using the **TransactionApi**. Here’s an [example](https://github.com/elliottech/lighter-python/blob/main/examples/send_batch_tx_http.py) that includes such an operation. Alternatively, you can use _create\_order_, which will send the tx as well. See more details [here](https://apidocs.lighter.xyz/docs/trading) . Note that _base\_amount, price_ are to be passed as integers, and _client\_order\_index_ is a unique (across all markets) identifier you provide for you to be able to reference this order later (e.g. if you want to cancel it). The SDK handles nonce management automatically. For complex systems, you can implement local nonce management. ### Price and Size precision [](https://apidocs.lighter.xyz/docs/get-started#price-and-size-precision) Query the [orderBookDetails](https://apidocs.lighter.xyz/reference/orderbookdetails) endpoint to get decimal precision for each market: Shell GET /api/v1/orderBookDetails ### Place Your First Market Order [](https://apidocs.lighter.xyz/docs/get-started#place-your-first-market-order) Python tx, tx_hash, err = await client.create_order( market_index=0, # ETH perps market client_order_index=1234, base_amount=10, # 0.001 ETH price=3100_00, # $3100 -- worst acceptable price for the order is_ask=False, # Bid, i.e. buy order order_type=client.ORDER_TYPE_MARKET, time_in_force=client.ORDER_TIME_IN_FORCE_IMMEDIATE_OR_CANCEL, reduce_only=False, order_expiry=client.DEFAULT_IOC_EXPIRY, ) ### Place Your First Limit Order [](https://apidocs.lighter.xyz/docs/get-started#place-your-first-limit-order) Python tx, tx_hash, err = await client.create_order( market_index=0, # ETH perps market client_order_index=1234, base_amount=100, # 0.01 ETH price=2900_00, # $2900 is_ask=False, # Bid, i.e. buy order order_type=client.ORDER_TYPE_LIMIT, time_in_force=client.ORDER_TIME_IN_FORCE_GOOD_TILL_TIME, reduce_only=False, order_expiry=client.DEFAULT_28_DAY_ORDER_EXPIRY, ) ### Cancel an order [](https://apidocs.lighter.xyz/docs/get-started#cancel-an-order) Python tx, tx_hash, err = await client.cancel_order( market_index=market_index, order_index=1234 ) ### Modify an order [](https://apidocs.lighter.xyz/docs/get-started#modify-an-order) Python tx, tx_hash, err = await client.modify_order( market_index=0, order_index=1234, base_amount=100, # 0.01 ETH price=2800_00, # $2800 ) Authentication Tokens [](https://apidocs.lighter.xyz/docs/get-started#authentication-tokens) ------------------------------------------------------------------------------------------------ For REST API calls and Websocket channels requiring authentication: Python auth_token, err = client.create_auth_token_with_expiry( deadline=3600, # seconds. Max is 8 hours, default is 10 minutes api_key_index=API_KEY_INDEX, ) Alternatively, you can use a read-only auth token. See more details [here](https://apidocs.lighter.xyz/docs/api-keys) . API via SDK [](https://apidocs.lighter.xyz/docs/get-started#api-via-sdk) ---------------------------------------------------------------------------- The SDK provides API classes that make calling the Lighter API easier. Here are some of them and the most important of their methods: * **AccountApi** - provides account data * _account_ - get account data either by l1\_address or index * _accounts\_by\_l1\_address_ - get data about all the accounts (master account and subaccounts) * _apikeys_ - get data about the api keys of an account (use api\_key\_index = 255 for getting data about all the api keys) * **TransactionApi** - provides transaction-related data * _next\_nonce_ - get next nonce to be used for signing a transaction using a certain api key * _send\_tx_ - push a transaction * _send\_tx\_batch_ - push several transactions at once * **OrderApi** - provides data about orders, trades and the orderbook * _order\_book\_details_ - get data about a specific market’s orderbook * _order\_books_ - get data about all markets’ orderbooks You can find the rest [here](https://github.com/elliottech/lighter-python/tree/main/lighter/api) . We also provide an [example](https://github.com/elliottech/lighter-python/blob/main/examples/get_info.py) showing how to use some of these. For the methods that require an auth token, you can generate one using the _create\_auth\_token\_with\_expiry_ method of the **SignerClient** (the same applies to the websockets auth). WebSockets [](https://apidocs.lighter.xyz/docs/get-started#websockets) -------------------------------------------------------------------------- Lighter also provides access to essential info using websockets. A simple version of an **WsClient** for subscribing to account and orderbook updates is implemented [here](https://github.com/elliottech/lighter-python/blob/main/lighter/ws_client.py) . You can also take it as an example implementation of such a client. To get access to more data, you will need to connect to the websockets without the provided WsClient. You can find the streams you can connect to, how to connect, and the data they provide in the [websockets](doc:websocket-reference) section. Updated 1 day ago * * * Ask AI --- # API keys You can use API keys to trade and manage your lighter account programmatically. Each API key will be assigned an index, ranging from 0 to 254 - note that indexes `{0,1,2,3}` are reserved for desktop and mobile interfaces. Each internal account, whether that's a master account or a sub-account, will have its own separate API key index - and each comes with a public & private key, and its own nonce. Permissions [](https://apidocs.lighter.xyz/docs/api-keys#permissions) ------------------------------------------------------------------------- API keys enable both write and read permissions, allowing you to query auth-gated REST endpoints and Websocket channel, but also send transactions and process withdrawals. While it allows to process withdrawals, you should consider that only secure withdrawals can be executed without also providing the account's Ethereum private key - as they can only be sent to the same L1 address that created the account. On the other hand, Fast Withdrawals and Transfers can be sent to other L1 addresses and will require the wallet's private key. Authentication [](https://apidocs.lighter.xyz/docs/api-keys#authentication) ------------------------------------------------------------------------------- To interact with certain endpoints, you will need to generate an auth token using your API private key. You can do so using our [GO SDK](https://github.com/elliottech/lighter-go) , or use the create\_auth\_token\_with\_expiry() function in our [Python SDK](https://github.com/elliottech/lighter-python) . Each auth code can have a maximum expiry of 8 hours, and it uses the following structure: `{expiry_unix}:{account_index}:{api_key_index}:{random_hex}`. Read-only Authentication [](https://apidocs.lighter.xyz/docs/api-keys#read-only-authentication) --------------------------------------------------------------------------------------------------- Using a canonical auth code, you can generate read-only auth tokens - those won't allow placing trades nor request withdrawals (essentially, you won't be able to sign transactions hence initialize a signer client), but you will be able to access auth-gated data via API. Each read-only auth code can have a maximum expiry of 10 years, and a minimum of 1 day. They will use the following structure: `ro:{account_index}:{single|all}:{expiry_unix}:{random_hex}`. You can generate one using the [createToken](https://apidocs.lighter.xyz/reference/tokens_create) endpoint, or [via front-end](https://app.lighter.xyz/read-only-tokens/) . How to create API keys programmatically [](https://apidocs.lighter.xyz/docs/api-keys#how-to-create-api-keys-programmatically) --------------------------------------------------------------------------------------------------------------------------------- You can create new keys programmatically using either the [Python SDK](https://github.com/elliottech/lighter-python/blob/main/examples/system_setup.py#L58) , or the [GO SDK](https://github.com/elliottech/lighter-go/blob/0d4ddf155950e8ad62164a9d34a139750deebe37/README.md?plain=1#L26) . While generating the API keys does not require your L1 private key, associating them with your Lighter account does. You can either do this via the SDKs, or interact with Lighter's smart contract directly using the [ChangePubKey function](https://app.lighter.xyz/ethereum-gateway/) (this is particularly helpful if you're running a multi-sig). Nonce management [](https://apidocs.lighter.xyz/docs/api-keys#nonce-management) ----------------------------------------------------------------------------------- Each API key will have its own nonce, and the API servers require it to be increased by 1 for each transaction you submit, unless `SkipNonce` is enabled. While the [Python SDK](https://github.com/elliottech/lighter-python) handles nonce management on its own, you might want to manage it locally to handle more complex systems. Since some types of transactions may be subject to speed bumps based on your [account type](https://apidocs.lighter.xyz/docs/account-types) , and they are processed sequentially, you may want to use multiple API keys for the same account e.g. one for each type of order to always guarantee the fastest execution. If you'd like to skip nonces, you can set the `SkipNonce` (`skip_nonce` in the Python SDK) attribute (4th in `L2TxAttributes`) to `1`. If this attribute is not specified, we require `new_nonce = old_nonce + 1`. In any case, the following must hold true when skipping nonces: `2^47-1 > new_nonce > old_nonce`. Otherwise, nonces are capped at `2^48-1`. Updated 1 day ago * * * Ask AI --- # Rate Limits We enforce rate limits on both REST API and WebSocket usage. These limits apply to both IP address and L1 address. It's important to note that for premium accounts only, sendTx and sendTxBatch fall into a separate rate limit bucket [described below](https://apidocs.lighter.xyz/docs/rate-limits#sendtx-and-sendtxbatch-limits-premium-accounts) , and are [linked to account type and staked tokens](page:account-types) . * * * REST API Endpoint Limits [](https://apidocs.lighter.xyz/docs/rate-limits#rest-api-endpoint-limits) ------------------------------------------------------------------------------------------------------ The following limits apply to the `https://mainnet.zklighter.elliot.ai/api/v1/` base URL, excluding `sendTx` and `sendTxBatch` where different limits, listed [below](https://apidocs.lighter.xyz/docs/rate-limits#sendtx-and-sendtxbatch-limits-premium-accounts) , apply. Different limits, also listed [below](https://apidocs.lighter.xyz/docs/rate-limits#explorer-rest-api-endpoint-limits) , apply to `https://explorer.elliot.ai/api/`. | Builder accounts | Premium accounts | Standard accounts | | --- | --- | --- | | 240,000 weighted requests per rolling minute | 24,000 weighted requests per rolling minute | 60 requests per rolling minute | ### Weights: [](https://apidocs.lighter.xyz/docs/rate-limits#weights) | Endpoint | Weight | | --- | --- | | `sendTx, sendTxBatch, nextNonce` | 6 | | `publicPools, txFromL1TxHash` | 50 | | `accountInactiveOrders, deposit/latest` | 100 | | `apikeys` | 150 | | `transferFeeInfo` | 500 | | `trades, recentTrades` | 600 | | `changeAccountTier, tokens, tokens/revoke setAccountMetadata, notification/ack, createIntentAddress, fastwithdraw, referral/*` | 3000 | | `tokens/create` | 23000 | | Other endpoints | 300 | While standard accounts rate limits are not weighted, whenever `{premium_weighted_requests}/{endpoint_weight} < {standard_requests}`, the former limit is going to be applied. For example, both standard and premium accounts will be able to make a maximum of 8 requests per rolling minute to the `changeAccountTier` endpoint. You can apply for a Builder Account through our Discord support channel. It’s free of charge, but we reserve the right to review applications and verify the intended use. Builder Accounts include higher limits for querying our REST API endpoints; otherwise, standard account limits apply. Builders on this tier should authenticate every request, even when not explicitly required in our documentation. * * * WebSocket Limits [](https://apidocs.lighter.xyz/docs/rate-limits#websocket-limits) -------------------------------------------------------------------------------------- To prevent resource exhaustion, we enforce the following usage limits **per IP**: * **Connections**: 100 * **Subscriptions per connection**: 100 * **Total Subscriptions**: 1000 * **Max Connections Per Minute**: 80 (not to be confused with channel subscriptions) * **Max Messages Sent By Client Per Minute**: 200 (sendTx and sendBatchTx are **not** counted here, and follow the same limits as REST requests) * **Max Inflight Messages**: 50 (sendTx and sendBatchTx are **not** counted here) * **Unique Accounts**: 10 Additionally, every connection is automatically dropped after 24 hours. It's recommended to have proper reconnection logic, in addition to ping/pong logic. * * * SendTx and SendTxBatch Limits (premium accounts) [](https://apidocs.lighter.xyz/docs/rate-limits#sendtx-and-sendtxbatch-limits-premium-accounts) ---------------------------------------------------------------------------------------------------------------------------------------------------- The following limits apply to `sendTx` and `sendTxBatch` requests, regardless of whether you send the requests using REST via HTTP, or via WebSocket. For these two types, we do not enforce IP limits, but only check rate limits at the L1 address level. Standard accounts are still bound to the 60 requests per minute limit. For rate limit purposes, fee credits count as staked LIT.`sendTx` and `sendTxBatch` are the only two types constrained by [Volume Quota](doc:volume-quota-program) , necessary to create and modify orders. | Staked LIT | sendTx/sendTxBatch per minute | | --- | --- | | 0 | 4000 | | 1000 | 5000 | | 3000 | 6000 | | 10000 | 7000 | | 30000 | 8000 | | 100000 | 12000 | | 300000 | 24000 | | 500000 | 40000 | * * * Explorer REST API Endpoint Limits [](https://apidocs.lighter.xyz/docs/rate-limits#explorer-rest-api-endpoint-limits) ------------------------------------------------------------------------------------------------------------------------ The following limits apply to the `https://explorer.elliot.ai/api/` Base URL. Standard Users and Premium Users both have the same limit of 90 weighted requests per rolling minute window. ### Weights [](https://apidocs.lighter.xyz/docs/rate-limits#weights-1) | Endpoint | Weight | | --- | --- | | `search` | 3 | | `accounts/*` | 2 | | Other endpoints | 1 | * * * Transaction Type Limits (per user) [](https://apidocs.lighter.xyz/docs/rate-limits#transaction-type-limits-per-user) ------------------------------------------------------------------------------------------------------------------------ The following limits apply to both Standard and Premium accounts: | Transaction Type | Limit | | --- | --- | | Default | 40 requests / minute | | `L2Withdraw` | 2 requests / minute | | `L2CreateSubAccount` | 2 requests / minute | | `L2CreatePublicPool` | 2 requests / minute | | `L2UpdateLeverage` | 40 requests / minute | | `L2ChangePubKey` | 300 requests / minute | | `L2Transfer` | 120 request / minute | | `L2MintShares` | 1 request / 15 seconds | | `L2UnstakeAssets` | 1 request / 15 seconds | * * * Rate Limit Exceeding Behavior [](https://apidocs.lighter.xyz/docs/rate-limits#rate-limit-exceeding-behavior) ---------------------------------------------------------------------------------------------------------------- If you exceed any rate limit: * You will receive an HTTP `429 Too Many Requests` error * For WebSocket connections, excessive messages may result in disconnection * When you're rate-limited on REST, WebSocket connections also get rate-limited, and viceversa * For premium accounts only, mainnet endpoints fall into a separate bucket from `sendTx` and `sendTxBatch`, meaning that getting rate-limited in one of the two buckets will not affect activity on the other. Put simply, sending too many transactions in a minute will not affect your ability to fetch data from the exchange, and viceversa. To avoid this, please ensure your clients are implementing proper backoff and retry strategies. Cooldown [](https://apidocs.lighter.xyz/docs/rate-limits#cooldown) ---------------------------------------------------------------------- Depending on whether you have been rate-limited by our firewall, or by the api servers, the cooldown period varies: * **Firewall**: 60 seconds, static * **Api servers**: `weightOfEndpoint/(totalWeight/60)` As an example, making a request to the `account` endpoint (which carries a `weight` of 300) after having exhausted your weighted requests in a given minute window, results in a 750ms cooldown period. Updated 5 minutes ago * * * Ask AI --- # Account Types #### Premium Account (Opt-in) -- Suitable for HFT, the lowest latency on Lighter. Part of [volume quota program](doc:volume-quota-program) . [](https://apidocs.lighter.xyz/docs/account-types#premium-account-opt-in----suitable-for-hft-the-lowest-latency-on-lighter-part-of-volume-quota-program) Latency for maker & cancel orders is 0ms. Fee credits also count as staked LIT for the parameters described in the table. | Staked LIT | sendTx/sendTxBatch per minute | Maker/Taker Fee Discount | Maker Fee | Taker Fee | Taker Latency | Latency Improvement | Sub-accounts | | --- | --- | --- | --- | --- | --- | --- | --- | | 0 | 4000 | | 0.0040% | 0.0280% | 200 ms | | 8 | | 1,000 | 5000 | 2.5% | 0.0039% | 0.0273% | 195 ms | 2.5% | 8 | | 3,000 | 6000 | 5% | 0.0038% | 0.0266% | 190 ms | 5% | 8 | | 10,000 | 7000 | 10% | 0.0036% | 0.0252% | 180 ms | 10% | 8 | | 30,000 | 8000 | 15% | 0.0034% | 0.0238% | 170 ms | 15% | 8 | | 100,000 | 12000 | 20% | 0.0032% | 0.0224% | 160 ms | 20% | 8 | | 300,000 | 24000 | 25% | 0.0030% | 0.0210% | 150 ms | 25% | 8 | | 500,000 | 40000 | 30% | 0.0028% | 0.0196% | 140 ms | 30% | 64 | #### Standard Account (Default) -- Suitable for retail and latency-insensitive traders. [](https://apidocs.lighter.xyz/docs/account-types#standard-account-default----suitable-for-retail-and-latency-insensitive-traders) | Maker Fee | Taker Fee | Taker Latency | Maker/Cancel Latency | | --- | --- | --- | --- | | 0% | 0% | 300 ms | 200 ms | #### Account Switch [](https://apidocs.lighter.xyz/docs/account-types#account-switch) You can change your Account Type (tied to your L1 address) using the `/changeAccountTier` endpoint. You may call that endpoint if: * You have no open positions * You have no open orders * At least 24 hours have passed since the last call _Python snippet to switch tiers_: Python: switch to premiumPython: switch to standard import asyncio import logging import lighter import requests logging.basicConfig(level=logging.DEBUG) BASE_URL = "https://mainnet.zklighter.elliot.ai" # You can get the values from the system_setup.py script # API_KEY_PRIVATE_KEY = # ACCOUNT_INDEX = # API_KEY_INDEX = async def main(): client = lighter.SignerClient( url=BASE_URL, private_key=API_KEY_PRIVATE_KEY, account_index=ACCOUNT_INDEX, api_key_index=API_KEY_INDEX, ) err = client.check_client() if err is not None: print(f"CheckClient error: {err}") return auth, err = client.create_auth_token_with_expiry( lighter.SignerClient.DEFAULT_10_MIN_AUTH_EXPIRY ) response = requests.post( f"{BASE_URL}/api/v1/changeAccountTier", data={"account_index": ACCOUNT_INDEX, "new_tier": "premium"}, headers={"Authorization": auth}, ) if response.status_code != 200: print(f"Error: {response.text}") return print(response.json()) if __name__ == "__main__": asyncio.run(main()) import asyncio import logging import lighter import requests logging.basicConfig(level=logging.DEBUG) BASE_URL = "https://mainnet.zklighter.elliot.ai" # You can get the values from the system_setup.py script # API_KEY_PRIVATE_KEY = # ACCOUNT_INDEX = # API_KEY_INDEX = async def main(): client = lighter.SignerClient( url=BASE_URL, private_key=API_KEY_PRIVATE_KEY, account_index=ACCOUNT_INDEX, api_key_index=API_KEY_INDEX, ) err = client.check_client() if err is not None: print(f"CheckClient error: {err}") return auth, err = client.create_auth_token_with_expiry( lighter.SignerClient.DEFAULT_10_MIN_AUTH_EXPIRY ) response = requests.post( f"{BASE_URL}/api/v1/changeAccountTier", data={"account_index": ACCOUNT_INDEX, "new_tier": "standard"}, headers={"Authorization": auth}, ) if response.status_code != 200: print(f"Error: {response.text}") return print(response.json()) if __name__ == "__main__": asyncio.run(main()) #### How fees are collected: [](https://apidocs.lighter.xyz/docs/account-types#how-fees-are-collected) In isolated margin, fees are taken from the isolated position itself, but if needed, we automatically transfer from cross margin to keep the position healthy. In cross margin, fees are always deducted directly from the available cross balance. Sub-accounts share the same tier as the main L1 address on the account. Updated 3 days ago * * * Ask AI --- # SDK Public Python SDK for Lighter: [https://github.com/elliottech/lighter-python](https://github.com/elliottech/lighter-python) Public Go SDK for Lighter: [https://github.com/elliottech/lighter-go](https://github.com/elliottech/lighter-go) Updated 7 months ago * * * Ask AI --- # Signing Transactions Traders can trade programmatically using the [sendTx](https://apidocs.lighter.xyz/reference/sendtx) and [sendTxBatch](https://apidocs.lighter.xyz/reference/sendtxbatch) REST endpoints, or [json/sendTx](doc:websocket-reference#send-tx) and [json/sendTxBatch](doc:websocket-reference#send-batch-tx) types via Websocket. Creating an API key is required to sign transactions. Orders that have the correct syntax will be accepted by the API servers, returning code=200. This does not guarantee the execution of your order, as the sequencer could still reject it if parameters are not set properly. To monitor orders execution, you can use [websocket channels](doc:websocket-reference) . Sign Transactions [](https://apidocs.lighter.xyz/docs/trading#sign-transactions) ------------------------------------------------------------------------------------ Every [transaction](page:data-structures-constants-and-errors#constants) needs to be signed using the **SignerClient**. Using the [Python SDK](doc:repos) , you can initialize it as follows: Python client = lighter.SignerClient( url=BASE_URL, api_private_keys={API_KEY_INDEX:PRIVATE_KEY}, account_index=ACCOUNT_INDEX ) The code for the signer can be found in the same repo, in the [signer\_client.py](https://github.com/elliottech/lighter-python/blob/main/lighter/signer_client.py) file. You may notice that it uses a binary for the signer: the code for it can be found in the [lighter-go](https://github.com/elliottech/lighter-go) public repo, and you can compile it yourself using the [justfile](https://github.com/elliottech/lighter-go/blob/main/justfile) . Handle Nonces [](https://apidocs.lighter.xyz/docs/trading#handle-nonces) ---------------------------------------------------------------------------- When signing a transaction, you may need to provide a nonce (number used once). You can get the next nonce that you need to use using the TransactionApi’s next\_nonce method or take care of incrementing it yourself. Note that each nonce is handled per **API\_KEY**. If the transaction throws an error at the API server level, nonce will not increase. But if the syntax is correct (`code=200`) and order is only later rejected by the Sequencer (say, because the price was set incorrectly), the order is cancelled and the nonce increases regardless - this holds true except for a few edge cases e.g. when the order isn't executed by the sequencer before the ExpiredAt timestamps. One peculiarity is that maker orders with correct syntax can still fail at the API level if some conditions aren't met (e.g. not enough margin), resulting in nonce not increasing, while taker orders will go through regardless as long as the syntax is correct, and only fail at the sequencer level - increasing the nonce. If you'd like to skip nonces, you can set the `SkipNonce` (`skip_nonce` in the Python SDK) attribute (4th in `L2TxAttributes`) to `1`. If this attribute is not specified, we require `new_nonce = old_nonce + 1`. In any case, the following must hold true when skipping nonces: `2^47-1 > new_nonce > old_nonce`. Otherwise, nonces are capped at `2^48-1`. Handle price and size [](https://apidocs.lighter.xyz/docs/trading#handle-price-and-size) -------------------------------------------------------------------------------------------- To correctly handle decimals for both price and size, you can refer to the [orderBooks](https://apidocs.lighter.xyz/reference/orderbooks) and [orderBookDetails](https://apidocs.lighter.xyz/reference/orderbookdetails) endpoints. The number of decimals indicates the number of zeros you'll need to use in order to specify a whole unit (e.g. to buy a whole Ethereum coin where `supported_size_decimals` is 4, you will need to specify `size` equal to 1\*10^4). Additionally, those same endpoints will offer guidance on the minimum base amount and the minimum quota amount. The former indicates the minimum amount you can trade in coin terms, while the latter indicates it using the quote asset (so, USDC). The highest of the two is applied. Note that those minimums only apply to maker orders. As for prices, note that when specifying a price for a taker order, that is to be interpreted as the worst price you're willing to accept - if the sequencer cannot offer you an equal or better price, the order is cancelled. Additionally, when handling TP/SL orders, you should be mindful that, besides a trigger price, you should indicate a price as well, which indicates the allowed slippage for the execution of said order, with the same logic used for taker orders above. Handle Client Order Index, and Order Index [](https://apidocs.lighter.xyz/docs/trading#handle-client-order-index-and-order-index) ------------------------------------------------------------------------------------------------------------------------------------- When signing new orders, you can specify a `client_order_index` (uint48) allowing you to better reference your trades. Sometimes, e.g. in cancels, you may see `order_index` instead as an argument - this is fine and you can use the same value here. If `client_order_index` is missing (e.g. if you trade from the front-end, that'll be 0), you can use `trade_id` (assigned by the exchange) to reference the order. Order types [](https://apidocs.lighter.xyz/docs/trading#order-types) ------------------------------------------------------------------------ * ORDER\_TYPE\_LIMIT (0) * ORDER\_TYPE\_MARKET (1) * ORDER\_TYPE\_STOP\_LOSS (2) * ORDER\_TYPE\_STOP\_LOSS\_LIMIT (3) * ORDER\_TYPE\_TAKE\_PROFIT (4) * ORDER\_TYPE\_TAKE\_PROFIT\_LIMIT (5) * ORDER\_TYPE\_TWAP (6) Additionally, there are two internal order types: * TWAPSubOrder (7) * LiquidationOrder (8) Time in force [](https://apidocs.lighter.xyz/docs/trading#time-in-force) ---------------------------------------------------------------------------- * ORDER\_TIME\_IN\_FORCE\_IMMEDIATE\_OR\_CANCEL (0) * ORDER\_TIME\_IN\_FORCE\_GOOD\_TILL\_TIME (1) * ORDER\_TIME\_IN\_FORCE\_POST\_ONLY (2) Order types, time in force, and other types of transactions are specified on [signer\_client.py](https://github.com/elliottech/lighter-python/blob/b489f27896dd9df8c45c22b1b85adf5011861e3a/lighter/signer_client.py#L218) in the Python SDK, and in [constants.go](https://github.com/elliottech/lighter-go/blob/37514ad5630052c162fa0745ac59ae47ff33d148/types/txtypes/constants.go#L57) in the GO SDK. Updated 1 day ago * * * Ask AI --- # WebSocket Connection [](https://apidocs.lighter.xyz/docs/websocket-reference#connection) ================================================================================== URL: `wss://mainnet.zklighter.elliot.ai/stream`; `wss://testnet.zklighter.elliot.ai/stream` You can directly connect to the WebSocket server using wscat: Shell wscat -c 'wss://mainnet.zklighter.elliot.ai/stream' If you're connecting from a restricted region, you can still access read-only data: Shell wscat -c 'wss://mainnet.zklighter.elliot.ai/stream?readonly=true' Keepalive Requirements [](https://apidocs.lighter.xyz/docs/websocket-reference#keepalive-requirements) ========================================================================================================== Clients are responsible for keeping the connection alive by sending at least one frame every **2 minutes**. This can be either: * A **WebSocket ping frame** * **Any application-level message** If the server receives no frames from a client within the 2-minute window, it will close the connection. Support for `permessage-deflate` compression is enabled. Clients that fall behind on reading messages may be disconnected more aggressively than before. Send Tx [](https://apidocs.lighter.xyz/docs/websocket-reference#send-tx) ============================================================================ You can send transactions using the websocket as follows: JSON { "type": "jsonapi/sendtx", "data": { "tx_type": INTEGER, "tx_info": ... } } The _tx\_type_ options can be found in the [SignerClient](https://github.com/elliottech/lighter-python/blob/main/lighter/signer_client.py) file, while _tx\_info_ can be generated using the sign methods in the SignerClient. Example: [ws\_send\_tx.py](https://github.com/elliottech/lighter-python/blob/main/examples/ws_send_tx.py) Send Batch Tx [](https://apidocs.lighter.xyz/docs/websocket-reference#send-batch-tx) ======================================================================================== You can send batch transactions to execute up to 15 transactions in a single message. JSON { "type": "jsonapi/sendtxbatch", "data": { "tx_types": "[INTEGER]", "tx_infos": "[tx_info]" } } The _tx\_type_ options can be found in the [SignerClient](https://github.com/elliottech/lighter-python/blob/main/lighter/signer_client.py) file, while _tx\_info_ can be generated using the sign methods in the SignerClient. Example: [ws\_send\_batch\_tx.py](https://github.com/elliottech/lighter-python/blob/main/examples/ws_send_batch_tx.py) Types [](https://apidocs.lighter.xyz/docs/websocket-reference#types) ======================================================================== We first need to define some types that appear often in the JSONs. Transaction JSON [](https://apidocs.lighter.xyz/docs/websocket-reference#transaction-json) ---------------------------------------------------------------------------------------------- To decode `event_info`, you can refer to [Data Structures](https://apidocs.lighter.xyz/docs/data-structures-constants-and-errors) . JSON Transaction = { "hash": STRING, "type": INTEGER, "info": STRING, // json object as string, attributes depending on the tx type "event_info": STRING, // json object as string, attributes depending on the tx type "status": INTEGER, "transaction_index": INTEGER, "l1_address": STRING, "account_index": INTEGER, "nonce": INTEGER, "expire_at": INTEGER, "block_height": INTEGER, "queued_at": INTEGER, "executed_at": INTEGER, "sequence_index": INTEGER, "parent_hash": STRING, "api_key_index": INTEGER, "transaction_time": INTEGER } Example: JSON { "hash": "0xabc123456789def", "type": 15, "info": "{\"AccountIndex\":1,\"ApiKeyIndex\":2,\"MarketIndex\":3,\"Index\":404,\"ExpiredAt\":1700000000000,\"Nonce\":1234,\"Sig\":\"0xsigexample\"}", "event_info": "{\"a\":1,\"i\":404,\"u\":123,\"ae\":\"\"}", "status": 2, "transaction_index": 10, "l1_address": "0x123abc456def789", "account_index": 101, "nonce": 12345, "expire_at": 1700000000000, "block_height": 1500000, "queued_at": 1699999990000, "executed_at": 1700000000005, "sequence_index": 5678, "parent_hash": "0xparenthash123456", "api_key_index": 2, "transaction_time": 1700000000005000 } Used in: [Account Tx](doc:websocket-reference#account-tx) . Order JSON [](https://apidocs.lighter.xyz/docs/websocket-reference#order-json) ---------------------------------------------------------------------------------- JSON Order = { "order_index": INTEGER, "client_order_index": INTEGER, "order_id": STRING, // same as order_index but string "client_order_id": STRING, // same as client_order_index but string "market_index": INTEGER, "owner_account_index": INTEGER, "initial_base_amount": STRING, "price": STRING, "nonce": INTEGER, "remaining_base_amount": STRING, "is_ask": BOOLEAN, "base_size": INTEGER, "base_price": INTEGER, "filled_base_amount": STRING, "filled_quote_amount": STRING, "side": STRING, "type": "limit" | "market" | "stop-loss" | "stop-loss-limit" | "take-profit" | "take-profit-limit" | "twap" | "twap-sub" | "liquidation", "time_in_force": "good-till-time" | "immediate-or-cancel" | "post-only" | "Unknown", "reduce_only": BOOLEAN, "trigger_price": STRING, "order_expiry": INTEGER, "status": "in-progress" | "pending" | "open" | "filled" | "canceled" | "canceled-post-only" | "canceled-reduce-only" | "canceled-position-not-allowed" | "canceled-margin-not-allowed" | "canceled-too-much-slippage" | "canceled-not-enough-liquidity" | "canceled-self-trade" | "canceled-expired" | "canceled-oco" | "canceled-child" | "canceled-liquidation" | "canceled-invalid-balance", "trigger_status": "na" | "ready" | "mark-price" | "twap" | "parent-order", "trigger_time": INTEGER, "parent_order_index": INTEGER, "parent_order_id": STRING, "to_trigger_order_id_0": STRING, "to_trigger_order_id_1": STRING, "to_cancel_order_id_0": STRING, "integrator_fee_collector_index": STRING, "integrator_taker_fee": STRING, "integrator_maker_fee": STRING, "block_height": INTEGER, "timestamp": INTEGER, "created_at": INTEGER, "updated_at": INTEGER, "transaction_time": INTEGER } Used in: [Account Market](doc:websocket-reference#account-market) , [Account All Orders](doc:websocket-reference#account-all-orders) , [Account Orders](doc:websocket-reference#account-orders) . Trade JSON [](https://apidocs.lighter.xyz/docs/websocket-reference#trade-json) ---------------------------------------------------------------------------------- JSON Trade = { "trade_id": INTEGER, "trade_id_str": STRING, "tx_hash": STRING, "type": "trade" | "liquidation" | "deleverage" | "market-settlement", "market_id": INTEGER, "size": STRING, "price": STRING, "usd_amount": STRING, "ask_id": INTEGER, "ask_id_str": STRING, "bid_id": INTEGER, "bid_id_str": STRING, "ask_client_id": INTEGER, "ask_client_id_str": STRING, "bid_client_id": INTEGER, "bid_client_id_str": STRING, "ask_account_id": INTEGER, "bid_account_id": INTEGER, "is_maker_ask": BOOLEAN, "block_height": INTEGER, "timestamp": INTEGER, "taker_fee": INTEGER, // omitempty "taker_position_size_before": STRING, // omitempty "taker_entry_quote_before": STRING, // omitempty "taker_initial_margin_fraction_before": INTEGER, // omitempty "taker_position_sign_changed": BOOLEAN, // omitempty "maker_fee": INTEGER, // omitempty "maker_position_size_before": STRING, // omitempty "maker_entry_quote_before": STRING, // omitempty "maker_initial_margin_fraction_before": INTEGER, // omitempty "maker_position_sign_changed": BOOLEAN, // omitempty "transaction_time": INTEGER, "ask_account_pnl": STRING, // omitempty "bid_account_pnl": STRING // omitempty } Example: JSON { "trade_id":16164557907, "trade_id_str":"16164557907", "tx_hash":"019f2b9c9cc609196316a569541e135a739728e0837fcfb05c913534e305e503c01d5dcfeabeaf81", "type":"trade", "market_id":0, "size":"0.1336", "price":"2181.83", "usd_amount":"291.492488", "ask_id":281476612587355, "ask_id_str":"281476612587355", "bid_id":562948334068259, "bid_id_str":"562948334068259", "ask_client_id":363283, "ask_client_id_str":"363283", "bid_client_id":23004521241, "bid_client_id_str":"23004521241", "ask_account_id":57890, "bid_account_id":317068, "is_maker_ask":false, "block_height":198321831, "timestamp":1773854156654, "taker_position_size_before":"80.5467", "taker_entry_quote_before":"178806.039128", "taker_initial_margin_fraction_before":500, "taker_fee": 196, // omitted if zero "maker_fee":28, "maker_position_size_before":"-4.3180", "maker_entry_quote_before":"9419.085856", "maker_initial_margin_fraction_before":200, "transaction_time":1773854156686065 } Used in: [Trade](doc:websocket-reference#trade) , [Account All](doc:websocket-reference#account-all) , [Account Market](doc:websocket-reference#account-market) , [Account All Trades](doc:websocket-reference#account-all-trades) . Position JSON [](https://apidocs.lighter.xyz/docs/websocket-reference#position-json) ---------------------------------------------------------------------------------------- JSON Position = { "market_id": INTEGER, "symbol": STRING, "initial_margin_fraction": STRING, "open_order_count": INTEGER, "pending_order_count": INTEGER, "position_tied_order_count": INTEGER, "sign": INTEGER, "position": STRING, "avg_entry_price": STRING, "position_value": STRING, "unrealized_pnl": STRING, "realized_pnl": STRING, "liquidation_price": STRING, "total_funding_paid_out": STRING, // omitempty "margin_mode": INTEGER, "allocated_margin": STRING, "total_discount": STRING // omitempty } Example: JSON { "market_id": 101, "symbol": "BTC-USD", "initial_margin_fraction": "0.1", "open_order_count": 2, "pending_order_count": 1, "position_tied_order_count": 3, "sign": 1, "position": "0.5", "avg_entry_price": "20000.00", "position_value": "10000.00", "unrealized_pnl": "500.00", "realized_pnl": "100.00", "liquidation_price": "3024.66", "total_funding_paid_out": "34.2", "margin_mode": 1, "allocated_margin": "46342", } Used in: [Account All](doc:websocket-reference#account-all) , [Account Market](doc:websocket-reference#account-market) , [Account All Positions](doc:websocket-reference#account-all-positions) . PoolShares JSON [](https://apidocs.lighter.xyz/docs/websocket-reference#poolshares-json) -------------------------------------------------------------------------------------------- JSON PoolShares = { "public_pool_index": INTEGER, "shares_amount": INTEGER, "entry_usdc": STRING, "principal_amount": STRING, "entry_timestamp": INTEGER } Example: JSON { "public_pool_index": 1, "shares_amount": 100, "entry_usdc": "1000.00", "principal_amount": "3000", "entry_timestamp": 3600000 } Used in: [Account All](doc:websocket-reference#account-all) , [Account All Positions](doc:websocket-reference#account-all-positions) . Asset JSON [](https://apidocs.lighter.xyz/docs/websocket-reference#asset-json) ---------------------------------------------------------------------------------- JSON Asset = { "symbol": STRING, "asset_id": INTEGER, "balance": STRING, "locked_balance": STRING } Example: JSON Asset = { "symbol": "ETH", "asset_id": 1, "balance": "6691.4917", "locked_balance": "564.6135" } Used in: [Account All Assets](https://apidocs.lighter.xyz/docs/websocket-reference#account-all-assets) , [Account Market](https://apidocs.lighter.xyz/docs/websocket-reference#account-market) , [Account All](https://apidocs.lighter.xyz/docs/websocket-reference#account-all) . PositionFunding JSON [](https://apidocs.lighter.xyz/docs/websocket-reference#positionfunding-json) ------------------------------------------------------------------------------------------------------ JSON PositionFunding = { "timestamp": INTEGER, "market_id": INTEGER, "funding_id": INTEGER, "change": STRING, "rate": STRING, "position_size": STRING, "position_side": "long" | "short", "discount": STRING } JSON { "timestamp": 1773850000000, "market_id": 0, "funding_id": 2001, "change": "0.001", "rate": "0.0001", "position_size": "0.5", "position_side": "long", "discount": "0" } Channels [](https://apidocs.lighter.xyz/docs/websocket-reference#channels) ============================================================================== To unsubscribe from a channel, use the following syntax: JSON { "type": "unsubscribe", "channel": STRING } Order Book [](https://apidocs.lighter.xyz/docs/websocket-reference#order-book) ---------------------------------------------------------------------------------- The order book channel sends the new ask and bid orders for the given market in batches, every 50ms. While the nonce is tied to Lighter's matching engine, the offset is tied to the API servers; hence, you can expect the offset to change drastically on reconnection if you're routed to a different server. Regardless, on each update the offset will increase, but it's not guaranteed to be continuous. Additionally, this channel sends a complete snapshot on subscription, but only state changes after that. To verify the continuity of the data, you can check that `begin_nonce` on the current update matches the `nonce` (i.e. `last_nonce`) of the previous update. JSON { "type": "subscribe", "channel": "order_book/{MARKET_INDEX}" } **Example Subscription** JSON { "type": "subscribe", "channel": "order_book/0" } **Response Structure** JSON { "channel": "order_book:{MARKET_INDEX}", "last_updated_at": INTEGER, "offset": INTEGER, "order_book": { "code": INTEGER, "asks": [\ {\ "price": STRING,\ "size": STRING\ }\ ], "bids": [\ {\ "price": STRING,\ "size": STRING\ }\ ], "offset": INTEGER, "nonce": INTEGER, "last_updated_at": INTEGER, "begin_nonce": INTEGER, }, "timestamp": INTEGER, "type": "update/order_book" } **Example Response** JSON { "channel":"order_book:0", "last_updated_at":1774884082309144, "offset":1558300, "order_book":{ "code":0, "asks":[\ {\ "price":"2064.54",\ "size":"0.3285"\ }\ ], "bids":[\ \ ], "offset":1558300, "nonce":9182390020, "last_updated_at":1774884082309144, "begin_nonce":9182389998 }, "timestamp":1774884082326, "type":"update/order_book" } Best Bid and Offer (BBO) [](https://apidocs.lighter.xyz/docs/websocket-reference#best-bid-and-offer-bbo) ------------------------------------------------------------------------------------------------------------ Updates are triggered on every nonce update for a given market's order book. JSON { "type":"subscribe", "channel":"ticker/{MARKET_INDEX}" } **Example subscription:** JSON { "type":"subscribe", "channel":"ticker/0" } **Response Structure:** JSON { "channel": "ticker:{MARKET_INDEX}", "last_updated_at": INTEGER, "nonce": INTEGER, "ticker":{ "s": STRING, "a":{ "price": STRING, "size": STRING }, "b":{ "price": STRING, "size": STRING }, "last_updated_at":INTEGER }, "timestamp": INTEGER, "type":"update/ticker" } **Example Response:** JSON { "channel":"ticker:0", "last_updated_at":1774883844921166, "nonce":9182249734, "ticker":{ "s":"ETH", "a":{ "price":"2064.48", "size":"0.4950" }, "b":{ "price":"2064.30", "size":"1.0392" }, "last_updated_at":1774883844921166 }, "timestamp":1774883844933, "type":"update/ticker" } Market Stats [](https://apidocs.lighter.xyz/docs/websocket-reference#market-stats) -------------------------------------------------------------------------------------- The market stats channel sends the market stat data for a given market. `current_funding_rate` is an estimation of the upcoming funding payment, while `funding_rate` represents the last funding payment that occurred (at `funding_timestamp`). To fetch stats for spot markets, use [spot\_market\_stats](page:spot-market-stats) . JSON { "type": "subscribe", "channel": "market_stats/{MARKET_INDEX}" } or JSON { "type": "subscribe", "channel": "market_stats/all" } **Example Subscription** JSON { "type": "subscribe", "channel": "market_stats/0" } **Response Structure** JSON { "channel": "market_stats:{MARKET_INDEX}", "market_stats": { "symbol": STRING, "market_id": INTEGER, "index_price": STRING, "mark_price": STRING, "open_interest": STRING, "open_interest_limit": STRING, "funding_clamp_small": STRING, "funding_clamp_big": STRING, "last_trade_price": STRING, "current_funding_rate": STRING, "funding_rate": STRING, "funding_timestamp": INTEGER, "daily_base_token_volume": FLOAT, "daily_quote_token_volume": FLOAT, "daily_price_low": FLOAT, "daily_price_high": FLOAT, "daily_price_change": FLOAT }, "timestamp": INTEGER, "type": "update/market_stats" } **Example Response** JSON { "channel":"market_stats:0", "market_stats":{ "symbol":"ETH", "market_id":0, "index_price":"2965.30", "mark_price":"2963.63", "open_interest":"185926683.471886", "open_interest_limit":"72057594037927936.000000", "funding_clamp_small":"0.0500", "funding_clamp_big":"4.0000", "last_trade_price":"2963.67", "current_funding_rate":"-0.0005", "funding_rate":"0.0011", "funding_timestamp":1769187600001, "daily_base_token_volume":296009.9355, "daily_quote_token_volume":870882976.341333, "daily_price_low":2888.37, "daily_price_high":2984, "daily_price_change":0.830824189844348 }, "timestamp": 1773158679717, "type":"update/market_stats" } Trade [](https://apidocs.lighter.xyz/docs/websocket-reference#trade) ------------------------------------------------------------------------ The trade channel sends the new trade data for the given market. JSON { "type": "subscribe", "channel": "trade/{MARKET_INDEX}" } **Example Subscription** JSON { "type": "subscribe", "channel": "trade/0" } **Response Structure** JSON { "channel": "trade:{MARKET_INDEX}", "liquidation_trades": [Trade], "nonce":INTEGER, "trades": [Trade], "type": "update/trade" } **Example Response** JSON { "channel":"trade:0", "liquidation_trades":[], "nonce":8630448841, "trades":[\ {\ "trade_id":16164557907,\ "trade_id_str":"16164557907",\ "tx_hash":"019f2b9c9cc609196316a569541e135a739728e0837fcfb05c913534e305e503c01d5dcfeabeaf81",\ "type":"trade",\ "market_id":0,\ "size":"0.1336",\ "price":"2181.83",\ "usd_amount":"291.492488",\ "ask_id":281476612587355,\ "ask_id_str":"281476612587355",\ "bid_id":562948334068259,\ "bid_id_str":"562948334068259",\ "ask_client_id":363283,\ "ask_client_id_str":"363283",\ "bid_client_id":23004521241,\ "bid_client_id_str":"23004521241",\ "ask_account_id":57890,\ "bid_account_id":317068,\ "is_maker_ask":false,\ "block_height":198321831,\ "timestamp":1773854156654,\ "taker_position_size_before":"80.5467",\ "taker_entry_quote_before":"178806.039128",\ "taker_initial_margin_fraction_before":500,\ "taker_fee": 196, // omitted if zero\ "maker_fee":28,\ "maker_position_size_before":"-4.3180",\ "maker_entry_quote_before":"9419.085856",\ "maker_initial_margin_fraction_before":200,\ "transaction_time":1773854156686065\ }\ ], "type":"update/trade" } Account All [](https://apidocs.lighter.xyz/docs/websocket-reference#account-all) ------------------------------------------------------------------------------------ The account all channel sends specific account market data for all markets. On every new subscription message sent, you will reconnect and receive a new snapshot. JSON { "type": "subscribe", "channel": "account_all/{ACCOUNT_ID}" } **Example Subscription** JSON { "type": "subscribe", "channel": "account_all/1" } **Response Structure** JSON { "account": INTEGER, "assets": { "{ASSET_INDEX}": Asset }, "channel": "account_all:{ACCOUNT_ID}", "daily_trades_count": INTEGER, "daily_volume": FLOAT, "weekly_trades_count": INTEGER, "weekly_volume": FLOAT, "monthly_trades_count": INTEGER, "monthly_volume": FLOAT, "total_trades_count": INTEGER, "total_volume": FLOAT, "funding_histories": [PositionFunding], "positions": { "{MARKET_INDEX}": Position }, "shares": [PoolShares], "trades": { "{MARKET_INDEX}": [Trade] }, "type": "update/account_all" } **Example Response** JSON { "account": 10, "assets": { "1": { "symbol":"ETH", "asset_id":1, "balance":"1", "locked_balance":"0.00000000" } }, "channel": "account_all:10", "daily_trades_count": 123, "daily_volume": 234, "weekly_trades_count": 345, "weekly_volume": 456, "monthly_trades_count": 567, "monthly_volume": 678, "total_trades_count": 891, "total_volume": 912, "funding_histories": { "1": { "timestamp": 1700000000, "market_id": 101, "funding_id": 2001, "change": "0.001", "rate": "0.0001", "position_size": "0.5", "position_side": "long" } }, "positions": { "1": { "market_id": 101, "symbol": "BTC-USD", "initial_margin_fraction": "0.1", "open_order_count": 2, "pending_order_count": 1, "position_tied_order_count": 3, "sign": 1, "position": "0.5", "avg_entry_price": "20000.00", "position_value": "10000.00", "unrealized_pnl": "500.00", "realized_pnl": "100.00", "liquidation_price": "3024.66", "total_funding_paid_out": "34.2", "margin_mode": 1, "allocated_margin": "46342", } }, "shares": { "public_pool_index": 1, "shares_amount": 100, "entry_usdc": "1000.00" }, "trades": { "1": { "trade_id": 401, "tx_hash": "0xabc123456789", "type": "buy", "market_id": 101, "size": "0.5", "price": "20000.00", "usd_amount": "10000.00", "ask_id": 501, "bid_id": 502, "ask_account_id": 123456, "bid_account_id": 654321, "is_maker_ask": true, "block_height": 1500000, "timestamp": 1700000000, "taker_position_size_before":"1.14880", "taker_entry_quote_before":"136130.046511", "taker_initial_margin_fraction_before":500, "maker_position_size_before":"-0.02594", "maker_entry_quote_before":"3075.396750", "maker_initial_margin_fraction_before":400 } }, "type": "update/account_all" } Account Market [](https://apidocs.lighter.xyz/docs/websocket-reference#account-market) ------------------------------------------------------------------------------------------ The account market channel sends specific account market data for a market. If `{MARKET_ID}` is a perpetual market, `assets` will return `null`, if `{MARKET_ID}` is a spot market, `funding_history` will return `null`. JSON { "type": "subscribe", "channel": "account_market/{MARKET_ID}/{ACCOUNT_ID}", "auth": "{AUTH_TOKEN}" } **Example Subscription** JSON { "type": "subscribe", "channel": "account_market/0/40", "auth": "{AUTH_TOKEN}" } **Response Structure** JSON { "account": INTEGER, "assets": [Asset], "channel": "account_market/{MARKET_ID}/{ACCOUNT_ID}", "funding_history": { "timestamp": INTEGER, "market_id": INTEGER, "funding_id": INTEGER, "change": STRING, "rate": STRING, "position_size": STRING, "position_side": STRING }, "orders": [Order], "position": [Position], "trades": [Trade], "type": "update/account_market" } Account Stats [](https://apidocs.lighter.xyz/docs/websocket-reference#account-stats) ---------------------------------------------------------------------------------------- The account stats channel sends account stats data for the specific account. JSON { "type": "subscribe", "channel": "user_stats/{ACCOUNT_ID}" } **Example Subscription** JSON { "type": "subscribe", "channel": "user_stats/1234" } **Response Structure** JSON { "channel": "user_stats:{ACCOUNT_ID}", "stats": { "collateral": STRING, "portfolio_value": STRING, "leverage": STRING, "available_balance": STRING, "margin_usage": STRING, "buying_power": STRING, "account_trading_mode": INTEGER, "cross_stats":{ "collateral": STRING, "portfolio_value": STRING, "leverage": STRING, "available_balance": STRING, "margin_usage": STRING, "buying_power": STRING }, "total_stats":{ "collateral": STRING, "portfolio_value": STRING, "leverage": STRING, "available_balance": STRING, "margin_usage": STRING, "buying_power": STRING } }, "timestamp": INTEGER, "type": "update/user_stats" } **Example Response** JSON { "channel": "user_stats:10", "stats": { "collateral": "5000.00", "portfolio_value": "15000.00", "leverage": "3.0", "available_balance": "2000.00", "margin_usage": "0.80", "buying_power": "4000.00", "account_trading_mode": 1, "cross_stats":{ "collateral":"0.000000", "portfolio_value":"0.000000", "leverage":"0.00", "available_balance":"0.000000", "margin_usage":"0.00", "buying_power":"0" }, "total_stats":{ "collateral":"0.000000", "portfolio_value":"0.000000", "leverage":"0.00", "available_balance":"0.000000", "margin_usage":"0.00", "buying_power":"0" } }, "timestamp": 1773158679717, "type": "update/user_stats" } Account Tx [](https://apidocs.lighter.xyz/docs/websocket-reference#account-tx) ---------------------------------------------------------------------------------- This channel sends transactions related to a specific account. JSON { "type": "subscribe", "channel": "account_tx/{ACCOUNT_ID}", "auth": "{AUTH_TOKEN}" } **Response Structure** JSON { "channel": "account_tx:{ACCOUNT_ID}", "txs": [Account_tx], "type": "update/account_tx" } Account All Orders [](https://apidocs.lighter.xyz/docs/websocket-reference#account-all-orders) -------------------------------------------------------------------------------------------------- The account all orders channel sends data about all the orders of an account. JSON { "type": "subscribe", "channel": "account_all_orders/{ACCOUNT_ID}", "auth": "{AUTH_TOKEN}" } **Response Structure** JSON { "channel": "account_all_orders:{ACCOUNT_ID}", "orders": { "{MARKET_INDEX}": [Order] }, "type": "update/account_all_orders" } Height [](https://apidocs.lighter.xyz/docs/websocket-reference#height) -------------------------------------------------------------------------- Blockchain height updates JSON { "type": "subscribe", "channel": "height" } **Response Structure** JSON { "channel": "height", "height": INTEGER, "timestamp": INTEGER, "type": "update/height" } Pool data [](https://apidocs.lighter.xyz/docs/websocket-reference#pool-data) -------------------------------------------------------------------------------- Provides data about pool activities: trades, orders, positions, shares and funding histories. JSON { "type": "subscribe", "channel": "pool_data/{ACCOUNT_ID}", "auth": "{AUTH_TOKEN}" } **Response Structure** JSON { "channel": "pool_data:{ACCOUNT_ID}", "account": INTEGER, "trades": { "{MARKET_INDEX}": [Trade] }, "orders": { "{MARKET_INDEX}": [Order] }, "positions": { "{MARKET_INDEX}": [Position] }, "shares": [PoolShares], "funding_histories": { "{MARKET_INDEX}": [PositionFunding] }, "type": "subscribed/pool_data" } Pool info [](https://apidocs.lighter.xyz/docs/websocket-reference#pool-info) -------------------------------------------------------------------------------- Provides information about pools. JSON { "type": "subscribe", "channel": "pool_info/{ACCOUNT_ID}", "auth": "{AUTH_TOKEN}" } **Response Structure** JSON { "channel": "pool_info:{ACCOUNT_ID}", "pool_info": { "status": INTEGER, "operator_fee": STRING, "min_operator_share_rate": STRING, "total_shares": INTEGER, "operator_shares": INTEGER, "annual_percentage_yield": FLOAT, "sharpe_ratio": FLOAT, "daily_returns": [\ {\ "timestamp": INTEGER,\ "daily_return": FLOAT\ }\ ], "share_prices": [\ {\ "timestamp": INTEGER,\ "share_price": FLOAT\ }\ ], "strategies": [\ {\ "collateral": STRING\ }\ ] }, "type": "subscribed/pool_info" } Notification [](https://apidocs.lighter.xyz/docs/websocket-reference#notification) -------------------------------------------------------------------------------------- Provides notifications received by an account. Notifications can be of three kinds: liquidation, deleverage, or announcement. Each kind has a different content structure. JSON { "type": "subscribe", "channel": "notification/{ACCOUNT_ID}", "auth": "{AUTH_TOKEN}" } **Response Structure** JSON { "channel": "notification:{ACCOUNT_ID}", "notifs": [\ {\ "id": STRING,\ "created_at": STRING,\ "updated_at": STRING,\ "kind": STRING,\ "account_index": INTEGER,\ "content": NotificationContent,\ "ack": BOOLEAN,\ "acked_at": STRING\ }\ ], "type": "subscribed/notification" } **Liquidation Notification Content** JSON { "id": STRING, "is_ask": BOOL, "usdc_amount": STRING, "size": STRING, "market_index": INTEGER, "price": STRING, "timestamp": INTEGER, "avg_price": STRING } **Deleverage Notification Content** JSON { "id": STRING, "usdc_amount": STRING, "size": STRING, "market_index": INTEGER, "settlement_price": STRING, "timestamp": INTEGER } **Announcement Notification Content** JSON { "title": STRING, "content": STRING, "created_at": INTEGER } **Example response** JSON { "channel": "notification:12345", "notifs": [\ {\ "id": "notif_123",\ "created_at": "2024-01-15T10:30:00Z",\ "updated_at": "2024-01-15T10:30:00Z",\ "kind": "liquidation",\ "account_index": 12345,\ "content": {\ "id": "notif_123",\ "is_ask": false,\ "usdc_amount": "1500.50",\ "size": "0.500000",\ "market_index": 1,\ "price": "3000.00",\ "timestamp": 1705312200,\ "avg_price": "3000.00"\ },\ "ack": false,\ "acked_at": null\ },\ {\ "id": "notif_124",\ "created_at": "2024-01-15T11:00:00Z",\ "updated_at": "2024-01-15T11:00:00Z",\ "kind": "deleverage",\ "account_index": 12345,\ "content": {\ "id": "notif_124",\ "usdc_amount": "500.25",\ "size": "0.200000",\ "market_index": 1,\ "settlement_price": "2501.25",\ "timestamp": 1705314000\ },\ "ack": false,\ "acked_at": null\ }\ ], "type": "update/notification" } Account Orders [](https://apidocs.lighter.xyz/docs/websocket-reference#account-orders) ------------------------------------------------------------------------------------------ The account orders channel sends data about the orders of an account on a certain market. JSON { "type": "subscribe", "channel": "account_orders/{MARKET_INDEX}/{ACCOUNT_ID}", "auth": "{AUTH_TOKEN}" } **Response Structure** JSON { "account": {ACCOUNT_INDEX}, "channel": "account_orders:{MARKET_INDEX}", "nonce": INTEGER, "orders": { "{MARKET_INDEX}": [Order] // the only present market index will be the one provided }, "type": "update/account_orders" } Account All Trades [](https://apidocs.lighter.xyz/docs/websocket-reference#account-all-trades) -------------------------------------------------------------------------------------------------- The account all trades channel sends data about all the trades of an account. `auth` is required, unless `account_id` pertains to a public pool. JSON { "type": "subscribe", "channel": "account_all_trades/{ACCOUNT_ID}", "auth": "{AUTH_TOKEN}" } **Response Structure** JSON { "channel": "account_all_trades:{ACCOUNT_ID}", "trades": [], "total_volume": FLOAT, "monthly_volume": FLOAT, "weekly_volume": FLOAT, "daily_volume": FLOAT, "type": "subscribed/account_all_trades" } JSON { "channel": "account_all_trades:{ACCOUNT_ID}", "trades": { "{MARKET_INDEX}": [Trade] }, "type": "update/account_all_trades" } Account All Positions [](https://apidocs.lighter.xyz/docs/websocket-reference#account-all-positions) -------------------------------------------------------------------------------------------------------- The account all positions channel sends data about all the positions of an account. `auth` is required, unless `account_id` pertains to a public pool. JSON { "type": "subscribe", "channel": "account_all_positions/{ACCOUNT_ID}", "auth": "{AUTH_TOKEN}" } **Response Structure** JSON { "channel": "account_all_positions:{ACCOUNT_ID}", "positions": { "{MARKET_INDEX}": Position }, "shares": [PoolShares], "type": "subscribed/account_all_positions", } JSON { "channel": "account_all_positions:{ACCOUNT_ID}", "positions": { "{MARKET_INDEX}": Position }, "shares": [PoolShares], "last_funding_round": { // optional, only present when funding occurs "{MARKET_INDEX}": STRING }, "last_funding_discount": { // optional, only present when funding occurs "{MARKET_INDEX}": STRING }, "type": "update/account_all_positions", } Spot Market Stats [](https://apidocs.lighter.xyz/docs/websocket-reference#spot-market-stats) ------------------------------------------------------------------------------------------------ The spot market stats channel sends the market stat data for the given spot market. JSON { "type": "subscribe", "channel": "spot_market_stats/{MARKET_INDEX}" } or JSON { "type": "subscribe", "channel": "spot_market_stats/all" } **Example Subscription** JSON { "type": "subscribe", "channel": "spot_market_stats/2048" } **Response Structure** **using `all`** JSON { "channel": "spot_market_stats:all", "spot_market_stats": { "{MARKET_INDEX}": { "symbol": STRING, "market_id": INTEGER, "index_price": STRING, "mid_price": STRING, "last_trade_price": STRING, "daily_base_token_volume": FLOAT, "daily_quote_token_volume": FLOAT, "daily_price_low": FLOAT, "daily_price_high": FLOAT, "daily_price_change": FLOAT } }, "timestamp": INTEGER, "type": "update/spot_market_stats" } **Example Response** **using `all`** JSON { "channel":"spot_market_stats:all", "spot_market_stats":{ "2048":{ "symbol":"ETH/USDC", "market_id":2048, "index_price":"2188.994707", "mid_price":"2188.90", "last_trade_price":"2190.25", "daily_base_token_volume":681.5806, "daily_quote_token_volume":1535781.121577, "daily_price_low":2166.63, "daily_price_high":2347.78, "daily_price_change":-5.917096219931271 } }, "timestamp":1773860622360, "type":"update/spot_market_stats" } **Response Structure** **using `MARKET_INDEX`** JSON { "channel": "spot_market_stats:{MARKET_INDEX}", "spot_market_stats": { "symbol": STRING, "market_id": INTEGER, "index_price": STRING, "mid_price": STRING, "last_trade_price": STRING, "daily_base_token_volume": FLOAT, "daily_quote_token_volume": FLOAT, "daily_price_low": FLOAT, "daily_price_high": FLOAT, "daily_price_change": FLOAT }, "timestamp": INTEGER, "type": "update/spot_market_stats" } **Example Response** **using `MARKET_INDEX`** JSON { "channel":"spot_market_stats:2048", "spot_market_stats":{ "symbol":"ETH/USDC", "market_id":2048, "index_price":"2183.030179", "mid_price":"2182.60", "last_trade_price":"2179.81", "daily_base_token_volume":670.444, "daily_quote_token_volume":1511428.664237, "daily_price_low":2166.63, "daily_price_high":2347.78, "daily_price_change":-6.365549828178694 }, "timestamp":1773860440362, "type":"update/spot_market_stats" } Account All Assets [](https://apidocs.lighter.xyz/docs/websocket-reference#account-all-assets) -------------------------------------------------------------------------------------------------- The account all assets channel sends specific account market data for all spot markets for a specific account. `balance` is in coin terms, not USDC (unless asset\_index=3, in which case they coincide). JSON { "type": "subscribe", "channel": "account_all_assets/{ACCOUNT_ID}", "auth": "{AUTH_TOKEN}" } **Example Subscription** JSON { "type": "subscribe", "channel": "account_all_assets/1234", "auth": "{AUTH_TOKEN}" } **Response Structure** JSON { "assets": { "{ASSET_INDEX}": Asset, "{ASSET_INDEX}": Asset }, "channel": "account_all_assets:{ACCOUNT_ID}", "timestamp": INTEGER, "type": "update/account_all_assets" } **Example Response** JSON { "assets": { "1": { "symbol": "ETH", "asset_id": 1, "balance": "7.1072", "locked_balance": "0.0000" }, "3": { "symbol": "USDC", "asset_id": 3, "balance": "6343.581906", "locked_balance": "297.000000" } }, "channel": "account_all_assets:1234", "timestamp": 1773158679717, "type": "update/account_all_assets" } Average Entry Prices [](https://apidocs.lighter.xyz/docs/websocket-reference#average-entry-prices) ------------------------------------------------------------------------------------------------------ Updates on the `account_spot_avg_entry_prices` channel are triggered whenever an event occurs for a given spot asset. Each event is accounted for as a buy or sell executed at the index price. Events include trades, deposits, withdrawals, transfers, and staking. The `last_trade_id` field confirms the validity of the data returned up to that `trade_id`. JSON { "type": "subscribe", "channel": "account_spot_avg_entry_prices/{ACCOUNT_ID}", "auth": "{AUTH_TOKEN}" } **Example subscription:** JSON { "type": "subscribe", "channel": "account_spot_avg_entry_prices/1234", "auth": "{AUTH_TOKEN}" } **Response Structure:** JSON { "avg_entry_prices":{ "{ASSET_INDEX}":{ "asset_id":INTEGER, "avg_entry_price":STRING, "asset_size":STRING, "last_trade_id":INTEGER } }, "channel":"account_spot_avg_entry_prices:{account_index}", "timestamp": INTEGER, "type":"subscribed/account_spot_avg_entry_prices" } **Example Response:** JSON { "avg_entry_prices":{ "1":{ "asset_id":1, "avg_entry_price":"1850.45", "asset_size":"0.01234567", "last_trade_id":13472591098 } }, "channel":"account_spot_avg_entry_prices:1234", "timestamp": 1773158679717, "type":"subscribed/account_spot_avg_entry_prices" } Updated 3 days ago * * * Ask AI --- # Volume Quota **Volume Quota** gives users higher rate limits on `SendTx` and `SendTxBatch`based on trading volume and is **only available to Premium accounts now**. The only types of transactions that consume volume quota are: * `L2CreateOrder` (14) * `L2CancelAllOrders` (16) * `L2ModifyOrder` (17) * `L2CreateGroupedOrders` (28) Other types of transactions has separate rate limits, see [Transaction Type Limits](https://apidocs.lighter.xyz/docs/rate-limits#transaction-type-limits-per-user) . For more details on transaction types, see [constants.go](https://github.com/elliottech/lighter-go/blob/37514ad5630052c162fa0745ac59ae47ff33d148/types/txtypes/constants.go#L57) . Grouped orders only consume one quota. Cancels do not consume quota. If you include `n` transactions in a `SendTxBatch` request, `n` quota will be consumed. For every 3 USD of trading volume, traders receive an additional transaction limit (i.e. volume quota increases by 1). `SendTx` and `SendTxBatch` requests will return a response indicating the remaining quota, e.g. "10780 volume quota remaining.". Every 15 seconds, you get a free `SendTx` which won't consume volume quota (nor show remaining quota). Volume quota is shared across all sub-accounts under the same L1 address. New accounts start at 1K quota, and you can stack at most 5.000.000 TX allowance in your volume quota, which does not expire. This differs from Rate Limits, which enforce a maximum of **24000** weight per **60** seconds (rolling minute) for premium accounts. You can check the weight of the endpoints, and standard accounts limits here: [Rate Limits](doc:rate-limits) . Updated 10 days ago * * * Ask AI --- # Historical Data Users can fetch historical data using various REST endpoints, mainly: * [accountInactiveOrders](https://apidocs.lighter.xyz/reference/accountinactiveorders) * [trades](https://apidocs.lighter.xyz/reference/trades) * [logs](https://apidocs.lighter.xyz/reference/get_accounts-param-logs) * [tx](https://apidocs.lighter.xyz/reference/tx) * [pnl](https://apidocs.lighter.xyz/reference/pnl) * [deposit\_history](https://apidocs.lighter.xyz/reference/deposit_history) , [transfer\_history](https://apidocs.lighter.xyz/reference/transfer_history) , [withdraw\_history](https://apidocs.lighter.xyz/reference/withdraw_history) * [candles](https://apidocs.lighter.xyz/reference/candles) * [fundings](https://apidocs.lighter.xyz/reference/fundings) , [positionFunding](https://apidocs.lighter.xyz/reference/positionfunding) * [liquidations](https://apidocs.lighter.xyz/reference/liquidations) * [exchangeMetrics](https://apidocs.lighter.xyz/reference/exchangemetrics) , [executeStats](https://apidocs.lighter.xyz/reference/executestats) Alternatively, you can use [export](https://apidocs.lighter.xyz/reference/export) to obtain CSVs containing up to 12 months of trades, or up to 3 months of funding payments, for a specific account index. For interested parties, we're now able to share an S3 bucket containing all trade events going back to mainnet genesis updated daily. To obtain access, you can reach out to us via Discord #support. Updated about 23 hours ago * * * Ask AI --- # Partner Integration This guide explains how partners can integrate with Lighter programmatically to earn additional fees for trades executed through their applications. The program is permissionless, allowing any account index to be used to collect fees, including subaccounts. * * * Definitions [](https://apidocs.lighter.xyz/docs/partner-integration#definitions) ------------------------------------------------------------------------------------ **Partner**: You, the integrator building on top of Lighter. **Client**: Your user, or customer, whose transactions you send on their behalf. Both standard and premium accounts are accepted. * * * Integrator Approval [](https://apidocs.lighter.xyz/docs/partner-integration#integrator-approval) ---------------------------------------------------------------------------------------------------- Before you can append partner attributes to client transactions, they must submit an `ApproveIntegrator` transaction. Approving an account index associated with a different L1 address requires an L1 signature. However, if the account index is associated with the same L1 address, only an L2 signature is needed, so the Ethereum private key can be omitted in that case. This transaction authorizes you to charge additional taker/maker fees on trades originating from orders created through your platform, as defined via the [systemConfig](https://apidocs.lighter.xyz/reference/systemconfig) endpoint. At any point in time, there can only be a maximum of 4 approved Partners per Client. ### Example (Python SDK) [](https://apidocs.lighter.xyz/docs/partner-integration#example-python-sdk) Python client.approve_integrator( eth_private_key=STRING, integrator_account_index=INTEGER, max_perps_taker_fee=INTEGER, max_perps_maker_fee=INTEGER, max_spot_taker_fee=INTEGER, max_spot_maker_fee=INTEGER, approval_expiry=INTEGER # in ms ) Python client.approve_integrator( eth_private_key="", integrator_account_index=1234, max_perps_taker_fee=1000, # 10 bps max_perps_maker_fee=1000, # 10 bps max_spot_taker_fee=1000, # 10 bps max_spot_maker_fee=1000, # 10 bps approval_expiry=1775518466000 # in ms ) You can find the full example [here](https://github.com/elliottech/lighter-python/blob/main/examples/integrator_approve.py) . To revoke an integrator before the allowance expires, you can send another `ApproveIntegrator` request setting all fees to zero. ### Fields Explanation [](https://apidocs.lighter.xyz/docs/partner-integration#fields-explanation) **IntegratorAccountIndex**: Partner's account index. All partner fees collected from client trades will be credited to this account. For perpetual markets, the fees are paid and credited in USDC (perps). For spot markets, the fees are paid and credited in the received asset (e.g. buying spot ETH means the Client pays fees in ETH directly). **Max Fees**: These values define the maximum fees you are allowed to charge your client. Fees are calculated as: `fee(bps) = trade_size × (fee_value / 1e6)` **Example:** MaxPerpsTakerFee = 500 500 / 1e6 = 0.0005 = 5 basis points This means you can charge up to **5 bps** of the trade quote for each perpetual taker order. **System-wide Maximums** Lighter enforces global maximum fee limits. If you submit an approval transaction exceeding these limits, the transaction will fail. Current limits can be checked via the [systemConfig](https://apidocs.lighter.xyz/reference/systemconfig) endpoint. **ApprovalExpiry** The timestamp when the integrator approval expires in a form of Unix timestamp in **milliseconds**. After this time, the partner must obtain approval again from the client. The maximum value you can send is equivalent to `2^48-1`. Creating Orders for Your Client [](https://apidocs.lighter.xyz/docs/partner-integration#creating-orders-for-your-client) ---------------------------------------------------------------------------------------------------------------------------- Once the integrator approval is successfully submitted, you can begin sending transactions for the client and collecting partner fees. When creating orders, include the following fields: Python IntegratorAccountIndex: INTEGER # the partner account index, where integrator fees will accrue IntegratorMakerFee: INTEGER # fee the partner wants to charge for maker trades IntegratorTakerFee: INTEGER # fee the partner wants to charge for taker trades These fees **must not exceed the maximum values** defined during the approval step. ### Example: Creating an Order via Python SDK [](https://apidocs.lighter.xyz/docs/partner-integration#example-creating-an-order-via-python-sdk) Python client.create_order( market_index=0, client_order_index=0 # bound to 2^48-1 base_amount=1000, # decimals as described in the orderBookDetails endpoint price=4050_00, # decimals as descibred in the orderBookDetails endpoin is_ask=True, # sell order_type=client.ORDER_TYPE_LIMIT, time_in_force=client.ORDER_TIME_IN_FORCE_GOOD_TILL_TIME, reduce_only=False, trigger_price=0, integrator_account_index=integrator_account_index, integrator_taker_fee=integrator_taker_fee, integrator_maker_fee=integrator_maker_fee, nonce=nonce, api_key_index=api_key_index, ) You can find the full example [here](https://github.com/elliottech/lighter-python/blob/main/examples/integrator_create_modify_order.py) . Updated 23 days ago * * * Ask AI --- # Manage Referrals Using an `auth` code, you can set which referral code to use on an account. To do so, use [referral\_use](https://apidocs.lighter.xyz/reference/use_referral_code) indicating your L1 address and the referral code you want to assign to it. Once done, you can check [userReferrals](https://apidocs.lighter.xyz/reference/userreferrals) from the account that created the referral code: there you should see the newly referred account with zero points earned (this updates based on points distribution). Updated 1 day ago * * * Ask AI --- # Priority Transactions Priority Transactions offer a way to interact with the Lighter protocol directly via Ethereum directly. You can think of them as censorship-resistant operations - and use them to e.g. cancel all orders or withdraw your collateral. They can be executed via Lighter's proxy smart contract on Ethereum, which holds the platform's collateral: `0x3B4D794a66304F130a4Db8F2551B0070dfCf5ca7`. **Read functions**: * `desertMode`: boolean, set to False unless desert mode gets activated. * `getPendingBalance`: the pending balance for a certain layer 1 account, you can find a complete list of asset IDs via the assetDetails [endpoint](https://apidocs.lighter.xyz/reference/assetdetails) . * `getPendingBalanceLegacy`: the pending balance for a certain layer 1 account before the spot upgrade. In this case, it can only be a USDC value. * `lastAccountIndex`: the highest account index assigned. Only accounts that deposit get assigned an account index, so that would represent the total number of wallets on the exchange. * `tokenToAssetIndex`: match an ERC20 contract address to its corresponding asset\_index on the Lighter protocol Most have been left out, but you can check out all functions on Ethereum block explorers, e.g. [Etherscan](https://etherscan.io/address/0x3B4D794a66304F130a4Db8F2551B0070dfCf5ca7#readProxyContract) . **Write functions**: * `activateDesertMode` * `burnShares`: allows you to burn shares of a Public Pool. * `cancelAllorders`: cancels all open orders on Lighter for the specified account index. * `cancelOustandingDepositsForDesertMode` * `changePubKey`: assign a newly created api key to an account index. Each key is tied to a single account index (if you use sub-accounts, you'll need to create new ones). * `deposit`: deposit assets to the platform. See [Deposits, Transfers and Withdrawals](doc:deposits-transfers-and-withdrawals) for more details. * `depositBatch`: deposit to multiple addresses. * `transferERC20`: transfer non-ETH spot assets between addresses. * `transferETH`: transfer mainnet ETH between addresses. * `withdraw`: withdraw assets from the platform. See [Deposits, Transfers and Withdrawals](doc:deposits-transfers-and-withdrawals) for more details. * `withdrawPendingBalance`: claim an existing secure withdrawal. Whenever the gas isn't too steep in price, withdrawals will be claimed by the platform on the users' behalf. * `withdrawPendingBalanceLegacy`: claim an existing secure withdrawal that was requested before the addition of spot assets to the protocol. Unlisted functions are reserved for the governor (a multi-sig controlled by the protocol) to manage markets and the protocol's settings. If you specify an account\_index, you should sign with the wallet that controls said index. Updated 2 months ago * * * Ask AI --- # Manage Public Pools Something to keep in mind is that Lighter considers Public Pools as a special type of Subaccount, where multiple users in addition to its owner can deposit in exchange for pool shares. Hence, you can trade on it via API as you would with a subaccount. Users can participate in Public Pools by creating and modifying them (on a whitelist basis), but also mint and burn shares via API. The corresponding transaction types are: * [TxTypeL2CreatePublicPool (10)](https://github.com/elliottech/lighter-python/blob/main/examples/public_pool_create_modify.py) * [TxTypeL2UpdatePublic Pool (11)](https://github.com/elliottech/lighter-python/blob/main/examples/public_pool_create_modify.py) * [TxL2TypeMintShares (18)](https://github.com/elliottech/lighter-python/blob/main/examples/public_pool_deposit.py) * [TxL2TypeBurnShares (19)](https://github.com/elliottech/lighter-python/blob/main/examples/public_pool_withdraw.py) In the hyperlinks, you can find the corresponding examples on the Python SDK using wrapper functions. You can monitor your shares using the [account](https://apidocs.lighter.xyz/reference/account-1) endpoint, the [publicPoolsMetadata](https://apidocs.lighter.xyz/reference/publicpoolsmetadata) endpoint, or any Websocket channel that contains the [PoolShares JSON](https://apidocs.lighter.xyz/docs/websocket-reference#poolshares-json) . Note that `entry_usdc` represents the USDC used to acquire pool shares - if you're looking to get an accurate price per share to date, you can query the [publicPoolsMetadata](https://apidocs.lighter.xyz/reference/publicpoolsmetadata) endpoint using `account_id` plus one. Staking pools are to be considered similar to public pools in structure, wth `principal_amount` representing the number of coins staked. This is what a request to fetch LLP's (281474976710654) metadata would look like: Shell curl --request GET \ --url 'https://mainnet.zklighter.elliot.ai/api/v1/publicPoolsMetadata?index=281474976710655&limit=1' \ --header 'accept: application/json' The response will look like this: JSON { "code": 200, "public_pools": [\ {\ "code": 0,\ "account_index": 281474976710654,\ "created_at": 1737098583,\ "master_account_index": 1,\ "account_type": 3,\ "name": "Lighter Liquidity Provider (LLP)",\ "l1_address": "0x0000000000000000000000000000000000000000",\ "annual_percentage_yield": 30.733724772746875,\ "sharpe_ratio": 5.004736993685667,\ "status": 0,\ "operator_fee": "0.0000",\ "total_asset_value": "693552603.614245",\ "total_shares": 208742636824\ }\ ] } If you provide `auth`, you can fetch your account's data as well from this endpoint without having to query the `account` one. To obtain `price_per_share` you can then simply calculate `total_asset_value`/`total_shares`. Updated 2 months ago * * * Ask AI --- # Multi-signature and smart wallets In the case of multi-signature and smart wallets, you can still access the front-end by signing with your api key with a priority transaction (i.e. using ethereum's priority transactions). To do this, make sure to tick the box shown in the authentication modal. ![](https://files.readme.io/7435a2372a7f5778f8d77ec3a9fdafa40e7738beec9e415c850aae293f54dd2d-image.png) While most features are available these type of wallts, there are some key differences if you're interacting with them through API. Specifically, functions that require your Ethereum private key as an argument won't be available (e.g. changing public key, and signing a transfer). While you can change public key via priority transactions, you cannot perform a transfer that way - making a secure withdrawal the only way to withdraw funds off the platform. Updated 2 months ago * * * Ask AI --- # Data Structures, Constants and Errors Data and Event Structures [](https://apidocs.lighter.xyz/docs/data-structures-constants-and-errors#data-and-event-structures) ================================================================================================================================= Go type Order struct { OrderIndex int64 `json:"i"` ClientOrderIndex int64 `json:"u"` OwnerAccountId int64 `json:"a"` InitialBaseAmount int64 `json:"is"` Price uint32 `json:"p"` RemainingBaseAmount int64 `json:"rs"` IsAsk uint8 `json:"ia"` Type uint8 `json:"ot"` TimeInForce uint8 `json:"f"` ReduceOnly uint8 `json:"ro"` TriggerPrice uint32 `json:"tp"` Expiry int64 `json:"e"` Status uint8 `json:"st"` TriggerStatus uint8 `json:"ts"` ToTriggerOrderIndex0 int64 `json:"t0"` ToTriggerOrderIndex1 int64 `json:"t1"` ToCancelOrderIndex0 int64 `json:"c0"` IntegratorFeeCollectorIndex int64 `json:"ifci"` IntegratorTakerFee uint32 `json:"itf"` IntegratorMakerFee uint32 `json:"imf"` } type OrderExecution struct { MarketId int16 `json:"m"` Trade *Trade `json:"t"` MakerOrder *Order `json:"mo"` TakerOrder *Order `json:"to"` AppError string `json:"ae"` } type CancelOrder struct { AccountId int64 `json:"a"` OrderIndex int64 `json:"i"` ClientOrderIndex int64 `json:"u"` AppError string `json:"ae"` } type ModifyOrder struct { MarketId uint8 `json:"m"` OldOrder *Order `json:"oo"` NewOrder *Order `json:"no"` AppError string `json:"ae"` } type Trade struct { Price uint32 `json:"p"` Size int64 `json:"s"` TakerFee int32 `json:"tf"` MakerFee int32 `json:"mf"` } // Order Status const ( InProgressOrder = iota // In register PendingOrder // Pending to be triggered ActiveLimitOrder // Active limit order FilledOrder // 3 CanceledOrder // 4 CanceledOrder_PostOnly // 5 CanceledOrder_ReduceOnly // 6 CanceledOrder_PositionNotAllowed // 7 CanceledOrder_MarginNotAllowed // 8 CanceledOrder_TooMuchSlippage // 9 CanceledOrder_NotEnoughLiquidity // 10 CanceledOrder_SelfTrade // 11 CanceledOrder_Expired // 12 CanceledOrder_OCO // 13 CanceledOrder_Child // 14 CanceledOrder_Liquidation // 15 CanceledOrder_InvalidBalance // 16 ) Constants [](https://apidocs.lighter.xyz/docs/data-structures-constants-and-errors#constants) ================================================================================================= Go TxTypeL2ChangePubKey = 8 TxTypeL2CreateSubAccount = 9 TxTypeL2CreatePublicPool = 10 TxTypeL2UpdatePublicPool = 11 TxTypeL2Transfer = 12 TxTypeL2Withdraw = 13 TxTypeL2CreateOrder = 14 TxTypeL2CancelOrder = 15 TxTypeL2CancelAllOrders = 16 TxTypeL2ModifyOrder = 17 TxTypeL2MintShares = 18 TxTypeL2BurnShares = 19 TxTypeL2UpdateLeverage = 20 TxTypeL2CreateGroupedOrders = 28 TxTypeL2UpdateMargin = 29 TxTypeL1BurnShares = 30 See all constants here: [https://github.com/elliottech/lighter-go/blob/37514ad5630052c162fa0745ac59ae47ff33d148/types/txtypes/constants.go](https://github.com/elliottech/lighter-go/blob/37514ad5630052c162fa0745ac59ae47ff33d148/types/txtypes/constants.go) Transaction Status Mapping [](https://apidocs.lighter.xyz/docs/data-structures-constants-and-errors#transaction-status-mapping) =================================================================================================================================== Go 0: Failed 1: Pending 2: Executed 3: Pending - Final State Error Codes [](https://apidocs.lighter.xyz/docs/data-structures-constants-and-errors#error-codes) ===================================================================================================== Go // Account AppErrAccountNotFound = NewBusinessError(21100, "account not found") AppErrAccountNonceNotFound = NewBusinessError(21101, "account nonce not found") AppErrInvalidAccountIndex = NewBusinessError(21102, "invalid account index") AppErrInvalidAccountL1Address = NewBusinessError(21103, "invalid account l1 address") AppErrInvalidNonce = NewBusinessError(21104, "invalid nonce") AppErrNonIncreasingNonce = NewBusinessError(21105, "batch transaction nonce is not increasing") AppErrAccountInvalidToAccount = NewBusinessError(21106, "invalid ToAccount") AppErrInvalidAccount = NewBusinessError(21107, "invalid account") AppErrInvalidPublicKey = NewBusinessError(21108, "invalid PublicKey,please run changePubKey") AppErrApiKeyNotFound = NewBusinessError(21109, "api key not found") AppErrInvalidApiKeyIndex = NewBusinessError(21110, "invalid api key index") AppErrPreLiquidation = NewBusinessError(21111, "account is in pre-liquidation and the transaction doesn't increase the account health") AppErrAccountIsInLiquidation = NewBusinessError(21112, "account is in liquidation") AppErrInvalidInitialMarginFraction = NewBusinessError(21113, "invalid initial margin fraction") AppErrFaultyLiquidation = NewBusinessError(21114, "account value is over maintenance margin, can't activate liquidation") AppErrWithdrawalAmountTooLow = NewBusinessError(21116, "withdrawal amount is too small") AppErrWithdrawalAmountTooHigh = NewBusinessError(21117, "withdrawal amount is too high") AppErrTransferAmountTooLow = NewBusinessError(21118, "transfer amount is too small") AppErrTransferAmountTooHigh = NewBusinessError(21119, "transfer amount is too high") AppErrInvalidSignature = NewBusinessError(21120, "invalid signature") AppErrBatchTxMultipleOwner = NewBusinessError(21121, "all transactions in the batch must have use same account and apikey") AppErrDeadMansSwitchShouldBeTriggered = NewBusinessError(21122, "dead man's switch should be triggered") AppErrInvalidAccountType = NewBusinessError(21123, "invalid account type") AppErrInvalidRouteType = NewBusinessError(21124, "invalid route type") // 21124 deprecated AppErrWitnessNotFound = NewBusinessError(21125, "witness not found") AppErrAccountHasZeroCollateral = NewBusinessError(21126, "Account with zero collateral can't change PublicKey") AppErrWithdrawalFromPublicPool = NewBusinessError(21127, "withdrawal from public pool is not allowed") AppErrInvalidMasterAccountIndex = NewBusinessError(21128, "invalid master account index") AppErrTooManySubAccounts = NewBusinessError(21129, "too many sub accounts") AppErrTooManyPublicPools = NewBusinessError(21130, "too many public pools") AppErrInvalidL1Address = NewBusinessError(21131, "invalid l1 address") AppErrMarginModeChangeOnActivePosition = NewBusinessError(21132, "margin mode change on a market with position or open order is not allowed") AppErrInvalidRiskChange = NewBusinessError(21133, "invalid risk change") AppErrInvalidFee = NewBusinessError(21134, "invalid fee") AppErrAssetAlreadyExist = NewBusinessError(21135, "asset already exist for given index") AppErrPublicKeyUpdateSdk = NewBusinessError(21136, "invalid PublicKey, update the sdk to the latest version") AppErrRestrictedWithdrawal = NewBusinessError(21137, "Withdrawals are restricted for this asset") AppErrMaxPendingUnlocksExceeded = NewBusinessError(21138, "maximum pending unlocks per account exceeded") AppErrNoPendingUnlocks = NewBusinessError(21139, "no pending unlocks for the account") AppErrPendingUnlockStillWaiting = NewBusinessError(21140, "pending unlock is still in waiting period") AppErrPendingUnlockInvalidAsset = NewBusinessError(21141, "only LIT asset can be used for pending unlock") // Public Pool AppErrInvalidPublicPoolIndex = NewBusinessError(21200, "invalid public pool index") AppErrInvalidOperatorFee = NewBusinessError(21201, "invalid operator fee") AppErrInvalidPublicPoolStatus = NewBusinessError(21202, "invalid public pool status") AppErrPublicPoolIsFrozen = NewBusinessError(21203, "public pool is frozen, only burning is allowed") AppErrPoolInitialTotalSharesInvalid = NewBusinessError(21204, "invalid pool initial usdc amount") AppErrInvalidMinOperatorShareRate = NewBusinessError(21205, "invalid min operator share rate") AppErrTooManyInvestedPublicPools = NewBusinessError(21206, "too many invested public pools") AppErrInsufficientAvailableShares = NewBusinessError(21207, "insufficient available shares") AppErrOwnerDropsBelowMinimumOwnership = NewBusinessError(21208, "owner drops below minimum ownership") AppErrInvalidMintShareAmount = NewBusinessError(21209, "invalid mint share amount") AppErrInvalidBurnShareAmount = NewBusinessError(21210, "invalid burn share amount") AppErrShareUSDCAmountTooHigh = NewBusinessError(21211, "burnt share usdc amount is too high") AppErrEntryUSDCAmountTooHigh = NewBusinessError(21212, "entry usdc amount is too high") AppErrInvalidUpdatePublicPoolStatus = NewBusinessError(21213, "invalid update public pool status") AppErrInvalidPoolPositionToTransfer = NewBusinessError(21214, "invalid pool position to transfer") AppErrInvalidMasterAccount = NewBusinessError(21215, "only master account can update public pool") AppErrPoolInLiquidation = NewBusinessError(21216, "public pool is in liquidation") AppErrPoolReachedMaximumInvestedPools = NewBusinessError(21217, "public pool reached maximum invested pools") AppErrPoolCreationDisabled = NewBusinessError(21218, "pool creation is disabled") AppErrMaxLLPPercentageExceeded = NewBusinessError(21219, "max llp percentage exceeded") AppErrPublicPoolHasOpenPositions = NewBusinessError(21220, "public pool has open positions") AppErrPublicPoolHasActiveOrders = NewBusinessError(21221, "public pool has active orders") AppErrPoolHasNoShares = NewBusinessError(21222, "public pool has no shares") AppErrMaxLLPAmountExceeded = NewBusinessError(21223, "max llp amount exceeded") AppErrStakingPoolIsFrozen = NewBusinessError(21224, "staking pool is frozen, only burning is allowed") AppErrInvalidStakingPoolIndex = NewBusinessError(21225, "invalid staking pool index") AppErrEntryStakedAmountTooHigh = NewBusinessError(21226, "entry staked amount is too high") AppErrShareLITAmountTooHigh = NewBusinessError(21227, "burnt share lit amount is too high") AppErrInsufficientAvailableStakingShares = NewBusinessError(21228, "insufficient available staking shares") AppErrInvalidUnstakeAmount = NewBusinessError(21229, "invalid unstake amount") AppErrStakingPoolAlreadyInitialized = NewBusinessError(21230, "staking pool is already initialized") AppErrMintShareAmountExceedsStakedLIT = NewBusinessError(21231, "mint share amount exceeds staked LIT value") AppErrInvalidStakeAssetAmount = NewBusinessError(21232, "invalid stake asset amount") AppErrInvalidUnstakeAssetAmount = NewBusinessError(21233, "invalid unstake asset amount") AppErrLiquidityPoolCooldownPeriodNotPassed = NewBusinessError(21234, "liquidity pool cooldown period has not passed yet") AppErrOperatorSharesCantBeForced = NewBusinessError(21235, "operator shares can't be force burned") AppErrStakingPoolDoesNotExist = NewBusinessError(21236, "staking pool does not exist") AppErrForceBurnSharesExceedsStakedLIT = NewBusinessError(21237, "force burn shares amount exceeds staked LIT value") // Collateral AppErrInvalidAssetAmount = NewBusinessError(21300, "invalid asset amount") AppErrNotEnoughCollateral = NewBusinessError(21301, "not enough collateral") AppErrInvalidReceiverAssetAmount = NewBusinessError(21302, "invalid receiver asset amount") AppErrInvalidFeeAccountAssetAmount = NewBusinessError(21303, "invalid fee account asset amount") AppErrNotEnoughAssetBalance = NewBusinessError(21304, "not enough asset balance") AppErrNotEnoughAssetBalanceForFee = NewBusinessError(21305, "not enough asset balance for fee") // Block AppErrBlockNotFound = NewBusinessError(21400, "block not found") AppErrInvalidBlockHeight = NewBusinessError(21401, "invalid block height") // Tx AppErrTxNotFound = NewBusinessError(21500, "transaction not found") AppErrInvalidTxInfo = NewBusinessError(21501, "invalid tx info") AppErrMarshalTxFailed = NewBusinessError(21502, "marshal tx failed") AppErrMarshalEventsFailed = NewBusinessError(21503, "marshal event failed") AppErrFailToL1Signature = NewBusinessError(21504, "fail to l1 signature") AppErrUnsupportedTxType = NewBusinessError(21505, "unsupported tx type") AppErrTooManyTxs = NewBusinessError(21506, "too many pending txs. Please try again later") AppErrAccountBelowMaintenanceMargin = NewBusinessError(21507, "account is below maintenance margin, can't execute transaction") AppErrAccountBelowInitialMargin = NewBusinessError(21508, "account is below initial margin, can't execute transaction") AppErrInvalidTxTypeForAccount = NewBusinessError(21511, "invalid tx type for account") AppErrInvalidL1RequestId = NewBusinessError(21512, "invalid l1 request id") AppErrTxInfoTxTypeLengthMismatch = NewBusinessError(21513, "TxInfos and TxTypes should have the same length") AppErrMaxBatchTx = NewBusinessError(21514, "maximum 50 transactions allowed per batch") AppErrCannotCreateTxOnAsset = NewBusinessError(21515, "transaction is not allowed") AppErrTreasuryOutgoingTransferNotAllowed = NewBusinessError(21516, "outgoing transfers from treasury account are not allowed") // OrderBook AppErrInactiveCancel = NewBusinessError(21600, "given order is not an active limit order") AppErrOrderBookFull = NewBusinessError(21601, "order book is full") AppErrInvalidMarketIndex = NewBusinessError(21602, "invalid market index") AppErrInvalidMinAmountsForMarket = NewBusinessError(21603, "invalid min amounts for market") // 21604 deprecated AppErrInvalidMarketStatus = NewBusinessError(21605, "invalid market status") AppErrMarketAlreadyExist = NewBusinessError(21606, "market already exist for given index") AppErrInvalidMarketFees = NewBusinessError(21607, "invalid market fees") AppErrInvalidQuoteMultiplier = NewBusinessError(21608, "invalid quote multiplier") AppErrInvalidInterestRate = NewBusinessError(21611, "invalid interest rate") AppErrInvalidOpenInterest = NewBusinessError(21612, "invalid open interest") AppErrInvalidMarginMode = NewBusinessError(21613, "invalid margin mode") AppErrNoPositionFound = NewBusinessError(21614, "no position found") AppErrInvalidUpdateMarginDirection = NewBusinessError(21615, "invalid update margin direction") AppErrAssetNotExist = NewBusinessError(21616, "asset does not exists for given index") AppErrInvalidCreateMarketParameters = NewBusinessError(21617, "invalid create market parameters") AppErrInvalidOrderTypeForMarket = NewBusinessError(21618, "invalid order type for market") AppErrInvalidMarketType = NewBusinessError(21619, "invalid market type") AppErrInvalidFundingClamp = NewBusinessError(21620, "invalid funding clamp") AppErrInvalidPerpsMarketIndex = NewBusinessError(21621, "invalid perps market index") AppErrInvalidOrderQuoteLimit = NewBusinessError(21622, "invalid order quote limit") AppErrInvalidOpenInterestLimit = NewBusinessError(21623, "invalid open interest limit") AppErrInvalidMinBaseAmount = NewBusinessError(21624, "invalid min base amount") AppErrInvalidMinQuoteAmount = NewBusinessError(21625, "invalid min quote amount") AppErrInvalidMarginFraction = NewBusinessError(21626, "invalid margin fraction") // Order AppErrInvalidOrderIndex = NewBusinessError(21700, "invalid order index") AppErrInvalidBaseAmount = NewBusinessError(21701, "invalid base amount") AppErrInvalidPrice = NewBusinessError(21702, "invalid price") AppErrInvalidIsAsk = NewBusinessError(21703, "invalid isAsk") AppErrInvalidOrderType = NewBusinessError(21704, "invalid OrderType") AppErrInvalidOrderTimeInForce = NewBusinessError(21705, "invalid OrderTimeInForce") AppErrInvalidOrderAmount = NewBusinessError(21706, "invalid order base or quote amount") AppErrInvalidOrderOwner = NewBusinessError(21707, "account is not owner of the order") AppErrEmptyOrder = NewBusinessError(21708, "order is empty") AppErrInactiveOrder = NewBusinessError(21709, "order is inactive") AppErrUnsupportedOrderType = NewBusinessError(21710, "unsupported order type") AppErrInvalidOrderExpiry = NewBusinessError(21711, "invalid expiry") AppErrAccountHasAQueuedCancelAllOrdersRequest = NewBusinessError(21712, "account has a queued cancel all orders request") AppErrInvalidCancelAllTimeInForce = NewBusinessError(21713, "invalid cancel all time in force") AppErrInvalidCancelAllTime = NewBusinessError(21714, "invalid cancel all time") AppErrInctiveOrder = NewBusinessError(21715, "given order is not an active order") AppErrOrderNotExpired = NewBusinessError(21716, "order is not expired") AppErrMaxOrdersPerAccount = NewBusinessError(21717, "maximum active limit order count reached") AppErrMaxOrdersPerAccountPerMarket = NewBusinessError(21718, "maximum active limit order count per market reached") AppErrMaxPendingOrdersPerAccount = NewBusinessError(21719, "maximum pending order count reached") AppErrMaxPendingOrdersPerAccountPerMarket = NewBusinessError(21720, "maximum pending order count per market reached") AppErrMaxTWAPOrdersInExchange = NewBusinessError(21721, "maximum twap order count reached") AppErrMaxConditionalOrdersInExchange = NewBusinessError(21722, "maximum conditional order count reached") AppErrInvalidAccountHealth = NewBusinessError(21723, "invalid account health") AppErrInvalidLiquidationSize = NewBusinessError(21724, "invalid liquidation size") AppErrInvalidLiquidationPrice = NewBusinessError(21725, "invalid liquidation price") AppErrInsuranceFundCannotBePartiallyLiquidated = NewBusinessError(21726, "insurance fund cannot be partially liquidated") AppErrInvalidClientOrderIndex = NewBusinessError(21727, "invalid client order index") AppErrClientOrderIndexExists = NewBusinessError(21728, "client order index already exists") AppErrInvalidOrderTriggerPrice = NewBusinessError(21729, "invalid order trigger price") AppOrderStatusIsNotPending = NewBusinessError(21730, "order status is not pending") AppPendingOrderCanNotBeTriggered = NewBusinessError(21731, "order can not be triggered") AppReduceOnlyIncreasesPosition = NewBusinessError(21732, "reduce only increases position") AppErrFatFingerPrice = NewBusinessError(21733, "order price flagged as an accidental price") AppErrPriceTooFarFromMarkPrice = NewBusinessError(21734, "limit order price is too far from the mark price") AppErrPriceTooFarFromTrigger = NewBusinessError(21735, "SL/TP order price is too far from the trigger price") AppErrInvalidOrderTriggerStatus = NewBusinessError(21736, "invalid order trigger status") AppErrInvalidOrderStatus = NewBusinessError(21737, "invalid order status") AppErrInvalidReduceOnlyDirection = NewBusinessError(21738, "invalid reduce only direction") AppErrNotEnoughOrderMargin = NewBusinessError(21739, "not enough margin to create the order") AppErrInvalidReduceOnlyMode = NewBusinessError(21740, "invalid reduce only mode") AppErrInvalidGroupingType = NewBusinessError(21741, "invalid grouping type") AppErrInvalidOrderGroupSize = NewBusinessError(21742, "invalid order group size") AppErrInvalidOrderInfo = NewBusinessError(21743, "invalid order info") AppErrInvalidAccountTypeForSpotMarket = NewBusinessError(21744, "pools are not allowed to trade in spot markets") AppErrInvalidMarketTypeForL1Order = NewBusinessError(21745, "only perps markets are allowed for L1 orders") // Asset AppErrInvalidAssetIndex = NewBusinessError(21801, "invalid asset index") AppErrInvalidAssetMarginMode = NewBusinessError(21802, "invalid asset margin mode") AppErrAssetAlreadyExists = NewBusinessError(21803, "asset already exists for given index") AppErrAssetDoesNotExists = NewBusinessError(21804, "asset does not exist for given index") AppErrOnlyUSDCTransferSupported = NewBusinessError(21805, "only usdc transfer supported") AppErrInvalidExtensionMultiplier = NewBusinessError(21806, "invalid extension multiplier") AppErrInvalidMinTransferAmount = NewBusinessError(21807, "invalid min transfer amount") AppErrInvalidMinWithdrawalAmount = NewBusinessError(21808, "invalid min withdrawal amount") AppErrAssetNotFound = NewBusinessError(21809, "asset not found") // Deleverage AppErrDeleverageAgainstItself = NewBusinessError(21901, "deleverage against itself") AppErrDeleverageDoesNotMatchLiquidationStatus = NewBusinessError(21902, "deleverage does not match liquidation status") AppErrDeleverageWithOpenOrders = NewBusinessError(21903, "deleverage with open orders") AppErrInvalidDeleverageSize = NewBusinessError(21904, "invalid deleverage size") AppErrInvalidDeleveragePrice = NewBusinessError(21905, "invalid deleverage price") AppErrInvalidDeleverageSide = NewBusinessError(21906, "invalid deleverage side") // Candlestick AppErrInvalidTimestamps = NewBusinessError(22400, "invalid timestamps: end_timestamp must be greater than start_timestamp") AppErrInvalidTimestamp = NewBusinessError(22401, "invalid timestamp: timestamp must be greater than 0 and less than year 2286") AppErrInvalidResolution = NewBusinessError(22402, "invalid resolution: resolution unsupported") AppErrTimeRangeExceedsLimit = NewBusinessError(22403, "time range exceeds maximum allowed range for the specified resolution") // RateLimit AppErrTooManyRequest = NewBusinessError(23000, "Too Many Requests!") AppErrTooManySubscriptions = NewBusinessError(23001, "Too Many Subscriptions!") AppErrTooManyDifferentAccounts = NewBusinessError(23002, "Too Many Different Accounts!") AppErrTooManyConnections = NewBusinessError(23003, "Too Many Connections!") AppErrTooManyL2Withdrawals = NewBusinessError(23004, "Too Many L2 Withdrawal Requests!") // General Errors AppErrNotFound = NewBusinessError(29404, "not found") AppErrInternal = NewBusinessError(29500, "internal server error") AppTimeout = NewBusinessError(29501, "process timeout") // Websocket AppErrWebsocketInvalidJson = NewBusinessError(30000, "Invalid Json") AppErrWebsocketInvalidType = NewBusinessError(30001, "Invalid Type") AppErrWebsocketNotSubscribed = NewBusinessError(30002, "Not Subscribed to ") AppErrWebsocketAlreadySubscribed = NewBusinessError(30003, "Already Subscribed to ") AppErrWebsocketFetchFailed = NewBusinessError(30004, "Failed to fetch ") AppErrWebsocketInvalidChannel = NewBusinessError(30005, "Invalid Channel") AppErrWebsocketNotSupported = NewBusinessError(30006, "Operation isn't supported ") AppErrWebsocketInvalidData = NewBusinessError(30007, "Invalid Data") AppErrWebsocketInvalidAccountType = NewBusinessError(30008, "Invalid account type") AppErrWebsocketRateLimit = NewBusinessError(30009, "Too Many Websocket Messages!") AppErrWebsocketTooManyInflight = NewBusinessError(30010, "Too Many Inflight Messages!") AppErrWebsocketFailedToConnect = NewBusinessError(30011, "Failed to connect") AppErrWebsocketFailedToSubscribe = NewBusinessError(30012, "Failed to subscribe") // Referral AppErrReferralAlreadyExists = NewBusinessError(41001, "Referral code already exists") AppErrReferralExpired = NewBusinessError(41002, "Referral code is expired") AppErrReferralAlreadyUsed = NewBusinessError(41003, "Referral code already used") AppErrReferralUserHasAccess = NewBusinessError(41004, "User can already access") AppErrReferralUserCantInvite = NewBusinessError(41005, "User can't invite") AppErrReferralInvalid = NewBusinessError(41006, "Invalid referral code") AppErrReferralRequired = NewBusinessError(41007, "Referral code is required") AppErrReferralKickbackUpdate = NewBusinessError(41008, "Kickback can only be updated once per week") AppErrReferralCodeAlreadyUpdated = NewBusinessError(41009, "Referral code has already been updated once, cannot update again") AppErrReferralCodeInvalid = NewBusinessError(41010, "Referral code must be 4-14 characters and contain only uppercase letters (A-Z) and numbers (0-9)") AppErrReferralOnlyMainAccount = NewBusinessError(41011, "only main account index is valid, please use the main account") AppErrReferralCannotUseOwnCode = NewBusinessError(41012, "cannot use your own referral code") // Read Only API Token AppErrAPITokenExpiryBeforeMinAllowed = NewBusinessError(61001, "api token expiry is before minimum allowed expiry of 1 day") AppErrAPITokenExpiryAfterMaxAllowed = NewBusinessError(61002, "api token expiry is after maximum allowed expiry of 10 years") AppErrAPITokenMaxTokensExceeded = NewBusinessError(61003, "maximum number of 10 api tokens for the account exceeded") AppErrAPITokenCustomScopesNotSupported = NewBusinessError(61004, "custom scopes for api tokens are not supported yet") AppErrAPITokenNotFound = NewBusinessError(61005, "api token not found or does not belong to this account") AppErrAPITokenAlreadyRevoked = NewBusinessError(61006, "api token has already been revoked") AppErrAPITokenNameEmpty = NewBusinessError(61007, "api token name cannot be empty") AppErrAPITokenNameTooLong = NewBusinessError(61008, "api token name cannot exceed 50 characters") AppErrAPITokenNameInvalidChars = NewBusinessError(61009, "api token name can only contain letters, numbers, spaces, hyphens, underscores, and periods") // Tier Change AppErrTierChangeInProgress = NewBusinessError(62001, "tier change already in progress") AppErrTierChangeInvalidTier = NewBusinessError(62002, "invalid tier") AppErrTierChangeSameTier = NewBusinessError(62003, "account already part of requested tier") AppErrTierChangeHasOpenPositions = NewBusinessError(62004, "account has open positions") AppErrTierChangeHasOpenOrders = NewBusinessError(62005, "account has open orders") AppErrTierChangeTooManyRequest = NewBusinessError(62006, "too frequent tier change request") Updated 24 days ago * * * Ask AI --- # Create accounts programmatically To create a Lighter account, you can simply deposit some assets to Lighter using the procedure [here](doc:deposits-transfers-and-withdrawals) . The crediting on mainnet takes a few minutes, after which a master account index gets generated, allowing you to interact with the exchange without ever needing to touch the front-end. If you're using other EVM-compatible chains routed via CCTP, deposits will take around 15-20 minutes to get credited. Once the account is created, you can verify the assigned `account_index` [querying](https://etherscan.io/address/0x3B4D794a66304F130a4Db8F2551B0070dfCf5ca7#readProxyContract) `addressToAccountIndex` (0xabf6a038) on Lighter's Ethereum contract, or using the [account](https://apidocs.lighter.xyz/reference/account-1) or [accountsByL1Address](https://apidocs.lighter.xyz/reference/accountsbyl1address) endpoints. You can refer to [this documentation](doc:api-keys) to then generate API keys in a programmatic way. Updated 2 months ago * * * Ask AI --- # Deposits, Transfers and Withdrawals Deposit via Ethereum Mainnet [](https://apidocs.lighter.xyz/docs/deposits-transfers-and-withdrawals#deposit-via-ethereum-mainnet) ------------------------------------------------------------------------------------------------------------------------------------- To deposit via Ethereum mainnet, you can use the `deposit` method (0x8a857083) directly. You'll need to specify the following parameters: * `deposit`: the amount of Ether you're depositing. That is optional and only needed when interacting with the contract directly, Lighter's Ethereum gateway page does not require this. You can leave this at zero if you're depositing other kind of assets. * `_to`: the L1 address you want to credit the deposit to * `_assetIndex`: the asset you want to deposit. You can grab the correct asset id from the assetDetails endpoint (add hyperlink when added to docs) * `_routeType`: whether you want to deposit the asset to your perps (0), or spot account (1). Only USDC can be deposited to your perps account * `_amount`: the amount you're depositing. _it should be in line with the ERC20's decimals. E.g. 6 decimals for USDC, 18 decimals for Ether etc. 1 USDC, or equivalent, minimum._ If you're depositing assets different from ETH (e.g. USDC), make sure to approve spending for Lighter's smart contract (0x3B4D794a66304F130a4Db8F2551B0070dfCf5ca7) for that ERC20. There is a minimum of 1 USDC, and equivalent for other ERC20s, per deposit. Deposit USDC via other EVM-compatible chains [](https://apidocs.lighter.xyz/docs/deposits-transfers-and-withdrawals#deposit-usdc-via-other-evm-compatible-chains) --------------------------------------------------------------------------------------------------------------------------------------------------------------------- At the moment, the following chains are supported via Circle's CCTP: Arbitrum, Base, Avalanche C-Chain. Minimum deposit is 5 USDC. You can either generate an intent address via the front-end, or via [API](https://apidocs.lighter.xyz/reference/createintentaddress) : Shell `curl -X POST https://mainnet.zklighter.elliot.ai/api/v1/createIntentAddress \` `-H "Content-Type: application/x-www-form-urlencoded" \` `-d "chain_id=42161&from_addr=0xyourL1address&amount=0&is_external_deposit=true"` Withdrawals: Secure and Fast [](https://apidocs.lighter.xyz/docs/deposits-transfers-and-withdrawals#withdrawals-secure-and-fast) ------------------------------------------------------------------------------------------------------------------------------------ You can process both [secure](https://github.com/elliottech/lighter-python/blob/main/examples/withdraw_normal.py) , [fast withdrawals](https://github.com/elliottech/lighter-python/blob/main/examples/withdraw_fast.py#L59) , and [transfers](https://github.com/elliottech/lighter-python/blob/main/examples/transfer.py) via both SDKs, you can find linked examples with the Python SDK. If you're processing a Fast Withdrawal (USDC only, 4 USDC minimum), or a Transfer to another L1, you'll need to provide an Ethereum private key as well. If you prefer, you can process secure withdrawals from the contract directly, using the `withdraw` (0xd20191bd) method. Both Transfers and Secure Withdrawals have a 1 USDC, or equivalent, minimum. Updated about 2 months ago * * * Ask AI ---