Skip to main content
POST
Build close-position payload
Lighter requires the wallet to be a registered account before any trade/withdraw action.If the EOA has never deposited on Lighter, this endpoint will fail. First-time setup is a two-step prerequisite:
  1. Deposit ≥ 5 USDC via /2/perp/payloads/deposit → Lighter creates an accountIndex on-chain once the bridge settles. (5 USDC is a Lighter requirement, not a Mobula limit.)
  2. Provision API key + auth token via /2/perp/payloads/create-account using that accountIndex.
Read the Build Create-Account Payload page for the full setup flow including how to discover the accountIndex after a deposit.
Builds the payload for closing an existing position. Close size is either explicit (amountRaw) or percentage-based (closePercentage).

Request Body

dex
string
required
gains or lighter.
chainId
string
required
Chain of the position (e.g., evm:42161, lighter:301).
marketId
string
required
Mobula market identifier (e.g., lighter-btc-usd).
positionId
string
Gains only — required. The Gains trade index, sent as a string that parses as a non-negative integer (e.g. "0", "919").
The Gains positions endpoints (GET /2/wallet/positions/perp/open, perp-positions-open WSS channel) expose a composite position id of the form:
e.g. pos-gains-inj-usd-usdc-0xaa0055ef84ef93138c7c11be1d19dac5dcd08741-0.payloads/close-position does not accept this composite id — passing it returns 400 close-position payload generation failed: gains - positionId must be a non-negative integer, got "<composite>".Extract the trailing trade index segment (the final -<integer>) and send it as a string:
Not used for Lighter.
closePercentage
number
Portion of the position to close, in percent (0 < value ≤ 100). Use 100 for a full close. Mutually exclusive with amountRaw.
amountRaw
number
Raw base-token amount to close. Mutually exclusive with closePercentage.
params
object
Additional DEX-specific parameters. For Gains partial closes, the API transparently injects currentCollateralRaw from the position cache when available, so you do not need to supply it.

Authentication

Every /2/perp/payloads/<action> endpoint verifies the caller by requiring two extra fields in the request body alongside the action parameters:
timestamp
number
required
Unix timestamp in milliseconds. Must be within 30 seconds of server time. Older timestamps are rejected to prevent replay.
signature
string
required
Hex signature (EIP-191 personal_sign) of the message `${endpoint}-${timestamp}`, where endpoint is the path of this endpoint without the leading slash (e.g., for this page: api/2/perp/payloads/<this-action>). The recovered signer address becomes the user for the request. Single-use — replay returns 403 signature already used.

Authentication errors

Statusmessage
403timestamp expired — timestamp older than 30s
403signature already used — replay attempt
400zod validation failedtimestamp/signature shape invalid

Response envelope

Every /2/perp/payloads/<action> endpoint returns the same envelope shape. You pass these fields verbatim into POST /2/perp/execute-v2 to execute the action.
Top-level shape. Successful (2xx) responses return { data: { ... } }. A success: true flag is only present inside the body of execute-v2’s response, not on the payload-build endpoints. Parse defensively: read body.data, then check for the action-specific fields you need (e.g. data.payloadStr).
data
object

Endpoint-specific errors

Statusmessage
400close-position payload generation failed — position not found, invalid close size, or DEX refusal

Full flow — close a position end-to-end

Single example covering both DEXes (Lighter offchain-api, Gains evm-tx). The flow branches on data.transport.

Body

application/json
timestamp
number
required
signature
string
required
dex
enum<string>
required
Available options:
gains,
lighter
chainId
string
required
marketId
string
required
positionId
string

Gains trade index. Required for Gains.

closePercentage
number

Portion to close (0 < value ≤ 100). Mutually exclusive with amountRaw.

amountRaw
number

Raw base-token amount to close. Mutually exclusive with closePercentage.

params
object

Response

200 - application/json

Canonical payload envelope

success
boolean
required
data
object
required