On this page

REST API overview

The REST API is the surface with nothing to install. If you can make an HTTP request you can call every Wexa tool, and the two SDKs are thin clients over exactly these routes — nothing is reachable from them that is not reachable here.

If you have not made a first call yet, start at the REST quickstart and come back here for the shape of the whole surface.

One convention for tools, conventional REST for everything else

Wexa splits its routes in two, and the split is worth learning before anything else.

Every tool is POST /v1/<tool-name>, kebab-cased, with a JSON body of arguments. There are no path parameters, no query strings and no verbs other than POST. GET on a tool route answers 405 with an Allow: POST header.

curl -s -X POST "$BASE/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 LIMIT 5"}'

Everything else is conventional REST — GET for reads, plural collections, sub-paths for actions:

curl -s "$BASE/v1/whoami"        -H "Authorization: Bearer $WEXA_API_KEY"
curl -s "$BASE/v1/approvals"     -H "Authorization: Bearer $WEXA_API_KEY"
curl -s "$BASE/v1/lifecycles/qlc_000002" -H "Authorization: Bearer $WEXA_API_KEY"

The gateway states this rule about itself. Calling the documentation tool and reading the rules array returns, verbatim:

REST shape: every TOOL is `POST /v1/<tool-name>` in kebab-case; everything else (whoami, approvals,
audit, lifecycles, catalog) is conventional REST — GET for reads, plural collections, sub-paths for
actions

The uniform envelope

Every successful tool call returns the same two-key object. There is no per-tool wrapper to learn.

{
  "lifecycle_id": "qlc_000007",
  "result": { "nodes_merged": 1, "relationships_merged": 0, "ontology_extended": true, "new_labels": ["Customer"] }
}

lifecycle_id identifies the governed lifecycle the call ran as. Hand it to GET /v1/lifecycles/{id} and you get the stage-by-stage record — which stage passed, which refused, and why. A refusal carries the same lifecycle_id in its error body, so a failure is traceable by exactly the same means as a success.

result is the tool's own payload, and its shape is documented per tool in the tool reference.

The documentation tool is a tool, not a specification

POST /v1/docs is a tool like any other. It takes a topic, it returns prose and structured facts about your own scope, and it is invoked to read — it is not a machine-readable API specification, it serves no OpenAPI or Swagger document, and it returns no schema of any kind.

What it does return is worth a call before you debug anything: your effective grants, your project's mode, your live quota headroom, and the gateway's own operating rules.

curl -s -X POST "$BASE/v1/docs" \
  -H "Authorization: Bearer $WEXA_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"topic":"governance"}'

That returns a result containing:

{
  "grants": ["fabric:query.read", "fabric:docs.read", "fabric:ontology.write", "fabric:orchestrate.read",
             "fabric:orchestrate.write", "fabric:agent.run", "fabric:skill.write", "fabric:model.write"],
  "mode": "auto",
  "quota": { "org_window_max": 600, "org_window_used": 1, "project_window_max": 120, "project_window_used": 1 },
  "rules": ["..."],
  "scope": { "org_id": "org_c10", "project_id": "proj_c10", "role": "OWNER", "auth_kind": "api_key" }
}

It is the fastest answer to "why did that call fail", because it tells you what your credential actually holds rather than what you meant it to hold.

Four arguments are never yours to send

project_id, projectID, organization_id and executed_by are filled in from your credential's scope. Both SDKs refuse them before a request is built.

Every tool exists on every deployment

Sixty-two tools exist, and every gateway registers all of them. GET /v1/connection-info lists them in a tools array. A tool whose backing service the deployment has not configured still has its route, and a call to it fails with an error naming what is missing — <tool> is not configured (no data-service URL), (no harness URL) or (needs the harness and data-service URLs).

A path that names no tool is not a special error: the route simply is not there, and you get an ordinary JSON 404 — {"error":"not_found","error_description":"no route for POST /v1/<tool>"} — with content-type: application/json like every other response. Both SDKs map that to NotFound.

Per-tool arguments, returns and errors live in the tool reference, whose arguments are checked against the gateway's own registration and whose responses are captured from real calls.

The non-tool routes

RouteWhat it is for
GET /healthzLiveness. Unauthenticated.
GET /v1/connection-infoDiscovery: the API base URL, the issuer, the registered tool list. Unauthenticated.
GET /v1/whoamiWho your credential says you are — user, role, organization, department, project, grants.
POST /v1/apikeys, GET /v1/apikeys, DELETE /v1/apikeys/{id}Credential management. Requires a user token, not an API key.
GET /v1/approvals, POST /v1/approvals/{id}/approve, POST /v1/approvals/{id}/rejectThe approval queue and its decisions.
GET /v1/lifecycles/{id}The stage-by-stage record of one governed call.
GET /v1/audit, GET /v1/audit/verifyThe audit record and its hash-chain verification.
GET /v1/policy-decisionsWhat the policy engine ruled, and when.
GET and PUT /v1/projects/{projectId}/modeRead or change a project's mode.
GET /v1/catalog/*The data catalog: assets, lineage, scorecards, connector status, sync statistics.
/v1/codesync/*Repository registration, ingestion and job status for code sync.
POST /v1/agents/{agentflowId}/chat/completionsAn OpenAI-compatible proxy onto a promoted agent version.
/oauth/* and /.well-known/*OAuth 2.1 registration, authorization, token, and the two discovery documents.

Discovery before configuration

The only address you should hard-code is your workspace URL. GET /v1/connection-info is unauthenticated and tells you the rest, so the gateway decides its own address and moving it needs no client change:

curl -s "$WEXA_WORKSPACE/v1/connection-info"
{
  "api": { "base_url": "http://localhost:7123/v1" },
  "issuer": "http://localhost:7123",
  "workspace_header": "X-Wexa-Workspace",
  "tools": ["query-context", "create-ontology", "save-context", "docs", "search-code", "fetch-code"]
}

Both SDKs do exactly this on your behalf before their first call.