Skip to main content

API Documentation

Overview

Observability API for ingesting and searching telemetry data. This API allows you to ingest application metrics, OpenTelemetry logs and traces, then search through the collected data using SQL queries.

Base URL: https://<INSTANCE_NAME>

Authentication

Include your API key in the Authorization header for all requests.

Authorization: Basic <YOUR_API_KEY>

Endpoints

Search through ingested data using SQL queries.

Request

POST /api/{org_id}/_search

Path Parameters

NameTypeRequiredDescription
org_idstringYesOrganization ID

Request Body

FieldTypeRequiredDescription
sqlstringYesSQL query to execute on the stream
start_timeintegerNoStart timestamp (Unix microseconds)
end_timeintegerNoEnd timestamp (Unix microseconds)
fromintegerNoOffset for pagination (default: 0)
sizeintegerNoNumber of results to return (default: 100)

Example Request

curl -X POST "https://<INSTANCE_NAME>/api/default/application_logs/_search" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"sql": "SELECT * FROM application_logs WHERE level = '\''ERROR'\''",
"start_time": 1705756200000,
"end_time": 1705759800000,
"from": 0,
"size": 100
}'

Response - Success

{
"success": true,
"arrow_data": [],
"hits": [
{
"timestamp": "2024-01-20T10:30:00Z",
"level": "ERROR",
"message": "Connection failed",
"service": "payment-api"
},
{
"timestamp": "2024-01-20T10:31:00Z",
"level": "ERROR",
"message": "Database timeout",
"service": "payment-api"
}
],
"execution_time": 0.234,
"total": 156,
"start_time": 1705756200000.0,
"end_time": 1705759800000.0,
"from": 0,
"size": 100
}

Response Fields

FieldTypeDescription
successbooleanWhether the search executed successfully
arrow_databytesBinary Apache Arrow data buffer (base64 encoded in JSON)
hitsarrayOptional JSON array of matching results
execution_timenumberQuery execution time in seconds
totalintegerTotal number of results found
start_timenumberUnix timestamp of query start
end_timenumberUnix timestamp of query end
fromintegerOffset used in the query
sizeintegerPage size used in the query

Error Response Examples

Invalid SQL syntax:

{
"error": "Failed to parse SQL query",
"code": "BAD_REQUEST",
"details": "Syntax error near 'SLECT'"
}

Stream not found:

{
"error": "Stream not found",
"code": "NOT_FOUND",
"details": "Stream 'application_logs' does not exist in organization 'default'"
}

Status Codes

CodeDescription
200Search successful
400Invalid query or malformed request
401Unauthorized
404Stream not found
500Internal server error

Ingest - JSON

Ingest JSON data to a stream.

Request

POST /api/{org_id}/{stream_name}/_json_evolving

Path Parameters

NameTypeRequiredDescription
org_idstringYesOrganization ID
stream_namestringYesStream name to ingest into

Request Body

JSON object or array of JSON objects. Schema is inferred and evolved based on incoming data.

Example Request

curl -X POST "https://<INSTANCE_NAME>/api/default/application_logs/_json_evolving" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"timestamp": "2024-01-20T10:30:00Z",
"level": "ERROR",
"message": "Database connection failed",
"service": "payment-api",
"trace_id": "abc123def456"
}'

Response - Success

OK

Error Response Examples

Invalid JSON:

{
"error": "Failed to parse JSON",
"code": "BAD_REQUEST",
"details": "Invalid JSON at line 1, column 15"
}

Organization not found:

{
"error": "Organization not found",
"code": "NOT_FOUND",
"details": "Organization 'default' does not exist"
}

Status Codes

CodeDescription
200Data ingested successfully
400Invalid JSON format
401Unauthorized
403Forbidden - no write permission
404Organization or stream not found
429Rate limit exceeded
500Internal server error

Ingest - OpenTelemetry Logs

Ingest OpenTelemetry logs.

Request

POST /api/{org_id}/{stream_name}/_otel/v1/logs

Path Parameters

