Real-World CRM Integration Scenario
The Scenario
Company: TechSupport Inc. (50 agents, 3 locations)
Location: Austin, Toronto, São Paulo
CRM: Salesforce Service Cloud
Requirement: Integrate Genesys Cloud so agents see customer context during calls
Business Requirements
What We Need
When customer calls:
├─ Agent sees: Name, account, last 3 cases, contact history
├─ Call logged in Salesforce (Task)
└─ Contact list stays in sync
Manual Requirements:
├─ Support agents can edit notes in Salesforce
├─ Notes should show in next call
└─ Compliance: GDPR deletion within 30 days
Success Metrics
✓ 100% of calls show customer context (no "Contact not found")
✓ Average call handle time reduced by 10% (less lookup time)
✓ Agent satisfaction > 4/5 (easy to use)
✓ Salesforce Task creation 99%+ success (activity logging)
✓ Contact data fresh (synced daily)
✓ Zero GDPR compliance violations
Architecture
┌─────────────────────────────────────────────────────────┐
│ Salesforce Cloud │
│ (Master Contact DB, Cases, Tasks, Activity Timeline) │
└────────────────┬──────────────────────────────────────────┘
│
│ ← Data Sync (1-way: SF → Genesys)
│ Every 30 minutes
│
┌────────────────▼──────────────────────────────────────────┐
│ Genesys Cloud Contact DB │
│ (Cached contacts for quick lookup during calls) │
│ │
│ Architect Flows: │
│ ├─ Inbound IVR: ANI lookup → screen pop │
│ ├─ Agent Desktop: Show contact context │
│ └─ Webhooks: Log calls back to SF │
└────────────────┬──────────────────────────────────────────┘
│
│ ← Activity Logging (Genesys → SF)
│ After each call
│
└─ Create Salesforce Task
(with call duration, recording, agent)
Phase 1: Screen Pop (Week 1-2)
Goal: When customer calls, agent sees their record
Step 1: Create Salesforce Apex Endpoint
// ContactLookupService.cls
@RestResource(urlMapping='/contact-lookup')
global class ContactLookupService {
@HttpPost
global static Response lookup(String phoneNumber) {
Response response = new Response();
try {
// Normalize phone (remove formatting)
String normalizedPhone = normalizePhone(phoneNumber);
// Search for contact
List<Contact> contacts = [
SELECT Id, FirstName, LastName, Email, Phone,
AccountId, Account.Name
FROM Contact
WHERE Phone = :normalizedPhone
OR MobilePhone = :normalizedPhone
LIMIT 1
];
if (contacts.isEmpty()) {
response.success = false;
return response;
}
Contact contact = contacts[0];
response.success = true;
response.contactId = contact.Id;
response.firstName = contact.FirstName;
response.lastName = contact.LastName;
response.email = contact.Email;
response.accountId = contact.AccountId;
response.accountName = contact.Account?.Name;
} catch (Exception e) {
response.success = false;
response.error = e.getMessage();
}
return response;
}
private static String normalizePhone(String phone) {
// Remove all non-digits
String digits = phone.replaceAll('[^0-9]', '');
// Add +1 if US number (10 digits)
if (digits.length() == 10) {
digits = '1' + digits;
}
return '+' + digits;
}
global class Response {
public Boolean success;
public String contactId;
public String firstName;
public String lastName;
public String email;
public String accountId;
public String accountName;
public String error;
}
}
Step 2: Create Genesys Data Action
In Architect → Data Actions:
Name: lookup-contact-by-phone
Method: POST
URL: https://your-instance.salesforce.com/services/apexrest/contact-lookup
Input:
phoneNumber: ${interaction.caller.phoneNumber}
Output:
success: ${dataAction.response.success}
contactId: ${dataAction.response.contactId}
firstName: ${dataAction.response.firstName}
lastName: ${dataAction.response.lastName}
accountId: ${dataAction.response.accountId}
accountName: ${dataAction.response.accountName}
Step 3: Create Architect Inbound Flow
START
│
├─ Play: "Thank you for calling TechSupport..."
│
├─ Data Action: lookup-contact-by-phone
│ Input: ANI = ${interaction.caller.phoneNumber}
│
├─ Decision: ${dataAction.result.success}?
│ ├─ YES:
│ │ ├─ Set interaction attributes:
│ │ │ ├─ contact_id = ${dataAction.result.contactId}
│ │ │ ├─ contact_name = ${dataAction.result.firstName} ${dataAction.result.lastName}
│ │ │ ├─ account_id = ${dataAction.result.accountId}
│ │ │ └─ account_name = ${dataAction.result.accountName}
│ │ │
│ │ └─ Transfer to Support Queue
│ │
│ └─ NO:
│ ├─ Play: "Please hold while we locate your account..."
│ └─ Transfer to Support Queue (no attributes)
│
└─ DISCONNECT
Expected Result
Customer dials: +1-512-555-1234
↓
Agent receives call
↓
Agent's Genesys desktop shows:
Contact Name: John Doe
Account: Acme Corp
Email: john@acmecorp.com
Last 3 Cases: [list]
Contact History: [last 5 calls]
Phase 2: Contact Sync (Week 2-3)
Goal: Keep Genesys contact list in sync with Salesforce
Step 1: Create Sync Job
// sync-job.js (runs every 30 minutes)
const SalesforceGenesysSync = require('./lib/sync');
async function syncDaily() {
const sync = new SalesforceGenesysSync({
sfInstance: process.env.SALESFORCE_INSTANCE,
sfToken: process.env.SALESFORCE_TOKEN,
gzToken: process.env.GENESYS_TOKEN
});
const result = await sync.runFullSync();
console.log(`✓ Sync complete: ${result.created} created, ${result.updated} updated`);
if (result.errors.length > 0) {
await sendAlert('warning', result);
}
}
syncDaily().catch(error => {
console.error('Sync failed:', error);
process.exit(1);
});
Step 2: Deploy as Lambda (AWS)
# serverless.yml
service: techsupport-crm-sync
provider:
name: aws
runtime: nodejs18.x
environment:
SALESFORCE_INSTANCE: ${env:SALESFORCE_INSTANCE}
SALESFORCE_TOKEN: ${env:SALESFORCE_TOKEN}
GENESYS_TOKEN: ${env:GENESYS_TOKEN}
functions:
sync:
handler: sync-job.syncDaily
events:
- schedule:
rate: rate(30 minutes) # Every 30 minutes
enabled: true
resources:
Resources:
SyncLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: /aws/lambda/techsupport-crm-sync
RetentionInDays: 30
Deploy: serverless deploy
Step 3: Monitor Sync
Logs:
2026-03-14 10:00:00 ✓ Fetched 2345 contacts from Salesforce
2026-03-14 10:00:05 ✓ Found 2100 existing Genesys contacts
2026-03-14 10:00:30 ✓ Created: 50, Updated: 200, Skipped: 5
2026-03-14 10:00:31 Duration: 31 seconds
Metrics:
- Success rate: 99.7%
- Avg duration: 32 sec
- Contacts synced: 250/day
Phase 3: Activity Logging (Week 3-4)
Goal: After call, log details in Salesforce Task
Step 1: Enable Genesys Webhooks
In Genesys Admin → Integrations → Webhooks:
Event: conversation.ended
URL: https://your-backend.com/webhook/call-ended
Payload: Include all details (recording ID, agent, duration)
Retries: 3 times
Step 2: Create Webhook Handler
// webhook-handler.js
app.post('/webhook/call-ended', async (req, res) => {
const {
conversationId,
callerId,
durationSeconds,
recordingId,
agentName,
queueName,
attributes
} = req.body;
try {
// 1. Find matching Salesforce contact
const contact = await findContactByPhone(callerId);
if (!contact) {
console.warn(`Contact not found for ${callerId}`);
return res.status(200).json({ message: 'Contact not found' });
}
// 2. Get recording URL
const recordingUrl = await getRecordingUrl(recordingId);
// 3. Create Salesforce Task
const task = {
Subject: `Call with ${contact.Name}`,
Description: `
Call Details:
Duration: ${Math.floor(durationSeconds / 60)} min
Agent: ${agentName}
Queue: ${queueName}
Recording: ${recordingUrl || 'Not available'}
`.trim(),
WhoId: contact.Id,
WhatId: contact.AccountId,
ActivityDate: new Date().toISOString().split('T')[0],
CallType: 'Inbound',
Status: 'Completed',
Type: 'Call'
};
const taskResult = await createSalesforceTask(task);
console.log(`✓ Task created: ${taskResult.id}`);
// 4. Update Contact's LastActivityDate
await updateSalesforceContact(contact.Id, {
LastActivityDate: new Date().toISOString().split('T')[0]
});
res.status(200).json({ taskId: taskResult.id });
} catch (error) {
console.error('Webhook error:', error);
res.status(500).json({ error: error.message });
}
});
Step 3: Verify Logging
In Salesforce Contact record:
Activity Timeline shows:
- Call with John Doe (10 min)
Agent: Sarah Smith
Queue: Support
Recording: [link]
[Add note/next steps]
Phase 4: GDPR Compliance (Week 4)
Goal: Handle data deletion requests
Step 1: Create GDPR Deletion Procedure
// gdpr-delete.js
async function handleGDPRDeletion(email) {
console.log(`🛑 GDPR Deletion: ${email}`);
// 1. Find contact
const sfContact = await findSalesforceContactByEmail(email);
const gzContact = await findGenesysContactByEmail(email);
// 2. Delete from both
if (sfContact) {
await deleteSalesforceContact(sfContact.Id);
}
if (gzContact) {
await deleteGenesysContact(gzContact.id);
}
// 3. Delete recordings
const recordings = await findRecordingsByPhone(email);
for (const rec of recordings) {
await deleteRecording(rec.id);
}
// 4. Log deletion
await logGDPRDeletion({
email,
deletedAt: new Date(),
deletedFrom: ['salesforce', 'genesys', 'recordings']
});
console.log(`✅ Deleted: ${email}`);
}
Step 2: Document Privacy Policy
Update website:
We collect:
- Name, email, phone (for customer service)
- Call recordings (for 7 years per compliance)
You can:
- Request deletion: privacy@techsupport.com
- We'll delete within 30 days
Go-Live Plan
Week 1: Preparation
- Test screen pop in dev environment
- Train agents on new features
- Set up monitoring
Week 2: Screen Pop
- Deploy Salesforce Apex
- Deploy Genesys Data Action
- Deploy Architect Flow
- Pilot with 5 agents
- Full rollout if successful
Week 3: Contact Sync
- Deploy sync job to Lambda
- Monitor logs for errors
- Verify contacts are syncing
- Set up Slack alerts
Week 4: Activity Logging
- Deploy webhook handler
- Configure Genesys webhooks
- Test call logging
- Verify Salesforce tasks created
Week 5: GDPR & Training
- Document privacy procedures
- Train staff on GDPR
- Set up GDPR deletion process
- Final full-system testing
Expected Results
Before Integration
Agent experience:
- Customer calls
- Agent types customer name into Salesforce search (30 sec)
- Wait for results
- Navigate to account/cases
- Get context, THEN handle call
Average handle time: 8 minutes
Agent satisfaction: 3/5
Customer satisfaction: 3.5/5
After Integration
Agent experience:
- Customer calls
- Record auto-pops (1 sec)
- Agent sees name, account, last cases
- Agent handles call with context immediately
- Call logged to Salesforce automatically
Average handle time: 7 minutes (12.5% improvement)
Agent satisfaction: 4.5/5
Customer satisfaction: 4.2/5
Monitoring & Maintenance
Weekly Checks
□ Screen pop success rate > 99%
□ Contact sync duration < 2 min
□ Activity logging > 99% success
□ GDPR deletion requests: 0
□ Errors: < 5 per week
Monthly Review
□ Agent feedback on usability
□ Performance trends
□ Cost analysis
□ Compliance status
□ Planned improvements
Budget Estimate
Implementation:
├─ Salesforce Apex: $3,000 (5 days)
├─ Genesys Architect: $2,000 (3 days)
├─ Sync Job (Lambda): $1,500 (2 days)
├─ Webhook Handler: $1,500 (2 days)
├─ Testing & QA: $2,000 (3 days)
└─ Total Dev: $10,000
Operations (annual):
├─ AWS Lambda: $50/month ($600/year)
├─ Genesys API calls: $200/month ($2,400/year)
├─ Salesforce: Included in license
├─ Monitoring: $100/month ($1,200/year)
└─ Total Ops: $4,200/year
ROI:
├─ Productivity gain: 12.5% = ~200 agents × 30 min/day
├─ Annual value: 200 × 250 working days × 0.5 hours × $25/hr = $625,000
├─ Cost: $10,000 dev + $4,200 ops = $14,200
└─ Payback: < 1 week
Related Topics
- Chapter 12: Screen Pop Architecture & Implementation
- Chapter 12: Contact Sync Patterns
- Chapter 12: Activity Logging & Webhooks
- Chapter 12: GDPR & Data Governance
- Chapter 11: API Endpoints Reference