Skip to main content
When a request fails, the API returns a non-2xx HTTP status and a consistent error envelope. Read the HTTP status for the category and the error.code for the specific, stable reason.

Error envelope

Status codes

Nested config fields on agent writes

Wherever POST /public-api/agents or PUT/PATCH /public-api/agents/{id} accepts a config object, it is a top-level, sibling field of the agent body and never a child of another: agent_settings, agent_settings_edits, toolbox, integrations, schedule, callback_settings, actions, ticket_conditions and time_entry_conditions. Which of them a given body accepts is a separate question, answered by that body’s schema. agent_settings_edits is PUT/PATCH only, so send the full agent_settings on create; and the POST body is a discriminated union on autonomy_type, so each variant declares its own subset — a CONVERSATIONAL create takes no actions, a CHAINED_ACTIONS create no toolbox. Check the schema for your route and autonomy_type under Endpoints in the sidebar. A field the schema does not declare is ignored rather than rejected. A tool that reaches an agent only at run time is dropped from toolbox on a create or update, and the rest of the write goes through. GET /public-api/schemas/tools never lists such a tool, under any filter: a permission group grants it and holds its settings, or Neo adds it by its own rule. To give an agent a tool a permission group grants, grant that group in integrations. A tool Neo adds by its own rule cannot be requested; Neo adds it wherever it applies. Putting one config object directly inside another returns 400 validation_error and writes nothing. The check reads the immediate keys of each top-level config object, and of each actions entry. A container buried deeper than that — inside agent_settings_edits.custom_instructions, say — is ignored rather than rejected, which is why you read the agent back after a write. The message names both the field and the depth:
Move the named field out to the top level and resend. This is easiest to get wrong when custom_instructions is long, so the closing brace is far from where the object opened.
The update response is the lean agent summary — id, name, state, timestamps — and carries no config. A 200 does not by itself prove a config field was applied; GET /public-api/agents/{id} to confirm.
Treat any 4xx as a bug in the request to fix, not to retry blindly — except 429, which you should retry after the Retry-After delay. Retry 5xx with exponential backoff.

What’s next

Rate limits

How much you can call, and how to stay under the limit.