Skip to main content
This page enumerates the public API of @lifi/composer-sdk. For the authoritative TypeScript types, browse the package source at unpkg.com/browse/@lifi/composer-sdk.
There is no sdk.compile(). Compile lives on the builder: builder.compile(run). sdk.request(flow, run) is the escape hatch for custom transports.

createComposeSdk(options)

Declared in sdk.ts.
const sdk = createComposeSdk({
  baseUrl: 'https://composer.li.quest',
  apiKey: process.env.LIFI_API_KEY,
  fetch: globalThis.fetch,
});

ComposeSdkOptions

FieldTypeNotes
baseUrlstringBase URL of the Compose API.
apiKeystringRequired during the technical preview. Sent as the x-lifi-api-key header on every request. Get one at portal.li.fi.
fetchtypeof globalThis.fetch?Defaults to the global fetch.

ComposeSdk

Members:
MemberSignatureNotes
clientComposeClientLow-level HTTP client (compile, getManifest, getZapPacks). See sdk.client.
flow<T>(chainId, options: FlowOptions<T>) => FlowBuilder<T>Creates a new flow builder.
request<T>(flow: TypedFlow<T>, run: ComposeRunInput<T>) => ComposeCompileRequestBuilds a compile request without sending it.

sdk.flow(chainId, options)FlowBuilder

const builder = sdk.flow(1, {
  name: 'my-flow',                                 // optional; defaults to a UUID
  inputs: {
    amountIn: resources.erc20(WETH, 1),
    deadline: 'uint256',
  },
});

FlowOptions<T>

FieldTypeNotes
namestring?Human-readable id. Defaults to crypto.randomUUID().
inputsT extends InputSchemaRecord of input name → Resource or SolType.
The generic T carries through to typed handles at builder.inputs.<name>.

FlowBuilder<T>

A FlowBuilder is a FlowBuilderCore<T> (declared in FlowBuilderCore.ts) augmented with a typed method per op plus a compile method.

Inherited FlowBuilderCore members

MemberSignatureNotes
contextContextAccessor{ sender, executionAddress } — typed refs to runtime context values.
inputsInputHandles<T>Typed handle per declared input. Resource inputs → ResourceInputHandle; scalar → InputHandle<T>.
untypedOp(id, op, { bind, config, guards? }) => voidEscape hatch for ops not yet covered by a typed builder method. Accepts raw Ref values.
build() => TypedFlow<T>Serialises the builder state to a Flow document.

Op methods

The SDK exposes a typed method per op the Composer API supports. Examples:
  • builder.lifi.swap(id, args), builder.lifi.zap(id, args)
  • builder.core.call(id, args), builder.core.asResource(id, args), builder.core.balanceOf(id, args), and the arithmetic methods builder.core.add(id, args), subtract, multiply, divideDown, divideUp, bpsDown, bpsUp — one method per arithmetic op.
Each method returns a typed Record<portName, OutputHandle> for the op’s outputs. See the live Ops catalog.

builder.compile(run)

One-shot: calls build(), forms a ComposeCompileRequest via sdk.request, POSTs it to /compose, and returns a ComposeCompileResult.
const result = await builder.compile({
  signer: '0xYourSigner',
  inputs: {
    amountIn: materialisers.directDeposit({ amount: '1000000000000000000' }),
  },
  sweepTo: builder.context.sender,
});
Throws a ComposeError on network, validation, or server errors.

sdk.request(flow, run)ComposeCompileRequest

Use when you need the raw request payload — queueing, server-side proxy, signing the request, inspection in tests.
const flow = builder.build();
const request = sdk.request(flow, {
  signer: '0xYourSigner',
  inputs: { amountIn: materialisers.directDeposit({ amount: '1000000000000000000' }) },
});

const response = await fetch('https://composer.li.quest/compose', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify(request),
});

sdk.client

The low-level HTTP client. Most integrations only need builder.compile(); reach for the client when you build a request via sdk.request() and submit it yourself, or when you need protocol/manifest discovery.
MethodSignatureNotes
compile(request: ComposeCompileRequest) => Promise<ComposeCompileResult>POST /compose. The transport builder.compile() calls under the hood.
getManifest() => Promise<ComposeManifest>GET /compose/manifest. The live catalog of ops, materialisers, and guards the backend accepts — the same source that powers the Ops, Materialisers, and Guards catalogs.
getZapPacks(options?: GetZapPacksOptions) => Promise<readonly ZapPackOverview[]>GET /compose/zap-packs. The dynamic routing-edge catalog — which tokens can be routed into which protocol positions on which chains. Use it to discover valid lifi.zap resourceOut targets.
// Discover which tokens can be zapped into Aave positions.
const packs = await sdk.client.getZapPacks({ protocols: 'aave' });
for (const pack of packs) {
  for (const edge of pack.edges) {
    // edge.type ('enter-position' | 'exit-position' | …), edge.in, edge.out
  }
}
getZapPacks accepts an optional { protocols?: string | readonly string[] } filter. Results are not cached by the SDK — cache as appropriate for your refresh needs. See the routing edges catalog for the rendered live view.

