Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.open.cx/llms.txt

Use this file to discover all available pages before exploring further.

OpenCX phone agents and Zendesk Talk integrate in two directions, each with its own setup. Inbound uses standard Zendesk Talk call forwarding to an OpenCX phone number. Outbound transfers ride over Zendesk’s SIP-IN line so the call lands directly inside the Agent Workspace with a recoverable ticket id. This page covers both. Pick the section that matches the leg you’re configuring.

Receiving inbound calls (Zendesk Talk → OpenCX)

Use this when you want the OpenCX AI phone agent to answer first — for triage, qualification, deflection, or full automation — before optionally handing the call to a human in Zendesk. Zendesk Talk does not support SIP-OUT or custom SIP headers when forwarding outbound. The only supported transport from Zendesk Talk to an external system is plain PSTN call forwarding to a regular phone number, which strips all metadata. To work around this, OpenCX exposes a small webhook that a Zendesk Trigger fires on inbound phone-channel ticket creation. The webhook stamps the originating ticket_id onto the OpenCX phone session, then uses that ticket id to fetch the authoritative Zendesk requester and update the OpenCX contact with verified name, email, phone, and any configured Zendesk user/organization attributes.

Prerequisites

  • A phone number provisioned and verified in OpenCX. See phone setup if you haven’t done that yet.
  • The Zendesk integration connected — see the Zendesk overview.
  • Admin access in your Zendesk account to create webhooks and triggers.

Step 1 — Get your webhook URL

The dashboard surfaces a per-org webhook URL with a JWT in the path, so Zendesk doesn’t need to manage a separate secret.
GET /backend/zendesk-v2/voice-prefetch-url
Authorization: Bearer <opencx-dashboard-jwt>
{
  "webhookUrl": "https://api.open.cx/backend/zendesk-v2/voice-prefetch/<token>"
}
Copy the webhookUrl — you’ll paste it into Zendesk in the next step.

Step 2 — Create the Zendesk webhook target

In your Zendesk admin: Apps and integrations → Webhooks → Create webhook.
FieldValue
NameOpenCX voice prefetch
Endpoint URLThe webhookUrl from Step 1
Request methodPOST
Request formatJSON
AuthenticationNone (the JWT is already in the URL path)

Step 3 — Create the Zendesk trigger

Admin Center → Objects and rules → Business rules → Triggers → Create trigger. ConditionsMeet ALL of the following:
  • Ticket: IsCreated
  • Ticket: ChannelIsPhone call (incoming)
Actions:
  • Notify byActive webhook → select OpenCX voice prefetch.
  • JSON body:
{
  "ticket_id": {{ticket.id}},
  "caller_phone": "{{ticket.via.source.from.phone}}",
  "requester_phone": "{{ticket.requester.phone}}",
  "subject": "{{ticket.title}}"
}
Only ticket_id and one of caller_phone / requester_phone are required. Sending both phone fields gives OpenCX a fallback if Zendesk renders one of them blank for an anonymous caller.

Step 4 — Forward the call to OpenCX

Configure your Zendesk Talk number (or IVR / call queue branch) to forward to your verified OpenCX phone number using Zendesk Talk’s standard forwarding flow. Nothing OpenCX-specific is required at this step — the webhook from Step 3 carries the metadata; the call itself rides over PSTN.

Timing notes

Zendesk fires the trigger when the ticket is created, which often happens before the call has finished its IVR and arrived at OpenCX. If the webhook lands before the OpenCX session exists, the response body returns success: false with a clear message, and the ticket id won’t be stamped on the session. If you have a short or skipped IVR, the call may land first; the webhook then arrives and stamps the existing session. Both orderings are supported — OpenCX reads the stamped ticket id at SIP-transfer time, so any value present before the transfer flows through. When the webhook successfully matches a session, OpenCX also fetches the Zendesk ticket/requester and updates the linked OpenCX contact from Zendesk rather than doing an unreliable phone-number user search.

Contact enrichment

When the webhook matches a live OpenCX session, OpenCX fetches:
  • the Zendesk ticket identified by ticket_id, and
  • the ticket requester (ticket.requester_id).
OpenCX then updates the session’s linked contact with:
  • requester name,
  • requester email,
  • requester phone,
  • Zendesk user id / external id, and
  • Zendesk user fields plus organization fields in contact custom_data (organization fields are prefixed with org_, matching the regular Zendesk chat webhook behavior).
This is intentionally driven by the ticket id, not by searching Zendesk users by phone number. Zendesk’s phone search can return fuzzy/prefix matches, which is not safe enough for identity enrichment. For deployments where the webhook reliably arrives after the call has landed, you can configure a second trigger on Ticket: Is updated with a condition that matches a later event in the call lifecycle (for example, the AI’s first comment being added) so the webhook fires after the OpenCX session has been created.

