ThunderPhone 2.0 is live.Self-serve, from 2¢/min.Read the announcement

Contact centers

Connect from NICE CXone

Send NICE CXone calls to a ThunderPhone agent from a Studio script with the ContactID in a SIP header, and look up the agent

Your CXone Studio script places a call to the agent with SIP headers that carry the contact id and any other context. When the agent is done, it hangs up, and a REST API action in the script fetches the hand-off.

Before you start

  • A ThunderPhone agent and an organization API key.
  • A CXone SIP trunk group that accepts custom headers. Your NICE account representative has to turn this setting on before CXone sends them.

1. Create the SIP endpoint

Placecall dials a phone number over a CXone trunk group, not a SIP address. NICE doesn't document SIP credentials for it, and another AI provider's CXone integration uses TLS with an IP allowlist. So create an ip_allowlist endpoint with the number the script will dial as a dial-in number (see Platforms that dial a phone number):

curl -X POST https://api.thunderphone.com/v1/sip-endpoints \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": 12,
    "name": "NICE CXone",
    "auth": "ip_allowlist",
    "allowed_source_cidrs": ["CXONE_SIGNALLING_RANGE_1", "CXONE_SIGNALLING_RANGE_2"],
    "dial_in_numbers": ["+14155550188"]
  }'
  • allowed_source_cidrs: the SIP signalling ranges of your CXone cluster, from NICE. Each must be a public IPv4 range of /16 or narrower (IPv6 /48 or narrower).
  • dial_in_numbers: the number Placecall will dial, written the way CXone sends it. It doesn't have to be a real phone number. It can't already be in use on ThunderPhone, as a phone number or on another endpoint: that returns 409.

CXone's addresses are shared by all its customers, so any other CXone customer who dials the number reaches your agent. Where you choose the number, pick a long one nobody would guess (up to 15 digits), make sure CXone sends it to ThunderPhone rather than out to the phone network, and don't publish it.

2. Send calls with context

In your Studio script, before Placecall:

  1. Add a Sipputheader action with header X-Call-ID and the value of ContactID. CXone sends no call-id header of its own; ThunderPhone stores this one as the call's external_call_id.
  2. Add a Sipputheader action for each other value the agent should know, such as X-Skill set to support. It reaches the prompt as {{sip_x_skill}}. Sipputheader takes User-to-User, any X- header, and most P- headers; NICE recommends values of 256 characters or less.

Then Placecall to that number, over a trunk group that sends it to sip.thunderphone.com with the number in both the request URI and the To header. The endpoint takes TLS (port 5061) or TCP (port 5060) and refuses UDP, and NICE doesn't document the trunk's transport, so make sure it isn't UDP.

3. Get the call back

CXone reads SIP headers only on the INVITE and its final response, so the agent returns the call: it says goodbye and hangs up, and your script picks the caller up again. Add this transfer number (see Add the transfer number):

{"name": "NICE CXone", "action": "return"}

NICE doesn't document that a script continues after Placecall when the placed call ends. Other AI providers' CXone integrations instead signal the script through CXone's Signal API (POST /interactions/{contactId}/signal) before they hang up; ThunderPhone doesn't call it. Confirm with NICE how your script takes the caller back, then fetch the hand-off with a REST API action:

  • GET https://api.thunderphone.com/v1/calls/handoff?external_call_id= followed by ContactID.
  • Header Authorization: Bearer sk_live_….
  • Read handoff.summary and handoff.intent from the response to route the contact.

See Look up a handed-off call.

Test it

Call a number that runs the script, ask the agent for a person, and check that the script continues and the REST API action returns the hand-off. If the call never reaches the agent, check the number CXone sends, that its source address is in allowed_source_cidrs, and that the call came over TCP or TLS. Then open the call with GET /v1/calls/{call_id}: sip_headers should list x-call-id, and external_call_id should equal the ContactID.

Limits

  • CXone sends and reads headers only on the INVITE and its final 2xx, so nothing on the agent's BYE reaches the script.
  • NICE doesn't document accepting a REFER from the agent.
  • The REST API action times out after 10 seconds by default (under 90 at most) and reads responses up to 32 KB.