Skip to content

API Reference

Overview

Complete reference for the two Analytics Query API endpoints. For a worked example, see Getting Started.

Base URL — your tenant hostname:

https://<tenant>.britive-app.com

Authentication — every request carries a token for an identity holding bizintel.analytics.manage:

Authorization: TOKEN <token>

POST /api/bizintel/analytics/query

Submits a query and starts its execution.

Request body

FieldTypeRequiredDescription
sqlstringyesA single read-only SELECT. Non-empty. See SQL rules.
{
  "sql": "SELECT username, status FROM users_latest WHERE status = 'active' LIMIT 100"
}

Response — 202 Accepted

FieldTypeDescription
query_execution_idstringIdentifier to poll for status and results.
statusstringAlways SUBMITTED.
{
  "query_execution_id": "3f7c1a92-5d84-4b0e-9a11-2c6de0f8b7a3",
  "status": "SUBMITTED"
}

Status codes

CodeMeaning
202Query accepted and started.
400Body is not valid JSON, is not a JSON object, sql is missing or empty, sql is not a single read-only SELECT, or the query engine rejected the SQL text itself.
403Identity lacks bizintel.analytics.manage.
502Upstream failure starting the query. Retry.

202 means the query started, not that it will succeed. Errors that need the data to be read — an unknown column, a type mismatch — surface as a FAILED status when you poll.

GET /api/bizintel/analytics/query/{query_execution_id}

Returns the current state of a query, and a result download URL once it succeeds.

Path parameter

NameTypeDescription
query_execution_idstringThe id returned by the submit call.

Response — 200 OK

Fields present depend on status:

FieldTypeWhenDescription
query_execution_idstringalwaysEcho of the id polled.
statusstringalwaysQUEUED, RUNNING, SUCCEEDED, FAILED, or CANCELLED.
download_urlstringSUCCEEDEDSigned URL to the result CSV. Fetch with no Authorization header.
expires_inintegerSUCCEEDEDSeconds the download_url stays valid. Default 300.
errorstringFAILED, CANCELLEDReason the query did not complete.

Still running:

{
  "query_execution_id": "3f7c1a92-5d84-4b0e-9a11-2c6de0f8b7a3",
  "status": "RUNNING"
}

Finished successfully:

{
  "query_execution_id": "3f7c1a92-5d84-4b0e-9a11-2c6de0f8b7a3",
  "status": "SUCCEEDED",
  "download_url": "https://.../3f7c1a92-5d84-4b0e-9a11-2c6de0f8b7a3.csv?X-Amz-Signature=...",
  "expires_in": 300
}

Failed:

{
  "query_execution_id": "3f7c1a92-5d84-4b0e-9a11-2c6de0f8b7a3",
  "status": "FAILED",
  "error": "COLUMN_NOT_FOUND: line 1:8: Column 'usrname' cannot be resolved"
}

Status codes

CodeMeaning
200Status retrieved — including for a FAILED or CANCELLED query. The lookup succeeded, so the query’s failure is reported as data rather than an HTTP error.
403Identity lacks bizintel.analytics.manage.
404No such query execution id. Unknown and expired ids are deliberately indistinguishable.
502Upstream failure checking status or signing the result URL. Retry.

Treat FAILED as an application-level outcome, not an HTTP error. A client that only checks the HTTP status code will read 200 and assume success. Always branch on the status field.

Error Response Shape

4xx and 5xx responses from the API carry a JSON body:

FieldTypeDescription
statusCodeintegerRepeats the HTTP status code.
messagestringHuman-readable reason.
{
  "statusCode": 400,
  "message": "only read-only SELECT queries are permitted (got INSERT)"
}

Upstream errors present as 502.

SQL Rules

Only a single read-only SELECT is accepted. Enforcement is an allowlist: the statement’s first top-level verb must be SELECT. A leading WITH is fine, because CTE bodies are nested in parentheses — the verb after the CTE list is what counts.

Accepted

StatementNote
SELECT ...The ordinary case.
WITH t AS (SELECT ...) SELECT ...CTEs are allowed.
(SELECT ...) UNION (SELECT ...)Set operations are allowed.
SELECT 'INSERT INTO t'Keywords inside string literals are harmless.
SELECT unload FROM tColumn names that collide with verbs are unaffected.
SELECT ...;A single trailing semicolon is fine.

Rejected with 400

StatementMessage
INSERT / UPDATE / DELETE / MERGEonly read-only SELECT queries are permitted (got INSERT)
CREATE / DROP / ALTER / TRUNCATE / MSCKonly read-only SELECT queries are permitted (got CREATE)
UNLOAD (SELECT ...) TO 's3://...'only read-only SELECT queries are permitted (got UNLOAD)
SHOW / DESCRIBE / EXPLAIN / USE / SETonly read-only SELECT queries are permitted (got SHOW)
SELECT 1; DROP TABLE xmultiple SQL statements are not permitted; submit a single SELECT query
`` (empty string)query must not be empty
SELECT 'unclosedunterminated quoted literal in query

Comments and quoted literals are stripped before the statement is analysed, so no keyword can hide inside them, and only top-level tokens are examined, so a subquery can never be mistaken for the statement’s verb.

SHOW, DESCRIBE, and EXPLAIN are rejected by design, not oversight. This API serves query data; schema exploration belongs in Britive Analytics.

Statement Checking Is Not the Only Safeguard

Rejecting non-SELECT statements gives you a clean 400 rather than an opaque failure part-way through execution. Underneath it, the data is read-only — nothing in this API can delete or alter it.

Limits

LimitValueNote
Result URL lifetime300 secondsReported per-response as expires_in. Poll again for a fresh URL.
Statements per request1Stacked statements are rejected.
Result formatCSVIncludes a header row of column names.

Related

Last updated on