API Reference
The End of Line REST API lets you access your call intelligence data programmatically. All endpoints are available at https://api.endofline.ai/api/v1/.
Authentication
End of Line supports two authentication methods:
JWT Tokens (recommended for web apps)
Obtained via Stack Auth. Include the token in the Authorization header:
GET /api/v1/calls
Authorization: Bearer <jwt_token>
X-Tenant-ID: <tenant_uuid>API Keys (recommended for server-to-server)
Create API keys in Settings → API Keys (Business plan and above). Include the key in the X-API-Key header:
GET /api/v1/calls
X-API-Key: eol_live_abc123...
X-Tenant-ID: <tenant_uuid>Rate Limits
Rate limits vary by plan. All responses include rate limit headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 98
X-RateLimit-Reset: 1707900000| Plan | Requests/minute |
|---|---|
| Free | 30 |
| Pro | 100 |
| Business | 300 |
| Enterprise | Custom |
Pagination
List endpoints support cursor-based pagination using page and per_page parameters:
GET /api/v1/calls?page=2&per_page=50
Response:
{
"items": [...],
"total": 1250,
"page": 2,
"per_page": 50,
"pages": 25
}Error Codes
Errors follow a consistent format:
{
"detail": "Human-readable error message"
}| Status | Meaning |
|---|---|
| 400 | Bad Request — invalid parameters |
| 401 | Unauthorized — missing or invalid auth |
| 403 | Forbidden — insufficient permissions or plan limit exceeded |
| 404 | Not Found — resource does not exist |
| 429 | Rate Limited — too many requests |
| 500 | Server Error — contact support |
Calls
List calls
GET /api/v1/calls?page=1&per_page=50&sort=-call_started_at
Query parameters:
page int Page number (default: 1)
per_page int Results per page (1-100, default: 50)
sort str Sort field, prefix with - for descending
status str Filter by status (pending, processing, completed, failed)
date_from int Unix timestamp lower bound
date_to int Unix timestamp upper bound
agent str Filter by agent name
campaign str Filter by campaign name
Response:
{
"items": [
{
"call_id": "uuid",
"inbound_number": "+15551234567",
"caller_number": "+15559876543",
"agent_name": "John Smith",
"campaign_name": "Summer Promo",
"call_started_at": 1707850000,
"duration_seconds": 342,
"status": "completed",
"sentiment_score": 0.72,
"summary": "Customer inquired about pricing..."
}
],
"total": 1250,
"page": 1,
"per_page": 50,
"pages": 25
}Get call detail
GET /api/v1/calls/{call_id}
Response:
{
"call_id": "uuid",
"inbound_number": "+15551234567",
"caller_number": "+15559876543",
"agent_name": "John Smith",
"campaign_name": "Summer Promo",
"call_started_at": 1707850000,
"duration_seconds": 342,
"status": "completed",
"sentiment_score": 0.72,
"summary": "Customer inquired about pricing...",
"entities": ["Acme Corp", "Premium Plan"],
"topics": ["pricing", "features"],
"compliance_flags": [],
"agent_score": {
"overall": 8.5,
"empathy": 9.0,
"objection_handling": 7.5,
"closing": 8.0
}
}Get call transcript
GET /api/v1/calls/{call_id}/transcript
Response:
{
"call_id": "uuid",
"segments": [
{
"speaker": "Agent",
"text": "Hi, thanks for calling...",
"start_time": 0.0,
"end_time": 3.5
},
{
"speaker": "Caller",
"text": "Hi, I'm interested in...",
"start_time": 3.8,
"end_time": 8.2
}
]
}Get audio URL
GET /api/v1/calls/{call_id}/audio
Response:
{
"url": "https://s3.amazonaws.com/...",
"expires_in": 3600
}Export calls (CSV)
GET /api/v1/calls/export?date_from=...&date_to=...&format=csv
Returns: CSV file downloadSearch
Semantic search
POST /api/v1/search
Request:
{
"query": "customer asked about refund policy",
"limit": 10,
"date_from": 1707000000,
"date_to": 1707900000
}
Response:
{
"results": [
{
"call_id": "uuid",
"score": 0.92,
"snippet": "...the customer then asked about our refund policy...",
"agent_name": "Jane Doe",
"call_started_at": 1707850000
}
],
"total": 42,
"query": "customer asked about refund policy"
}Analytics
Overview KPIs
GET /api/v1/analytics/overview?date_from=...&date_to=...
Response:
{
"total_calls": 1250,
"avg_duration": 245.5,
"avg_sentiment": 0.68,
"conversion_rate": 0.32,
"trend": {
"total_calls_change": 12.5,
"avg_sentiment_change": -2.1
}
}Trends
GET /api/v1/analytics/trends?date_from=...&date_to=...&granularity=day
Response:
{
"points": [
{
"date": "2025-02-01",
"total_calls": 42,
"avg_sentiment": 0.71,
"avg_duration": 230.5
}
]
}Agent rankings
GET /api/v1/analytics/agents?date_from=...&date_to=...
Response:
{
"agents": [
{
"agent_name": "John Smith",
"total_calls": 150,
"avg_score": 8.5,
"avg_sentiment": 0.75,
"conversion_rate": 0.38
}
]
}Campaign performance
GET /api/v1/analytics/campaigns?date_from=...&date_to=...
Response:
{
"campaigns": [
{
"campaign_name": "Summer Promo",
"total_calls": 320,
"avg_duration": 210.3,
"avg_sentiment": 0.69,
"conversion_rate": 0.28
}
]
}Conversions
List conversions
GET /api/v1/conversions
Response:
{
"items": [
{
"id": "uuid",
"name": "Appointment Set",
"rules": {"field": "summary", "operator": "contains", "value": "appointment"},
"created_at": "2025-02-01T00:00:00Z",
"match_count": 145
}
],
"total": 5
}Create conversion
POST /api/v1/conversions
Request:
{
"name": "Sale Closed",
"rules": {
"field": "summary",
"operator": "contains",
"value": "sale completed"
}
}
Response: 201 Created
{
"id": "uuid",
"name": "Sale Closed",
"rules": {...},
"created_at": "2025-02-14T00:00:00Z",
"match_count": 0
}Get conversion stats
GET /api/v1/conversions/{id}/stats?date_from=...&date_to=...
Response:
{
"conversion_id": "uuid",
"name": "Sale Closed",
"total_matches": 145,
"rate": 0.32,
"trend": [
{"date": "2025-02-01", "matches": 12, "total": 42, "rate": 0.286}
]
}Integrations
List integrations
GET /api/v1/integrations
Response:
{
"items": [
{
"id": "uuid",
"platform": "ringba",
"status": "active",
"last_sync_at": "2025-02-14T12:00:00Z",
"calls_synced": 1250
}
]
}Create integration
POST /api/v1/integrations
Request:
{
"platform": "ringba",
"credentials": {
"account_id": "...",
"api_token": "..."
}
}
Response: 201 Created
{
"id": "uuid",
"platform": "ringba",
"status": "active",
"created_at": "2025-02-14T00:00:00Z"
}Webhooks
List webhooks
GET /api/v1/webhooks
Response:
{
"items": [
{
"id": "uuid",
"url": "https://your-app.com/webhook",
"events": ["call.completed", "conversion.matched"],
"active": true
}
]
}Create webhook
POST /api/v1/webhooks
Request:
{
"url": "https://your-app.com/webhook",
"events": ["call.completed"],
"secret": "your_webhook_secret"
}
Response: 201 Created
{
"id": "uuid",
"url": "https://your-app.com/webhook",
"events": ["call.completed"],
"active": true,
"created_at": "2025-02-14T00:00:00Z"
}Webhook payload
Webhook payloads are sent as POST requests with a X-Webhook-Signature header for verification:
POST https://your-app.com/webhook
Content-Type: application/json
X-Webhook-Signature: sha256=...
{
"event": "call.completed",
"timestamp": "2025-02-14T12:00:00Z",
"data": {
"call_id": "uuid",
"status": "completed",
"agent_name": "John Smith",
"duration_seconds": 342,
"sentiment_score": 0.72,
"summary": "..."
}
}Knowledge Graph
Query graph
POST /api/v1/graph/query
Request:
{
"query": "MATCH (a:Agent)-[:HANDLED]->(c:Call) RETURN a, count(c)",
"limit": 100
}
Response:
{
"nodes": [...],
"edges": [...],
"total": 42
}Get entity relationships
GET /api/v1/graph/entities/{entity_name}
Response:
{
"entity": "Acme Corp",
"type": "Company",
"relationships": [
{"type": "MENTIONED_IN", "target": "call_uuid", "count": 15},
{"type": "ASSOCIATED_WITH", "target": "Premium Plan", "count": 8}
]
}