---
title: "Responses and errors"
description: "The status codes and the error format of the HTTP API, and the order of the checks of a request."
canonical: responses.html
navigation-title: "Responses"
---

<a id="usage-responses"></a>

<a id="responses-and-errors"></a>

# Responses and errors

A successful request returns the status `200` and the result of the action as
JSON. If the action has no result, the status is `204`. If you create a record
or upload a file, the status is `201`, and the `Location` header contains the
URL of the new record or file.

An error returns problem details (`application/problem+json`, see
[RFC 9457](https://datatracker.ietf.org/doc/html/rfc9457)):

```json
{
    "type": "about:blank",
    "title": "Forbidden",
    "status": 403,
    "detail": "Missing scope: content:write"
}
```

- **`type`**

  The URL of the exception code in the TYPO3 exception reference, for an
  error from an action. For example
  `https://typo3.org/go/exception/CMS/1766253177`. For an error without an
  exception code, for example a missing scope or an unknown endpoint, and
  for the status `500`, the value is `about:blank`.
- **`title`**

  The reason phrase of the status code, for example `Not Found`.
- **`status`**

  The HTTP status code.
- **`detail`**

  The message of the error.
- **`errors`**

  For invalid parameters (status `400`), the list of all invalid parameters.
  Each entry has a `detail`. It also has the JSON `pointer` into the request body, or the
  name of the query or path `parameter`.
- **`requestId`**

  For the status `500`, the ID of the request in the log. The response
  contains no internal details.

The response lists all invalid parameters of a request

```json
{
    "type": "https://typo3.org/go/exception/CMS/1793870606",
    "title": "Bad Request",
    "status": 400,
    "detail": "The request contains invalid parameters",
    "errors": [
        {
            "pointer": "#/record/title",
            "detail": "Integer value found, but a string is required"
        }
    ]
}
```

The OAuth endpoints use the error format of OAuth 2.0
([RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749#section-5.2)), for
example `{"error": "invalid_client", …}`, because OAuth client libraries expect
it.

| Status | Meaning |
| --- | --- |
| `400` | A parameter is missing, the JSON is not valid, or a value does not agree with the JSON Schema of the action. The action can also reject a value, for example an invalid `cursor`. |
| `401` | The token is missing, not valid, expired or revoked. The header `WWW-Authenticate` contains `Bearer`, with `error="invalid_token"` if the request contained a token. |
| `403` | The app does not have a scope of the action, or the data needs a scope that the app does not have, for example `admin` for backend users. Or the backend user does not have a permission. For a missing scope, the header `WWW-Authenticate` names the scope with `error="insufficient_scope"`. |
| `404` | The endpoint or the requested entity does not exist, or the action is only for the backend user interface. If you change a record or create it on a page that does not exist, the status is `400`. |
| `409` | The request conflicts with the current state, for example a file with the same name exists. |
| `415` | The content type of the request body is not `application/json`. |
| `500` | An unexpected error occurred, for example the result of the action does not agree with its JSON Schema. TYPO3 logs the error, and the response contains its `requestId`. |

<a id="usage-responses-order"></a>

<a id="order-of-the-checks"></a>

## Order of the checks

A request passes these checks in this order. The first check that fails sets
the response. A request with a token that is not valid thus never gets the
status `400`.

```diagram
flow canvas=940
  columns 2,1
  gap 110,16
title "The first failing check answers the request"
description "A request passes the token, the target of the action, the scopes, the content type, the parameters, the action itself and the validation of its result. Each of these answers with its own error status. If all of them pass, the request is answered with 200, 201 or 204."

token "Token"
  at 0,0
  body "Missing, invalid, expired or revoked"
target "Endpoint"
  at 0,1
  body "Does not exist, or does not offer the app target"
scopes "Scopes"
  at 0,2
  body "A scope is missing"
type "Content type"
  at 0,3
  body "The request body is not application/json"
params "Parameters"
  at 0,4
  body "Do not match the JSON Schema"
action "Action"
  at 0,5
  body "Reports an error, for example a conflict"
result "Result"
  at 0,6
  body "Does not match the JSON Schema"
done "Response"
  at 0,7
  ink

e401 "401"
  at 1,0
  dashed
e404 "404"
  at 1,1
  dashed
e403 "403"
  at 1,2
  dashed
e415 "415"
  at 1,3
  dashed
e400 "400"
  at 1,4
  dashed
eaction "400, 403, 404 or 409"
  at 1,5
  dashed
e500 "500"
  at 1,6
  dashed
ok "200, 201 or 204"
  at 1,7

token -> target
target -> scopes
scopes -> type
type -> params
params -> action
action -> result
result -> done
token -x e401
target -x e404
scopes -x e403
type -x e415
params -x e400
action -x eaction
result -x e500
done => ok
```

*Only actions that declare the created resource return the status 201 and the Location header.*
