Discovery
Two routes answer without a credential and exist to be called first: GET /healthz, which says
whether the gateway is up, and GET /v1/connection-info, which says where everything else is. Both
SDKs call the second one before their first tool call, and a client that does the same needs only
one hard-coded value — the workspace URL.
Neither route takes a credential, and neither returns a secret.
GET /healthz
Liveness. No parameters, no authentication, and no dependency on any downstream service — it answers
200 whether or not anything it depends on is reachable.
curl -sS https://fabric.wexa.ai/healthz
{ "status": "ok", "service": "api-gateway" }
GET /v1/connection-info
The public connection contract. Unauthenticated by design: it is what a client reads in order to authenticate, so requiring a credential would be circular.
curl -sS https://fabric.wexa.ai/v1/connection-info
{
"mcp": {
"url_template": "https://fabric.wexa.ai/mcp/{projectId}",
"sse_url": "https://fabric.wexa.ai/sse",
"auth": "OAuth 2.1 (PKCE) or Bearer API key (fab_sk_…)"
},
"api": { "base_url": "https://fabric.wexa.ai/v1" },
"sdk": {
"python": { "package": "wexa", "install": "pip install wexa" },
"node": { "package": "@wexa-fabric/sdk", "install": "npm install @wexa-fabric/sdk" }
},
"workspace_header": "X-Wexa-Workspace",
"issuer": "https://fabric.wexa.ai",
"tools": ["query-context", "create-ontology", "save-context", "docs", "search-code", "fetch-code",
"... every tool this deployment registers, one entry each"]
}
tools is the whole list, not a sample: it names every tool the deployment registers, all sixty-two. The excerpt above is shortened for the page. sdk carries an entry per SDK — both
python and node — so a client can report the package a reader should install without hard-coding
its name.
Field by field
| Field | What it is |
|---|---|
mcp.url_template | The per-project connect URL for the Wexa MCP server. Substitute the project id for {projectId}. This is the value to configure a client with. |
mcp.sse_url | The legacy SSE transport's address. See the warning below — the default value is wrong. |
mcp.auth | A human-readable note on which credentials that surface accepts. Not machine-readable; do not parse it. |
api.base_url | The REST base. Every tool is POST <base_url>/<tool-name>. |
sdk.python / sdk.node | Package name and install command for each published SDK. node is omitted entirely when the deployment has not configured one, so treat its absence as "not advertised here" rather than "not published". |
workspace_header | The header name this deployment uses to carry the workspace. |
issuer | The OAuth issuer. Both .well-known documents hang off it. |
tools | The tools this deployment registered, by wire name. |
tools is the only honest tool list
Every gateway registers every tool, whichever services the deployment is configured with. A tool
whose backing service is missing is still in this array, 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.
So read this array rather than hard-coding a list. Per-tool arguments and returns live in the tool reference.
Discovery before configuration
The pattern these two routes support is worth stating plainly, because it is what keeps a client working when the platform moves.
Hard-code one value — the workspace URL. Derive everything else:
export WEXA_WORKSPACE=https://fabric.wexa.ai
BASE=$(curl -sS "$WEXA_WORKSPACE/v1/connection-info" | python3 -c 'import sys,json;print(json.load(sys.stdin)["api"]["base_url"])')
curl -sS "$BASE/whoami" -H "Authorization: Bearer $WEXA_API_KEY"
Both SDKs do exactly this on your behalf before their first call. The gateway then decides its own address, and moving it — to a different host, a different port, a different path prefix — needs no client change and no coordinated release.
The same reasoning applies to the OAuth documents, which the issuer field locates and
OAuth 2.1 documents field by field. Between the three of them, a client that
starts with a URL and no configuration can reach a credential without anyone telling it anything.
What these routes will not tell you
Discovery is deliberately thin. It carries no secrets, no per-caller state and no organization detail, because anyone who can reach the gateway can read it. In particular it does not report your grants, your project's mode, or your quota headroom — those depend on who is asking, so they need a credential and live on identity and the documentation tool instead.