---
title: "Connect from NICE CXone"
description: "Send NICE CXone calls to a ThunderPhone agent from a Studio script with the ContactID in a SIP header, and look up the agent's hand-off when the script continues."
---

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](/guides/api-keys).
- 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](/guides/sip-addresses#platforms-that-dial-a-phone-number)):

```bash
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](/guides/contact-centers/overview#add-the-transfer-number)):

```json
{"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](/api-reference/calls#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.
