I am trying to hand over a voice session from CXone Studio to a NICE Cognigy bot. The flow uses the SessionHandover action with a custom JSON payload. When the bot tries to connect, the Studio trace shows a 400 Bad Request from the handover endpoint. The payload looks correct to me:
{"sessionId": "12345", "botName": "CognigyBot"}
Is there a specific header or format required for the handover API call that I am missing? The bot logs show it never receives the request.
The 400 usually isn’t about the JSON structure itself but rather how the endpoint expects the session context to be framed. If you’re hitting the CXone handover API directly, it often requires the Accept and Content-Type headers to be explicitly set to application/json, which some SDKs don’t default to for custom payloads.
It’s also worth checking if the sessionId in your payload matches the actual active session ID from the Studio trace. A common gotcha is passing a conversation ID or a custom variable instead of the raw session identifier that the routing engine is tracking.
Try adding the explicit headers and verify the session ID source. Here’s a curl example of what a successful handover request typically looks like when debugging outside of Studio:
curl -X POST "https://api.niceincontact.com/api/v2/sessions/handover" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"sessionId": "ACTUAL_SESSION_ID_FROM_TRACE",
"botName": "CognigyBot",
"context": {
"transferReason": "voice_to_bot"
}
}'
If the payload is still being rejected, check the Cognigy side to ensure the incoming webhook is configured to accept the specific payload schema CXone sends. Sometimes the bot expects a wrapper object like {"payload": {...}} instead of the raw fields. You might need to adjust the Data Action in CXone to wrap the JSON accordingly.
Be careful with that SessionHandover approach. You’re likely hitting a schema mismatch on the CXone side because the payload is too sparse. The endpoint expects a full session context object, not just a bare ID and bot name. If you strip out the required metadata like mediaType or routingData, the validation layer throws a 400 before it even talks to Cognigy. Check the event delivery logs in Admin to see the exact rejection reason. It’s usually a missing required field in the nested object structure.
Here’s the minimal valid payload structure you should be sending. Make sure the sessionId matches the active voice call ID from the trace.
{
"sessionId": "12345",
"botName": "CognigyBot",
"metadata": {
"source": "StudioHandover",
"mediaType": "voice"
}
}
Also verify your webhook retry policy isn’t masking the initial failure. If the first attempt fails with 400, retries won’t help since the payload is invalid. You’ll need to fix the schema first.