Skip to main content

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

MetricTargetImpact
Cross-Channel CSAT> 9.0Customer delight
Channel Switch Resolution< 3 minEfficiency
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


Ready for unified customer experience? Sign up for free →