Docs
Tutorials
How-to guides
Reference
Explanation
Release notes
Search
Docs
/

SDK API Reference

@ligantic/sdk is a thin, result-based, versioned mirror of the Ligantic OpenAPI v1 surface. Every operation returns Promise<LiganticResult<T>> and request methods return failures as the Err side (no thrown API/transport errors).

Note: Constructing new Ligantic({ apiKey }) validates apiKey and throws if it is missing/empty.

  • Package: @ligantic/sdk
  • Requires Node.js 22+
  • Entry point: import { Ligantic } from "@ligantic/sdk"

The Ligantic Client

new Ligantic(options: LiganticOptions)

The client owns authentication, the User-Agent header, the base URL, and the retry-aware transport. It exposes five resource groups: identity, spaces, schemas, records, and flows.

LiganticOptions

Field

Type

Default

Description

apiKey

string

— (required)

Sent as Authorization: Bearer <key>.

baseUrl

string

https://ligantic.cloud/api/v1

Override for staging or self-hosted deployments.

retry

RetryOptions

{}

Retry policy. See Retry.

fetch

typeof fetch

global fetch

Injectable for tests.

userAgent

string

ligantic-sdk/<version> (node <major>)

The User-Agent header value.

Instance Properties

Property

Type

Description

identity

Identity

The authenticated user.

spaces

Spaces

Spaces: list, get, create, rename, delete.

schemas

Schemas

Schemas: list, get, create, update, delete, get config.

records

Records

Records: list, query, get, create, update, delete, json-patch.

flows

Flows

Flows: CRUD, run, and run inspection.

experiences

Experiences

Experiences: list, get, create, rename, delete, clone.

client.request(method, path, options?)

The transport boundary. Performs a single, retry-aware request and returns the parsed JSON body as a LiganticResult<TransportResult>. Applies authentication, the User-Agent, and the retry policy, and normalises failures into a LiganticError. It never throws.

request(
  method: string,
  path: string,
  options?: {
    query?: Record<string, unknown>;
    body?: unknown;
    signal?: AbortSignal;
  },
): Promise<LiganticResult<TransportResult>>

TransportResult is { status: number; headers: Headers; body: unknown }.

Exported Constants

Constant

Value

Description

SDK_VERSION

"1.59.0"

The SDK version, sent in User-Agent.

DEFAULT_BASE_URL

https://ligantic.cloud/api/v1

The default base URL.

Result and Error Types

Result<T, E>

type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };
type LiganticResult<T> = Result<T, LiganticError>;

Helpers: ok(value), err(error), and tryOr(fn, toError) (captures a thrown error as the Err side).

See The Result-Based Error Model.

LiganticError

The Err side of every result. Mirrors the API error envelope { message, code, issues? } and adds the HTTP status and requestId.

Field

Type

Description

message

string

Human-readable message.

status

number | null

HTTP status, or null for transport-level failures (no response).

code

string

The API error code, for example, "NOT_FOUND", "UNAUTHORIZED".

issues

LiganticErrorIssue[]

Validation issues, present for 422-style responses.

requestId

string

The x-request-id header, when present.

retryAfterMs

number

The Retry-After wait in milliseconds, on a 429; unset when the server sends no Retry-After.

isTransportError

boolean (getter)

True when status === null.

isRetryable

boolean (getter)

True for transport errors, 408, 429, or 5xx.

transportError(cause) normalises a thrown fetch failure: aborted requests become REQUEST_ABORTED, other failures become NETWORK_ERROR.

Retry

RetryOptions controls the retry policy.

Field

Type

Default

Description

maxRetries

number

3

Max retries, not counting the initial attempt.

baseDelayMs

number

500

Base backoff delay.

maxDelayMs

number

10000

Upper bound on a single backoff delay.

maxRetryAfterMs

number

60000

Upper bound on a single 429 Retry-After wait.

idempotentMethods

ReadonlySet<string>

GET, DELETE, PUT

Methods considered idempotent.

sleep

(ms) => Promise<void>

setTimeout

Injectable clock for tests.

random

() => number

Math.random

