Skip to Content
Interfaces & ToolsHTTP API

HTTP API Reference

KalamDB’s HTTP API covers SQL, authentication, files, topics, and procedure calls. GET /v1/api/openapi.json serves an OpenAPI 3.1 document generated from the live routine catalog.

Base URL: http://<host>:2900
Version prefix: /v1

Route Map

Health and status

  • GET /health (localhost-only)
  • GET /v1/api/healthcheck (localhost-only)
  • GET /v1/api/cluster/health (localhost-only)

SQL and files

  • POST /v1/api/sql
  • POST /v1/functions/{namespace}/{procedure}
  • GET /v1/api/openapi.json
  • GET /v1/files/{namespace}/{table_name}/{subfolder}/{file_id}

WebSocket

  • GET /v1/ws

Auth

  • POST /v1/api/auth/login
  • POST /v1/api/auth/refresh
  • POST /v1/api/auth/logout
  • POST /v1/api/auth/oidc/exchange-token
  • POST /v1/api/auth/oidc/exchange-code
  • GET /v1/api/auth/me
  • POST /v1/api/auth/setup
  • GET /v1/api/auth/status

Topic HTTP API

  • POST /v1/api/topics/consume
  • POST /v1/api/topics/ack

Authentication Rules

Bearer token required

HTTP
Authorization: Bearer <JWT_TOKEN>
  • POST /v1/api/sql
  • POST /v1/functions/{namespace}/{procedure}
  • GET /v1/api/openapi.json
  • GET /v1/files/...
  • POST /v1/api/topics/consume
  • POST /v1/api/topics/ack

Basic auth is rejected on these endpoints.

  • POST /v1/api/auth/refresh
  • GET /v1/api/auth/me

Public endpoints

  • POST /v1/api/auth/login
  • POST /v1/api/auth/oidc/exchange-token
  • POST /v1/api/auth/oidc/exchange-code
  • POST /v1/api/auth/logout
  • POST /v1/api/auth/setup (localhost-only unless auth.allow_remote_setup = true)
  • GET /v1/api/auth/status (localhost-only unless remote setup enabled)
  • GET /health and GET /v1/api/healthcheck (localhost-only)
  • GET /v1/api/cluster/health (localhost-only)

SQL Endpoint

POST /v1/api/sql

Headers:

  • Authorization: Bearer <JWT_TOKEN>
  • Content-Type: application/json or multipart/form-data

JSON body

JSON
{  "sql": "SELECT * FROM app.messages WHERE id = $1",  "params": [123],  "namespace_id": "app"}

namespace_id applies only to that request. Interactive clients such as the CLI can store the namespace locally after a successful USE namespace and send it again on later requests.

Multipart body for FILE(...)

Parts:

  • sql
  • params (optional JSON array string)
  • namespace_id (optional request-scoped default namespace)
  • file parts named file:<placeholder>

SQL:

SQL
INSERT INTO app.docs (id, attachment) VALUES ('d1', FILE("contract"));

Multipart file key must be file:contract.

Success shape

SELECT statements and INSERT ... ON CONFLICT ... DO UPDATE ... RETURNING statements return query rows in results[]:

JSON
{  "status": "success",  "results": [    {      "schema": [{"name":"id","data_type":"BigInt","index":0}],      "rows": [[1]],      "row_count": 1,      "as_user": "alice"    }  ],  "took": 12.3}

Plain INSERT, UPDATE, and DELETE statements without RETURNING return an affected-row count instead of data rows. Upsert without RETURNING follows the insert result shape.

Example upsert that returns rows:

SQL
INSERT INTO app.items (id, name)VALUES (1, 'beta')ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.nameRETURNING id, name;

Error shape

JSON
{  "status": "error",  "results": [],  "took": 1.2,  "error": {    "code": "INVALID_SQL",    "message": "...",    "details": null  }}

Common SQL error codes

  • INVALID_SQL
  • PERMISSION_DENIED
  • TABLE_NOT_FOUND
  • RATE_LIMIT_EXCEEDED
  • NOT_LEADER
  • CLUSTER_UNAVAILABLE
  • FILE_TOO_LARGE
  • TOO_MANY_FILES
  • INVALID_MIME_TYPE

Functions endpoint

POST /v1/functions/{namespace}/{procedure}

Invokes a function or procedure as an HTTP-origin root. The SQL return value is the HTTP body (no {status, result} wrapper). ctx.http is present on this path only.

HTTP
POST /v1/functions/app/echoAuthorization: Bearer <JWT_TOKEN>Content-Type: application/json { "msg": "hello" }

Success for RETURNS TEXT is the scalar:

JSON
"hello"

Success for a structured RETURNS type is that object. Failures use a typed error envelope (code, message) mapped to HTTP status.

The same procedure can also be invoked with SQL CALL on POST /v1/api/sql or PGWire; that origin sets ctx.http to null. Topic triggers use CREATE TRIGGER ... ON TOPIC ... EXECUTE PROCEDURE and do not go through this route. See Server Functions.

OpenAPI specification

GET /v1/api/openapi.json

Returns an OpenAPI 3.1.0 document for the current routine catalog. The server builds it on each request. It describes POST /v1/functions/{namespace}/{procedure} only. SQL, auth, files, topics, and this endpoint itself are not in the document.

HTTP
GET /v1/api/openapi.jsonAuthorization: Bearer <JWT_TOKEN>

A bearer token is required. Basic auth is rejected. Any authenticated caller receives every catalogued routine. EXECUTE grants do not filter the document, so topic-trigger procedures and routines normally invoked with CALL appear as HTTP operations too.

