POST /api/v2/conversations/webchat/messages 400: Invalid canned response payload

  • Genesys Cloud API v2
  • Node.js SDK
  • Webchat conversation

I cannot figure out why my canned response send fails with a 400 Bad Request. The documentation is sparse on the exact payload structure for text objects when using canned responses. Here is my payload:

{
 "from": { "id": "agent-id" },
 "text": "{\"type\":\"canned\",\"cannedId\":\"123\"}"
}

The error returns invalid_input. Should I be using a different endpoint or payload format for canned responses in webchat?

According to the docs, they say the text field in the message body must be a plain string, not a JSON-encoded string. When you pass "{\"type\":\"canned\",\"cannedId\":\"123\"}", the API receives a literal string containing quotes and escapes, which it tries to parse as text content, failing validation. You need to send the actual JSON object as the value, or structure the payload so the SDK serializes it correctly. In Laravel, I handle this by building the payload array and letting Guzzle handle the JSON encoding.

use GuzzleHttp\Client;

$client = new Client();
$payload = [
 'from' => ['id' => $agentId],
 'to' => ['id' => $conversationId],
 'text' => [
 'type' => 'canned',
 'cannedId' => '123'
 ]
];

$response = $client->post($baseUrl . '/api/v2/conversations/webchat/messages', [
 'headers' => ['Authorization' => 'Bearer ' . $token, 'Content-Type' => 'application/json'],
 'json' => $payload
]);

This ensures the text node is a proper object in the final JSON, matching the schema requirement.

It depends, but generally…

const payload = {
 from: { id: agentId },
 text: {
 type: "canned",
 cannedId: "123"
 }
};

The issue is serialization. You are sending a JSON-encoded string inside the text field, but the API expects a structured object. The Node.js SDK handles the JSON.stringify step during the HTTP request preparation. If you manually stringify the text value, the server receives a string literal containing escape characters, which fails the schema validation for the Message object.

I have seen this frequently in CI pipelines where payloads are constructed dynamically. Ensure you are passing the raw object to the SDK method, not a pre-stringified version. If you are using fetch or axios directly, the same rule applies: the body must be a JSON object with text as a nested object, not a string. Check your network tab to verify the raw request body matches the expected schema.

{
 "from": { "id": "agent-id" },
 "text": {
 "type": "canned",
 "cannedId": "123"
 }
}

This is caused by double-encoding the text payload. The Node.js SDK handles serialization; passing a pre-stringified JSON fragment results in a 400 Bad Request. Send the raw object. I verify this structure in every Newman run to avoid invalid type errors on the wire.