# REST API reference

> Source: https://docs.strapi.io/cms/api/rest

Strapi's REST API automatically generates endpoints for content-types to fetch, create, update, and delete documents using GET, POST, PUT, and DELETE methods, with support for filtering, sorting, field selection, and relation population.

The REST API allows accessing the [content-types](/cms/backend-customization/models) through API endpoints. Strapi automatically creates [API endpoints](#endpoints) when a content-type is created. [API parameters](/cms/api/rest/parameters) can be used when querying API endpoints to refine the results.

This section of the documentation is for the REST API reference for content-types. We also have [guides](/cms/api/rest/guides/intro) available for specific use cases.

:::prerequisites
All content types are private by default and need to be either made public or queries need to be authenticated with the proper permissions. See the [Quick Start Guide](/cms/quick-start#step-8-set-roles--permissions), the user guide for the [Users & Permissions feature](/cms/features/users-permissions#roles), and [API tokens configuration documentation](/cms/features/api-tokens) for more details.
:::

:::note
By default, the REST API responses only include top-level fields and does not populate any relations, media fields, components, or dynamic zones. Use the [`populate` parameter](/cms/api/rest/populate-select) to populate specific fields. Ensure that the find permission is given to the field(s) for the relation(s) you populate.
:::

:::tip Performance best practices
For production applications, be intentional about data fetching: use explicit population, limit population depth, and centralize population logic in route middlewares. See [Building High-Performance Strapi Applications](https://strapi.io/blog/building-high-performance-strapi-applications-common-pitfalls-and-best-practices) on the Strapi blog for a comprehensive guide.
:::

:::strapi Strapi Client
The [Strapi Client](/cms/api/client) library simplifies interactions with your Strapi back end, providing a way to fetch, create, update, and delete content.
:::

## Endpoints

For each Content-Type, the following endpoints are automatically generated:

<details>
<summary>Plural API ID vs. Singular API ID:</summary>

In the following tables:

- `:singularApiId` refers to the value of the "API ID (Singular)" field of the content-type,
- and `:pluralApiId` refers to the value of the "API ID (Plural)" field of the content-type.

These values are defined when creating a content-type in the Content-Type Builder, and can be found while editing a content-type in the admin panel (see [User Guide](/cms/features/content-type-builder#creating-content-types)). For instance, by default, for an "Article" content-type:

- `:singularApiId` will be `article`
- `:pluralApiId` will be `articles`

</details>

| Method   | URL                             | Description                           |
| -------- | ------------------------------- | ------------------------------------- |
| `GET`    | `/api/:pluralApiId`             | [Get a list of documents](#get-all)   |
| `POST`   | `/api/:pluralApiId`             | [Create a document](#create)          |
| `GET`    | `/api/:pluralApiId/:documentId` | [Get a document](#get)                |
| `PUT`    | `/api/:pluralApiId/:documentId` | [Update a document](#update)          |
| `DELETE` | `/api/:pluralApiId/:documentId` | [Delete a document](#delete)          |
| Method   | URL                   | Description                                |
| -------- | --------------------- | ------------------------------------------ |
| `GET`    | `/api/:singularApiId` | [Get a document](#get)                     |
| `PUT`    | `/api/:singularApiId` | [Update/Create a document](#update)        |
| `DELETE` | `/api/:singularApiId` | [Delete a document](#delete)               |

:::strapi Upload API
The Upload package (which powers the [Media Library feature](/cms/features/media-library)) has a specific API accessible through its [`/api/upload` endpoints](/cms/api/rest/upload).
:::

:::note
[Components](/cms/backend-customization/models#components-json) don't have API endpoints.
:::

## Requests

:::strapi Strapi 5 vs. Strapi v4
Strapi 5's Content API includes 2 major differences with Strapi v4:

- The response format has been flattened, which means attributes are no longer nested in a `data.attributes` object and are directly accessible at the first level of the `data` object (e.g., a content-type's "title" attribute is accessed with `data.title`).
- Strapi 5 now uses **documents**  and documents are accessed by their `documentId` (see [breaking change entry](/cms/migration/v4-to-v5/breaking-changes/use-document-id) for details)
:::

Requests return a response as an object which usually includes the following keys:

- `data`: the response data itself, which could be:
  - a single document, as an object with the following keys:
    - `id` (integer)
    - `documentId` (string), which is the unique identifier to use when querying a given document,
    - the attributes (each attribute's type depends on the attribute, see [models attributes](/cms/backend-customization/models#model-attributes) documentation for details)
    - `meta` (object)
  - a list of documents, as an array of objects
  - a custom response

- `meta` (object): information about pagination, publication state, available locales, etc.

- `error` (object, _optional_): information about any [error](/cms/error-handling) thrown by the request

:::note
Some plugins (including Users & Permissions and Upload) may not follow this response format.
:::

### Get documents {#get-all}

:::tip Tip: Strapi 5 vs. Strapi 4
In Strapi 5 the response format has been flattened, and attributes are directly accessible from the `data` object instead of being nested in `data.attributes`.

You can pass an optional header while you're migrating to Strapi 5 (see the [related breaking change](/cms/migration/v4-to-v5/breaking-changes/new-response-format)).
:::

#### GET /api/:pluralApiId — List documents

Returns a paginated list of documents. Supports filtering, sorting, field selection, and relation population.

**Parameters:**
- `sort` (string | string[]): Sort by field. Use `field:asc` or `field:desc`
- `filters` (object): Filter with operators: `$eq`, `$contains`, `$gt`, `$lt`. See filtering (/cms/api/rest/filters).
- `populate` (string | object): Relations and components to include. Use `*` for all. See populate (/cms/api/rest/populate-select).
- `fields` (string[]): Select specific fields to return. See field selection (/cms/api/rest/populate-select#field-selection).
- `pagination[page]` (integer): Page number. Default: `1`
- `pagination[pageSize]` (integer): Items per page. Default `25`, max `100`
- `locale` (string): Locale of the documents to fetch. See locale (/cms/api/rest/locale).
- `status` (string): `published` or `draft`. See status (/cms/api/rest/status).

**cURL:**
```
curl 'http://localhost:1337/api/restaurants' \\
  -H 'Authorization: Bearer <token>'
```

**JavaScript:**
```
const response = await fetch(
  'http://localhost:1337/api/restaurants',
  {
    headers: {
      Authorization: 'Bearer <token>',
    },
  }
);
const data = await response.json();
```

**Response 200 OK:**
```json
{
  "data": [
    {
      "id": 2,
      "documentId": "hgv1vny5cebq2l3czil1rpb3",
      "Name": "BMK Paris Bamako",
      "Description": null,
      "createdAt": "2024-03-06T13:42:05.098Z",
      "updatedAt": "2024-03-06T13:42:05.098Z",
      "publishedAt": "2024-03-06T13:42:05.103Z",
      "locale": "en"
    },
    {
      "id": 4,
      "documentId": "znrlzntu9ei5onjvwfaalu2v",
      "Name": "Biscotte Restaurant",
      "Description": [
        {
          "type": "paragraph",
          "children": [
            {
              "type": "text",
              "text": "Welcome to Biscotte restaurant! Restaurant Biscotte offers a cuisine based on fresh, quality products, often local, organic when possible, and always produced by passionate producers."
            }
          ]
        }
      ],
      "createdAt": "2024-03-06T13:43:30.172Z",
      "updatedAt": "2024-03-06T13:43:30.172Z",
      "publishedAt": "2024-03-06T13:43:30.175Z",
      "locale": "en"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "pageSize": 25,
      "pageCount": 1,
      "total": 2
    }
  }
}
```

### Get a document {#get}

:::strapi Strapi 5 vs. Strapi v4
In Strapi 5, a specific document is reached by its `documentId`.
:::

#### GET /api/:pluralApiId/:documentId — Get a document

Returns a single document by its documentId. Supports field selection and relation population.

**Parameters:**
- `pluralApiId` (string, required): Plural API ID of the content-type (e.g. `restaurants`)
- `documentId` (string, required): Unique document identifier

**cURL:**
```
curl 'http://localhost:1337/api/restaurants/znrlzntu9ei5onjvwfaalu2v' \\
  -H 'Authorization: Bearer <token>'
```

**JavaScript:**
```
const response = await fetch(
  'http://localhost:1337/api/restaurants/znrlzntu9ei5onjvwfaalu2v',
  {
    headers: {
      Authorization: 'Bearer <token>',
    },
  }
);
const data = await response.json();
```

**Response 200 OK:**
```json
{
  "data": {
    "id": 6,
    "documentId": "znrlzntu9ei5onjvwfaalu2v",
    "Name": "Biscotte Restaurant",
    "Description": [
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "text": "Welcome to Biscotte restaurant! Restaurant Biscotte offers a cuisine based on fresh, quality products."
          }
        ]
      }
    ],
    "createdAt": "2024-02-27T10:19:04.953Z",
    "updatedAt": "2024-03-05T15:52:05.591Z",
    "publishedAt": "2024-03-05T15:52:05.600Z",
    "locale": "en"
  },
  "meta": {}
}
```

**Response 200 Not Found:**
```json
{
  "error": {
    "status": 404,
    "name": "NotFoundError",
    "message": "Document not found"
  }
}
```

### Create a document {#create}

If the [Internationalization (i18n) plugin](/cms/features/internationalization) is installed, it's possible to use POST requests to the REST API to [create localized documents](/cms/api/rest/locale#rest-delete).

:::note
While creating a document, you can define its relations and their order (see [Managing relations through the REST API](/cms/api/rest/relations.md) for more details).
:::

:::info Dynamic zones
When you POST a document, each object inside a dynamic zone array must include `__component` with that variant's UID (for example `shared.slider`). Put `__component` on the object that represents one row in the dynamic zone. Nested fields inside that object should mirror the JSON you get back when the same document is fetched with `populate` so you do not place `__component` on inner objects unless the schema treats that level as another discriminated structure.
:::

#### POST /api/:pluralApiId — Create a document

Creates a new document and returns it. Send field values inside a data object in the request body.

**Parameters:**
- `data` (object, required): Object containing the field values for the new document

**cURL:**
```
curl -X POST \\
  'http://localhost:1337/api/restaurants' \\
  -H 'Authorization: Bearer <token>' \\
  -H 'Content-Type: application/json' \\
  -d '{
    "data": {
      "Name": "Restaurant D",
      "Description": [
        {
          "type": "paragraph",
          "children": [{ "type": "text", "text": "A very short description goes here." }]
        }
      ]
    }
  }'
```

**JavaScript:**
```
const response = await fetch(
  'http://localhost:1337/api/restaurants',
  {
    method: 'POST',
    headers: {
      Authorization: 'Bearer <token>',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      data: {
        Name: 'Restaurant D',
        Description: [
          {
            type: 'paragraph',
            children: [{ type: 'text', text: 'A very short description goes here.' }],
          },
        ],
      },
    }),
  }
);
const data = await response.json();
```

**Response 200 OK:**
```json
{
  "data": {
    "documentId": "bw64dnu97i56nq85106yt4du",
    "Name": "Restaurant D",
    "Description": [
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "text": "A very short description goes here."
          }
        ]
      }
    ],
    "createdAt": "2024-03-05T16:44:47.689Z",
    "updatedAt": "2024-03-05T16:44:47.689Z",
    "publishedAt": "2024-03-05T16:44:47.687Z",
    "locale": "en"
  },
  "meta": {}
}
```

### Update a document {#update}

:::note NOTES
* Even with the [Internationalization (i18n) plugin](/cms/features/internationalization) installed, it's currently not possible to [update the locale of a document](/cms/api/rest/locale#rest-update).
* While updating a document, you can define its relations and their order (see [Managing relations through the REST API](/cms/api/rest/relations) for more details).
:::

:::info Dynamic zones
Each entry you send for a [dynamic zone](/cms/backend-customization/models#dynamic-zones) must include `__component` with the target component's UID (for example `shared.media`). Strapi uses that field to pick the component schema when you create or update items in the zone; without it, writes can fail validation or return success without changing data. Use the UID shown in the Content-Type Builder for each component in the zone.
:::

#### PUT /api/:pluralApiId/:documentId — Update a document

Partially updates a document by documentId and returns its value. Send a null value to clear fields.

**Parameters:**
- `data` (object, required): Object containing the field values to update

**cURL:**
```
curl -X PUT \\
  'http://localhost:1337/api/restaurants/hgv1vny5cebq2l3czil1rpb3' \\
  -H 'Authorization: Bearer <token>' \\
  -H 'Content-Type: application/json' \\
  -d '{
    "data": {
      "Name": "BMK Paris Bamako",
      "Description": [
        {
          "type": "paragraph",
          "children": [{ "type": "text", "text": "A very short description goes here." }]
        }
      ]
    }
  }'
```

**JavaScript:**
```
const response = await fetch(
  'http://localhost:1337/api/restaurants/hgv1vny5cebq2l3czil1rpb3',
  {
    method: 'PUT',
    headers: {
      Authorization: 'Bearer <token>',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      data: {
        Name: 'BMK Paris Bamako',
        Description: [
          {
            type: 'paragraph',
            children: [{ type: 'text', text: 'A very short description goes here.' }],
          },
        ],
      },
    }),
  }
);
const data = await response.json();
```

**Response 200 OK:**
```json
{
  "data": {
    "id": 9,
    "documentId": "hgv1vny5cebq2l3czil1rpb3",
    "Name": "BMK Paris Bamako",
    "Description": [
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "text": "A very short description goes here."
          }
        ]
      }
    ],
    "createdAt": "2024-03-06T13:42:05.098Z",
    "updatedAt": "2024-03-06T14:16:56.883Z",
    "publishedAt": "2024-03-06T14:16:56.895Z",
    "locale": "en"
  },
  "meta": {}
}
```

### Delete a document {#delete}

#### DELETE /api/:pluralApiId/:documentId — Delete a document

Permanently deletes a document by documentId. This action is irreversible.

**Parameters:**
- `pluralApiId` (string, required): Plural API ID (e.g. `restaurants`)
- `documentId` (string, required): Document ID of the entry to delete

**cURL:**
```
curl -X DELETE \\
  'http://localhost:1337/api/restaurants/bw64dnu97i56nq85106yt4du' \\
  -H 'Authorization: Bearer <token>'
```

**JavaScript:**
```
const response = await fetch(
  'http://localhost:1337/api/restaurants/bw64dnu97i56nq85106yt4du',
  {
    method: 'DELETE',
    headers: {
      Authorization: 'Bearer <token>',
    },
  }
);
```
