Log Ingestion
Send logs to Timberlogs via the ingestion API.
Endpoint
POST /v1/logsBase URL: https://timberlogs-ingest.enaboapps.workers.dev
Request
Headers
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer <api-key> or Bearer <jwt> |
Content-Type | Yes | application/json |
Body
{
"logs": [
{
"level": "info",
"message": "User signed in",
"source": "api-server",
"environment": "production",
"data": {
"userId": "user_123"
}
}
]
}Log Entry Schema
| Field | Type | Required | Description |
|---|---|---|---|
level | string | Yes | Log level: debug, info, warn, error |
message | string | Yes | Log message (1-10,000 characters) |
source | string | Yes | Application/service name (1-100 characters) |
environment | string | Yes | development, staging, or production |
dataset | string | No | Dataset name for grouping (default: default) |
version | string | No | Application version |
userId | string | No | User identifier |
sessionId | string | No | Session identifier |
requestId | string | No | Request identifier for correlation |
data | object | No | Arbitrary JSON data |
errorName | string | No | Error class/name |
errorStack | string | No | Error stack trace |
tags | string[] | No | Array of tags (max 20 tags, 50 chars each) |
timestamp | number | No | Unix timestamp in milliseconds |
flowId | string | No | Flow identifier for grouping related logs |
stepIndex | number | No | Step index within a flow (0-1000) |
Batch Limits
- Minimum: 1 log per request
- Maximum: 100 logs per request
Response
Success (200)
{
"success": true,
"count": 5,
"timestamp": 1704067200000
}| Field | Type | Description |
|---|---|---|
success | boolean | Always true on success |
count | number | Number of logs ingested |
timestamp | number | Server timestamp of ingestion |
Error Responses
400 Bad Request - Invalid request body
{
"error": "Validation error",
"issues": [
{
"path": ["logs", 0, "level"],
"message": "Invalid enum value"
}
]
}401 Unauthorized - Invalid or missing API key
{
"error": "Invalid API key"
}429 Too Many Requests - Rate limit exceeded
{
"error": "Rate limit exceeded",
"retryAfter": 60
}Examples
Basic Log
curl -X POST https://timberlogs-ingest.enaboapps.workers.dev/v1/logs \
-H "Authorization: Bearer tb_live_xxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"logs": [{
"level": "info",
"message": "Application started",
"source": "my-app",
"environment": "production"
}]
}'Log with Data
curl -X POST https://timberlogs-ingest.enaboapps.workers.dev/v1/logs \
-H "Authorization: Bearer tb_live_xxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"logs": [{
"level": "info",
"message": "User signed in",
"source": "auth-service",
"environment": "production",
"userId": "user_123",
"sessionId": "sess_abc",
"data": {
"method": "oauth",
"provider": "google"
},
"tags": ["auth", "login"]
}]
}'Error Log
curl -X POST https://timberlogs-ingest.enaboapps.workers.dev/v1/logs \
-H "Authorization: Bearer tb_live_xxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"logs": [{
"level": "error",
"message": "Database connection failed",
"source": "api-server",
"environment": "production",
"errorName": "ConnectionError",
"errorStack": "ConnectionError: ECONNREFUSED\n at connect (/app/db.js:42:11)\n at ...",
"tags": ["database", "critical"]
}]
}'Batch Logs
curl -X POST https://timberlogs-ingest.enaboapps.workers.dev/v1/logs \
-H "Authorization: Bearer tb_live_xxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"logs": [
{
"level": "info",
"message": "Request received",
"source": "api",
"environment": "production",
"requestId": "req_xyz"
},
{
"level": "debug",
"message": "Processing request",
"source": "api",
"environment": "production",
"requestId": "req_xyz"
},
{
"level": "info",
"message": "Request completed",
"source": "api",
"environment": "production",
"requestId": "req_xyz",
"data": {"duration": 145}
}
]
}'Flow Tracking
curl -X POST https://timberlogs-ingest.enaboapps.workers.dev/v1/logs \
-H "Authorization: Bearer tb_live_xxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"logs": [
{
"level": "info",
"message": "Checkout started",
"source": "checkout-service",
"environment": "production",
"flowId": "checkout-a1b2c3d4",
"stepIndex": 0
},
{
"level": "info",
"message": "Payment processed",
"source": "checkout-service",
"environment": "production",
"flowId": "checkout-a1b2c3d4",
"stepIndex": 1
}
]
}'Rate Limits
Rate limits depend on your plan:
| Plan | Requests/minute | Logs/month |
|---|---|---|
| Free | 60 | 10,000 |
| Pro | 600 | 1,000,000 |
| Enterprise | Unlimited | Custom |
When rate limited, you’ll receive a 429 response with a retryAfter value indicating when to retry.
Best Practices
- Batch logs - Send multiple logs per request to reduce overhead
- Use the SDK - The TypeScript SDK handles batching and retries automatically
- Include context - Add
userId,sessionId, andrequestIdfor correlation - Use structured data - Put details in
datarather than interpolating intomessage - Tag appropriately - Use consistent tags for filtering
- Handle errors - Implement retry logic with exponential backoff
Last updated on