Troubleshooting

The trigger fired before OpenCX had created the phone session for this caller. Either accept that the first transfer of this call won’t carry the ticket id, or add a second trigger that fires later in the ticket lifecycle (see Timing notes above). The webhook is idempotent: re-firing it with the same payload after the session exists will succeed and stamp the id.
The JWT in the URL has expired or doesn’t belong to this org. Fetch a fresh URL from the dashboard (Step 1) and re-paste it into the Zendesk webhook target.
Check Admin Center → Apps and integrations → Webhooks → your webhook → Activity. Triggers won’t fire for tickets that match a suspended state or that hit a higher-priority trigger first; reorder your triggers if needed.

Transferring calls from OpenCX to Zendesk (SIP-IN)

Use this when the OpenCX AI agent has triaged the call and needs to hand it to a human agent in Zendesk Talk. The transfer rides over Zendesk SIP-IN, which means the call shows up natively inside the Agent Workspace as a Zendesk Talk call — the agent picks it up, sees the caller ID, and (when the ticket id is known) can correlate the leg back to the ticket OpenCX received the call against.

How it works

OpenCX initiates a SIP outbound bridge to your Zendesk SIP-IN line and attaches the original caller’s phone as the From and the originating Zendesk ticket id (when known) as a custom header. Specifically every transferred leg carries:
  • X-OPENCX-SESSION-ID — the OpenCX phone session id.
  • X-OPENCX-AGENT-ID — the OpenCX AI agent id.
  • X-OPENCX-TRANSFERtrue.
  • X-OPENCX-CONTACT-ID — the OpenCX contact id (when resolved).
  • X-OPENCX-ZENDESK-TICKET-ID — the originating Zendesk ticket id, only when:
    • the active OpenCX session has a ticket id stamped on it (from the inbound flow above), and
    • the destination is a SIP URI (PSTN-only destinations don’t carry the header).
The originating caller’s phone number is preserved as the From so Zendesk Talk renders the correct caller ID inside the Agent Workspace.

Prerequisites

  • A configured Zendesk SIP-IN line — follow the Zendesk SIP-IN setup docs. You’ll end up with a SIP URI of the form sip:<your-line>@<subdomain>.zendesk.sip.twilio.com.
  • An OpenCX AI phone agent with at least one transfer destination configured.

Step 1 — Add the Zendesk SIP-IN URI as a transfer destination

In the OpenCX dashboard, open the AI phone agent’s settings and add a new Transfer destination of type SIP. Paste the SIP URI from your Zendesk SIP-IN line as the destination URI, and give it a label your AI agent will recognize (“Zendesk human agent”, “Tier 2”, etc.). The AI agent then picks this destination at runtime when the conversation logic — your prompt, knowledge, or tools — decides to hand off.

Step 2 — (Optional) Receive the ticket id on the Zendesk side

If you’ve also configured the inbound flow above, every transfer leg will carry X-OPENCX-ZENDESK-TICKET-ID whenever the ticket id was successfully stamped on the OpenCX session. Most Zendesk Talk SIP-IN deployments expose received SIP headers as ticket fields or webhook payloads — consult Zendesk’s SIP-IN documentation for how to surface the header to the agent picking up the call.

What does not work

  • PSTN-only transfers (carrier-issued REFER to a regular phone number) won’t reach Zendesk Talk natively — Zendesk Talk only accepts inbound SIP via SIP-IN. If your transfer destination is a regular phone number rather than a SIP URI, the call will route through your carrier as a normal outbound, not through Zendesk.
  • Zendesk SIP-OUT. Zendesk Talk does not support SIP-OUT, which is why the inbound direction has to use PSTN forwarding plus the trigger webhook.

Troubleshooting

Double-check that the OpenCX session knows the caller’s phone number. SIP transfers use the original caller’s phone as the From — if the inbound leg arrived without caller ID (anonymous, blocked, or stripped by an upstream IVR), Zendesk will see the OpenCX-side From instead. There’s no workaround for an anonymous caller.
Verify three things in order:
  1. The inbound trigger from Section 1 fired and returned success: true for this call (check the webhook activity in Zendesk).
  2. The OpenCX session row for this call has zendesk_ticket_id set (check call details in the OpenCX dashboard).
  3. The transfer destination is a SIP URI — PSTN destinations don’t carry the header.
Confirm the SIP-IN URI is correct and reachable from your OpenCX SIP egress IP range — Zendesk SIP-IN requires IP allow-listing on the Zendesk side. See the Zendesk SIP-IN docs for the current allow-list values.

Next steps