Skip to main content
All mutating operations — trading, withdrawals, leverage changes, position margin, account setup — flow through the same two service functions: createAction and executeAction. For trading actions, the Trading pages document the convenience wrappers (placeOrder, cancelOrders, etc.) that handle createAction, agent-signing, and executeAction automatically. Those wrappers are the supported public surface for trade dispatch — createAction/executeAction are documented here for completeness and for action types that don’t have a dedicated wrapper. Withdrawals and account setup use the same authorization model, but the SDK exposes higher-level helpers (withdraw, checkSetup / executeProviderSetupAction) that should be preferred. Session-only actions execute directly through the provider plugin and intentionally skip executeAction.

Pattern

  1. Create — call createAction() with the action type and params. Returns one or more ActionStep payloads. Each step’s shape depends on the action’s signingMethod: EIP-712 typed data, a WASM-signer blob, an EVM transaction, an HMAC request, a SIWE challenge, or a client-only session marker.
  2. Authorize — let the provider plugin sign or execute each step according to ProviderAction.signer and signingMethod. USER means the user’s wallet or consent must act (usually the wallet, or a client-held provider session for session steps); SDK means the SDK fulfils the step with its own credentials. Use executeProviderSetupAction for setup steps instead of embedding scheme-specific logic.
  3. Execute — call executeAction() with signed EIP-712, WASM, EVM, or HMAC payloads. session and SIWE steps are completed client-side by the provider plugin and never sent: they produce no signed step to submit, and /executeAction rejects siweLogin.
Every non-meta createAction and executeAction call fails with 401 / 2012 (TermsNotAccepted) until the address has accepted the current terms version. Only meta actions are exempt. Call getTermsAcceptance, then submitOnboarding, before any setup, trading, or withdrawal call, and again after a terms-version change.

createAction

Build action payloads for signing.

Parameters

Returns

CreateActionResponse — { actions: ActionStep[] }. ActionStep is a discriminated union by structural shape — the SDK dispatches to the correct signer based on which key is present. The variant that comes back is determined by the action’s signingMethod on the provider descriptor (see SigningMethod). Eip712ActionStep — EIP-712 typed-data flow (Hyperliquid; most actions): WasmBlobActionStep — WASM signer flow (Lighter): EvmTxActionStep — on-chain EVM transaction (e.g. Lighter deposit): HmacActionStep — provider request signed SDK-side with a client-held API key: SiweActionStep — ERC-4361 login challenge. The provider plugin completes it client-side; it is never sent to executeAction: SessionActionStep — provider-session marker completed client-side, not sent to executeAction. Ondo’s createDepositAddress carries a public { network: 'ethereum', symbol: 'USDC', depositDestination: { wallet: 'margin' } } policy marker; acceptProviderTerms, registerApiKey, and addWithdrawalAddress use an empty marker (session: {}). A session-signed action can also be wire-shaped as a request-bearing step instead of a marker — Ondo’s setReferrer carries a real { method, path, body } request that the SDK submits directly with the session credential rather than HMAC-signing it.
On Hyperliquid, placeOrder with a leverage param always returns an updateLeverage step ahead of the placeOrder step; the SDK never compares leverage with the current setting. Omit leverage to leave the venue setting untouched.

EvmCall

The txParams on the EVM-transaction step variants is an EvmCall:

executeAction

Submit signed action payloads.
executeAction is the HTTP call. It resolves with the backend’s 202 report and does not throw for a failed or indeterminate step. A request or transport error throws. See Execution reports.

Parameters

SignedActionStep is a discriminated union that mirrors ActionStep — each variant carries the original payload plus its signed artefact. Eip712SignedActionStep: WasmBlobSignedActionStep: EvmTxSignedActionStep: HmacSignedActionStep: SiweSignedActionStep ({ action, siwe, signature }) exists in the SignedActionStep union, but the SDK never submits it: siweLogin is completed client-side and /executeAction rejects it.

Returns

ExecuteActionResponse — { results: ActionResult[] }: Each ActionResult:

Execution reports

