> 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/integration-guides/signing-transactions.md).

# Signing Transactions

{% hint style="info" %}
**Lighter on Robinhood Chain**

Signing works the same on RH; only the chain ID (`466324`) and base URL change. See [Lighter on Robinhood Chain](/developers/robinhood-chain/overview.md) for everything that differs on RH.
{% endhint %}

Market, limit, stop and TWAP orders; modify, cancel and batch; leverage and margin.

Traders can trade programmatically using the [sendTx](https://docs.lighter.xyz/api/transactions) and [sendTxBatch](https://docs.lighter.xyz/api/transactions) REST endpoints, or [json/sendTx](https://docs.lighter.xyz/api/websocket#send-tx) and [json/sendTxBatch](https://docs.lighter.xyz/api/websocket#send-batch-tx) types via Websocket. Creating an API key is required to sign transactions.

{% hint style="info" %}
For the current binary options discovery methods and response models, use [lighter-sdk 1.1.8](https://pypi.org/project/lighter-sdk/1.1.8/) or newer, or [lighter-go v1.0.12](https://github.com/elliottech/lighter-go/releases/tag/v1.0.12) or newer. Python 1.1.8 also fixes the `boPnl` authorization header. The standard create, modify and cancel order flow is unchanged; discover binary options market IDs through `events`.

The shared-library signer uses signed 64-bit market indices (`int64`). If you call it directly from C/C++ or a custom FFI binding, use a `.h` file and bindings that match your signer library. Update declarations that still use `int cMarketIndex` to `long long int cMarketIndex`, as shown in the [current signer header](https://github.com/elliottech/lighter-python/blob/v1.1.8/lighter/signers/lighter-signer-linux-amd64.h#L158).

See the [Python binary options examples](https://github.com/elliottech/lighter-python/tree/v1.1.8/examples/binary-options), especially [create\_order\_from\_event.py](https://github.com/elliottech/lighter-python/blob/v1.1.8/examples/binary-options/create_order_from_event.py), for market discovery through `events` followed by `create_order`.
{% endhint %}

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, see [Confirming execution](#confirming-execution).

## Sign Transactions

Every [transaction](/developers/reference/data-structures-constants-and-errors.md#constants) needs to be signed using the **SignerClient**. Using the [Python SDK](/developers/getting-started/sdks.md), 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).

The TypeScript examples on this page use the WASM signer from the [TypeScript quickstart](/developers/getting-started/quickstart-typescript.md) and this helper:

```typescript
async function sendTx(tx: { txType: number; txInfo: string }) {
  const r = await fetch(`${BASE_URL}/api/v1/sendTx`, {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({ tx_type: String(tx.txType), tx_info: tx.txInfo }),
  }).then(r => r.json());
  if (r.code !== 200) throw new Error(`${r.code}: ${r.message}`);
  return r; // { tx_hash, predicted_execution_time_ms, volume_quota_remaining }
}
```

Every order carries a **nonce** and uses **integer prices and sizes**. Both are explained in [Core concepts](/developers/getting-started/core-concepts.md): see [Nonce](/developers/getting-started/core-concepts.md#nonce) (including which rejected transactions consume a nonce) and [Integer prices and sizes](/developers/getting-started/core-concepts.md#integer-prices-and-sizes) (including minimum order sizes).

{% hint style="info" %}
Binary options support limit and market orders only, with `reduceOnly = 0` and `triggerPrice = 0`. Up/Down markets use integer price ticks from `1` to `99`. Create and modify requests must be within the market's trading window and pass its frozen-book and price-cap checks. See [Binary options: Trading and fees](/developers/binary-options/trading-and-fees.md).
{% endhint %}

## Order parameters

| Parameter          | Notes                                                                                                                                                               |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `marketIndex`      | `market_id` from `orderBookDetails`                                                                                                                                 |
| `clientOrderIndex` | Your ID (uint48, ≤ 2^48−1), **unique across all markets**. Used to cancel/modify.                                                                                   |
| `baseAmount`       | Integer: size × 10^`size_decimals`                                                                                                                                  |
| `price`            | Integer: price × 10^`price_decimals`. For taker orders = **worst acceptable price**: if the sequencer cannot offer an equal or better price, the order is cancelled |
| `isAsk`            | `0` buy, `1` sell                                                                                                                                                   |
| `orderType`        | See [Order types](#order-types)                                                                                                                                     |
| `timeInForce`      | `0` Immediate-or-cancel · `1` Good-till-time · `2` Post-only                                                                                                        |
| `reduceOnly`       | `1` to only reduce a position                                                                                                                                       |
| `triggerPrice`     | For stop-loss / take-profit                                                                                                                                         |
| `orderExpiry`      | Unix **ms** timestamp, between 5 minutes and 30 days ahead. `0` for IOC orders                                                                                      |

When cancelling, you may see `order_index` instead of `client_order_index` as an argument – you can use the same value. 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

| Value | Type              | Use                                     |
| ----- | ----------------- | --------------------------------------- |
| 0     | Limit             | Resting or IOC limit order              |
| 1     | Market            | Immediate execution up to `price`       |
| 2     | Stop-loss         | Market order when `triggerPrice` is hit |
| 3     | Stop-loss limit   | Limit order when `triggerPrice` is hit  |
| 4     | Take-profit       | Market order when `triggerPrice` is hit |
| 5     | Take-profit limit | Limit order when `triggerPrice` is hit  |
| 6     | TWAP              | Time-weighted execution                 |

Additionally, there are two internal order types: TWAPSubOrder (7) and LiquidationOrder (8).

### Other order enums

| Enum                | Values                                                             |
| ------------------- | ------------------------------------------------------------------ |
| Grouping type       | `1` OTO · `2` OCO · `3` OTOCO                                      |
| Self-trade behavior | `0` Expire maker · `1` Expire taker · `2` Expire both · `3` Reduce |
| Self-trade equality | `0` Same account index · `1` Same master account                   |
| Cancel-all TIF      | `0` Immediate · `1` Scheduled · `2` Abort                          |
| Margin mode         | `0` Cross · `1` Isolated                                           |
| Route type          | `0` Perps · `1` Spot                                               |

These are also defined in [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.

## Market order

```typescript
// Buy 0.05 ETH, paying at most $3,150
const tx = check(lighter.SignCreateOrder(
  0, clientOrderIndex, toInt(0.05, 4), toInt(3150, 2),
  0,      // buy
  1,      // MARKET
  0,      // IOC
  0, 0,
  0,      // orderExpiry: 0 for IOC
  0, 0, 0, 0, 0,
  0, await nextNonce(), API_KEY_INDEX, ACCOUNT_INDEX,
));
await sendTx(tx);
```

Pick `price` from the order book with a slippage buffer (e.g. best ask × 1.01 for buys). If the book can't fill at that price or better, the rest is cancelled.

## Post-only limit order

```typescript
const tx = check(lighter.SignCreateOrder(
  0, clientOrderIndex, toInt(0.05, 4), toInt(2900, 2),
  0, 0 /* LIMIT */, 2 /* POST_ONLY */, 0, 0,
  Date.now() + 7 * 24 * 3600e3,
  0, 0, 0, 0, 0,
  0, await nextNonce(), API_KEY_INDEX, ACCOUNT_INDEX,
));
```

## Stop-loss and take-profit

Set `triggerPrice` **and** `price`. `price` is the worst fill price once triggered, i.e. the allowed slippage, with the same logic as taker orders. Use `reduceOnly = 1` to protect a position.

To attach TP/SL to an entry in one go, use `SignCreateGroupedOrders` (OTO / OCO / OTOCO groupings). Grouped orders count as one transaction for quota. See [WASM signer functions](/developers/reference/wasm-signer.md#signcreategroupedorders).

## Modify

```typescript
const tx = check(lighter.SignModifyOrder(
  marketIndex, clientOrderIndex, newBaseAmount, newPrice, newTriggerPrice,
  0, 0, 0,  // integrator fields (keep the same as the original order)
  0, 0,     // self-trade modes
  0, await nextNonce(),
  0,        // orderVersion: optional; if set, must be > current version
  API_KEY_INDEX, ACCOUNT_INDEX,
));
```

### Order Version

You can specify an `order_version` when modifying orders, so that the sequencer will reject any version that is not strictly greater than the order's current stored version, returning `AppErrInvalidOrderOrderVersion`. This is optional, and examples can be found [here](https://github.com/elliottech/lighter-python/blob/main/examples/orders/modify_order_version_http.py) (http) and [here](https://github.com/elliottech/lighter-python/blob/main/examples/orders/modify_order_version_ws.py) (ws). Order events will include `order_version`, and Trade events will include `ask_order_version`, `bid_order_version`.

## Self-trade prevention

`selfTradeBehaviorMode` and `selfTradeEqualityMode` control what happens when your order would match another order of yours. The default `0, 0` expires the resting (maker) order when both orders come from the same account index. Other values are listed in [Other order enums](#other-order-enums).

{% hint style="warning" %}
**Not combinable with partner fees**

A non-default self-trade mode **can't be combined with non-zero integrator fees** on the same order (error `21159`). If you charge [partner fees](/developers/integration-guides/partner-attribution.md), leave both self-trade modes at `0`.
{% endhint %}

## Cancel

```typescript
// One order
lighter.SignCancelOrder(marketIndex, clientOrderIndex, 0, nonce, API_KEY_INDEX, ACCOUNT_INDEX);

// All orders (timeInForce 0 = now; cancelAllMarketIndex 255 = all markets)
lighter.SignCancelAllOrders(0, 0, 255, 0, nonce, API_KEY_INDEX, ACCOUNT_INDEX);
```

## Batch

Send up to **50 transactions** in one request. All transactions in a batch must use the same account and API key, with consecutive nonces:

```typescript
const n = await nextNonce();
const txs = [0, 1, 2].map(i => check(lighter.SignCreateOrder(/* … */ 0, n + i, API_KEY_INDEX, ACCOUNT_INDEX)));

await fetch(`${BASE_URL}/api/v1/sendTxBatch`, {
  method: "POST",
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
  body: new URLSearchParams({
    tx_types: JSON.stringify(txs.map(t => t.txType)),
    tx_infos: JSON.stringify(txs.map(t => t.txInfo)),
  }),
});
```

* The whole batch waits for the **longest speed bump** of any transaction in it. Mixing a taker order into a batch of post-only orders delays all of them.
* **Large batches:** request-body size limits at the CDN edge can reject a large REST batch before it reaches the API (you'll get an HTTP error without Lighter's JSON body). REST batches of up to \~15 orders are safe. For bigger batches, use WebSocket `jsonapi/sendtxbatch` ([below](#sending-over-websocket)), which accepts messages up to 64 KB, enough for 50 orders.

Python example: [send\_batch\_tx\_http.py](https://github.com/elliottech/lighter-python/blob/main/examples/batch-orders/send_batch_tx_http.py).

## Leverage and margin

```typescript
// Initial margin fraction in basis points of 10,000: 10x leverage -> 1000
lighter.SignUpdateLeverage(marketIndex, 1000, 0 /* 0 cross, 1 isolated */, 0, nonce, API_KEY_INDEX, ACCOUNT_INDEX);

// Add/remove isolated margin
lighter.SignUpdateMargin(marketIndex, usdcAmount, direction /* 1 add, 0 remove */, 0, nonce, API_KEY_INDEX, ACCOUNT_INDEX);
```

## Sending over WebSocket

Lower latency than REST, same limits:

```json
{ "type": "jsonapi/sendtx", "data": { "id": "my-req-1", "tx_type": 14, "tx_info": { … } } }
```

`jsonapi/sendtxbatch` takes `tx_types` and `tx_infos` arrays (max 50). Messages are limited to **64 KB** after decompression. `permessage-deflate` is supported, but it doesn't raise that limit. Full message format: [Send Tx](https://docs.lighter.xyz/api/websocket#send-tx) and [Send Batch Tx](https://docs.lighter.xyz/api/websocket#send-batch-tx).

## Confirming execution

`sendTx` returning `code: 200` only means the transaction was accepted. Subscribe to `account_orders/{market}/{account}` or `account_tx/{account}` to see fills and rejections. See [Account data & positions](/developers/integration-guides/account-data.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/integration-guides/signing-transactions.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.
