Quick Start Guide
Get up and running with Sticky Calls in 5 minutes.
1. Get Your API Key
Sign up instantly at stickycalls.com
✅ Passwordless signup with Auth0 ✅ 100 free credits to get started ✅ Self-service dashboard for API key management ✅ Usage tracking and analytics
2. Make Your First API Call
Call Start (Identify Caller)
curl -X POST https://api.stickycalls.com/v1/calls/start \
-H "Authorization: Bearer sk_test_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"call_id": "test_call_001",
"identity_hints": {
"ani": "+14155551234"
}
}'
First Call Response (New Customer):
{
"call_id": "test_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": {}
}
This means: "No match found - treat as new customer"
Call End (Save Context)
curl -X POST https://api.stickycalls.com/v1/calls/end \
-H "Authorization: Bearer sk_test_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"call_id": "test_call_001",
"customer_ref": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"intent": "demo_call",
"intent_status": "resolved",
"variables": {
"name": "John Doe",
"email": "john@example.com"
}
}'
Response:
{
"call_id": "test_call_001",
"customer_ref": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"call_start": "2026-02-07T10:30:00.000Z",
"call_end": "2026-02-07T10:30:15.000Z",
"duration_seconds": 15,
"intents_updated": 1,
"variables_updated": 2
}
Second Call (Returning Customer)
curl -X POST https://api.stickycalls.com/v1/calls/start \
-H "Authorization: Bearer sk_test_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"call_id": "test_call_002",
"identity_hints": {
"ani": "+14155551234"
}
}'
Second Call Response (Match Found):
{
"call_id": "test_call_002",
"customer_ref": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"call_start": "2026-02-07T10:31:00.000Z",
"identity": {
"confidence": 0.4,
"level": "low",
"sources": ["ani:unknown", "recency:1day"],
"recommendation": "confirm"
},
"open_intents": [],
"variables": {
"name": {
"value": "John Doe",
"source": null,
"ttl_seconds": 2592000
},
"email": {
"value": "john@example.com",
"source": null,
"ttl_seconds": 2592000
}
}
}
This means: "Customer found! Confidence is low (unknown/landline phone type), so ask to confirm identity before using context."
3. Understand Confidence Scoring
Sticky Calls uses multiple signals to identify callers:
| Signal | Confidence Boost | Example |
|---|---|---|
| Mobile ANI | +0.5 | Mobile phone (personal device) |
| External ID match | +0.4 | CRM ID, account number match |
| Recent call (1 day) | +0.1 | Called yesterday |
| Open intent | +0.1 | Unresolved issue from last call |
| DNIS match | +0.05 | Called this number before |
| Landline ANI | +0.3 | Landline (could be shared) |
| VoIP ANI | +0.2 | VoIP line |
| Toll-free ANI | +0.05 | Toll-free number (business) |
| Unknown ANI | +0.0 | No telco data available |
Confidence Levels:
- very_high (≥0.9): Auto-reuse context with highest confidence
- high (≥0.7): Auto-reuse context
- medium (≥0.5): Auto-reuse recommended
- low (<0.5): Confirm identity before using context
Recommendations:
- reuse (≥0.5): Automatically load and use customer context
- confirm (0.3-0.5): Ask customer to confirm identity first
- ignore (<0.3): Treat as new customer, don't use context
4. Production Integration
With External IDs (Stronger Matching)
curl -X POST https://api.stickycalls.com/v1/calls/start \
-H "Authorization: Bearer sk_prod_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"call_id": "call_20260201_143000_abc",
"identity_hints": {
"ani": "+14155551234",
"external_ids": {
"crm_id": "crm_12345",
"account_number": "ACC-789"
}
}
}'
With External IDs:
- Confidence: Up to 0.9+ (mobile + external_id = 0.9)
- Recommendation: "reuse" (very high confidence)
- Best practice: Always send external_ids when available
With Telco Data (Better Confidence)
curl -X POST https://api.stickycalls.com/v1/calls/start \
-H "Authorization: Bearer sk_prod_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"call_id": "call_20260201_143100_def",
"identity_hints": {
"ani": "+14155551234"
},
"telco": {
"line_type": "mobile"
}
}'
With Telco Data:
- Mobile: 0.5 confidence (personal device)
- Landline: 0.3 confidence (could be shared)
- VoIP: 0.2 confidence (often business)
- Recommended providers: Twilio Lookup, numverify, Telnyx
5. Save Useful Context
What to Save
{
"variables": {
// Identity
"name": "John Doe",
"email": "john@example.com",
"phone_alternate": "+14155559999",
// Account
"account_number": "ACC-12345",
"account_balance": "$1,234.56",
"account_status": "active",
"vip_tier": "Gold",
// Preferences
"preferred_language": "English",
"communication_preference": "email",
"timezone": "America/New_York",
// Recent Activity
"last_order_date": "2026-01-28",
"last_payment_date": "2026-02-01",
"last_interaction_summary": "Resolved billing issue - refunded $45.99"
},
"intent": "billing_inquiry",
"intent_status": "resolved" // "resolved" = resolved, "open" = still open
}
Open Intents (Unresolved Issues)
Mark intent_status: "open" when:
- Issue not resolved this call
- Customer needs callback
- Waiting on something (refund processing, part delivery, etc.)
- Multi-call issue (research needed, escalation pending)
{
"intent": "refund_request",
"intent_status": "open", // Will appear on next call
"variables": {
"refund_amount": "$99.99",
"refund_status": "processing",
"expected_date": "2026-02-05"
}
}
Next call: Agent will see open_intents and can proactively ask "I see your refund is processing - has that come through yet?"
6. Code Examples
Node.js / TypeScript
import axios from 'axios';
const STICKY_CALLS_API_KEY = process.env.STICKY_CALLS_API_KEY;
const API_URL = 'https://api.stickycalls.com';
// Start call
async function startCall(callId: string, ani: string, externalIds?: object) {
const response = await axios.post(`${API_URL}/v1/calls/start`, {
call_id: callId,
identity_hints: {
ani: ani,
external_ids: externalIds
}
}, {
headers: {
'Authorization': `Bearer ${STICKY_CALLS_API_KEY}`,
'Content-Type': 'application/json'
}
});
return response.data;
}
// End call
async function endCall(
callId: string,
customerRef: string,
variables: object,
intent: string,
intentStatus: 'open' | 'resolved'
) {
const response = await axios.post(`${API_URL}/v1/calls/end`, {
call_id: callId,
customer_ref: customerRef,
variables: variables,
intent: intent,
intent_status: intentStatus
}, {
headers: {
'Authorization': `Bearer ${STICKY_CALLS_API_KEY}`,
'Content-Type': 'application/json'
}
});
return response.data;
}
// Usage
const startResponse = await startCall('call_123', '+14155551234', { crm_id: 'crm_789' });
console.log('Confidence:', startResponse.identity.confidence);
console.log('Recommendation:', startResponse.identity.recommendation);
if (startResponse.identity.confidence >= 0.5) {
console.log('Welcome back,', startResponse.variables.name?.value);
console.log('Open intents:', startResponse.open_intents);
}
await endCall('call_123', startResponse.customer_ref, { name: 'John' }, 'demo', 'resolved');
Python
import requests
import os
STICKY_CALLS_API_KEY = os.environ['STICKY_CALLS_API_KEY']
API_URL = 'https://api.stickycalls.com'
def start_call(call_id, ani, external_ids=None):
response = requests.post(
f'{API_URL}/v1/calls/start',
json={
'call_id': call_id,
'identity_hints': {
'ani': ani,
'external_ids': external_ids
}
},
headers={
'Authorization': f'Bearer {STICKY_CALLS_API_KEY}',
'Content-Type': 'application/json'
}
)
return response.json()
def end_call(call_id, customer_ref, variables, intent, intent_status):
response = requests.post(
f'{API_URL}/v1/calls/end',
json={
'call_id': call_id,
'customer_ref': customer_ref,
'variables': variables,
'intent': intent,
'intent_status': intent_status
},
headers={
'Authorization': f'Bearer {STICKY_CALLS_API_KEY}',
'Content-Type': 'application/json'
}
)
return response.json()
# Usage
start_response = start_call('call_123', '+14155551234', {'crm_id': 'crm_789'})
print(f"Confidence: {start_response['identity']['confidence']}")
print(f"Recommendation: {start_response['identity']['recommendation']}")
if start_response['identity']['confidence'] >= 0.5:
name = start_response['variables'].get('name', {}).get('value')
print(f"Welcome back, {name}")
print(f"Open intents: {start_response['open_intents']}")
end_call('call_123', start_response['customer_ref'], {'name': 'John'}, 'demo', 'resolved')
curl (bash script)
#!/bin/bash
API_KEY="sk_test_YOUR_API_KEY"
API_URL="https://api.stickycalls.com"
# Start call
curl -X POST "$API_URL/v1/calls/start" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"call_id": "call_'"$(date +%s)"'",
"identity_hints": {
"ani": "+14155551234",
"external_ids": {"crm_id": "crm_123"}
}
}'
# End call
curl -X POST "$API_URL/v1/calls/end" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"call_id": "call_'"$(date +%s)"'",
"customer_ref": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"intent": "test",
"intent_status": "resolved",
"variables": {"name": "John Doe"}
}'
7. Error Handling
Common Errors
| Status | Error | What It Means | What To Do |
|---|---|---|---|
| 400 | Bad Request | Invalid request format | Check request body matches schema |
| 401 | Unauthorized | Invalid API key | Verify API key is correct |
| 402 | Payment Required | Insufficient credits | Add credits to account |
| 409 | Conflict | Duplicate call_id or call already ended | Use unique call_id for each call |
| 429 | Too Many Requests | Exceeded tier rate limit (after 10% grace) | Wait retryAfter seconds, implement exponential backoff |
| 500 | Internal Server Error | Server error | Retry, contact support if persists |
Example Error Response
{
"error": "Bad Request",
"message": "Validation failed",
"details": {
"issues": [
{
"path": ["identity_hints"],
"message": "identity_hints must include ani, external_ids, or customer_ref"
}
]
}
}
8. Best Practices
✅ DO:
- Always call
/calls/startat beginning of call - Always call
/calls/endat end of call - Send
external_idswhen available (CRM ID, account number) - Save meaningful variables (name, preferences, account details)
- Mark intents
intent_status: "open"if unresolved - Use unique
call_idfor each call (timestamp + random recommended) - Use same
customer_reffor same customer across calls - Interpret confidence scores correctly (reuse ≥0.5, confirm 0.3-0.5, ignore <0.3)
- Monitor rate limit headers (
X-RateLimit-Remaining) and implement exponential backoff
❌ 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 as open if they're resolved
- Don't use different
customer_reffor same customer
9. Next Steps
- API Reference - Complete endpoint documentation
- AI Agent Integration - For AI voice agents
- Best Practices - Production optimization
- Use Cases - Real-world integration examples
Support
- Email: nate@bananaintelligence.ai
- Dashboard: https://stickycalls.com
- API Status: https://api.stickycalls.com/v1/health
Pricing
Credit-based billing:
- API calls are charged per request
- View detailed pricing at stickycalls.com/dashboard/billing
Free Tier:
- 100 credits on signup
- Test keys have separate credit balance
Paid Tiers:
- View pricing at stickycalls.com/dashboard/billing
Ready to get started? Sign up now →