Skip to main content
Before trading on Lighter, the user must satisfy a single mandatory setup descriptor:
  • REGISTER_API_KEY — Register a per-account API key (Schnorr-style keypair) on-chain. This is the key the SDK uses to sign every trade thereafter. Dual-signed (USER + API_KEY).
It is the only entry in the provider’s setup array on GET /providers, and trading is impossible until it is satisfied. The setup flow:
  1. Deposit firstREGISTER_API_KEY requires an existing on-chain account_index. On a fresh address, fund the account with a DEPOSIT first, or registration fails with AccountNotFound. The deposit is a funding action, not a setup descriptor.
  2. CheckcheckSetup() returns the outstanding REGISTER_API_KEY step (or empty if it is already satisfied).
  3. Register API key — The SDK generates a fresh API keypair, signs the WASM ChangePubKey blob with the new private key, and asks the user’s L1 wallet to sign the corresponding EIP-191 message (the dual-signed flow described in Signing Model).
  4. ExecuteexecuteProviderSetup() submits the dual-signed REGISTER_API_KEY blob to Lighter; on success the API key is on-chain at the chosen slot and the SDK’s LighterKeyStore persists the keypair locally for subsequent trading.
// High-level — the SDK orchestrates both signatures and the on-chain submit
const required = await perps.checkSetup({
  provider: 'lighter',
  address: userAddress,
});

if (!required.isReady) {
  // signProviderSetupAction generates the API keypair, signs the WASM blob
  // client-side, and prompts the L1 wallet for the EIP-191 countersignature.
  const signedActions = await Promise.all(
    required.setup.map((step) =>
      perps.signProviderSetupAction('lighter', userAddress, step),
    ),
  );
  await perps.executeProviderSetup({
    provider: 'lighter',
    address: userAddress,
    setup: required.setup,
    signedActions,
  });
}

API key slot

The default API key slot is 42 (the DEFAULT_API_KEY_INDEX). Lighter’s contract allows slot indices 0-254 (255 is the nil sentinel); slots 0-3 are reserved, so user keys use 4-254. The SDK reuses a single slot per account by convention.
Re-registering the same slot overwrites the prior key. If the SDK regenerates an API key (for example after the local LighterKeyStore is cleared), the user must re-sign a new REGISTER_API_KEY to put the fresh public key on-chain at the same slot.

Idempotency

The REGISTER_API_KEY step that checkSetup() returns is idempotent against repeated calls:
  • If the target slot already holds a registered key, the step is omitted — isReady becomes true.
  • If a created record already exists with the same Lighter-authoritative nonce, that record is reused (no fresh nonce allocation).
  • If the existing record is stale (different nonce), the prior record is dropped and a fresh one is written matching Lighter’s current expected nonce.
This means callers can poll checkSetup() freely without accumulating duplicate UserAction records or burning nonces.

Setup descriptors

The following action is returned in the setup array from GET /providers for Lighter:

registerApiKey

Generates a per-account Lighter API keypair and registers its public key on-chain via Lighter’s ChangePubKey transaction. The new private key is held client-side by the SDK’s LighterKeyStore and used to sign all subsequent trading actions.
TitleRegister Trading API Key
SignersUSER (L1 EIP-191 signature) and API_KEY (WASM blob signed by the new key)
Signing methodwasmBlob
Sequence10
When neededFirst time trading on Lighter for this account, or after the local LighterKeyStore for this address is cleared
See Signing Model for the full two-step signing dance.

Options descriptors

The following actions are returned in the options array from GET /providers for Lighter. Options never gate trading — they are post-setup controls. The accepted parameter values are enumerated on each descriptor’s params[].values array.

accountMode

Surfaces Lighter’s account-mode setting: Unified Trading Account or Simple Trading Account. This descriptor is read-only — Lighter does not currently expose a public API to switch modes, so the control is display-only and the backend registers no handler for it.
TitleAccount Mode
SignersAPI_KEY
Signing methodwasmBlob
Parammode (string, readOnly)
ValuesunifiedTradingAccount (Unified Trading Account), simpleTradingAccount (Simple Trading Account) — no default; Lighter’s docs do not designate one

accountType

Switches Lighter’s fee tier between Standard and Premium. Premium reduces fees and improves matching priority. Editable, but Lighter enforces server-side rules: no open positions, no pending orders, and a 24-hour cooldown between switches. Lighter also publishes a “Plus” tier, but it is not currently settable via the public API — only Standard ↔ Premium are exposed here.
TitleAccount Tier
SignersAPI_KEY
Signing methodwasmBlob
Paramtier (string)
Valuesstandard (Standard, default), premium (Premium)