Quickstart — REST API
The REST API is the surface with nothing to install. If you can make an HTTP request, you can call every Wexa tool. This page takes you from nothing to one successful call and one deliberate failure, so that you know what both look like.
Before you start
You need a Wexa project and an administrator role on it. Everything else is on this page.
Step 1 — Get a credential
Every call is authenticated with an API key, and every key is pinned to exactly one project at the moment it is minted. The key carries your organization, department, project, user and role, and that scope never widens — which is why you never pass a project to a tool.
Keys are minted with your own Wexa sign-in token — the session token the console holds once you
have signed in, which is what $FABRIC_USER_TOKEN stands for below. The token identifies you; the
request body says which project the key is for. If you would rather not handle it yourself, the
console mints keys from the same endpoint under Simple mode → Generate API key.
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"
}'
{
"id": "key_...",
"name": "quickstart",
"note": "store this secret now; it is not retrievable again",
"scope": {
"org_id": "org_...",
"dept_id": "dept_...",
"project_id": "proj_...",
"user_id": "user_...",
"role": "OWNER",
"grants": ["fabric:query.read", "fabric:docs.read", "fabric:ontology.write"],
"auth_kind": "api_key"
},
"secret": "fab_sk_..."
}
The note is not decoration. The secret is returned once and is stored only as a hash, so a key you
lose is a key you replace. Put it somewhere your shell can reach it:
export WEXA_API_KEY="fab_sk_..."
Step 2 — Confirm the credential works
Before calling a tool, ask Wexa who it thinks you are. This is a plain GET and it takes no
arguments, so a failure here is unambiguously about the credential.
curl -sS https://fabric.wexa.ai/v1/whoami \
-H "Authorization: Bearer $WEXA_API_KEY"
{
"org_id": "org_...",
"dept_id": "dept_...",
"project_id": "proj_...",
"user_id": "user_...",
"role": "OWNER",
"grants": ["fabric:query.read", "fabric:docs.read", "fabric:ontology.write"]
}
That response is the scope every later call runs in. Nothing you send can change it.
Step 3 — Make your first tool call
Every tool is POST /v1/<tool-name>, in kebab-case, with a JSON body of the tool's arguments. The
documentation tool is the best first call: it is registered in every deployment, takes no data, and
returns your own limits — so a successful response proves the credential, the scope and the quota
all at once.
curl -sS -X POST https://fabric.wexa.ai/v1/docs \
-H "Authorization: Bearer $WEXA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"topic": "governance"}'
{
"lifecycle_id": "qlc_...",
"result": {
"mode": "auto",
"quota": {
"org_window_max": 600,
"org_window_used": 7,
"project_window_max": 120,
"project_window_used": 7
},
"grants": ["fabric:query.read", "fabric:docs.read", "fabric:ontology.write"],
"rules": ["query-context is read-only; queries MUST filter project_id ..."],
"scope": { "project_id": "proj_...", "role": "OWNER", "auth_kind": "api_key" }
}
}
That is a successful call. Every tool returns the same envelope: a lifecycle_id naming the
governance record for this call, and a result holding whatever the tool produced. Reading result
and ignoring the rest is fine; keeping the lifecycle_id is what lets you ask later why a call was
allowed, refused or held.
Step 4 — Write something, then read it back
save-context writes nodes into the project's context graph. Each node needs a label, a merge key
naming which property identifies it, and the properties themselves.
curl -sS -X POST https://fabric.wexa.ai/v1/save-context \
-H "Authorization: Bearer $WEXA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"nodes": [
{
"label": "Customer",
"key": "name",
"properties": { "name": "Acme Corp", "tier": "enterprise" }
}
]
}'
{
"lifecycle_id": "qlc_...",
"result": {
"nodes_merged": 1,
"relationships_merged": 0,
"ontology_extended": true,
"new_labels": ["Customer"]
}
}
ontology_extended and new_labels are the interesting part. In a Simple-mode project the ontology
self-organizes: a label Wexa has not seen before is registered as you write it, rather than being
refused until someone declares it. Write the same node again and ontology_extended comes back
false, because there was nothing new to register.
Reading is query-context, which takes read-only Cypher:
curl -sS -X POST https://fabric.wexa.ai/v1/query-context \
-H "Authorization: Bearer $WEXA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "MATCH (c:Customer) WHERE c.project_id = $project_id RETURN c.name AS name, c.tier AS tier",
"limit": 10
}'
Step 5 — See a refusal
A quickstart that only shows success teaches you half of the surface. Two refusals are worth provoking now, because you will meet both.
Leave out the project filter and the query is rejected before it touches any data:
{
"error": "S4:validate-input",
"error_description": "cypher rejected: query must filter on project_id: use `project_id = $project_id` for this project, or `project_id IN $project_ids` to include projects you were granted",
"lifecycle_id": "qlc_..."
}
Send no credential at all and you never reach the tool:
{
"error": "invalid_token",
"error_description": "missing bearer credential"
}
A key that has been revoked, or simply mistyped, reports itself as such rather than as a permission problem:
{
"error": "invalid_token",
"error_description": "api key invalid or revoked"
}