POST /api/v2/flows/executions returns 400 Bad Request with cryptic error

I’m trying to kick off an Architect flow from an external Node.js app using the REST API. The goal is simple: trigger a flow that handles a specific webhook payload.

I’m using the endpoint POST /api/v2/flows/executions with the flow ID in the path. I’ve verified the flow ID is correct by checking the Architect UI. I’m passing the required application/json content type and a valid access token obtained via client_credentials.

Here is the request body I’m sending:

{
 "flowId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
 "parameters": {
 "customerId": "12345",
 "issueType": "billing"
 }
}

I’m getting a 400 Bad Request response. The error payload isn’t very helpful:

{
 "errors": [
 {
 "code": "bad_request",
 "message": "Invalid input"
 }
 ]
}

I’ve tried the following:

  • Checked the token. It’s valid. I can call GET /api/v2/users/me with the same token.
  • Verified the flowId format. It’s a standard UUID.
  • Tried removing the parameters object entirely. Same error.
  • Tried adding a routingData object. Same error.
  • Checked the timestamp. My server clock is synced via NTP.

The documentation for this endpoint is sparse. It mentions that the flow must be active, which it is. I’m stuck. Is there a specific format for the parameters that I’m missing? Or is this a known issue with the API version I’m using (v2)?

Any insights would be appreciated. I’m running out of ideas.

The 400 usually happens when the payload structure doesn’t match what the flow expects. The API doesn’t just take a raw JSON blob. It needs a specific envelope.

You’re likely sending the data directly in the body. The endpoint expects the data wrapped in a data object. If your flow has a payload variable defined in the webhook trigger, that’s what goes inside.

Here is the correct structure. Note the data key.

{
 "data": {
 "orderId": "12345",
 "customerEmail": "test@example.com"
 }
}

If you send { "orderId": "12345" } directly, the API throws a 400 because it can’t map the root keys to the flow’s input schema.

Also check the application/json header. It’s case-sensitive. Some SDKs default to Application/JSON which breaks the parser in older gateway versions.

I instrument these calls with New Relic to catch the exact error message from the response body. The 400 often contains a errors array with the specific field that failed validation.

const response = await axios.post(
 `https://api.mypurecloud.com/api/v2/flows/executions/${flowId}`,
 { data: payload }, // Wrap in data
 {
 headers: {
 'Content-Type': 'application/json', // Lowercase
 'Authorization': `Bearer ${token}`
 }
 }
);

Check the response body for the errors field. It’ll tell you exactly which property is missing or malformed.