Ir al contenido

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.

The full reference, with request and response schemas, is served by Querri itself:

For local development they’re at http://localhost/api/v1/docs and http://localhost/api/v1/redoc.

https://app.querri.com/api/v1

With an API key:

Terminal window
Authorization: Bearer qk_live_...
X-Tenant-ID: your_org_id

With a JWT, send only Authorization: Bearer eyJ...; the organization comes from the token. With an embed session, send X-Embed-Session: es_....

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.

Most list endpoints use cursors:

ParameterDefaultNotes
limit201 to 100
afternoneThe 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.

These routes exist but return 501 with the code not_implemented:

  • POST /dashboards
  • DELETE /dashboards/{dashboard_id}
  • POST /dashboards/from-template
  • POST /dashboards/{dashboard_id}/export-template
  • POST /sources/{source_id}/sync

Manage organization members. Give users an external_id to map them to your own user system.

MethodEndpointDescriptionScope
POST/usersCreate a useradmin:users:write
GET/usersList users (supports ?external_id=)admin:users:read
GET/users/{user_id}Get a useradmin:users:read
PUT/users/external/{external_id}Get or create a user by external IDadmin:users:write
PATCH/users/{user_id}Update a user’s role or nameadmin:users:write
DELETE/users/{user_id}Delete a useradmin:users:write
DELETE/users/external/{external_id}Remove an external ID mapping, leaving the user in placeadmin: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.

MethodEndpointDescriptionScope
GET/projectsList projectsadmin:projects:read
POST/projectsCreate a project (name, user_id, optional description)admin:projects:write
GET/projects/{project_id}Get a projectadmin:projects:read
PUT/projects/{project_id}Update name or descriptionadmin:projects:write
DELETE/projects/{project_id}Delete a projectadmin:projects:write
POST/projects/{project_id}/sourcesAdd an uploaded file (file_id; runs the project unless run is false)admin:projects:write
POST/projects/{project_id}/runRun a project (user_id)admin:projects:write
GET/projects/{project_id}/run/statusCheck a runadmin:projects:read
POST/projects/{project_id}/run/cancelCancel a runadmin:projects:write
GET/projects/{project_id}/stepsList stepsadmin:projects:read
GET/projects/{project_id}/steps/{step_id}/dataGet a step’s rows (paged, row-filtered)admin:projects:read

Chats inside a project. The stream endpoint returns server-sent events.

MethodEndpointDescriptionScope
POST/projects/{project_id}/chatsCreate a chatadmin:projects:write
GET/projects/{project_id}/chatsList chatsadmin:projects:read
GET/projects/{project_id}/chats/{chat_id}Get a chat and its messagesadmin:projects:read
DELETE/projects/{project_id}/chats/{chat_id}Delete a chatadmin:projects:write
POST/projects/{project_id}/chats/{chat_id}/streamSend a message and stream the responseadmin:projects:write
GET/projects/{project_id}/chats/{chat_id}/streamReconnect to a response that’s still runningadmin:projects:read
POST/projects/{project_id}/chats/{chat_id}/cancelCancel a running responseadmin:projects:write

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.

MethodEndpointDescriptionScope
GET/dashboardsList dashboardsadmin:dashboards:read
GET/dashboards/{dashboard_id}Get a dashboardadmin:dashboards:read
PATCH/dashboards/{dashboard_id}Update name or descriptionadmin:dashboards:write
POST/dashboards/{dashboard_id}/refreshRefresh a dashboardadmin:dashboards:write
GET/dashboards/{dashboard_id}/refresh/statusCheck a refreshadmin:dashboards:read
POST/dashboardsNot implemented yet (501)admin:dashboards:write
DELETE/dashboards/{dashboard_id}Not implemented yet (501)admin:dashboards:write
POST/dashboards/from-templateNot implemented yet (501)admin:dashboards:write
POST/dashboards/{dashboard_id}/export-templateNot implemented yet (501)admin:dashboards:read

Access policies filter which rows of a source a user can see.

MethodEndpointDescriptionScope
POST/access/policiesCreate a policy (name, source_ids, row_filters)admin:policies:write
GET/access/policiesList policies (supports ?name=)admin:policies:read
GET/access/policies/{policy_id}Get a policyadmin:policies:read
PATCH/access/policies/{policy_id}Update a policyadmin:policies:write
DELETE/access/policies/{policy_id}Delete a policyadmin:policies:write
POST/access/policies/{policy_id}/usersAssign users (user_ids)admin:policies:write
DELETE/access/policies/{policy_id}/users/{user_id}Remove a useradmin:policies:write
PUT/access/users/{user_id}/policiesReplace all of a user’s policies (policy_ids)admin:policies:write
POST/access/resolvePreview a user’s access to a source (user_id, source_id)admin:policies:read
GET/access/columnsList filterable columnsadmin:policies:read

A row filter is {"column": "region", "values": ["APAC", "EMEA"]}.

