REST API
Read-only access to the Centic data lake for API clients. Same query pipeline as the MCP server: PII is auto-obfuscated, only SELECT/WITH queries are permitted, and every request is logged to the restaurant's query log.
Machine-readable version: /docs/api.md · LLM index: /llms.txt
Authentication
All endpoints require an API key sent as a Bearer token in the Authorization header. Ask a Centic admin to issue one for you via /admin/api-keys.
Authorization: Bearer oh_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Keys are issued with either global scope (access to every restaurant, including any created later) or restaurant scope (access to an explicit list of restaurants). Requests to a restaurant outside the key's scope return 403.
Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /api/v1/restaurants | List restaurants the key can access. |
| GET | /api/v1/restaurants/:id/schema/tables | List public-schema tables with row estimates. |
| GET | /api/v1/restaurants/:id/schema/tables/:name/columns | Column names, types, PII flag, and BSM label/description if available. |
| GET | /api/v1/restaurants/:id/schema/bsm | Brand Semantic Map: every annotated field with label/description/unit/source. |
| POST | /api/v1/restaurants/:id/query | Run a SELECT. Body {"sql": "..."}. Results capped at 10,000 rows; 30s timeout. |
| POST | /api/v1/restaurants/:id/query/validate | Validate a SELECT without executing (via EXPLAIN). |
Read-only guarantees
Four layers stop writes:
- SQL validator: rejects anything but a single
SELECT/WITH. - Postgres role: the connection uses a read-only DB user.
- Per-transaction
SET LOCAL default_transaction_read_only = on. - Statement timeout of 30 seconds.
Query response shape
{
"columns": ["order_id", "guest_email", "total"],
"rows": [
["4a1c...", "j***@e.com", 42.10],
["9b2d...", "s***@m.com", 88.00]
],
"row_count": 2,
"truncated": false,
"obfuscated_fields": ["guest_email"],
"duration_ms": 74
}Rows are returned as column-ordered arrays (not objects). Look up positions in columns. Any field annotated as PII in the restaurant's bsm_metadata is auto-masked and listed in obfuscated_fields.
Example: run a query
curl -X POST https://centic.ai/api/v1/restaurants/cmmnwg8wf0000e8sx27g8m2hi/query \
-H "Authorization: Bearer oh_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"sql": "SELECT business_date, SUM(total) FROM brink_orders GROUP BY 1 ORDER BY 1 DESC LIMIT 7"}'Error format
{ "error": "restaurant_not_in_scope", "message": "API key does not have access to this restaurant" }Common codes: missing_bearer_token, invalid_key, revoked_key, expired_key, restaurant_not_in_scope, invalid_query, query_timeout, query_failed, no_data_lake.