API Reference
Complete reference for Sticky Calls API endpoints.
Base URL
https://api.stickycalls.com
Authentication
All API requests require Bearer token authentication:
Authorization: Bearer YOUR_API_KEY
Get your API key from the dashboard.
Endpoints
POST /v1/calls/start
Start a new call and identify the caller.
Request:
curl -X POST https://api.stickycalls.com/v1/calls/start \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"call_id": "call_001",
"identity_hints": {
"ani": "+14155551234",
"external_ids": {
"customer_id": "12345"
}
}
}'
Request Body Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
call_id | string | Yes | Unique identifier for this call (max 128 chars) |
identity_hints | object | Yes | Caller identification information |
identity_hints.ani | string | No* | Caller's phone number in E.164 format |
identity_hints.dnis | string | No | Dialed number (your phone number they called) |
identity_hints.external_ids | object | No* | Key-value pairs of external IDs (CRM ID, account number, etc.) |
identity_hints.customer_ref | string | No* | Previously returned customer_ref UUID |
telco | object | No | Telco lookup data for better confidence scoring |
telco.line_type | enum | No | One of: mobile, landline, voip, unknown |
*At least one of ani, external_ids, or customer_ref must be provided.
Response (Returning Customer):
{
"call_id": "call_001",
"customer_ref": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"call_start": "2026-02-07T10:30:00.000Z",
"identity": {
"confidence": 0.9,
"level": "very_high",
"sources": ["ani:mobile", "external_id", "recency:1day"],
"recommendation": "reuse"
},
"open_intents": [
{
"intent": "refund_request",
"status": "open",
"attempt_count": 2
}
],
"variables": {
"name": {
"value": "John Doe",
"source": null,
"ttl_seconds": 2592000
},
"email": {
"value": "john@example.com",
"source": null,
"ttl_seconds": 2592000
},
"account_balance": {
"value": "$1,234.56",
"source": null,
"ttl_seconds": 2592000
}
}
}
Response (New Customer):
{
"call_id": "call_001",
"customer_ref": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"call_start": "2026-02-07T10:30:00.000Z",
"identity": {
"confidence": 0,
"level": "low",
"sources": [],
"recommendation": "ignore"
},
"open_intents": [],
"variables": {}
}
Response Fields:
| Field | Type | Description |
|---|---|---|
call_id | string | Echo of the request call_id |
customer_ref | string | UUID for this customer (use in /calls/end) |
call_start | string | ISO 8601 timestamp when call started |
identity.confidence | number | 0.0 to 1.0 confidence score |
identity.level | enum | low, medium, high, or very_high |
identity.sources | array | Confidence factors (e.g., ["ani:mobile", "external_id"]) |
identity.recommendation | enum | reuse (≥0.5), confirm (0.3-0.5), or ignore (<0.3) |
open_intents | array | Unresolved intents from previous calls |
variables | object | Customer context (name, preferences, account info, etc.) |
Confidence Recommendations:
reuse(≥0.5): Automatically use customer context without verificationconfirm(0.3-0.5): Ask customer to verify identity before using contextignore(<0.3): Treat as new customer, don't use context
POST /v1/calls/end
End a call and save context for future interactions.
Request (Simple Form):
curl -X POST https://api.stickycalls.com/v1/calls/end \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"call_id": "call_001",
"customer_ref": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"intent": "billing_inquiry",
"intent_status": "resolved",
"variables": {
"name": "John Doe",
"email": "john@example.com",
"last_interaction": "Resolved billing issue - refunded $50"
}
}'
Request Body Parameters (Simple Form):
| Field | Type | Required | Description |
|---|---|---|---|
call_id | string | Yes | Must match call_id from /calls/start |
customer_ref | string | No* | UUID from /calls/start response |
identity_hints | object | No* | Same structure as /calls/start |
intent | string | No | Primary topic discussed (max 128 chars) |
intent_status | enum | No | open (unresolved) or resolved (completed) |
variables | object | No | Key-value pairs to save (keys max 128 chars, values max 1024 chars) |
*Either customer_ref or identity_hints must be provided.
Request (Advanced Form with Multiple Intents):
{
"call_id": "call_001",
"customer_ref": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"intent_updates": [
{
"intent": "refund_request",
"status": "resolved",
"resolution": {
"type": "processed",
"external_reference": "refund_12345"
}
},
{
"intent": "account_upgrade",
"status": "open"
}
],
"variable_updates": {
"name": {
"value": "John Doe",
"source": "agent_collected",
"ttl_seconds": 7776000
},
"vip_tier": {
"value": "Gold",
"source": "crm_sync",
"ttl_seconds": 2592000
}
}
}
Response:
{
"call_id": "call_001",
"customer_ref": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"call_start": "2026-02-07T10:30:00.000Z",
"call_end": "2026-02-07T10:35:30.000Z",
"duration_seconds": 330,
"intents_updated": 2,
"variables_updated": 5
}
Response Fields:
| Field | Type | Description |
|---|---|---|
call_id | string | Echo of the request call_id |
customer_ref | string | Customer UUID |
call_start | string | When call started (from /calls/start) |
call_end | string | When call ended |
duration_seconds | number | Call duration in seconds |
intents_updated | number | Number of intents saved/updated |
variables_updated | number | Number of variables saved/updated |
GET /v1/health
Health check endpoint (no authentication required).
Request:
curl https://api.stickycalls.com/v1/health
Response:
{
"status": "healthy",
"timestamp": "2026-02-07T10:30:00.000Z",
"database": "connected"
}
Error Codes
| Code | Meaning | What To Do |
|---|---|---|
| 400 | Bad Request - Invalid parameters | Check request body matches schema |
| 401 | Unauthorized - Invalid or missing API key | Verify API key is correct and not revoked |
| 402 | Payment Required - Insufficient credits | Add credits in dashboard |
| 409 | Conflict - Duplicate call_id or already ended | Use unique call_id for each call |
| 429 | Too Many Requests - Rate limit exceeded (10% grace period used) | Wait for retryAfter seconds, implement exponential backoff |
| 500 | Internal Server Error - Server error | Retry, contact support if persists |
Error Response Format:
{
"error": "Bad Request",
"message": "Validation failed",
"details": {
"issues": [
{
"path": ["identity_hints"],
"message": "identity_hints must include ani, external_ids, or customer_ref"
}
]
}
}
Rate Limit Error (429) Response:
{
"error": "Too Many Requests",
"message": "Rate limit exceeded for your tier. Limit: 600 requests/minute.",
"retryAfter": 42,
"currentUsage": 661,
"limit": 600,
"resetAt": "2026-02-07T10:31:00.000Z"
}
Rate Limit Response Fields:
retryAfter: Seconds to wait before retryingcurrentUsage: Your current request count this minutelimit: Your tier's base limit (before grace period)resetAt: When the rate limit window resets
Rate Limits
Rate limits vary by tier with a 10% grace period before hard blocking:
| Tier | Limit (per minute) | Grace Period (10%) |
|---|---|---|
| Free | 100 requests | 110 requests |
| Starter | 600 requests | 660 requests |
| Growth | 3,000 requests | 3,300 requests |
| Scale | 10,000 requests | 11,000 requests |
How it works:
- ⏱️ Rate limits reset every 60 seconds
- ⚡ 10% grace period allows brief burst traffic without blocking
- 📊 Rate limit headers included in every response
- 🚫 Hard block after grace period exceeded
Rate Limit Headers:
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 523
X-RateLimit-Reset: 1675789200000
Best Practice: Implement exponential backoff for 429 responses.
Credits & Billing
Credit-based billing:
- API calls are charged per request
- Failed requests (4xx, 5xx) are not charged
Free Tier:
- 100 credits on signup
- Test keys have separate credit balance
Paid Tiers: See Pricing
Idempotency
Use the Idempotency-Key header for safe retries on /calls/end:
curl -X POST https://api.stickycalls.com/v1/calls/end \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: end_call_001_attempt1" \
-H "Content-Type: application/json" \
-d '{"call_id": "call_001", ...}'
- Same idempotency key returns cached response (no duplicate save)
- Keys expire after 24 hours
- Only applicable to /calls/end
- Recommended for production use
Best Practices
✅ DO:
- Always call /calls/start at beginning of call
- Always call /calls/end at end of call
- Send
external_idswhen available (boosts confidence to 0.9+) - Use unique
call_idfor each call (timestamp + random recommended) - Use same
customer_reffor same customer across calls - Interpret confidence correctly (reuse ≥0.5, confirm 0.3-0.5, ignore <0.3)
- Save meaningful variables (name, preferences, account details)
- Mark intents
status: "open"if unresolved - Use Idempotency-Key header for /calls/end
- Implement exponential backoff for 429 errors
❌ DON'T:
- Don't skip /calls/start - you'll miss returning customer context
- Don't skip /calls/end - context won't be saved for next call
- Don't reuse
call_idwithin 30 days - violates uniqueness constraint - Don't save sensitive data (SSN, credit card numbers, passwords)
- Don't expose confidence scores to customers ("I'm 70% sure you're John")
- Don't mark intents
status: "open"if they're resolved - Don't use different
customer_reffor same customer
Code Examples
See Quick Start Guide for complete code examples in:
- Node.js / TypeScript
- Python
- Bash / curl
Need Help?
- Quick Start Guide - Get started in 5 minutes
- Best Practices - Production patterns
- AI Agent Guide - AI integration
- Contact Support - Get help
Ready to build? Sign up now →