ExecuteActionResponse.results is an execution report: one ActionResult for each step that the backend attempted, in execution order. @lifi/perps-types exports UserActionStatus with five values, and @lifi/perps-sdk exports isSubmittedOrAccepted(result). Three axes are separate:
  • HTTP status. 202 means that the backend processed the request. It does not mean that the venue accepted a step.
  • Action status. result.status says how far each step went.
  • Error cause. result.errorCode and result.error say why a step failed or is uncertain.
What the report holds:
  • Execution stops at the first step that is Failed or Indeterminate. The later steps are not attempted and have no result.
  • Every member of an attempted atomic batch has its own result. Lighter sends an order and its trigger orders as one batch.
  • Two steps with the same action keep two results. Do not key the results by action.
  • Results of earlier acknowledged steps stay in the report after a later step fails.
  • For a client-executed step, the report holds the SDK result before the backend results. Lighter token-authenticated venue calls and confirmed EVM legs are examples.
Handle every result. The first result does not stand for the report, results.every(isSubmittedOrAccepted) hides the cause of a stop, and a blind retry can repeat an order that the venue already took:
Two cases look alike, and they are not the same:
  • A returned result with status Failed is a confirmed refusal. The errorCode is the venue or LI.FI classification.
  • A thrown error is a request, signing or transport failure with no report. The SDK did not get a result for it. See Error Handling.
When a later stage throws after some results are known, for example the explorer-link step or the onExecuteResults callback, the SDK throws PerpsExecutionError. Its response.results holds every result known at that point, and cause holds the original error. If no result is known, the original error propagates unchanged. The Submitted status does not mean that the SDK pushes later verification updates to your code. Track the outcome with the account reads, for example Order Status.

Setup, options and revoke

executeProviderSetupAction, executeProviderOption and executeProviderRevoke return Promise<ExecuteActionResponse>. They return the report and do not return void. They do not throw for a Failed or Indeterminate step, so read status on each result. They throw PerpsError for the cases in their method reference, and PerpsExecutionError when a later stage fails after a result is known. submitOnboarding, createReferralCode and executeMetaAction follow the same rule. PerpsProviderPlugin.signActions returns { signed, executed }. executed holds the results of steps that the plugin executed on the client. The client puts them in the report before the executeAction results, and it submits signed only when every executed result is Submitted or Accepted.

Release and migration

The status contract is a coordinated breaking release. It replaces the success boolean on ActionResult. Release requirements:
  • Install matching versions of @lifi/perps-sdk, @lifi/perps-types and the provider packages. @lifi/perps-sdk 27.0.0 depends on @lifi/perps-types 24.0.0. Mixed majors read a different result shape.
  • Update the backend and widget consumer pins in the same release. Do not deploy the new backend beneath a consumer that still reads success: the new ActionResult has no such field.
  • This release changes the ActionResult response of /v1/perps/executeAction in place and adds no new API version. If an existing external consumer must keep the old shape, the API needs an explicitly versioned boundary, and this release does not provide one.

Action Types

All action types from the provider’s setup and actions arrays can be used with createAction/executeAction. The relay of the action descriptor says where each signed step goes: API steps go to executeAction, and CLIENT steps go from the client to the venue. See Providers. For parameter schemas per action type, see Actions API. For the high-level convenience wrappers that handle agent signing automatically, see SDK / Trading. API Reference: POST /createAction, POST /executeAction

App-level onboarding

The three Meta actions above are provider-independent: the SDK sends them with the META_PROVIDER ('meta') sentinel instead of a real provider key, so the backend dispatches them without resolving a venue plugin. They carry no ProviderAction descriptor and are always signed as EIP-712 typed data with the end-user’s wallet — never with a provider’s agent, native key, or session credential. PerpsClient exposes three matching methods:
All three methods throw PerpsError when no user wallet is configured, when the backend returns more than one step or a non-EIP-712 step, or when the request fails; a wallet signature refusal propagates as the wallet’s own error. A refused or uncertain step is a result in the report, not an exception. Read status on each result. Use getTermsAcceptance to check the current terms version and whether an address has already accepted it before calling submitOnboarding.