Injectable jitter source (0..1).

onRetry

(info) => void

—

Called before each retry with { attempt, delayMs, status }.

A 429 is always auto-retried, for any method — the server rejects it before the handler runs, so it is safe even for POST and PATCH. Other retryable failures (transport failures, 408, 5xx) are retried only for idempotent requests (GET, DELETE, PUT). Backoff is exponential with full jitter; a 429 with a Retry-After waits at least that long, capped by maxRetryAfterMs.

Identity

Method

Signature

Returns

me

me()

LiganticResult<User>

GET /users/me — the authenticated user for the current API key.

Spaces

Method

Signature

Returns

list

list()

LiganticResult<SpaceSummary[]>

get

get(spaceId)

LiganticResult<Space>

create

create(input: CreateSpaceInput)

LiganticResult<CreateSpaceResult>

rename

rename(spaceId, input: UpdateSpaceTitleInput)

LiganticResult<null>

delete

delete(spaceId)

LiganticResult<null>

  • list — GET /spaces. Returns a summary per Space (id, title, role, owner info).
  • get — GET /spaces/{spaceId}.
  • create — POST /spaces. CreateSpaceInput is { title, parentSpaceId?, organisationId?, organisationBillingAccountId?, cloneFromSpaceId? }. Returns { spaceId }.
  • rename — PATCH /spaces/{spaceId}/title. Updates the Space title.
  • delete — DELETE /spaces/{spaceId}.

Schemas

Method

Signature

Returns

list

list(spaceId)

LiganticResult<SchemaSummary[]>

get

get(spaceId, schemaId)

LiganticResult<Schema>

create

create(spaceId, input: CreateSchemaInput)

LiganticResult<CreateSchemaResult>

update

update(spaceId, schemaId, input: UpdateSchemaInput)

LiganticResult<UpdateSchemaResult>

delete

delete(spaceId, schemaId)

LiganticResult<null>

getConfig

getConfig(spaceId, schemaId)

LiganticResult<SchemaConfig>

  • list — GET /spaces/{spaceId}/schemas.
  • get — GET /spaces/{spaceId}/schemas/{schemaId}. Includes the Schema's versions.
  • create — POST /spaces/{spaceId}/schemas.
  • update — PATCH /spaces/{spaceId}/schemas/{schemaId}. Updates name, display template, auto-save, and config.
  • delete — DELETE /spaces/{spaceId}/schemas/{schemaId}.
  • getConfig — GET /spaces/{spaceId}/schemas/{schemaId}/config.

Records

A Record is an instance of a Schema. Its API paths use entities; the SDK exposes it as records.

Method

Signature

Returns

list

list(spaceId, schemaId, params?: ListRecordsParams)

LiganticResult<ListRecordsResult>

query

query(spaceId, schemaId, input: QueryRecordsInput)

LiganticResult<QueryRecordsResult>

get

get(spaceId, schemaId, recordId)

LiganticResult<LiganticRecord>

create

create(spaceId, schemaId, input: CreateRecordInput)

LiganticResult<CreateRecordResult>

update

update(spaceId, schemaId, recordId, input: UpdateRecordInput)

LiganticResult<UpdateRecordResult>

delete

delete(spaceId, schemaId, recordId)

LiganticResult<null>

patch

patch(spaceId, schemaId, recordId, input: JsonPatchInput)

LiganticResult<JsonPatchResult>

createRelationship

createRelationship(spaceId, schemaRelationshipVersionId, input: { fromId, toId })

LiganticResult<{ entityRelationshipId }>

removeRelationship

removeRelationship(spaceId, schemaRelationshipVersionId, entityRelationshipId)

LiganticResult<null>

getFileUrl

getFileUrl(spaceId, schemaId, recordId, fileId)

LiganticResult<{ url }>

prepareFile

prepareFile(spaceId, schemaId, input: PrepareFileInput)

LiganticResult<PrepareFileResult>

createFileUploadUrl

createFileUploadUrl(spaceId, schemaId, recordId, fileId)

LiganticResult<FileUploadUrl>

confirmUploads

