Improved

2026-10-06 Request parameter validation error format

Affected Endpoints

MethodEndpoint
POST/api/v3/account/account_data_type_values
PUT/api/v3/account/project_templates/:project_template_id/floorplans/flags/collections
POST/api/v3/projects
POST/api/v3/projects/:id/notification
POST/api/v3/projects/:project_id/attachments
PATCH/api/v3/projects/:project_id/attachments/:id
POST/api/v3/projects/:project_id/attachments/batch
PATCH/api/v3/projects/:project_id/bubbles/:id
GET/api/v3/projects/:project_id/budget_actual_costs
POST/api/v3/projects/:project_id/budget_actual_costs
DELETE/api/v3/projects/:project_id/budget_actual_costs/:id
PATCH/api/v3/projects/:project_id/budget_actual_costs/:id
POST/api/v3/projects/:project_id/budget_line_items
DELETE/api/v3/projects/:project_id/budget_line_items/:id
PATCH/api/v3/projects/:project_id/budget_line_items/:id
POST/api/v3/projects/:project_id/change_orders
DELETE/api/v3/projects/:project_id/change_orders/:id
PATCH/api/v3/projects/:project_id/change_orders/:id
POST/api/v3/projects/:project_id/data_type_values
POST/api/v3/projects/:project_id/financials/import_budget_line_items
POST/api/v3/projects/:project_id/financials/import_cost_codes
POST/api/v3/projects/:project_id/floorplans/batch_move
PUT/api/v3/projects/:project_id/floorplans/flags/collections
POST/api/v3/projects/:project_id/forms/:id/email
POST/api/v3/projects/:project_id/multi_hyperlinks/:multi_hyperlink_id/attachments
POST/api/v3/projects/:project_id/rfis
PATCH/api/v3/projects/:project_id/rfis/:id
PATCH/api/v3/projects/:project_id/rfis/:id/transition
POST/api/v3/projects/:project_id/submittal_attachments
POST/api/v3/projects/:project_id/submittals
PATCH/api/v3/projects/:project_id/submittals/:id
PATCH/api/v3/projects/:project_id/submittals/:id/transition
POST/api/v3/projects/:project_id/submittals/batch_import
PATCH/api/v3/projects/:project_id/task_attributes/:id
POST/api/v3/projects/:project_id/tasks
PATCH/api/v3/projects/:project_id/tasks/:id
POST/api/v3/projects/:project_id/tasks/:task_id/bubbles
POST/api/v3/projects/:project_id/tasks/:task_id/task_attributes
PATCH/api/v3/projects/:project_id/tasks/:task_id/task_attributes/:id
POST/api/v3/projects/:project_id/teams/:team_id/tasks
POST/api/v3/projects/:project_id/tier_one_cost_codes
DELETE/api/v3/projects/:project_id/tier_one_cost_codes/:id
PATCH/api/v3/projects/:project_id/tier_one_cost_codes/:id
POST/api/v3/projects/:project_id/tier_two_cost_codes
DELETE/api/v3/projects/:project_id/tier_two_cost_codes/:id
PATCH/api/v3/projects/:project_id/tier_two_cost_codes/:id

Breaking Changes

⚠️

The changes below apply to all requests using API version 2026-10-06 or later. Clients pinned to earlier versions will continue to receive the legacy validation error format shown below and are unaffected.

All affected endpoints

Validation error responses are now structured. Requests that fail parameter validation continue to return 422 Unprocessable Entity, but the errors array now contains one structured object per invalid field instead of a single combined string.

Previous (legacy) format:

{
  "errors": [
    "Invalid parameters: {:original_submittal_attachment_id=>[\"is missing\"]}"
  ]
}

New format (API version 2026-10-06 and later):

{
  "errors": [
    {
      "type": "validation_error",
      "code": "missing_or_empty",
      "message": "original_submittal_attachment_id is missing or empty",
      "details": { "param": "original_submittal_attachment_id" }
    }
  ]
}

When a request has multiple invalid fields, each one is now reported as its own entry in the errors array:

{
  "errors": [
    {
      "type": "validation_error",
      "code": "invalid_type",
      "message": "some_field is not allowed",
      "details": { "param": "some_field" }
    },
    {
      "type": "validation_error",
      "code": "missing_or_empty",
      "message": "original_submittal_attachment_id is missing or empty",
      "details": { "param": "original_submittal_attachment_id" }
    }
  ]
}

Migration guidance: Clients that parsed the legacy errors[0] string (e.g. via regex or substring matching) should switch to iterating over the errors array and reading the code and details.param fields on each entry instead.