Ingestion API
Full reference for the DeepTracer ingestion endpoints — logs, errors, traces, LLM usage, and Vercel log drains.
Base URL: https://ingest.deeptracer.dev
All /ingest/* endpoints require an API key in the Authorization header. See Authentication for details.
The API uses snake_case for all field names (e.g., trace_id, error_message). The JavaScript SDK accepts camelCase and converts automatically. If you're calling the API directly with curl, Python, Go, etc., use snake_case.
POST /ingest/logs
Send a batch of log entries. You can send between 1 and 1,000 logs per request.
curl -X POST https://ingest.deeptracer.dev/ingest/logs \
-H "Authorization: Bearer dt_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"service": "my-app",
"environment": "production",
"logs": [
{
"level": "info",
"message": "User signed up",
"metadata": { "userId": "u_123", "plan": "pro" }
},
{
"level": "error",
"message": "Payment failed",
"metadata": { "orderId": "ord_456", "reason": "card_declined" }
}
]
}'Response 200 OK:
{ "ok": true, "count": 2 }Fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
service | string | no | "unknown" | Service name (e.g., "web", "api") |
environment | string | no | "production" | Environment (e.g., "staging", "development") |
release | string | no | -- | Release identifier, max 128 chars |
logs | array | yes | -- | Array of log entries (1-1000) |
logs[].level | string | yes | -- | "debug", "info", "warn", or "error" |
logs[].message | string | yes | -- | Log message |
logs[].timestamp | string | no | now | ISO 8601 timestamp |
logs[].metadata | object | no | -- | Arbitrary key-value data |
logs[].trace_id | string | no | -- | Trace ID for correlation |
logs[].span_id | string | no | -- | Span ID for correlation |
logs[].request_id | string | no | -- | Request ID |
logs[].context | string | no | -- | Logger context name |
logs[].release | string | no | -- | Per-entry release override, max 128 chars |
POST /ingest/errors
Report a single error with stack trace and optional context. DeepTracer generates a fingerprint to group identical errors together.
curl -X POST https://ingest.deeptracer.dev/ingest/errors \
-H "Authorization: Bearer dt_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"service": "my-app",
"environment": "production",
"error_message": "Cannot read properties of undefined (reading '\''id'\'')",
"stack_trace": "TypeError: Cannot read properties of undefined\n at getUser (/app/src/users.ts:42:15)\n at handler (/app/src/api/route.ts:10:3)",
"severity": "high",
"context": { "userId": "u_123", "route": "/api/users" }
}'Response 200 OK:
{ "ok": true, "fingerprint": "a1b2c3d4e5f6..." }The fingerprint is a SHA-256 hash used to group identical errors. Errors with the same fingerprint show up as a single error group in the dashboard.
Fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
service | string | no | "unknown" | Service name |
environment | string | no | "production" | Environment |
error_message | string | yes | -- | Error message text |
stack_trace | string | yes | -- | Full stack trace |
severity | string | no | "medium" | "low", "medium", "high", or "critical" |
context | object | no | -- | Arbitrary context data |
trace_id | string | no | -- | Trace ID for correlation |
user_id | string | no | -- | User ID who triggered the error |
release | string | no | -- | Release identifier, max 128 chars |
breadcrumbs | array | no | -- | Recent actions leading to the error |
breadcrumbs[].type | string | yes | -- | Breadcrumb type (e.g., "http", "ui", "navigation") |
breadcrumbs[].message | string | yes | -- | What happened |
breadcrumbs[].timestamp | string | yes | -- | ISO 8601 timestamp |
POST /ingest/traces
Send a single distributed trace span. Group multiple spans into a trace using the same trace_id.
curl -X POST https://ingest.deeptracer.dev/ingest/traces \
-H "Authorization: Bearer dt_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"service": "my-app",
"environment": "production",
"trace_id": "abc123def456",
"span_id": "span_001",
"parent_span_id": "",
"operation": "GET /api/users",
"start_time": "2026-02-23T00:00:00.000Z",
"duration_ms": 145,
"status": "ok",
"metadata": { "http.status_code": 200 }
}'Response 200 OK:
{ "ok": true }Fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
service | string | no | "unknown" | Service name |
environment | string | no | "production" | Environment |
trace_id | string | yes | -- | Trace ID (groups spans into a trace) |
span_id | string | yes | -- | Unique span identifier |
parent_span_id | string | no | "" | Parent span ID (empty for root spans) |
operation | string | yes | -- | Operation name (e.g., "GET /api/users") |
start_time | string | yes | -- | ISO 8601 start timestamp |
duration_ms | number | yes | -- | Duration in milliseconds (>= 0, rounded to integer) |
status | string | no | "ok" | "ok" or "error" |
metadata | object | no | -- | Arbitrary span attributes |
release | string | no | -- | Release identifier, max 128 chars |
POST /ingest/llm
Report LLM/AI model usage for cost tracking and performance monitoring.
curl -X POST https://ingest.deeptracer.dev/ingest/llm \
-H "Authorization: Bearer dt_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"service": "my-app",
"environment": "production",
"model": "gpt-4o",
"provider": "openai",
"operation": "chat.completion",
"input_tokens": 1250,
"output_tokens": 340,
"cost_usd": 0.0089,
"latency_ms": 2100,
"metadata": { "feature": "support-chat" }
}'Response 200 OK:
{ "ok": true }Fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
service | string | no | "unknown" | Service name |
environment | string | no | "production" | Environment |
model | string | yes | -- | Model identifier (e.g., "gpt-4o", "claude-sonnet-4-5-20250514") |
provider | string | yes | -- | Provider name (e.g., "openai", "anthropic") |
operation | string | yes | -- | Operation type (e.g., "chat.completion", "embedding") |
input_tokens | number | yes | -- | Input/prompt token count (>= 0, rounded to integer) |
output_tokens | number | yes | -- | Output/completion token count (>= 0, rounded to integer) |
cost_usd | number | no | 0 | Estimated cost in USD |
latency_ms | number | yes | -- | Request latency in milliseconds (>= 0, rounded to integer) |
metadata | object | no | -- | Arbitrary metadata |
release | string | no | -- | Release identifier, max 128 chars |
POST /ingest/drain
Vercel Log Drain webhook endpoint. Receives logs forwarded by Vercel's log drain integration.
This endpoint is configured in your Vercel project settings, not called directly. It accepts the standard Vercel log drain payload format (an array of log entries).
For setup instructions, see the Vercel integration guide.
GET /health
Liveness check. No authentication required.
curl https://ingest.deeptracer.dev/healthResponse 200 OK:
{ "status": "ok", "timestamp": "2026-02-23T00:00:00.000Z" }GET /health/ready
Readiness check with dependency status. No authentication required. Returns the health status of ClickHouse, Redis, and PostgreSQL connections.
curl https://ingest.deeptracer.dev/health/readyError responses
All endpoints return JSON error responses with appropriate HTTP status codes.
401 Unauthorized — Missing or invalid API key:
{ "error": "Missing or invalid API key" }400 Bad Request — Validation failed. The response includes Zod error details telling you exactly which fields failed:
{
"success": false,
"error": {
"issues": [
{
"code": "invalid_type",
"expected": "string",
"received": "undefined",
"path": ["error_message"],
"message": "Required"
}
],
"name": "ZodError"
}
}403 Forbidden — Browser request from an origin not in your allowed list:
{ "error": "Origin not allowed" }429 Too Many Requests — Rate limit exceeded. See Rate Limits for details:
{ "error": "Rate limit exceeded" }Field naming convention
| SDK (camelCase) | API (snake_case) |
|---|---|
errorMessage | error_message |
stackTrace | stack_trace |
traceId | trace_id |
spanId | span_id |
parentSpanId | parent_span_id |
startTime | start_time |
durationMs | duration_ms |
inputTokens | input_tokens |
outputTokens | output_tokens |
costUsd | cost_usd |
latencyMs | latency_ms |
userId | user_id |
requestId | request_id |
If you're using the JavaScript SDK, you write camelCase and the SDK translates automatically. If you're hitting the API directly, use snake_case.