> For the complete documentation index, see [llms.txt](https://docs.lighter.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.lighter.xyz/developers/getting-started/core-concepts.md).

# Core concepts

The handful of concepts every Lighter integration depends on.

## L1 address

The user's **Ethereum address**. It owns the Lighter account, is used for deposits and secure withdrawals, and signs a few sensitive actions (registering an API key, transfers to other addresses, fast withdrawals, approving an integrator with fees).

## Account index

Lighter's **integer ID** for an account. One L1 address can own several:

* **Master account** – created automatically on the first deposit.
* **Sub-accounts** – created with a `CreateSubAccount` transaction. Each has its own index, balances and API keys.
* **Public pools** – a special kind of sub-account that other users can deposit into for shares.

How indexes are assigned:

* **Master accounts** count **up** from 0, in order of creation. The lowest indexes (0–2) are system accounts such as the treasury and insurance fund.
* **Sub-accounts and pools** count **down** from `2^48 - 2` = `281474976710654`, which is the LLP. Every new sub-account, public pool or staking pool gets the next lower index.

So a small index is a master account and a very large one is a sub-account or pool. Don't assume a sub-account's index is close to its master's; look it up.

Find account indexes for an L1 address with [accountsByL1Address](https://docs.lighter.xyz/api/account). The first entry in `sub_accounts` is the master account:

```shell
curl "https://mainnet.zklighter.elliot.ai/api/v1/accountsByL1Address?l1_address=0xYourAddress"
```

## API key

An API key is a keypair (separate from the Ethereum key) that signs Lighter transactions. Each key is bound to **one account index**, uses an index from **4 to 254** (0–3 are reserved for Lighter's apps), and is registered once with an L1 signature (`ChangePubKey`). Permissions, auth tokens and maker-only keys are covered in [API keys](/developers/integration-guides/api-keys.md).

Transactions are **queued per API key**. Each key has its own nonce stream, and a transaction can't execute before the ones sent earlier on the same key.

### Use separate API keys for independent workloads

Every transaction waits for a **speed bump** before it executes. The length depends on the account tier and the transaction type (for example, on Standard, taker orders wait 300 ms and post-only orders 0 ms; see [Account Types](/developers/reference/account-types.md)).

Because the queue is per key, a slow transaction delays everything sent after it **on the same key**. A post-only order sent right after a taker order on the same key waits for the taker order's 300 ms.

Use a dedicated key per workload (e.g. one for quoting/cancelling, one for taking, one for transfers) so that:

* delays on one workload don't hold up another, and
* each workload manages its own nonces without clashing.

Premium/Advanced accounts can go further with [maker-only API keys](/developers/integration-guides/api-keys.md#maker-only-api-keys), which skip the speed-bump queue entirely.

## Nonce

Every transaction carries a **nonce**, tracked **per API key**.

* Default rule: `new_nonce = previous_nonce + 1`.
* Get the next nonce: [nextNonce](https://docs.lighter.xyz/api/api-keys) (`GET /api/v1/nextNonce?account_index=…&api_key_index=…`).
* Skipping nonces: set the `SkipNonce` attribute (`skip_nonce` in the Python SDK, 4th in `L2TxAttributes`) to `1`. Then any `old_nonce < new_nonce < 2^47 - 1` is accepted. Nonces are capped at `2^48 - 1`.
* The Python SDK manages nonces for you. Manage them locally if you run several processes or need the lowest latency.

### When a rejected transaction consumes its nonce

| Where it's rejected                         | Examples                                                                                                                                                                               | Nonce consumed?                         |
| ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- |
| API server (`sendTx` returns an error code) | Bad signature, malformed tx, wrong nonce, rate limit, `ExpiredAt` less than \~5 s away, not enough margin for a resting order                                                          | **No**                                  |
| Sequencer, before the tx is applied         | `ExpiredAt` passed before execution, not enough margin or balance for a resting order (margin changed after the API accepted it), market inactive, invalid integrator fee, wrong nonce | **No**                                  |
| Sequencer, while applying the tx            | Invalid size or price, duplicate `clientOrderIndex`, wrong reduce-only direction, `orderExpiry` already passed, cancelling or modifying an unknown order                               | **Yes** (the tx is included as a no-op) |

"Resting order" means any order that can rest on the book, i.e. not IOC or TWAP. **Taker orders (IOC / market) and TWAP orders aren't margin-checked up front.** If a fill would leave the account without enough margin, the order is cancelled during matching and the nonce is consumed.

An order that executes normally and is then cancelled by matching rules (e.g. post-only would cross, IOC not filled, not enough margin for a taker fill, self-trade prevention) is a successful transaction and consumes its nonce.

When a transaction fails **without** consuming its nonce, any transactions you already sent on the same key with higher nonces will fail too. Re-sign them starting from the current `nextNonce`.

### Retrying safely

* **Rejected by the API server:** fix the issue and resend with the **same** nonce.
* **Accepted (`code: 200`), outcome unknown** (timeout, dropped connection, no WebSocket confirmation): **don't** re-sign blindly. First check the tx status by hash (`GET /api/v1/tx?by=hash&value=…`) or the `account_tx` channel, and compare `nextNonce` with the nonce you used.
  * Executed: done, don't resend.
  * Failed and `nextNonce` still equals your nonce: resend with the same nonce.
  * Failed and the nonce was consumed: re-sign with the new `nextNonce`.
* Re-signing with a **new** nonce while the original may still execute can place the order **twice**. Reusing the same `clientOrderIndex` helps: a second order with a `clientOrderIndex` that belongs to a still-open order is rejected. It doesn't protect you once the first order has filled or been cancelled, so always check status first.

## Integer prices and sizes

Prices and amounts are sent as **integers**. Each market publishes its decimals via [orderBookDetails](https://docs.lighter.xyz/api/orders):

```json
{ "symbol": "ETH", "market_id": 0, "size_decimals": 4, "price_decimals": 2,
  "min_base_amount": "0.0020", "min_quote_amount": "10.000000" }
```

* `base_amount = size × 10^size_decimals` → 0.01 ETH = `100`
* `price = price × 10^price_decimals` → $3,100.00 = `310000`

Minimum order: the larger of `min_base_amount` (in the base asset) and `min_quote_amount` (in USDC). Minimums apply to maker orders.

For taker orders, `price` is the **worst price** you accept. If the sequencer can't fill at that price or better, the rest is cancelled.

## Transaction lifecycle

1. **Sign** locally (WASM / Go / Python signer) → `tx_type`, `tx_info`, `tx_hash`.
2. **Send** via `POST /api/v1/sendTx` (or `sendTxBatch`, or WebSocket `jsonapi/sendtx`).
3. **API response `code: 200`** means *accepted*, not *executed*.
4. **Confirm** execution via [WebSocket](https://docs.lighter.xyz/api/websocket) account channels or `GET /api/v1/tx`.

Transaction status values are listed in [Data Structures, Constants and Errors](/developers/reference/data-structures-constants-and-errors.md).

## Auth tokens and account tiers

* Private REST endpoints and WebSocket channels need an **auth token** signed by an API key, or a **read-only token**. See [API keys](/developers/integration-guides/api-keys.md#authentication).
* Fees, latency and limits depend on the account tier (**Standard**, **Plus**, **Premium/Advanced**). See [Account Types](/developers/reference/account-types.md) and [Rate Limits](/developers/reference/rate-limits.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.lighter.xyz/developers/getting-started/core-concepts.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