Read and write data sources. Reads apply row-level security. The Data API guide has examples and integration patterns.

MethodEndpointDescriptionScope
GET/connectorsList your organization’s connectorsadmin:sources:read
GET/sourcesList sourcesdata:read or admin:sources:read
GET/sources/{source_id}Get a source and its schemadata:read or admin:sources:read
GET/sources/{source_id}/dataRead rows (paged)data:read
POST/sources/{source_id}/queryRun SQL against the sourcedata:read
POST/sources/{source_id}/askAsk a question; the AI writes and runs the SQLdata:read
POST/sourcesCreate a source from inline rows (name, rows)data:write
POST/sources/{source_id}/rowsAppend rowsdata:write
PUT/sources/{source_id}/dataReplace all rowsdata:write
PATCH/sources/{source_id}Update name, description, config or access_controlledadmin:sources:write
DELETE/sources/{source_id}Delete a sourcedata:write or admin:sources:write
POST/sources/{source_id}/syncNot implemented yet (501)admin:sources:write

There’s no endpoint for creating a connector-backed source. POST /sources only takes inline rows.

MethodEndpointDescriptionScope
POST/viewsCreate a view (name, sql_definition, description)data:write
GET/viewsList viewsdata:read
GET/views/{view_uuid}Get a viewdata:read
PATCH/views/{view_uuid}Update the SQL or descriptiondata:write
DELETE/views/{view_uuid}Delete a viewdata:write
POST/views/runMaterialize views (optional view_uuids; all when omitted)data:write
GET/views/runs/{run_id}Check a rundata:read
POST/views/{view_uuid}/previewPreview rows (limit, up to 10,000)data:read
POST/views/{view_uuid}/chatChange the view by chatting (message)data:write
POST/views/{view_uuid}/generate-metadataGenerate a name and descriptiondata:write
MethodEndpointDescriptionScope
GET/filesList filesadmin:files:read
GET/files/{file_id}Get a file’s detailsadmin:files:read
POST/files/uploadUpload a file (multipart, field file)admin:files:upload
DELETE/files/{file_id}Delete a fileadmin:files:delete

Short-lived tokens for embedding Querri in your own app.

MethodEndpointDescriptionScope
POST/embed/sessionsCreate a sessionembed:session:create
POST/embed/sessions/refreshSwap a session for a new one (session_token)embed:session:create
GET/embed/sessionsList active sessions (limit, up to 200)embed:session:create
DELETE/embed/sessions/{session_token}Revoke a sessionembed:session:create

The create body is:

FieldRequiredNotes
user_idYesA Querri user ID or an external ID. The user must belong to your organization.
originOnly with an allowlistThe site the embed runs on, up to 500 characters
ttlNoSeconds, 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.

MethodEndpointDescriptionScope
POST/keysCreate a key; the response includes the secret onceadmin:keys:manage
GET/keysList keysadmin:keys:manage
GET/keys/{key_id}Get a key’s detailsadmin:keys:manage
DELETE/keys/{key_id}Revoke a keyadmin: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.

MethodEndpointDescriptionScope
POST/projects/{project_id}/sharesShare a project (user_id, permission)admin:permissions:write
GET/projects/{project_id}/sharesList a project’s sharesadmin:permissions:read
DELETE/projects/{project_id}/shares/{user_id}Remove a project shareadmin:permissions:write
POST/dashboards/{dashboard_id}/sharesShare a dashboardadmin:permissions:write
GET/dashboards/{dashboard_id}/sharesList a dashboard’s sharesadmin:permissions:read
DELETE/dashboards/{dashboard_id}/shares/{user_id}Remove a dashboard shareadmin:permissions:write
POST/sources/{source_id}/sharesShare a source with a useradmin:permissions:write
POST/sources/{source_id}/org-shareTurn organization-wide sharing of a source on or off (enabled, permission)admin:permissions:write
POST/projects/{project_uuid}/steps/{step_uuid}/sharesShare one stepadmin:permissions:write
GET/projects/{project_uuid}/steps/{step_uuid}/sharesList a step’s sharesadmin:permissions:read
DELETE/projects/{project_uuid}/steps/{step_uuid}/shares/{subject_type}/{subject_id}Remove a step shareadmin:permissions:write

permission is view or edit (default view).

MethodEndpointDescriptionScope
GET/skillsList skillsadmin:skills:read
POST/skillsCreate a skilladmin:skills:write
GET/skills/{skill_uuid}Get a skilladmin:skills:read
PUT/skills/{skill_uuid}Update a skilladmin:skills:write
DELETE/skills/{skill_uuid}Delete a skilladmin:skills:write

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.

MethodEndpointDescriptionScope
GET/usageOrganization usageadmin:usage:read
GET/usage/users/{user_id}One user’s usageadmin:usage:read

Both take period: current_month, last_month or last_30_days.

MethodEndpointDescriptionScope
GET/audit/eventsQuery audit eventsadmin: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.