REST API
The 2Signal REST API is used by the Python SDK under the hood, but you can also call it directly for custom integrations in any language.
Base URL
https://api.2signal.dev/api/v1Authentication
All endpoints (except health) require a project API key via the Authorization header:
Authorization: Bearer ts_your_api_keyAPI keys are project-scoped — each key belongs to a specific project. Create them in your project settings at app.2signal.dev, via the CLI, or TUI.
Quick Example
curl -X POST https://api.2signal.dev/api/v1/traces \
-H "Authorization: Bearer ts_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"batch": [
{
"id": "evt-1",
"type": "trace-create",
"body": {
"id": "trace-1",
"name": "my-agent"
},
"timestamp": "2026-03-14T10:00:00Z"
}
]
}'Response Format
Success responses return data directly:
{ "accepted": 1 }Error responses include a code and message:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid trace ID format"
}
}Status Codes
| Code | Meaning | When |
|---|---|---|
200 | Success | GET requests, model routing |
201 | Created | Traces and scores created |
400 | Validation error | Malformed request body, missing fields |
401 | Unauthorized | Missing, invalid, or revoked API key |
404 | Not found | Unknown endpoint or resource |
413 | Payload too large | Batch exceeds size limit |
429 | Rate limited | Too many requests per second |
500 | Server error | Internal error (retry with backoff) |
Rate Limits
| Plan | Requests/sec |
|---|---|
| Free | 100 |
| Pro | 1,000 |
| Team | 1,000 |
| Enterprise | 10,000 |
Rate limiting uses a sliding window per API key. When rate limited, the response includes:
HTTP/1.1 429 Too Many Requests
Retry-After: 1
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Retry after 1 second."
}
}Retry Strategy
Recommended retry behavior for production integrations:
- 429 (rate limit) — wait for the
Retry-Afterheader duration, then retry - 500 / 502 / 503 — retry with exponential backoff (1s, 2s, 4s, max 3 retries)
- 400 / 401 / 404 — do not retry (fix the request)
The Python SDK handles retries automatically.
Payload Limits
| Endpoint | Max Size | Max Events |
|---|---|---|
| POST /traces | 5 MB | 1,000 events per batch |
| POST /otel/traces | 5 MB | — |
| POST /scores | 1 MB | — |
| POST /route-model | 512 KB | — |
Timestamps
All timestamps use ISO 8601 format in UTC:
2026-03-14T10:30:00ZThe API accepts both Z and +00:00 suffixes.
Endpoints
| Method | Path | Description |
|---|---|---|
POST | /api/v1/traces | Batch trace and span ingestion |
POST | /api/v1/otel/traces | OpenTelemetry OTLP/JSON trace ingestion |
POST | /api/v1/scores | Submit evaluation scores |
POST | /api/v1/route-model | Model routing |
GET | /api/v1/prompt-templates | List templates or resolve by name/version |
POST | /api/v1/prompt-templates | Create template or push new version |
GET | /api/v1/traces | Query traces with filters |
GET | /api/v1/health | Health check (no auth) |
Health Check
curl https://api.2signal.dev/api/v1/health
# response:
{ "status": "ok" }