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
Search through ingested data using SQL queries.
Request
POST /api/{org_id}/_search
Path Parameters
| Name | Type | Required | Description |
|---|---|---|---|
org_id | string | Yes | Organization ID |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
sql | string | Yes | SQL query to execute on the stream |
start_time | integer | No | Start timestamp (Unix microseconds) |
end_time | integer | No | End timestamp (Unix microseconds) |
from | integer | No | Offset for pagination (default: 0) |
size | integer | No | Number 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
| Field | Type | Description |
|---|---|---|
success | boolean | Whether the search executed successfully |
arrow_data | bytes | Binary Apache Arrow data buffer (base64 encoded in JSON) |
hits | array | Optional JSON array of matching results |
execution_time | number | Query execution time in seconds |
total | integer | Total number of results found |
start_time | number | Unix timestamp of query start |
end_time | number | Unix timestamp of query end |
from | integer | Offset used in the query |
size | integer | Page 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
| Code | Description |
|---|---|
| 200 | Search successful |
| 400 | Invalid query or malformed request |
| 401 | Unauthorized |
| 404 | Stream not found |
| 500 | Internal server error |
Ingest - JSON
Ingest JSON data to a stream.
Request
POST /api/{org_id}/{stream_name}/_json_evolving
Path Parameters
| Name | Type | Required | Description |
|---|---|---|---|
org_id | string | Yes | Organization ID |
stream_name | string | Yes | Stream 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
| Code | Description |
|---|---|
| 200 | Data ingested successfully |
| 400 | Invalid JSON format |
| 401 | Unauthorized |
| 403 | Forbidden - no write permission |
| 404 | Organization or stream not found |
| 429 | Rate limit exceeded |
| 500 | Internal server error |
Ingest - OpenTelemetry Logs
Ingest OpenTelemetry logs.
Request
POST /api/{org_id}/{stream_name}/_otel/v1/logs
Path Parameters
| Name | Type | Required | Description |
|---|---|---|---|
org_id | string | Yes | Organization ID |
stream_name | string | Yes | Stream 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
| Code | Description |
|---|---|
| 200 | Logs processed |
| 400 | Invalid OTEL format (JSON/protobuf decode error) |
| 401 | Unauthorized |
| 403 | Forbidden - no write permission |
| 404 | Organization or stream not found |
| 429 | Rate limit exceeded |
| 500 | Internal server error |
Ingest - OpenTelemetry Traces
Ingest OpenTelemetry traces.
Request
POST /api/{org_id}/v1/traces
Path Parameters
| Name | Type | Required | Description |
|---|---|---|---|
org_id | string | Yes | Organization 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
| Code | Description |
|---|---|
| 200 | Traces processed |
| 400 | Invalid OTEL format (JSON/protobuf decode error) |
| 401 | Unauthorized |
| 403 | Forbidden - no write permission |
| 404 | Organization not found |
| 429 | Rate limit exceeded |
| 500 | Internal 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