confirmUploads(spaceId, schemaId, recordId, action: "create" | "update")

LiganticResult<null>

  • list — GET /spaces/{spaceId}/schemas/{schemaId}/entities. Params are passed through raw: limit, offset, cursor, filter, sort, select, fullTextFilter, and more. Returns { entities, count, offset, limit }.
  • query — POST /spaces/{spaceId}/schemas/{schemaId}/entities/query. Runs a Record query. QueryRecordsInput is { select, groupBy?, filter?, sort?, offset?, limit?, cursor? }; limit above 1000 is lowered to 1000. Returns { rows, count, offset, limit }, one row per Record (or per group with groupBy), keyed by select alias.
  • get — GET /spaces/{spaceId}/schemas/{schemaId}/entities/{entityId}.
  • create — POST .../entities. CreateRecordInput is { data?, hasPendingUploads?, nameBased? }. Returns { entityId }.
  • update — PATCH .../entities/{entityId}. Full replace of the data object.
  • delete — DELETE .../entities/{entityId}.
  • patch — PATCH .../entities/{entityId}/json-patch. Applies a JSON Patch. JsonPatchInput is { operations: JsonPatchOperation[], hasPendingUploads?, nameBased? } where each operation is one of add, remove, replace, move, copy, or test. An add or replace of a field inside an object the Record does not have, or holds as null (for example /price/currency on a Record without a price), adds the object with that field.
  • createRelationship — POST /spaces/{spaceId}/schemas-relationships/{schemaRelationshipVersionId}/entities. Creates a relationship (link) row between two Records for a Schema relationship version. input is { fromId, toId } (the Record IDs on the version's from/to sides). Returns { entityRelationshipId }. A relationship version whose field is nested inside an array is rejected with a BAD_REQUEST — the link names no array row. Set such a field with a row-level update/patch on the specific array row instead.
  • removeRelationship — DELETE /spaces/{spaceId}/schemas-relationships/{schemaRelationshipVersionId}/entities/{entityRelationshipId}. Removes a relationship (link) row. The entityRelationshipId is the id of a relationship row (see get/list with relationships).
  • getFileUrl — GET /spaces/{spaceId}/schemas/{schemaId}/entities/{entityId}/files/{fileId}. Returns a short-lived signed URL for a file attached to the Record. Fetch the URL with a plain GET (no API key) to download the bytes. Needs read access to the Record; a file that is not on the Record returns NOT_FOUND. File IDs are the id of the file entries in the Record's data (f-…).
  • prepareFile — POST /spaces/{spaceId}/schemas/{schemaId}/files. Builds a file entry for a top-level file field, without writing anything. PrepareFileInput is { field, name, size, mimeTypeId? }. field is the field's name or id. mimeTypeId defaults to the type for name's extension. The server checks create or update access and the field's allowed types and maximum size; a failed check returns BAD_REQUEST with the reason. Returns { file, fieldId, fieldName, multiple }.
  • createFileUploadUrl — POST /spaces/{spaceId}/schemas/{schemaId}/entities/{entityId}/files/{fileId}. Returns { uploadUrl, uploadFields }, a short-lived signed upload for a file entry already in the Record's data. NOT_FOUND if the entry is not there.
  • confirmUploads — POST .../entities/{entityId}/confirm-uploads-complete. Runs the Record's create or update Flows that hasPendingUploads deferred.

Upload files the way the app does, so that required file fields are satisfied and Flows see the files:

  1. Call prepareFile for each file.
  2. Write each file into its field with create, update or patch, passing hasPendingUploads: true. For a multiple-file field, write a list.
  3. For each file, call createFileUploadUrl, then POST a multipart/form-data body to uploadUrl with every uploadFields entry, then the bytes as the last field, file. Send no API key. The body must be exactly size bytes, and the signed upload expires after a few minutes.
  4. Call confirmUploads with "create" or "update". Skip this step if an upload failed, so that Flows do not run without the file.

A Record from get or list and the result of update or patch include its version. It is 1 when the Record is created and increases by one with every write to it (including archiving and restoring), in the order the writes are applied, so of two reads of the same Record the one with the higher version is the newer. Adding or removing a Record's relationships does not change it.

Flows

run runs the current published Flow. The SDK cannot select a Flow version.

Method

Signature

Returns

list

list(spaceId, params?: ListFlowsParams)

LiganticResult<FlowSummary[]>

get

get(spaceId, flowId)

LiganticResult<Flow>

create

create(spaceId, input: CreateFlowInput)

LiganticResult<CreateFlowResult>

delete

delete(spaceId, flowId)

LiganticResult<null>

getBySchema

getBySchema(spaceId, schemaId, params?: ListFlowsBySchemaParams)

LiganticResult<FlowSummary[]>

run

run(spaceId, flowId, input: RunFlowInput)

LiganticResult<RunFlowResult>

listRuns

listRuns(spaceId, flowId, params?: ListRunsParams)

LiganticResult<ListRunsResult>

getRun

getRun(spaceId, flowId, runId)

LiganticResult<FlowRun>

getRunOutputs

getRunOutputs(spaceId, flowId, runId, params?: GetRunOutputsParams)

LiganticResult<RunOutputs>

cancelRun

cancelRun(spaceId, flowId, runId)

LiganticResult<null>

  • list — GET /spaces/{spaceId}/flows.
  • get — GET /spaces/{spaceId}/flows/{flowId}. Includes the Flow's versions.
  • create — POST /spaces/{spaceId}/flows.
  • delete — DELETE /spaces/{spaceId}/flows/{flowId}.
  • getBySchema — GET /spaces/{spaceId}/flows/by-schema/{schemaId}.
  • run — POST /spaces/{spaceId}/flows/{flowId}/execute. Asynchronous: returns { flowExecutionId, spaceId } immediately. RunFlowInput is { triggerNodeId?, inputs?, hasPendingUploadFiles?, nameBased?, logLevel?, scheduledAt? }.
  • listRuns — GET /spaces/{spaceId}/flows/{flowId}/executions. Returns { total, limit, offset, data }.
  • getRun — GET .../executions/{executionId}.
  • getRunOutputs — GET .../executions/{executionId}/outputs. Returns the run plus its outputs (a map of output handle name → value, or null).
  • cancelRun — POST .../executions/{executionId}/cancel.

FlowRunStatus

"scheduled" | "pending" | "executing" | "failed" | "succeeded" | "cancelled". The terminal statuses are succeeded, failed, and cancelled.

Experiences

Method

Signature

Returns

list

list(spaceId, params?: ListExperiencesParams)

LiganticResult<ExperienceSummary[]>

get

get(spaceId, experienceId, params?: GetExperienceParams)

LiganticResult<Experience>

create

create(spaceId, input: CreateExperienceInput)

LiganticResult<CreateExperienceResult>

rename

rename(spaceId, experienceId, name)

LiganticResult<null>

delete

delete(spaceId, experienceId)

LiganticResult<null>

clone

clone(spaceId, experienceId, input?: CloneExperienceInput)

LiganticResult<CloneExperienceResult>

listVersions

listVersions(spaceId, experienceId, params?: ListExperienceVersionsParams)

LiganticResult<ListExperienceVersionsResult>

createVersion

createVersion(spaceId, experienceId, input: CreateExperienceVersionInput)

LiganticResult<CreateExperienceVersionResult>

updateVersion

updateVersion(spaceId, experienceId, experienceVersionId, input: UpdateExperienceVersionInput)

LiganticResult<null>

setVersionContent

setVersionContent(spaceId, experienceId, experienceVersionId, block: ExperienceBlock | null)

LiganticResult<null>

publishVersion

publishVersion(spaceId, experienceId, experienceVersionId)

LiganticResult<null>

setVersionMetadata

setVersionMetadata(spaceId, experienceId, experienceVersionId, name: ExperienceMetadataName, value: ExperienceMetadataValue)

LiganticResult<null>

renameVersionMetadata

renameVersionMetadata(spaceId, experienceId, experienceVersionId, currentName, newName)

LiganticResult<null>

removeVersionMetadata

removeVersionMetadata(spaceId, experienceId, experienceVersionId, name)

LiganticResult<null>

  • list — GET /spaces/{spaceId}/experiences. ListExperiencesParams is { omitUnpublished?, omitExperiencesWithRequiredPathVariables? }. Each summary is { id, name, pathname, isPublished }.
  • get — GET /spaces/{spaceId}/experiences/{experienceId}. Returns the latest version, or the version given by experienceVersionId, including its block and metadata. Fails with a NOT_FOUND error when the Experience does not exist.
  • create — POST /spaces/{spaceId}/experiences. CreateExperienceInput is { name, title?, pathname? }. Creates a draft first version and returns { experienceId, experienceVersionId }.
  • rename — PATCH /spaces/{spaceId}/experiences/{experienceId}.
  • delete — DELETE /spaces/{spaceId}/experiences/{experienceId}.
  • clone — POST /spaces/{spaceId}/experiences/{experienceId}/clone. CloneExperienceInput is { experienceVersionId? }.
  • listVersions — GET /spaces/{spaceId}/experiences/{experienceId}/versions. Newest first. ListExperienceVersionsParams is { limit?, cursor? }; pass the returned nextCursor back as cursor while hasMore is true.
  • createVersion — POST .../versions. Creates a draft version. CreateExperienceVersionInput is { title, pathname, poweredByLogoRemoved, block?, version?, sourceExperienceVersionId? }; version defaults to the latest version with its patch number incremented, and sourceExperienceVersionId copies that version's metadata.
  • updateVersion — PATCH .../versions/{experienceVersionId}. UpdateExperienceVersionInput is { title, pathname? }.
  • setVersionContent — PUT .../versions/{experienceVersionId}/content. Replaces the version's root block. Only draft versions can be changed; a published version fails with NOT_FOUND.
  • publishVersion — POST .../versions/{experienceVersionId}/publish.
  • setVersionMetadata — PUT .../versions/{experienceVersionId}/metadata/{name}. Creates or replaces a page metadata value such as description, og:title, or og:image. ExperienceMetadataValue is a string, or a media source for image and icon names. Works on draft and published versions.
  • renameVersionMetadata — POST .../metadata/{currentName}/rename. Moves the value to newName, replacing any value already set there. Fails with NOT_FOUND when currentName is not set.
  • removeVersionMetadata — DELETE .../metadata/{name}.

Read a version's metadata from the metadata field of get.

A published Experience changes only through a draft version: createVersion creates the draft, setVersionContent sets its content, and publishVersion publishes it. Read a version's content with get(spaceId, experienceId, { experienceVersionId }).

Exported Types

The package re-exports the stable public types: User, Space, SpaceSummary, CreateSpaceInput, CreateSpaceResult, UpdateSpaceTitleInput, Schema, SchemaSummary, CreateSchemaInput, CreateSchemaResult, UpdateSchemaInput, UpdateSchemaResult, SchemaConfig, LiganticRecord, ListRecordsResult, ListRecordsParams, QueryRecordsInput, QueryRecordsResult, CreateRecordInput, CreateRecordResult, UpdateRecordInput, UpdateRecordResult, JsonPatchInput, JsonPatchOperation, JsonPatchResult, Flow, FlowSummary, CreateFlowInput, CreateFlowResult, ListFlowsParams, ListFlowsBySchemaParams, RunFlowInput, RunFlowResult, FlowRun, FlowRunStatus, ListRunsParams, ListRunsResult, RunOutputs, GetRunOutputsParams, Experience, ExperienceSummary, GetExperienceParams, ListExperiencesParams, CreateExperienceInput, CreateExperienceResult, CloneExperienceInput, CloneExperienceResult, ExperienceVersionSummary, ListExperienceVersionsParams, ListExperienceVersionsResult, CreateExperienceVersionInput, CreateExperienceVersionResult, UpdateExperienceVersionInput, ExperienceBlock, ExperienceMetadataName, ExperienceMetadataValue, plus the result/error types and the resource classes (Identity, Spaces, Schemas, Records, Flows, Experiences).

Related pages

Page not found. It may have moved or may not be published.
Browse documentation