API Reference
Esta página aún no está disponible en español. Se muestra la versión en inglés.
The Querri Public API v1 gives you programmatic access to projects, dashboards, data sources, views, users, access policies and more. Endpoints accept qk_ API keys (the usual choice for integrations), JWT bearer tokens, embed session tokens, and signed-in browser cookies. See Authentication.
The Python SDK (pip install querri) and the querri CLI (pip install "querri[cli]") cover most of these endpoints. Reach for them before writing raw HTTP requests.
Interactive documentation
Section titled “Interactive documentation”The full reference, with request and response schemas, is served by Querri itself:
- Swagger UI:
/api/v1/docs - ReDoc:
/api/v1/redoc - OpenAPI JSON:
/api/v1/openapi.json, which you can import into any OpenAPI client
For local development they’re at http://localhost/api/v1/docs and http://localhost/api/v1/redoc.
Base URL
Section titled “Base URL”https://app.querri.com/api/v1Required headers
Section titled “Required headers”With an API key:
Authorization: Bearer qk_live_...X-Tenant-ID: your_org_idWith a JWT, send only Authorization: Bearer eyJ...; the organization comes from the token. With an embed session, send X-Embed-Session: es_....
Error format
Section titled “Error format”Errors come back wrapped in detail:
{ "detail": { "error": { "type": "not_found_error", "code": "source_not_found", "message": "Source 8f14e45f-ceea-4ba1-9f3c-5d2b8a0c1e77 not found." } }}Many errors also include a doc_url, which links to that code on API errors. Error types include authentication_error, permission_error, invalid_request_error, not_found_error, rate_limit_error and api_error. Handle errors by code, and quote the X-Request-Id response header when you contact support.
IDs for projects, dashboards, sources, views and policies are UUIDs.
Pagination
Section titled “Pagination”Most list endpoints use cursors:
| Parameter | Default | Notes |
|---|---|---|
limit | 20 | 1 to 100 |
after | none | The next_cursor from the previous page |
{ "data": [...], "has_more": true, "next_cursor": "MjA="}Pass next_cursor back as after until has_more is false. The cursor is opaque, so don’t build one yourself.
Row data uses pages instead: page (from 1) and page_size (default 100, up to 10,000) on source data, SQL queries, source questions and step data.
Not implemented yet
Section titled “Not implemented yet”These routes exist but return 501 with the code not_implemented:
POST /dashboardsDELETE /dashboards/{dashboard_id}POST /dashboards/from-templatePOST /dashboards/{dashboard_id}/export-templatePOST /sources/{source_id}/sync
Manage organization members. Give users an external_id to map them to your own user system.
| Method | Endpoint | Description | Scope |
|---|---|---|---|
POST | /users | Create a user | admin:users:write |
GET | /users | List users (supports ?external_id=) | admin:users:read |
GET | /users/{user_id} | Get a user | admin:users:read |
PUT | /users/external/{external_id} | Get or create a user by external ID | admin:users:write |
PATCH | /users/{user_id} | Update a user’s role or name | admin:users:write |
DELETE | /users/{user_id} | Delete a user | admin:users:write |
DELETE | /users/external/{external_id} | Remove an external ID mapping, leaving the user in place | admin:users:write |
role is member or admin (default member). On the People page in Querri, member shows as Creator. PUT /users/external/{external_id} returns 200 with an existing user or 201 with a new one, and never changes an existing user.
Projects
Section titled “Projects”| Method | Endpoint | Description | Scope |
|---|---|---|---|
GET | /projects | List projects | admin:projects:read |
POST | /projects | Create a project (name, user_id, optional description) | admin:projects:write |
GET | /projects/{project_id} | Get a project | admin:projects:read |
PUT | /projects/{project_id} | Update name or description | admin:projects:write |
DELETE | /projects/{project_id} | Delete a project | admin:projects:write |
POST | /projects/{project_id}/sources | Add an uploaded file (file_id; runs the project unless run is false) | admin:projects:write |
POST | /projects/{project_id}/run | Run a project (user_id) | admin:projects:write |
GET | /projects/{project_id}/run/status | Check a run | admin:projects:read |
POST | /projects/{project_id}/run/cancel | Cancel a run | admin:projects:write |
GET | /projects/{project_id}/steps | List steps | admin:projects:read |
GET | /projects/{project_id}/steps/{step_id}/data | Get a step’s rows (paged, row-filtered) | admin:projects:read |
Chats inside a project. The stream endpoint returns server-sent events.
| Method | Endpoint | Description | Scope |
|---|---|---|---|
POST | /projects/{project_id}/chats | Create a chat | admin:projects:write |
GET | /projects/{project_id}/chats | List chats | admin:projects:read |
GET | /projects/{project_id}/chats/{chat_id} | Get a chat and its messages | admin:projects:read |
DELETE | /projects/{project_id}/chats/{chat_id} | Delete a chat | admin:projects:write |
POST | /projects/{project_id}/chats/{chat_id}/stream | Send a message and stream the response | admin:projects:write |
GET | /projects/{project_id}/chats/{chat_id}/stream | Reconnect to a response that’s still running | admin:projects:read |
POST | /projects/{project_id}/chats/{chat_id}/cancel | Cancel a running response | admin:projects:write |
Chat streaming
Section titled “Chat streaming”POST .../stream takes prompt and user_id (a Querri user ID or an external ID), plus optional model. It returns text/event-stream, one JSON part per data: line:
data: {"type": "start", "messageId": "..."}
data: {"type": "text-start", "id": "..."}
data: {"type": "text-delta", "id": "...", "delta": "Revenue grew "}
data: {"type": "text-delta", "id": "...", "delta": "in every region."}
data: {"type": "text-end", "id": "..."}
data: {"type": "finish", "finishReason": "stop"}
data: [DONE]The stream also carries other part types, such as tool calls and results, plus comment lines (starting with :) that keep the connection alive. If you disconnect, the response keeps running on the server, and GET .../stream picks it back up. A user who has used all of their monthly credits gets a short refusal in the stream, and nothing runs.
Dashboards
Section titled “Dashboards”| Method | Endpoint | Description | Scope |
|---|---|---|---|
GET | /dashboards | List dashboards | admin:dashboards:read |
GET | /dashboards/{dashboard_id} | Get a dashboard | admin:dashboards:read |
PATCH | /dashboards/{dashboard_id} | Update name or description | admin:dashboards:write |
POST | /dashboards/{dashboard_id}/refresh | Refresh a dashboard | admin:dashboards:write |
GET | /dashboards/{dashboard_id}/refresh/status | Check a refresh | admin:dashboards:read |
POST | /dashboards | Not implemented yet (501) | admin:dashboards:write |
DELETE | /dashboards/{dashboard_id} | Not implemented yet (501) | admin:dashboards:write |
POST | /dashboards/from-template | Not implemented yet (501) | admin:dashboards:write |
POST | /dashboards/{dashboard_id}/export-template | Not implemented yet (501) | admin:dashboards:read |
Access policies
Section titled “Access policies”Access policies filter which rows of a source a user can see.
| Method | Endpoint | Description | Scope |
|---|---|---|---|
POST | /access/policies | Create a policy (name, source_ids, row_filters) | admin:policies:write |
GET | /access/policies | List policies (supports ?name=) | admin:policies:read |
GET | /access/policies/{policy_id} | Get a policy | admin:policies:read |
PATCH | /access/policies/{policy_id} | Update a policy | admin:policies:write |
DELETE | /access/policies/{policy_id} | Delete a policy | admin:policies:write |
POST | /access/policies/{policy_id}/users | Assign users (user_ids) | admin:policies:write |
DELETE | /access/policies/{policy_id}/users/{user_id} | Remove a user | admin:policies:write |
PUT | /access/users/{user_id}/policies | Replace all of a user’s policies (policy_ids) | admin:policies:write |
POST | /access/resolve | Preview a user’s access to a source (user_id, source_id) | admin:policies:read |
GET | /access/columns | List filterable columns | admin:policies:read |
A row filter is {"column": "region", "values": ["APAC", "EMEA"]}.
Sources and data
Section titled “Sources and data”Read and write data sources. Reads apply row-level security. The Data API guide has examples and integration patterns.
| Method | Endpoint | Description | Scope |
|---|---|---|---|
GET | /connectors | List your organization’s connectors | admin:sources:read |
GET | /sources | List sources | data:read or admin:sources:read |
GET | /sources/{source_id} | Get a source and its schema | data:read or admin:sources:read |
GET | /sources/{source_id}/data | Read rows (paged) | data:read |
POST | /sources/{source_id}/query | Run SQL against the source | data:read |
POST | /sources/{source_id}/ask | Ask a question; the AI writes and runs the SQL | data:read |
POST | /sources | Create a source from inline rows (name, rows) | data:write |
POST | /sources/{source_id}/rows | Append rows | data:write |
PUT | /sources/{source_id}/data | Replace all rows | data:write |
PATCH | /sources/{source_id} | Update name, description, config or access_controlled | admin:sources:write |
DELETE | /sources/{source_id} | Delete a source | data:write or admin:sources:write |
POST | /sources/{source_id}/sync | Not implemented yet (501) | admin:sources:write |
There’s no endpoint for creating a connector-backed source. POST /sources only takes inline rows.
| Method | Endpoint | Description | Scope |
|---|---|---|---|
POST | /views | Create a view (name, sql_definition, description) | data:write |
GET | /views | List views | data:read |
GET | /views/{view_uuid} | Get a view | data:read |
PATCH | /views/{view_uuid} | Update the SQL or description | data:write |
DELETE | /views/{view_uuid} | Delete a view | data:write |
POST | /views/run | Materialize views (optional view_uuids; all when omitted) | data:write |
GET | /views/runs/{run_id} | Check a run | data:read |
POST | /views/{view_uuid}/preview | Preview rows (limit, up to 10,000) | data:read |
POST | /views/{view_uuid}/chat | Change the view by chatting (message) | data:write |
POST | /views/{view_uuid}/generate-metadata | Generate a name and description | data:write |
| Method | Endpoint | Description | Scope |
|---|---|---|---|
GET | /files | List files | admin:files:read |
GET | /files/{file_id} | Get a file’s details | admin:files:read |
POST | /files/upload | Upload a file (multipart, field file) | admin:files:upload |
DELETE | /files/{file_id} | Delete a file | admin:files:delete |
Embed sessions
Section titled “Embed sessions”Short-lived tokens for embedding Querri in your own app.
| Method | Endpoint | Description | Scope |
|---|---|---|---|
POST | /embed/sessions | Create a session | embed:session:create |
POST | /embed/sessions/refresh | Swap a session for a new one (session_token) | embed:session:create |
GET | /embed/sessions | List active sessions (limit, up to 200) | embed:session:create |
DELETE | /embed/sessions/{session_token} | Revoke a session | embed:session:create |
The create body is:
| Field | Required | Notes |
|---|---|---|
user_id | Yes | A Querri user ID or an external ID. The user must belong to your organization. |
origin | Only with an allowlist | The site the embed runs on, up to 500 characters |
ttl | No | Seconds, 900 to 86400 (default 3600) |
If your organization has a list of allowed embed domains, a missing origin returns 400 with origin_required, and one that isn’t on the list returns 403 with origin_not_allowed. The response is {session_token, expires_in, user_id}. Refreshing revokes the old token and returns a new one that lasts an hour.
API keys
Section titled “API keys”| Method | Endpoint | Description | Scope |
|---|---|---|---|
POST | /keys | Create a key; the response includes the secret once | admin:keys:manage |
GET | /keys | List keys | admin:keys:manage |
GET | /keys/{key_id} | Get a key’s details | admin:keys:manage |
DELETE | /keys/{key_id} | Revoke a key | admin:keys:manage |
The create body takes name, scopes, expires_in_days (1 to 365, default 90), rate_limit_per_minute (1 to 10,000, default 60), ip_allowlist, bound_user_id and source_scope. A source_scope restricts the key only in explicit mode, {"mode": "explicit", "source_ids": [...]}. A Source Scope set in Settings → API Keys doesn’t restrict the key. The body also accepts access_policy_ids, which has no effect. See Authentication.
Sharing
Section titled “Sharing”| Method | Endpoint | Description | Scope |
|---|---|---|---|
POST | /projects/{project_id}/shares | Share a project (user_id, permission) | admin:permissions:write |
GET | /projects/{project_id}/shares | List a project’s shares | admin:permissions:read |
DELETE | /projects/{project_id}/shares/{user_id} | Remove a project share | admin:permissions:write |
POST | /dashboards/{dashboard_id}/shares | Share a dashboard | admin:permissions:write |
GET | /dashboards/{dashboard_id}/shares | List a dashboard’s shares | admin:permissions:read |
DELETE | /dashboards/{dashboard_id}/shares/{user_id} | Remove a dashboard share | admin:permissions:write |
POST | /sources/{source_id}/shares | Share a source with a user | admin:permissions:write |
POST | /sources/{source_id}/org-share | Turn organization-wide sharing of a source on or off (enabled, permission) | admin:permissions:write |
POST | /projects/{project_uuid}/steps/{step_uuid}/shares | Share one step | admin:permissions:write |
GET | /projects/{project_uuid}/steps/{step_uuid}/shares | List a step’s shares | admin:permissions:read |
DELETE | /projects/{project_uuid}/steps/{step_uuid}/shares/{subject_type}/{subject_id} | Remove a step share | admin:permissions:write |
permission is view or edit (default view).
Skills
Section titled “Skills”| Method | Endpoint | Description | Scope |
|---|---|---|---|
GET | /skills | List skills | admin:skills:read |
POST | /skills | Create a skill | admin:skills:write |
GET | /skills/{skill_uuid} | Get a skill | admin:skills:read |
PUT | /skills/{skill_uuid} | Update a skill | admin:skills:write |
DELETE | /skills/{skill_uuid} | Delete a skill | admin:skills:write |
Library
Section titled “Library”The /library routes cover the Library: asking the Librarian (POST /library/ask, POST /library/chat), searching (POST /library/search), and reading and changing collections, questions, KPIs, facts and monitors. They use the admin:library:read and admin:library:write scopes. The interactive documentation lists every route and its body.
| Method | Endpoint | Description | Scope |
|---|---|---|---|
GET | /usage | Organization usage | admin:usage:read |
GET | /usage/users/{user_id} | One user’s usage | admin:usage:read |
Both take period: current_month, last_month or last_30_days.
| Method | Endpoint | Description | Scope |
|---|---|---|---|
GET | /audit/events | Query audit events | admin:audit:read |
Filter with actor_id, target_id, action (an exact action name such as api_key.create), start_date and end_date. Results use cursor pagination.