Skip to main content

HTTP API

Client connectivity is set up by request

Calling the HTTP API from outside Studio isn't self-service for new organizations yet. Email support@gnok.io to request client connectivity; Gnok support provides your organization's endpoint and how to obtain tokens. https://query.example.com below is a placeholder.

The query API endpoint is distinct from the Studio and catalog URLs; see connectivity. Administrative operations require explicit privileges.

Gnok exposes a JSON-based REST API for lightweight integrations. All request and response bodies use Content-Type: application/json.

Authentication​

All protected endpoints require a JWT bearer token in the Authorization header:

Authorization: Bearer eyJhbGciOiJSUzI1NiIs...

Gnok support explains how to obtain tokens for your organization when your client connectivity is set up. Tokens expire; request a new one rather than storing a token in code or shared files.

Query Endpoints​

Execute Query​

POST /api/query

Execute a SQL statement and return the results as JSON.

Request:

curl -X POST https://query.example.com/api/query \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"sql": "SELECT * FROM my_table LIMIT 10"}'

Request body:

FieldTypeRequiredDescription
sqlstringyesThe SQL statement to execute

Response (200):

{
"columns": ["id", "name", "value"],
"rows": [
[1, "alpha", 100.0],
[2, "beta", 200.0]
],
"row_count": 2,
"elapsed_ms": 42
}

Catalog Management​

Catalogs are the top-level namespace in Gnok. These endpoints list the catalogs visible to you, select the session's active catalog, and browse namespaces and tables. To create a catalog, use SQL; see catalogs in DDL.

List Catalogs​

GET /api/catalogs

Returns all catalogs visible to the authenticated user.

Request:

curl https://query.example.com/api/catalogs \
-H "Authorization: Bearer <token>"

Response (200):

[
{
"name": "production",
"type": "rest",
"uri": "https://catalog.example.com",
"warehouse": "s3://my-warehouse",
"isDefault": true
},
{
"name": "staging",
"type": "rest",
"uri": "https://catalog-staging.example.com",
"warehouse": "s3://staging-warehouse",
"isDefault": false
}
]

Select Active Catalog​

POST /api/catalogs/select

Set the active catalog for the current session. Executes USE CATALOG SQL internally.

Request:

curl -X POST https://query.example.com/api/catalogs/select \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"catalogId": "production"}'

Request body:

FieldTypeRequiredDescription
catalogIdstringyesName of the catalog to select

Response (200):

{
"success": true,
"selectedCatalogId": "production"
}

Response (404) -- catalog not found:

{
"error": "Catalog 'nonexistent' not found"
}

Get Selected Catalog​

GET /api/catalogs/selected

Return the currently active (default) catalog.

Request:

curl https://query.example.com/api/catalogs/selected \
-H "Authorization: Bearer <token>"

Response (200):

{
"name": "production",
"type": "rest",
"uri": "https://catalog.example.com",
"warehouse": "s3://my-warehouse",
"isDefault": true
}

List Namespaces in Catalog​

GET /api/catalogs/:id/namespaces

Response (200):

{
"namespaces": ["public", "analytics", "staging"]
}

List Tables in Namespace​

GET /api/catalogs/:id/namespaces/:ns/tables

Response (200):

{
"tables": ["orders", "customers", "products"]
}

Get Table Metadata​

GET /api/catalogs/:id/namespaces/:ns/tables/:table

Returns Iceberg table metadata including schema, partition spec, and snapshot information.

Response (200):

{
"format-version": 2,
"table-uuid": "a1b2c3d4-...",
"location": "s3://my-warehouse/analytics/orders",
"schemas": [
{
"schema-id": 0,
"fields": [
{"id": 1, "name": "id", "type": "long", "required": true},
{"id": 2, "name": "customer_id", "type": "long", "required": true},
{"id": 3, "name": "amount", "type": "decimal(10,2)", "required": false}
]
}
],
"partition-specs": [
{
"spec-id": 0,
"fields": []
}
],
"properties": {},
"current-snapshot-id": 7891011,
"snapshots": []
}

Organizations and Users​

The HTTP API doesn't create organizations or sign people up. Create an organization in Studio: on studio.gnok.io/login, choose New to gnok? Create an organization (see Quickstart). Organization administrators add members in Studio; see administration. Platform-wide limits are managed by Gnok.

Query History​

Track and inspect previously executed queries.

List Query History​

GET /api/query-history

Query parameters:

ParameterTypeDefaultDescription
limitinteger50Maximum records to return (max: 500)
offsetinteger0Offset for pagination
statusstring(none)Filter by status: completed, failed, cancelled
user_idstring(none)Filter by user ID
query_typestring(none)Filter by query type: select, insert, ddl, etc.

