Multi-Channel Consistency
Maintain unified customer context across phone, chat, email, and other channels.
Business Value
Problem: Customer repeats story across channels
Customer Journey (Without Sticky Calls):
- Monday: Chats with support about billing issue
- Tuesday: Emails follow-up question
- Wednesday: Calls - has to explain entire situation again
- Result: Frustrated customer
Customer Journey (With Sticky Calls):
- Monday: Chats with support
- Tuesday: Emails - agent sees chat history
- Wednesday: Calls - phone agent has full context from chat + email
- Result: Seamless experience
ROI:
- 35% improvement in cross-channel CSAT
- 45% faster resolution on channel switches
- 25% reduction in repeat contacts
- Unified customer view
Implementation
1. Save Context from Any Channel
From Chat:
POST /v1/calls/end
{
"call_id": "chat_session_123",
"customer_ref": "cust_abc123",
"intent": "billing_inquiry",
"intent_status": "open",
"variables": {
"channel": "chat",
"summary": "Customer chatted about billing issue. Explained refund process. Follow-up needed.",
"email": "customer@example.com",
"chat_session_id": "chat_123"
}
}
From Email:
POST /v1/calls/end
{
"call_id": "email_thread_456",
"customer_ref": "cust_abc123",
"intent": "refund_status",
"intent_status": "open",
"variables": {
"channel": "email",
"summary": "Email follow-up about refund timeline. Customer wants status update.",
"email": "customer@example.com",
"ticket_id": "TKT-789"
}
}
2. Retrieve on Phone Call
POST /v1/calls/start
{
"call_id": "phone_call_789",
"identity_hints": {
"ani": "+14155551234",
"external_ids": {
"email": "customer@example.com"
}
}
}
Response:
{
"call_id": "phone_call_789",
"customer_ref": "cust_abc123",
"call_start": "2026-02-06T15:30:00.000Z",
"identity": {
"confidence": 0.95,
"level": "very_high",
"sources": ["ani:mobile", "external_id", "recency:2day"],
"recommendation": "reuse"
},
"open_intents": [
{
"intent": "refund_status",
"status": "open",
"attempt_count": 2
}
],
"variables": {
"channel": {
"value": "email",
"source": null,
"ttl_seconds": 2592000
},
"summary": {
"value": "Customer previously contacted via chat (Mon) and email (Tue) about billing refund. Waiting for status update.",
"source": null,
"ttl_seconds": 2592000
}
}
}
Agent sees: "This customer chatted with us Monday and emailed Tuesday about a refund. They're calling for a status update."
Multi-Signal Matching
Use multiple identifiers for accuracy:
POST /v1/calls/start
{
"call_id": "call_001",
"identity_hints": {
"ani": "+14155551234",
"external_ids": {
"email": "customer@example.com",
"customer_id": "CUST-12345",
"account_number": "ACC-67890"
}
}
}
Match Logic:
- ANI match: 40% weight
- Email match: 30% weight
- Customer ID match: 20% weight
- Recency: 10% weight
- Total confidence: ~0.95 (shown in identity.confidence)
Example Scenarios
Scenario 1: Chat → Phone
Monday - Live Chat:
Customer: My card was charged twice
Agent: I'll submit a refund request
Context saved: "Duplicate charge reported via chat. Refund submitted."
Wednesday - Phone Call:
Customer calls same number
System matches via ANI
Agent sees: "Customer chatted Monday about duplicate charge"
Agent: "Hi! I see you chatted with us Monday about a duplicate charge.
I have an update - your refund was processed yesterday."
Customer: "Wow, you already know! That's great service."
Result: No story repetition, instant resolution
Scenario 2: Email → Chat → Phone
Day 1 - Email:
Customer sends email about account access issue
Support replies: "We're looking into this"
Context: "Email about account access. Under investigation."
Day 2 - Chat:
Customer starts chat
System shows agent: "Customer emailed yesterday about access issue"
Agent: "Hi! I see you emailed about account access. I have an update..."
Context updated: "Chat follow-up. Sent password reset link."
Day 3 - Phone:
Customer calls
System shows: Full email + chat history
Agent: "Hi! I see you emailed and chatted about account access.
Did the password reset link work?"
Customer: Impressed by continuity
Integration with Omnichannel Platforms
Zendesk + Sticky Calls
// On new ticket (any channel)
zendesk.on('ticket.created', async (ticket) => {
// Get customer_ref from existing call or use placeholder
const customerRef = await lookupOrCreateCustomer(ticket.requester.phone);
// Save context
await stickyCallsAPI.saveContext({
call_id: ticket.id,
customer_ref: customerRef,
intent: ticket.via.channel,
intent_status: ticket.status === 'solved' ? 'resolved' : 'open',
variables: {
channel: ticket.via.channel,
summary: ticket.description,
email: ticket.requester.email,
zendesk_user_id: ticket.requester.id
}
});
});
// On phone call
zendesk.on('call.incoming', async (call) => {
// Get cross-channel context
const context = await stickyCallsAPI.getContext({
call_id: call.id,
identity_hints: {
ani: call.from,
external_ids: {
email: lookupEmail(call.from)
}
}
});
// Display to agent
zendesk.ui.showContext({
summary: context.variables?.summary?.value || '',
openIntents: context.open_intents.filter(i => i.status === 'open')
});
});
Salesforce Service Cloud
// Save context from any channel
public static void saveInteractionContext(
String channel,
String customerId,
String customerRef,
String intent,
String summary,
Boolean isResolved
) {
HttpRequest req = new HttpRequest();
req.setEndpoint('https://api.stickycalls.com/v1/calls/end');
req.setMethod('POST');
req.setHeader('Authorization', 'Bearer ' + API_KEY);
req.setHeader('Content-Type', 'application/json');
req.setBody(JSON.serialize(new Map<String, Object>{
'call_id' => channel + '_' + Datetime.now().getTime(),
'customer_ref' => customerRef,
'intent' => intent,
'intent_status' => isResolved ? 'resolved' : 'open',
'variables' => new Map<String, String>{
'channel' => channel,
'summary' => summary,
'sfdc_id' => customerId
}
}));
Http http = new Http();
http.send(req);
}
Best Practices
1. Use Multiple Identifiers
✅ Include: ANI + Email + Customer ID
❌ Use only: ANI
2. Tag by Channel
{
"call_id": "interaction_123",
"customer_ref": "cust_abc123",
"intent": "billing_inquiry",
"intent_status": "open",
"variables": {
"channel_history": "[CHAT] Customer reported billing issue. [EMAIL] Follow-up sent. [PHONE] Now calling for status.",
"last_channel": "phone",
"chat_session": "cs_123",
"email_thread": "em_456"
}
}
3. Timestamp Everything
Context: "Customer chatted on 1/28 at 2 PM about refund.
Emailed on 1/29 at 10 AM for status.
Now calling on 1/30 at 3 PM."
4. Show Channel History to Agent
┌─ Cross-Channel History ───────────┐
│ Mon 1/28 2:00 PM - Chat │
│ "Reported duplicate charge" │
│ │
│ Tue 1/29 10:00 AM - Email │
│ "Asked for refund status" │
│ │
│ Wed 1/30 3:00 PM - Phone (now) │
│ "Following up" │
└───────────────────────────────────┘
Metrics
| Metric | Target | Impact |
|---|---|---|
| Cross-Channel CSAT | > 9.0 | Customer delight |
| Channel Switch Resolution | < 3 min | Efficiency |
| Repeat Contact Rate | < 10% | Reduced friction |
| Agent Confidence | > 90% | Better service |
ROI Calculation
Assumptions:
- 5,000 customer contacts/month
- 20% involve channel switching (1,000)
- 3 minutes saved per channel switch
- Agent cost: $25/hour
Time Savings:
- 1,000 × 3 min = 3,000 min/month = 50 hours
- Annual: 600 hours
Cost Savings:
- 600 hours × $25 = $15,000/year
Sticky Calls Cost:
- ~4,000 new lookups/month = $12/month = $144/year
Net Savings: $14,856/year ROI: 10,317%
Implementation Checklist
- Identify all customer touchpoints (phone, chat, email, etc.)
- Add Sticky Calls to each channel
- Use consistent customer identifiers across channels
- Test cross-channel context retrieval
- Train agents on unified view
- Monitor cross-channel CSAT
- Celebrate seamless experiences
Next Steps
- API Reference - Complete documentation
- Repeat Caller Use Case - Related scenario
- Best Practices - Optimization tips
- Contact Support - Get help
Ready for unified customer experience? Sign up for free →