Your payload is correct.
Your delivery mechanism is wrong.
ElevenLabs is not receiving:
{
"type": "conversation_initiation_client_data",
"user_id": "222210295",
"dynamic_variables": {
"user_first_name": "Robert"
}
}
It is receiving:
{
"statusCode": 200,
"body": {
"type": "conversation_initiation_client_data",
"user_id": "222210295",
"dynamic_variables": {
"user_first_name": "Robert"
}
}
}
That wrapper breaks ElevenLabs’ parser.
They expect the raw JSON as the HTTP response body, not an n8n-style structured response.
Root Cause
You are using Respond to Webhook in “Response Mode: Last Node” style output.
n8n is wrapping your data.
ElevenLabs reads only the top-level body → doesn’t see dynamic_variables → throws:
Missing required dynamic variables in first message
Fix (Do This Exactly)
In your Respond to Webhook node:
Set:
Response Mode → On Received
OR
Response Data → First Entry JSON
AND most importantly:
Response Body:
Use expression:
{{$json}}
NOT manual object.
Also Check This (Critical)
Make sure your Function node outputs:
return [
{
json: {
type: "conversation_initiation_client_data",
user_id: "222210295",
dynamic_variables: {
user_first_name: "Robert"
}
}
}
];
NOT:
return [
{
statusCode: 200,
body: {...}
}
];
Final Expected HTTP Response (What ElevenLabs Must Receive)
Raw response:
{
"type": "conversation_initiation_client_data",
"user_id": "222210295",
"dynamic_variables": {
"user_first_name": "Robert"
}
}
No wrapper.
No statusCode.
No body key.
Why This Happens
ElevenLabs Conversation Init webhook is strict.
It does not unwrap platform envelopes like:
It expects a direct payload.
If it still fails
Then the issue becomes timing (first message race condition).
But fix the response structure first — right now it’s definitely wrong.
Update this and test again.