---
id: conventions-errors
slug: /apis/conventions/errors
title: 'Errors'
description: 'The HTTP status codes the Agility APIs return, what each one means, and how to read the error payload.'
sidebar_label: 'Errors'
sidebar_position: 4
tags: ['api', 'conventions', 'errors', 'status-codes']
---

The Agility APIs signal failure with conventional HTTP status codes and, in most cases, a body
that explains what went wrong.

## Status Codes

| Code  | Message               | Meaning                                                                                                                                                                                                        |
| ----- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400` | Bad Request           | The most common error. The request could not be processed. The error message identifies the specific problem, and the payload may carry `Exception` elements with detailed information.                          |
| `401` | Unauthorized          | Credentials are missing, malformed, or invalid — including an expired or revoked access token.                                                                                                                   |
| `404` | Not Found             | The specified resource does not exist. For asset endpoints this also covers assets the caller cannot see, since visibility is enforced before existence is disclosed.                                            |
| `405` | Method Not Allowed    | The HTTP method is not valid at this URL. Returned for any method other than `GET` or `POST`, and for a `POST` to a URL that does not support updating.                                                          |
| `500` | Internal Server Error | An unexpected error occurred while processing the request. The response payload contains `Exception` elements with information that helps diagnose the cause.                                                    |

:::note `GET` and `POST` only
Notice what `405` implies: these APIs are not verb-rich REST. `PUT`, `PATCH` and `DELETE` are
generally *not* accepted, and destructive actions are modeled as `POST` to a command-shaped URL
instead. [Deleting a webhook subscription](/apis/webhooks/delete) is the clearest example —
it is a `POST` to `.../api/webhook/delete/:id`, not a `DELETE`.
:::

## Reading an Error Body

A `400` from the JSON endpoints returns a message describing the failure. The bulk
`~/api/asset` endpoint is the exception: it can return `200 OK` at the HTTP layer while
reporting per-command failures inside the response body, because a single request carries many
independent commands. Always inspect the body of a bulk response rather than trusting the
status code alone. See [Bulk API (api/asset)](/apis/asset-bulk).

### Query Parameter Errors

Malformed `sel`, `where`, `with`, `find`/`findin`, `sort` and `page` parameters produce their own
distinct `400` messages, returned in the `Error` / `Message` / `Exception` envelope. Those literal
wire strings and the envelope shape are documented once, in the "Query parameter errors" section
of the [HTTP status codes reference](/reference/status-codes) — they are not repeated here.

## Violation Tags Are Localizable

Many API errors arrive as **tags** — `Violation'AssetCannotDeleteClosed`,
`Violation'Authentication'InvalidAccessToken` — rather than prose. Some of
these resolve to human-readable messages through the
[localization API](/apis/loc-2-v1), verbatim from a live instance:

```json title="GET ~/loc-2.v1?[Violation'AssetCannotDeleteClosed,Violation'PrimaryWorkitemCannotHaveInvalidStatus]"
{
  "Violation'AssetCannotDeleteClosed": "Agility Warning: Attempting to delete a closed item.  This change was not saved.",
  "Violation'PrimaryWorkitemCannotHaveInvalidStatus": "The chosen Status is not valid for the Backlog with the assigned Team"
}
```

Not every error string is a resolvable tag, but a blanket "resolve every
error through the localizer" strategy is safe: `loc-2.v1`
[echoes unmatched tags back unchanged](/apis/loc-2-v1/tag-resolution), so
the worst case is the overhead of a request that returns the tag as-is —
never a wrong message. Resolved messages also arrive in the caller's
language, which is usually what you want to surface to a user.

## Related Topics

- [HTTP status codes reference](/reference/status-codes) — expanded treatment with handling guidance
- [Query grammar reference](/reference/query-grammar) — the syntax those parameters must satisfy
- [Error handling guide](/guides/error-handling) — retry and recovery patterns
- [HTTP headers](/apis/conventions/http-headers) — a wrong `Content-Type` is a common source of `400`
