@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 })validatesapiKeyand throws if it is missing/empty.
@ligantic/sdkimport { Ligantic } from "@ligantic/sdk"Ligantic Clientnew 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.
LiganticOptionsField | Type | Default | Description |
|---|---|---|---|
|
| — (required) | Sent as |
|
|
| Override for staging or self-hosted deployments. |
|
|
| Retry policy. See Retry. |
|
| global | Injectable for tests. |
|
|
| The |
Property | Type | Description |
|---|---|---|
|
| The authenticated user. |
|
| Spaces: list, get, create, rename, delete. |
|
| Schemas: list, get, create, update, delete, get config. |
|
| Records: list, query, get, create, update, delete, json-patch. |
|
| Flows: CRUD, run, and run inspection. |
|
| 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 }.
Constant | Value | Description |
|---|---|---|
|
| The SDK version, sent in |
|
| The default base URL. |
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.
LiganticErrorThe Err side of every result. Mirrors the API error envelope { message, code, issues? } and adds the HTTP status and requestId.
Field | Type | Description |
|---|---|---|
|
| Human-readable message. |
|
| HTTP status, or |
|
| The API error code, for example, |
|
| Validation issues, present for |
|
| The |
|
| The |
|
| True when |
|
| True for transport errors, |
transportError(cause) normalises a thrown fetch failure: aborted requests become REQUEST_ABORTED, other failures become NETWORK_ERROR.
RetryOptions controls the retry policy.
Field | Type | Default | Description |
|---|---|---|---|
|
|
| Max retries, not counting the initial attempt. |
|
|
| Base backoff delay. |
|
|
| Upper bound on a single backoff delay. |
|
|
| Upper bound on a single |
|
|
| Methods considered idempotent. |
|
|
| Injectable clock for tests. |
|
|
| Injectable jitter source (0..1). |
|
| — | Called before each retry with |
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.
Method | Signature | Returns |
|---|---|---|
|
|
|
GET /users/me — the authenticated user for the current API key.
Method | Signature | Returns |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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}.Method | Signature | Returns |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.A Record is an instance of a Schema. Its API paths use entities; the SDK exposes it as records.
Method | Signature | Returns |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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:
prepareFile for each file.file into its field with create, update or patch, passing hasPendingUploads: true. For a multiple-file field, write a list.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.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.
run runs the current published Flow. The SDK cannot select a Flow version.
Method | Signature | Returns |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.
Method | Signature | Returns |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 }).
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).