REST API
Use the faz REST API for non-MCP clients, scripts, and CI. Same safety pipeline, plain HTTP.
faz serve exposes faz's full surface as a FastAPI app on 127.0.0.1:8787. Use this when the client isn't an MCP-compatible AI assistant — scripts, custom agents, dashboards, CI checks, or anything that just wants to send HTTP requests.
For the per-endpoint reference (every path, every field, every status code), see REST endpoints.
Prerequisites
- faz installed (
pip install faz-core— see Install). - A
faz.yamlwith at least one database connection and a permissions block.
Start the server
faz serveuv run faz servepython -m faz serveOutput:
INFO: Uvicorn running on http://127.0.0.1:8787 (Press CTRL+C to quit)
INFO: Application startup complete.Default bind is 127.0.0.1:8787. To bind elsewhere:
faz serve --host 127.0.0.1 --port 9000uv run faz serve --host 127.0.0.1 --port 9000python -m faz serve --host 127.0.0.1 --port 9000Anything off-loopback prints a warning at startup:
warning: binding '0.0.0.0' exposes faz off-loopback. faz has
no built-in remote auth — put a reverse proxy with
your own auth (nginx / Cloudflare Tunnel / Tailscale)
in front before going to prod.This is not optional. faz has no auth surface of its own.
Quick example
The smallest useful request:
curl -X POST http://localhost:8787/v1/query/simple \
-H 'Content-Type: application/json' \
-d '{
"database": "<database>",
"table": "<table>",
"language": "sql",
"query": "SELECT COUNT(*) FROM <table>"
}'Response:
{
"request_id": "req_a1b2c3d4e5f6",
"status": "ok",
"data": {
"columns": ["count"],
"rows": [{ "count": 8421 }],
"row_count": 1
},
"safety": {
"stages_passed": ["PROMPT_GUARD", "RBAC_GATE", "AST_CHECKER", "INJECTION_ANALYSER", "GUARDRAILS"],
"warnings": []
},
"metadata": {
"database": "<database>",
"execution_time_ms": 12.4,
"transport": "rest/local",
"steps": [],
"merge_latency_ms": null
}
}A blocked query returns 403 with a structured envelope:
{
"request_id": "req_a1b2c3d4e5f6",
"status": "blocked",
"error": {
"stage": "RBAC_GATE",
"reason": "Access denied: <database>.<sensitive-table> requires permission for SELECT; policy grants none",
"suggestion": null
}
}The full request and response shapes for every endpoint are on REST endpoints.
Authentication
There isn't any.
faz has no built-in concept of users, tokens, or sessions. The model is: bind to loopback by default, and trust whatever auth your reverse proxy enforces if you expose faz remotely.
For development, this is fine — faz serve only listens on 127.0.0.1 so only processes on the same host can hit it.
For production, put faz behind something:
- nginx / Caddy / Traefik with HTTP basic auth, JWT validation, or mTLS.
- Cloudflare Tunnel with Cloudflare Access for SSO.
- Tailscale to scope access to a private network.
- A small auth-aware proxy you write that validates an
Authorizationheader and forwards.
The reverse proxy is responsible for identifying who's calling. faz doesn't read auth headers; it doesn't know who you are. Per-agent or per-user permissions aren't supported (there is no agent identity model — see Permissions).
Never expose faz serve directly to the public internet. Always front it with auth. faz's audit log is per-instance, not per-user — if you let multiple users hit the same instance, you can't tell which user ran which query.
Verify
curl http://localhost:8787/v1/health{ "status": "ok", "version": "0.1.0", "databases_connected": 1 }If databases_connected is 0, faz couldn't open any of the connections in faz.yaml. Check the server logs for connection errors and see Connection failed.
For a deeper check:
curl http://localhost:8787/v1/databasesReturns each configured database with reachable: true | false and discovered tables. Failed connections appear in the list with reachable: false and an error describing why.
Common patterns
Scripted ad-hoc queries:
#!/bin/bash
QUERY="SELECT COUNT(*) FROM <table> WHERE <condition>"
curl -sS -X POST http://localhost:8787/v1/query/simple \
-H 'Content-Type: application/json' \
-d "{\"database\":\"<database>\",\"table\":\"<table>\",\"language\":\"sql\",\"query\":$(jq -Rsa . <<<"$QUERY")}" \
| jq '.data.rows[0]'CI assertions:
COUNT=$(curl -sS http://faz.internal/v1/query/simple ... | jq -r '.data.rows[0].count')
[ "$COUNT" -gt 0 ] || exit 1Custom client SDKs: any HTTP client library works. The Pydantic schemas (SimpleQueryRequest, FederatedQueryRequest) are stable; generate types from /openapi.json if your language has codegen tooling.
Dashboards: point Grafana, Metabase, or any dashboard that accepts a custom JSON HTTP source at faz endpoints. The audit log captures the dashboard's queries the same way it captures an LLM's.
Operational notes
- faz reads
faz.yamlonce at startup. To pick up config changes, restartfaz serve. - Audit logging is identical across transports. REST requests log as
transport: "rest/local". - Long-running queries are bounded by the
safety.query_timeout_secondsfromfaz.yaml(default 30s) and HTTP keepalive timeouts at your proxy layer. - The OpenAPI schema is at
http://localhost:8787/docs(Swagger UI) andhttp://localhost:8787/openapi.json(raw JSON) for tooling.
Related
- REST endpoints — full per-endpoint reference.
- Verifying the connection — diagnostic checks for the HTTP path.
- How faz protects you — what runs on every request.
- Audit log — what gets written for each REST call.