Skip to main content

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:

SignalConfidence BoostExample
Mobile ANI+0.5Mobile phone (personal device)
External ID match+0.4CRM ID, account number match
Recent call (1 day)+0.1Called yesterday
Open intent+0.1Unresolved issue from last call
DNIS match+0.05Called this number before
Landline ANI+0.3Landline (could be shared)
VoIP ANI+0.2VoIP line
Toll-free ANI+0.05Toll-free number (business)
Unknown ANI+0.0No 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

StatusErrorWhat It MeansWhat To Do
400Bad RequestInvalid request formatCheck request body matches schema
401UnauthorizedInvalid API keyVerify API key is correct
402Payment RequiredInsufficient creditsAdd credits to account
409ConflictDuplicate call_id or call already endedUse unique call_id for each call
429Too Many RequestsExceeded tier rate limit (after 10% grace)Wait retryAfter seconds, implement exponential backoff
500Internal Server ErrorServer errorRetry, 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/start at beginning of call
  • Always call /calls/end at end of call
  • Send external_ids when available (CRM ID, account number)
  • Save meaningful variables (name, preferences, account details)
  • Mark intents intent_status: "open" if unresolved
  • Use unique call_id for each call (timestamp + random recommended)
  • Use same customer_ref for 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_id within 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_ref for same customer

9. Next Steps


Support


Pricing

Credit-based billing:

Free Tier:

  • 100 credits on signup
  • Test keys have separate credit balance

Paid Tiers:


Ready to get started? Sign up now →