Endpoint
POST/v1/logs
Base URL: https://timberlogs-ingest.enaboapps.workers.dev
Supported Formats
The ingestion endpoint accepts logs in multiple formats. Format is resolved by priority:?format=query parameter (highest priority)Content-Typeheader- Auto-detection via content sniffing (fallback)
| Format | Content-Type | ?format= | Description |
|---|---|---|---|
| JSON | application/json | json | Default. { logs: [...] }, bare array, or single object |
| JSONL | application/x-ndjson | jsonl | One JSON object per line |
| Syslog | application/x-syslog | syslog | RFC 5424 and RFC 3164 |
| Text | text/plain | text | One log per line, auto-extracts timestamp and level |
| CSV | text/csv | csv | Header row with field names, comma or tab delimited |
| OBL | application/x-obl | obl | Open Board Logging format for AAC device logs |
Request
Headers
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer <api-key> |
Content-Type | No | Format hint (see table above). Defaults to application/json |
Query Parameters
| Parameter | Description |
|---|---|
format | Explicit format override: json, jsonl, syslog, text, csv, obl |
source | Default source for logs that don’t include one |
environment | Default environment for logs that don’t include one |
level | Default level for logs that don’t include one |
dataset | Default dataset for logs that don’t include one |
source and environment may not be present in the log data.
Body (JSON)
[...] or a single object {...}.
Body (JSONL)
Body (Syslog)
RFC 5424:error, warning → warn, notice/info → info, debug → debug. The APP-NAME or TAG becomes source, and HOSTNAME/PROCID are stored in data.
Body (Plain Text)
YYYY-MM-DD HH:MM:SS, MM/DD/YYYY HH:MM:SS) and level keywords (ERROR, WARN, WARNING, INFO, DEBUG, case-insensitive). Use ?source= and ?environment= query params to set required fields.
Body (CSV)
Body (OBL)
button, utterance, action, and note.
Event mapping:
- button → message:
Button: {label}, data includesspoken,button_id,board_id - utterance → message:
Utterance: {text}, data includes constituentbuttons - action → message:
Action: {action}, data includesdestination_board_id,text - note → message:
Note: {text}, data includesauthor_name
user_id maps to userId, device_id maps to sessionId, and session/event metadata is stored in data. The root source field is used as the log source. Use ?source= and ?environment= query params to set defaults. Files may start with a /* ... */ comment block which is stripped before parsing. Auto-detection works by checking for "open-board-log-" in the JSON.
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)
| 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 or parse errorissues array. Common causes: invalid level enum value, missing required fields, malformed input, or exceeding the 100-log batch limit.
401 Unauthorized - Invalid or missing API key
retryAfter seconds before retrying. Consider batching logs into fewer requests or upgrading your plan.
Examples
Basic Log (JSON)
JSONL
Syslog
Plain Text
CSV
OBL (AAC Device Logs)
Log with Data
Error Log
Batch Logs
Flow Tracking
Raw Ingestion via SDK
The TypeScript and Python SDKs provideingestRaw() / ingest_raw() methods that send pre-formatted data directly to this endpoint. The SDK handles Content-Type headers, query parameter encoding, and retry logic automatically.
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 |
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 and Python SDKs handle 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
- Use explicit formats - Prefer
?format=orContent-Typeover auto-detection for reliability - Set defaults for non-JSON formats - Use
?source=and?environment=query params when sending plain text or syslog