ComposeCompileResult

A discriminated union on the status field. Branch on result.status before accessing shape-specific fields.
type ComposeCompileResult =
  | (ComposeCompileSuccessData & { status: 'success' })
  | (ComposeCompilePartialData  & {
      status: 'partial';
      error: { kind: ComposeErrorKind; message: string };
      simulationRevert: SimulationRevert;
    });
  • status: 'success' — returned under the default simulationPolicy: 'strict' when the compile and simulation both succeed.
  • status: 'partial' — returned only when simulationPolicy: 'allow-revert' was passed on the run and the simulation reverted. The transactionRequest is still present; the revert diagnostics are exposed for the caller to surface.
Both shapes carry the core fields: transactionRequest, userProxy, producedResources, producedHandles (values for any output handles marked expose: true), optional approvals, optional priceImpact, and optional fees.

ComposeRunInput<T>

Declared in run/inputs.ts.
FieldTypeNotes
inputs{ [K in keyof T]: InputSpecOf<T[K]> }Per-input value — bigint, hex string, or materialiser descriptor.
signerAddress0x-prefixed signer address.
preconditionsreadonly Precondition[]?Invariants asserted before execution.
assumptions{ [K in keyof T]?: bigint }?Assumed amounts when materialisers resolve at execution time.
referrerstring?Integrator referrer id.
integratorFeeBpsnumber?Integrator fee in basis points (1bp = 0.01%, max 9000). Defaults to 0. A non-zero value requires an integration-scoped API key — the integration is derived from the key, not this field.
maxPriceImpactBpsnumber?Reject compile if aggregate USD price impact exceeds the bound.
sweepToSweepTo?Destination for terminal proxy-held resources. Address literal or { $ref: "context.sender" }.
simulationPolicy"strict" | "allow-revert"?Default "strict".
checkOnChainAllowancesboolean?Omit approvals already satisfied on-chain.

Handles

Declared in authoring/handles.ts.
  • InputHandle<T>{ _tag: 'input', inputName, __outputKind?: T }. Carries the input’s output kind as a phantom type parameter.
  • ResourceInputHandleInputHandle<'resource'> & { resource: Resource }.
  • OutputHandle<T>{ _tag: 'output', nodeId, portName, __outputKind?: T }.
  • Bindable<T> — the union of values accepted in a typed bind slot: InputHandle<T>, OutputHandle<T>, TypedRef<T>. For 'uint256' slots, 'resource'-tagged handles are also accepted (resources are uint256 amounts).
Convert handles to raw refs with handleToRef (exported from the same module).

Namespaces

  • resources — helpers to declare token resources (resources.erc20(token, chainId), resources.native(chainId)).
  • materialisers — generated helpers for registered materialisers (materialisers.directDeposit({ amount }), materialisers.balanceOf({ ... }), …).
  • guards — generated helpers for registered guards (guards.slippage({ port, bps }), …).
  • raw — low-level escape hatches: raw.ref<T>(path) creates a TypedRef<T>; raw.guard(kind, config?) builds an AppliedGuard for guard kinds not yet covered by a typed helper; raw.materialiser(kind, config?) builds a MaterialiserInput for the same reason.

TypedFlow<T>

The Flow document returned by builder.build(). Structurally identical to Flow from @lifi/compose-spec, with a phantom __inputs?: T carrying the input schema through TypeScript inference (__inputs does not exist at runtime).

Error types

ComposeError (re-exported from @lifi/compose-spec) carries:
{
  kind: ComposeErrorKind;   // e.g. "validation_error" | "guard_error" | "simulation_revert" | …
  message: string;
  path?: string;
}
See Error codes for the full catalog and the HTTP status each kind maps to.

See also

  • Quickstart — five-minute first-flow walkthrough.
  • Build a Flow — production setup, inputs, ops, materialisers, guards, preconditions, submission.
  • Flow wire format — the JSON the SDK produces.