Skip to content
Technical Guides
Technical Guides16 min read0 views

AI Voice Agent + Salesforce Integration: Enterprise Developer Guide

A developer guide to integrating AI voice agents with Salesforce — lead push, call activity logging, and managed packages.

Why Salesforce is different

HubSpot is a REST API with sensible defaults. Salesforce is a platform with its own query language (SOQL), its own composite API batching rules, its own OAuth flavors, and dozens of permission settings that will silently block your writes. Getting an AI voice agent into Salesforce cleanly is an enterprise-grade integration task, not a weekend project.

This guide walks through the integration patterns CallSphere uses for enterprise customers — JWT Bearer OAuth, composite API writes, call activity logging, and lead capture.

caller → voice agent
            │
            │ tool: lookup_lead_by_phone
            ▼
         SOQL query
            │
            ▼
       Lead / Contact / Account
            │
            ▼
       Task (type=Call) inserted via composite API

Architecture overview

┌────────────────────┐
│ Voice agent edge   │
└─────────┬──────────┘
          │ tool call
          ▼
┌──────────────────────────┐
│ /salesforce service      │
│ • JWT Bearer OAuth       │
│ • Composite API batching │
│ • Bulk API 2.0 fallback  │
└──────────┬───────────────┘
           │
           ▼
┌──────────────────────────┐
│ Salesforce org           │
└──────────────────────────┘

Prerequisites

  • A Salesforce org (Enterprise, Performance, or Developer edition).
  • A Connected App with JWT Bearer flow enabled and a self-signed certificate.
  • The simple-salesforce Python library or jsforce for Node.
  • Familiarity with SOQL and the composite REST API.

Step-by-step walkthrough

1. Authenticate with JWT Bearer flow

Server-to-server. No user interaction. Re-used across calls.

import jwt, time, requests
from simple_salesforce import Salesforce

def get_access_token():
    claim = {
        "iss": SF_CLIENT_ID,
        "sub": SF_USERNAME,
        "aud": "https://login.salesforce.com",
        "exp": int(time.time()) + 300,
    }
    assertion = jwt.encode(claim, SF_PRIVATE_KEY, algorithm="RS256")
    resp = requests.post(
        "https://login.salesforce.com/services/oauth2/token",
        data={
            "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
            "assertion": assertion,
        },
    )
    resp.raise_for_status()
    body = resp.json()
    return body["access_token"], body["instance_url"]

token, instance = get_access_token()
sf = Salesforce(instance_url=instance, session_id=token)

2. Look up the caller

async def find_lead(phone: str):
    soql = f"""
        SELECT Id, FirstName, LastName, Company, Status
        FROM Lead
        WHERE Phone = '{phone}' OR MobilePhone = '{phone}'
        LIMIT 1
    """
    rows = sf.query(soql)["records"]
    return rows[0] if rows else None

3. Log the call as a Task

Salesforce's canonical "call activity" object is a Task with Type = 'Call'. Use the composite API to insert the task and update the lead in one round trip.

def log_call(lead_id: str, subject: str, description: str, duration_sec: int):
    payload = {
        "compositeRequest": [
            {
                "method": "POST",
                "url": "/services/data/v60.0/sobjects/Task",
                "referenceId": "newTask",
                "body": {
                    "Subject": subject,
                    "Description": description,
                    "Type": "Call",
                    "Status": "Completed",
                    "CallDurationInSeconds": duration_sec,
                    "WhoId": lead_id,
                    "ActivityDate": "2026-04-08",
                },
            },
            {
                "method": "PATCH",
                "url": f"/services/data/v60.0/sobjects/Lead/{lead_id}",
                "referenceId": "updateLead",
                "body": {"Status": "Working - Contacted"},
            },
        ]
    }
    return sf.restful("composite", method="POST", json=payload)

4. Create new leads from the call