X-Kalam-Epoch is optional. Omit it to accept the server epoch. When the header is present it must equal the current domain epoch (1). Any other value returns 409:

JSON
{  "status": "error",  "code": "EPOCH_MISMATCH",  "message": "unsupported protocol epoch '0'; current server epoch is 1"}

Authentication failures use the same bearer-token error envelope as the other authorized routes.

Document shape

JSON
{  "openapi": "3.1.0",  "info": {    "title": "KalamDB Routine & Contract API",    "version": "epoch-1"  },  "paths": {    "/v1/functions/app/echo": {      "post": {        "operationId": "app.echo",        "summary": "Echo a message",        "security": [{ "bearerAuth": [] }],        "requestBody": {          "required": true,          "content": {            "application/json": {              "schema": {                "type": "object",                "properties": {                  "msg": { "type": "string", "nullable": false }                },                "required": ["msg"]              }            },            "application/x-kalam-domain": {              "schema": { "type": "string", "format": "binary" }            }          }        },        "responses": {          "200": { "description": "Validated routine result" }        }      }    }  },  "components": {    "securitySchemes": {      "bearerAuth": {        "type": "http",        "scheme": "bearer",        "bearerFormat": "JWT"      }    }  }}

info.version is epoch- plus the server domain epoch. There is no servers array. Paths are rooted at the host, so /v1/functions/app/echo is the invoke URL on the same origin that served the document.

Each catalogued routine is one post operation:

  • operationId is the schema-qualified routine id, such as app.echo.
  • summary is the routine comment. When the routine has no comment, the summary is the routine id.
  • security requires the bearerAuth JWT scheme.
  • The JSON body is an object of input parameters (IN, INOUT, and VARIADIC). OUT parameters are omitted.
  • A parameter is required when it is NOT NULL and has no default expression. requestBody.required is true only when that list is non-empty.
  • application/x-kalam-domain is declared as binary and is not expanded into fields.
  • 200 is described as “Validated routine result” and has no response schema. Read the function’s RETURNS clause or procedure’s output parameters for the success body.
  • 400, 401, 403, 404, 409, 429, 500, and 504 reference #/components/responses/StructuredError.

Parameter schemas

SQL types map to JSON Schema as follows. Names are matched case-insensitively, and a precision suffix such as (10,2) is ignored.

SQL typeJSON Schema
BOOL, BOOLEAN{ "type": "boolean" }
INT, INTEGER, INT4, SMALLINT, INT2{ "type": "integer", "format": "int32" }
BIGINT, INT8, INT64{ "type": ["integer", "string"], "format": "int64" }
DECIMAL, NUMERIC{ "type": "string", "format": "decimal" }
FLOAT, FLOAT4, REAL, DOUBLE, FLOAT8{ "type": "number" }
JSON, JSONB{ "type": ["object", "array", "string", "number", "boolean", "null"] }
Any other type, including TEXT, UUID, and timestamps{ "type": "string" }

Array parameters wrap that schema in { "type": "array", "items": ... }.

Every field also has a nullable boolean. That property is not JSON Schema nullability: a nullable TEXT parameter stays "type": "string" with "nullable": true. JSON and JSONB already include null in type. A SQL DEFAULT expression is copied into default as a string, such as "'pending'" or "now()", not as a typed example value.

Structured error

JSON
{  "type": "object",  "required": ["status", "code", "message"],  "properties": {    "status": { "type": "string", "const": "error" },    "code": { "type": "string" },    "message": { "type": "string" },    "fieldPath": { "type": "string" }  }}

fieldPath is optional. This component describes errors from routine invocation. Fetching the document itself returns this shape for EPOCH_MISMATCH, and the bearer-token envelope for authentication failures.

File Download

GET /v1/files/{namespace}/{table_name}/{subfolder}/{file_id}

  • bearer token required
  • optional user_id query parameter for user-table scope resolution
  • SYSTEM and STREAM tables are rejected for file paths

Response:

  • 200 with binary content
  • 400/403/404 for validation, permission, or not-found failures

Auth Endpoints

POST /v1/api/auth/login

JSON
{  "user": "alice",  "password": "Secret123!"}

Returns user profile + access/refresh tokens and sets auth cookie.

POST /v1/api/auth/refresh

Accepts bearer token or cookie. Returns rotated token pair.

POST /v1/api/auth/logout

Clears auth cookie.

GET /v1/api/auth/me

Returns current authenticated user info.

POST /v1/api/auth/setup

Initial bootstrap only, when root has no password yet.

JSON
{  "user": "admin",  "password": "AdminPass123!",  "root_password": "RootPass123!",  "email": "admin@example.com"}

Sets root password and creates the DBA user. Does not auto-login.

GET /v1/api/auth/status

Returns setup status:

JSON
{  "needs_setup": true,  "message": "Server requires initial setup..."}

Topic Endpoints

Both require bearer auth and role in {service, dba, system}.

POST /v1/api/topics/consume

JSON
{  "topic_id": "orders_topic",  "group_id": "worker_group",  "start": "Latest",  "limit": 100,  "partition_id": 0,  "timeout_seconds": 10}

Accepted start formats:

  • "Latest"
  • "Earliest"
  • { "Offset": 123 }

POST /v1/api/topics/ack

JSON
{  "topic_id": "orders_topic",  "group_id": "worker_group",  "partition_id": 0,  "upto_offset": 10}

Health Endpoints

GET /health and GET /v1/api/healthcheck return the same payload and are localhost-only:

JSON
{  "status": "healthy",  "version": "...",  "api_version": "v1",  "build_date": "..."}

For live protocol details, continue to WebSocket Protocol.