NameTypeRequiredDescription
org_idstringYesOrganization ID
stream_namestringYesStream name to ingest into

Request Body

OpenTelemetry Protocol (OTLP) logs in JSON or protobuf format. Payload should conform to the OpenTelemetry specification.

Example Request

curl -X POST "https://<INSTANCE_NAME>/api/default/otel_logs/_otel/v1/logs" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"resourceLogs": [
{
"resource": {
"attributes": [
{
"key": "service.name",
"value": { "stringValue": "payment-service" }
}
]
},
"scopeLogs": [
{
"scope": {
"name": "my-instrumentation"
},
"logRecords": [
{
"timestamp": 1642598400000000000,
"severityNumber": 13,
"severityText": "ERROR",
"body": { "stringValue": "Payment processing failed" },
"attributes": [
{
"key": "transaction_id",
"value": { "stringValue": "txn_12345" }
}
]
}
]
}
]
}
]
}'

Response - Success

Plain text response:

OK

Error Response Examples

Invalid JSON format:

{
"error": "Failed to decode OTel JSON",
"code": "BAD_REQUEST",
"details": "Invalid field value in resourceLogs[0]"
}

Invalid protobuf format:

{
"error": "Failed to decode OTel protobuf",
"code": "BAD_REQUEST",
"details": "Protobuf deserialization error at offset 42"
}

Status Codes

CodeDescription
200Logs processed
400Invalid OTEL format (JSON/protobuf decode error)
401Unauthorized
403Forbidden - no write permission
404Organization or stream not found
429Rate limit exceeded
500Internal server error

Ingest - OpenTelemetry Traces

Ingest OpenTelemetry traces.

Request

POST /api/{org_id}/v1/traces

Path Parameters

NameTypeRequiredDescription
org_idstringYesOrganization ID

Request Body

OpenTelemetry Protocol (OTLP) traces in JSON or protobuf format. Payload should conform to the OpenTelemetry specification.

Example Request

curl -X POST "https://<INSTANCE_NAME>/api/default/v1/traces" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"resourceSpans": [
{
"resource": {
"attributes": [
{
"key": "service.name",
"value": { "stringValue": "api-server" }
}
]
},
"scopeSpans": [
{
"scope": {
"name": "my-instrumentation"
},
"spans": [
{
"traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
"spanId": "00f067aa0ba902b7",
"name": "payment_processing",
"startTimeUnixNano": 1642598400000000000,
"endTimeUnixNano": 1642598400000500000,
"status": { "code": 0 }
}
]
}
]
}
]
}'

Response - Success

Plain text response:

OK

Error Response Examples

Invalid JSON format:

{
"error": "Failed to decode OTel JSON",
"code": "BAD_REQUEST",
"details": "Invalid traceId format"
}

Invalid protobuf format:

{
"error": "Failed to decode OTel protobuf",
"code": "BAD_REQUEST",
"details": "Unexpected EOF while decoding spans"
}

Status Codes

CodeDescription
200Traces processed
400Invalid OTEL format (JSON/protobuf decode error)
401Unauthorized
403Forbidden - no write permission
404Organization not found
429Rate limit exceeded
500Internal server error

cURL

# Search
curl -X POST "https://<INSTANCE_NAME>/api/default/my_stream/_search" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"sql": "SELECT * FROM my_stream LIMIT 10", "from": 0, "size": 100, "start_time": 1705756200000, "end_time": 1705759800000}'

# Ingest JSON
curl -X POST "https://<INSTANCE_NAME>/api/default/my_stream/_json_evolving" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"timestamp": "2024-01-20T10:30:00Z", "level": "ERROR", "message": "Failed"}'

# Ingest OTel Logs
curl -X POST "https://<INSTANCE_NAME>/api/default/otel_logs/_otel/v1/logs" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"resourceLogs": [...]}'

# Ingest OTel Traces
curl -X POST "https://<INSTANCE_NAME>/api/default/v1/traces" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"resourceSpans": [...]}'

Support

For questions or issues, contact: support@ctrlb.ai