def create_lead(first: str, last: str, phone: str, company: str, source: str = "AI Voice Agent"):
    return sf.Lead.create({
        "FirstName": first,
        "LastName": last,
        "Phone": phone,
        "Company": company or "Unknown",
        "LeadSource": source,
        "Status": "New",
    })

5. Expose the tools to the agent

const sfTools = [
  { type: "function", name: "find_lead_by_phone", description: "Look up a Salesforce lead by phone", parameters: { type: "object", properties: { phone: { type: "string" } }, required: ["phone"] } },
  { type: "function", name: "create_lead", description: "Create a new Salesforce lead", parameters: { type: "object", properties: { first: { type: "string" }, last: { type: "string" }, phone: { type: "string" }, company: { type: "string" } }, required: ["last", "phone"] } },
  { type: "function", name: "log_call_task", description: "Log a completed call as a Task", parameters: { type: "object", properties: { lead_id: { type: "string" }, subject: { type: "string" }, description: { type: "string" }, duration_sec: { type: "number" } }, required: ["lead_id", "subject"] } },
];

6. Handle errors like an enterprise integrator

Salesforce will return REQUIRED_FIELD_MISSING, INVALID_SESSION_ID, and DUPLICATES_DETECTED. Map each to a clean tool response the LLM can act on.

Production considerations

  • API limits: orgs get 15k-100k API calls per 24h depending on edition. Monitor Sforce-Limit-Info.
  • Session expiry: JWT tokens last ~30 minutes. Cache them and refresh proactively.
  • Duplicate rules: they will block Lead.create. Handle the DUPLICATES_DETECTED error by surfacing the existing record.
  • Field-level security: the service user needs explicit field permissions, not just object permissions.
  • Governor limits on triggers: an insert can fire Apex triggers that fail silently if your payload is too large.

CallSphere's real implementation

CallSphere connects to Salesforce for enterprise sales and real estate customers. The real estate stack runs 10 agents (buyer specialist, seller specialist, rental specialist, tour coordinator, qualification agent, and more) coordinated through the OpenAI Agents SDK, and the sales pod pairs ElevenLabs TTS with 5 GPT-4 specialists for discovery, qualification, demo scheduling, objection handling, and close.

See AI Voice Agents Handle Real Calls

Book a free demo or calculate how much you can save with AI voice automation.

The voice plane runs on the OpenAI Realtime API with gpt-4o-realtime-preview-2025-06-03, PCM16 at 24kHz, and server VAD. Salesforce writes flow through a dedicated service that batches composite requests, mirrors every write to per-vertical Postgres for auditing, and attaches sentiment and lead score from the GPT-4o-mini post-call pipeline as custom fields on the Task. CallSphere runs 57+ languages with under one second end-to-end response time.

Common pitfalls

  • Per-call OAuth: re-authenticating on every call burns your API quota. Cache the token.
  • Ignoring duplicate rules: your agent will hallucinate "I added you" while nothing was saved.
  • Skipping composite API: individual writes blow through API limits under load.
  • Not handling REQUIRED_FIELD_MISSING: required fields vary by org; surface them as tool errors.
  • Hardcoding the API version: pin it, but plan to bump every year.

FAQ

Should I use Bulk API or REST?

REST for single-record writes, Bulk API 2.0 for backfills. Voice agents almost always want REST.

Can I use a managed package instead?

Yes, but the ROI is only there if you are selling to many Salesforce customers. For a single deployment, direct API is simpler.

How do I handle Person Accounts?

Check Account.IsPersonAccount. The field layout differs.

What about sandboxes?

Use a separate Connected App pointed at https://test.salesforce.com for sandbox JWT auth.

How do I test without burning API calls?

Use the cometd streaming API + simulator, or a Salesforce DX scratch org.

Next steps

Looking to integrate Salesforce with an AI voice agent in your org? Book a demo, see the technology page, or check pricing.

#CallSphere #Salesforce #CRM #VoiceAI #EnterpriseIntegration #SOQL #AIVoiceAgents

Share
C

Written by

CallSphere Team

Expert insights on AI voice agents and customer communication automation.

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.