On this page

Quickstart — TypeScript SDK

The TypeScript SDK is a typed client over the same tools the REST API exposes. It gives you typed arguments, typed results and a distinct error class per failure, and it refuses some mistakes before a request leaves your process.

Before you start

You need Node 18 or newer, a Wexa project, and an administrator role on that project so you can mint a credential.

Step 1 — Install

npm install @wexa-fabric/sdk

The package ships both ESM and CommonJS builds with type declarations for each, so it works from import and from require without a shim.

Step 2 — Get a credential

The SDK does not mint credentials; you mint one once and hand it to the client. An API key is pinned to exactly one project when it is created, and that scope never widens — which is why the client takes no project argument anywhere.

$FABRIC_USER_TOKEN below is your own Wexa sign-in token, the session token the console holds once you have signed in. The console mints keys from this same endpoint under Simple mode → Generate API key if you would rather not handle it yourself.

curl -sS -X POST https://fabric.wexa.ai/v1/apikeys \
  -H "Authorization: Bearer $FABRIC_USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"org_id":"org_...","dept_id":"dept_...","project_id":"proj_...","name":"quickstart"}'

The response carries the secret exactly once:

{
  "id": "key_...",
  "name": "quickstart",
  "note": "store this secret now; it is not retrievable again",
  "secret": "fab_sk_..."
}

Minting a key requires an owner, organization-administrator or project-administrator role; any other role is refused with API key creation requires an admin role on this project.

Step 3 — Construct a client

The client needs the workspace and the credential. Pass them explicitly, or leave the options out entirely and let it read WEXA_WORKSPACE and WEXA_API_KEY from the environment.

export WEXA_WORKSPACE="https://fabric.wexa.ai"
export WEXA_API_KEY="fab_sk_..."
import { Fabric } from '@wexa-fabric/sdk'

const fabric = new Fabric()

Step 4 — Make your first call

The documentation tool is the best first call: it is registered in every deployment, needs no data in your project, and returns your own scope and limits, so a successful response proves the credential and the scope together.

const governance = await fabric.docs({ topic: 'governance' })

console.log(governance.mode)
console.log(JSON.stringify(governance.quota))
auto
{"org_window_max":600,"org_window_used":4,"project_window_max":120,"project_window_used":4}

The SDK returns the result of the envelope directly, so you get the tool's own output rather than a wrapper to unpack. mode is the project mode — auto is Simple mode — and quota is your rolling call budget at both the project and the organization level.

Step 5 — Write and read the context graph

saveContext writes nodes. Each node needs a label, a merge key naming the property that identifies it, and the properties themselves.

const written = await fabric.saveContext({
  nodes: [
    {
      label: 'Customer',
      key: 'name',
      properties: { name: 'Acme Corp', tier: 'enterprise' },
    },
  ],
})

console.log(JSON.stringify(written))
{"nodes_merged":1,"relationships_merged":0,"ontology_extended":false}

ontology_extended reports whether writing that node taught the project a type it did not have. The first time a Customer is written it is true and new_labels names it; afterwards it is false, because there was nothing new to register.

Reading takes read-only Cypher, and the query must filter on the project:

const rows = await fabric.queryContext({
  query: 'MATCH (c:Customer) WHERE c.project_id = $project_id RETURN c.name AS name',
})

console.log(rows.row_count)

Step 6 — See a refusal

$project_id above is bound by Wexa from your credential. Try to supply it yourself and the SDK stops the call at the call site, before any request is built:

await fabric.queryContext({
  query: 'MATCH (n) WHERE n.project_id = $project_id RETURN n',
  project_id: 'someone_elses',
})
ValidationError: ['project_id'] are bound server-side from your token scope; sending them is rejected

This is a run-time refusal rather than a compile-time one: the argument is rejected when the call runs, not by the type checker. That is deliberate — the same check has to hold for arguments assembled at run time, which no type system sees. The four arguments treated this way are project_id, projectID, organization_id and executed_by.

Step 7 — Release the client

The client holds an abort controller so that an in-flight request and any approval poll can be cancelled together. In a long-lived process, close it when you are done:

fabric.close()

Calling it twice is a no-op, and the client cannot be reused afterwards.

Where to go next