Request:

curl "https://query.example.com/api/query-history?limit=10&status=completed" \
-H "Authorization: Bearer <token>"

Response (200):

{
"records": [
{
"queryId": "q-abc123",
"status": "completed",
"sql": "SELECT count(*) FROM orders",
"userId": "alice",
"tenantId": "tenant-001",
"queryType": "select",
"resourceGroup": "default",
"queuedAt": "2025-06-15T10:30:00Z",
"startedAt": "2025-06-15T10:30:00.050Z",
"endedAt": "2025-06-15T10:30:02.150Z",
"durationMs": 2100,
"rowsProduced": 1,
"bytesScanned": 104857600,
"fragments": 4,
"errorMessage": null,
"priority": 100
}
],
"total": 1458,
"limit": 10,
"offset": 0
}

Get Query Details​

GET /api/query-history/:id

Return the full record for a single query by its query ID.

Request:

curl https://query.example.com/api/query-history/q-abc123 \
-H "Authorization: Bearer <token>"

Response (200):

{
"queryId": "q-abc123",
"status": "completed",
"sql": "SELECT count(*) FROM orders",
"userId": "alice",
"tenantId": "tenant-001",
"queryType": "select",
"resourceGroup": "default",
"queuedAt": "2025-06-15T10:30:00Z",
"startedAt": "2025-06-15T10:30:00.050Z",
"endedAt": "2025-06-15T10:30:02.150Z",
"durationMs": 2100,
"rowsProduced": 1,
"bytesScanned": 104857600,
"fragments": 4,
"errorMessage": null,
"priority": 100
}

Response (404):

{
"error": "Query not found in history"
}

Table Browsing​

List Tables​

GET /api/tables

Returns tables visible in the current session context.

Response (200):

[
{
"catalog": "production",
"schema": "analytics",
"table": "orders"
},
{
"catalog": "production",
"schema": "analytics",
"table": "customers"
}
]

Stage Endpoints (COPY INTO)​

These endpoints support bulk data ingestion via presigned S3 URLs, used by the COPY INTO SQL command and client SDKs.

EndpointMethodDescription
/v1/stages/presignPOSTGenerate S3 presigned URLs for file upload
/v1/stages/presign/multipart/initPOSTInitialize a multipart upload
/v1/stages/presign/multipart/completePOSTComplete a multipart upload
/v1/stages/presign/multipart/abortPOSTAbort a multipart upload

Error Responses​

All error responses return a JSON body with an error field. The HTTP status code indicates the category of error.

Status CodeMeaningExample
200SuccessRequest completed normally
201CreatedResource created successfully
204No ContentDeletion completed successfully
400Bad RequestMissing or invalid request parameters
401UnauthorizedMissing or expired JWT token
403ForbiddenUser lacks permission for the requested operation
404Not FoundRequested resource does not exist
409ConflictResource already exists
429Too Many RequestsRate limit exceeded
500Internal Server ErrorUnexpected server-side failure
503Service UnavailableService dependency is unreachable

Error response format​

{
"error": "Human-readable error message describing what went wrong"
}

400 Bad Request​

Returned when the request body is missing required fields or contains invalid values.

{
"error": "catalogId is required"
}

401 Unauthorized​

Returned when the Authorization header is missing or the JWT token is expired or invalid.

{
"error": "Missing or invalid authentication token"
}

403 Forbidden​

Returned when the authenticated user does not have permission to perform the operation.

{
"error": "Access denied: insufficient privileges on table 'analytics.orders'"
}

404 Not Found​

Returned when the requested resource does not exist.

{
"error": "Catalog 'nonexistent' not found"
}

429 Too Many Requests​

Returned when per-user or per-organization rate limits are exceeded. Clients should implement exponential backoff and retry after the period indicated by the Retry-After header, if present.

{
"error": "Rate limit exceeded. Try again later."
}

500 Internal Server Error​

Returned on unexpected server failures. The error message may be generic to avoid leaking internal details.

{
"error": "Internal server error"
}

Rate Limiting​

The HTTP API enforces rate limits per user and per organization. When a rate limit is exceeded, the server returns a 429 Too Many Requests response.

Recommendations for client implementations:

  • Implement exponential backoff with jitter when receiving 429 responses.
  • Respect the Retry-After header if present in the response.
  • Batch queries where possible rather than issuing many small requests.
  • Use query history polling (GET /api/query-history/:id) instead of re-submitting failed queries.

Base URL and Ports​

All paths are relative to your organization's HTTPS query API endpoint, shown here as the placeholder https://query.example.com. Gnok support provides the endpoint when your client connectivity is set up; email support@gnok.io.