TypeScript SDK — Getting Started
TypeScript SDK — Getting Started
Section titled “TypeScript SDK — Getting Started”@sencai/sdk is a TypeScript/JavaScript client for the Sencai Platform API (/api/v1/*),
generated from the public OpenAPI spec (openapi-generator-cli, typescript-fetch template —
F4.DEVPORTAL.02). It lives at packages/sdk-ts/ in the monorepo.
Installation
Section titled “Installation”@sencai/sdk is not yet published to npm — public package distribution is a separate
business/release decision, out of scope for the SDK generation work itself. Until then, install
it from the monorepo path or directly from git:
# From inside the monorepo (npm workspace)npm install ./packages/sdk-ts
# From outside the monorepo, over gitnpm install git+https://github.com/sencai-space/packages.git#path:sdk-tsInitialize the client
Section titled “Initialize the client”import { Configuration, OrganisationApi } from "@sencai/sdk";
const config = new Configuration({ // Local dev: http://api.sencai.localhost/api/v1 or http://localhost:1337/api/v1 // Production: https://api.sencai.space/api/v1 basePath: process.env.SENCAI_API_BASE_URL, // Bearer JWT (Keycloak access token today) — or a future API-key header. The // client only provides the injection point; it does not fetch or refresh // the token for you. accessToken: async () => process.env.SENCAI_ACCESS_TOKEN!,});
const organisations = new OrganisationApi(config);basePath and accessToken are always constructor parameters — the package never hardcodes a
production URL.
Complete example: list organisations, invite a member
Section titled “Complete example: list organisations, invite a member”Verified against a local run-local-dev.sh stack (backend, backend-db, auth profiles).
import { Configuration, OrganisationApi } from "@sencai/sdk";
async function main() { const config = new Configuration({ basePath: process.env.SENCAI_API_BASE_URL, accessToken: async () => process.env.SENCAI_ACCESS_TOKEN!, }); const organisations = new OrganisationApi(config);
// List organisations the caller belongs to. const list = await organisations.findOrganisation({ paginationPageSize: 10 }); console.log(list.data.map((org) => org.name)); // -> [ "QA Admin Workspace", "e2e-org-d18a54e2", "e2e-org-d9e67836" ]
const targetOrg = list.data[0]; if (!targetOrg?.documentId) return;
// Invite an existing Strapi user into that organisation. `POST // /organisations/{id}/invite` requires the invitee to already have a // registered account (see the Error handling section below for what // happens otherwise) and the caller to be admin+ in the organisation. const invite = await organisations.organisationInviteMember({ id: targetOrg.documentId, organisationInviteMemberRequest: { email: "new-member@example.com", role: "viewer", }, }); console.log(invite.data); // -> { id: 1266, attributes: { email: "new-member@example.com", role: "viewer", // invitedBy: "you@example.com", invitedAt: "2026-07-05T12:02:45.279Z", status: "pending" } }}
main();Error handling
Section titled “Error handling”Every non-2xx response throws ResponseError (exported from @sencai/sdk, re-exported from its
runtime module) carrying the raw Response
object — the typed method never returns a partially-valid result on failure. Error bodies follow
Strapi’s standard envelope: { error: { status, name, message, details } }.
import { ResponseError } from "@sencai/sdk";
try { await organisations.organisationInviteMember({ id: targetOrg.documentId!, organisationInviteMemberRequest: { email: "new-member@example.com", role: "viewer" }, });} catch (err) { if (err instanceof ResponseError) { const body = await err.response.json(); console.error(err.response.status, body.error.name, body.error.message); // A real, commonly hit example — the organisation's plan seat limit: // 402 PaymentRequired "Member limit reached (3/3). Upgrade your plan." // body.error.details -> { limit: 3, current: 3, limit_source: "organisation_plan", ... } } else { throw err; }}Other status codes you should expect from this endpoint specifically: 400 (missing/invalid
email/role, or no Strapi user registered with that email — this endpoint does not invite
not-yet-registered emails), 401 (missing/expired token), 403 (caller is not admin+ in the
organisation), 409 (that user is already a member).
SDK versioning & breaking changes
Section titled “SDK versioning & breaking changes”The package version (package.json → version) is derived from the OpenAPI spec’s
info.version on every regeneration — it is never bumped by hand. A breaking API change ships as
a new spec major version, which regenerates this SDK as a new major version too. See
API versioning for what counts as breaking, the /api/v1/ →
/api/v2/ migration path, and the SUNSET_DATE deprecation-header convention — this page does
not repeat that policy, only how it surfaces in the generated client.
For the full generated reference of every operation this client exposes, see the API Reference.