---
title: "Appliquer un plan de site"
description: "Rédige les informations commerciales, le thème, la navigation, les entrées et les images d’un site en un seul appel, dans une seule entrée d’historique."
canonical: "https://atelier201.com/docs/fr/api/sites/apply-plan"
updated: "2026-11-06"
---

# Appliquer un plan de site

Nécessite `sites:write`. Ne coûte aucun crédit : les images de la bibliothèque sont gratuites. Le chemin se termine par `/plan:apply`. Les changements ne concernent que le brouillon. Les visiteurs ne voient rien tant que vous n’avez pas [publié](/docs/api/publishing/publish).

Le moyen le plus rapide de rédiger une première version d’un site ou d’en remanier un : tout ce qu’il faut pour une première version, dans une seule requête. Consultez d’abord le [modèle de contenu](/docs/api/content/model) pour connaître les champs.

- **`name`** : le nom du site dans Atelier201.
- **`singletons`** : `business`, `theme`, `navigation`... Chaque élément est fusionné avec le contenu du brouillon, clé par clé au niveau supérieur ; un groupe imbriqué fourni, comme `hero` ou `colors`, remplace ce groupe.
- **`entries`** : jusqu’à 200 entrées à créer, modifier ou supprimer, selon le format accepté par [Enregistrer plusieurs entrées](/docs/api/content/save-entries).
- **`images`** : jusqu’à 12 images, selon le format accepté par [Insérer une image dans un champ image](/docs/api/media/place) : `target`, `alt` et l’un des champs `query`, `stock_id` ou `media_path`. Si une image est introuvable, le résultat contient un `warning` et le reste du plan est tout de même appliqué.
- **`keep_samples`** : les exemples d’entrées du modèle de départ (`service-one`, `service-two`) sont supprimés, sauf si le plan les renseigne ou si la valeur est `true`.

Tout est validé avant la moindre écriture. Si une partie est refusée, rien n’est enregistré et le `400` répertorie tous les éléments à corriger, pour que vous puissiez tout régler en une fois. En cas de réussite, une seule entrée est ajoutée à l’historique et la compilation démarre : la réponse contient `build`. Ensuite, [vérifiez la publication](/docs/api/publishing/review) : elle est refusée tant qu’il reste du texte d’exemple du modèle de départ.

```http
POST https://api.atelier201.com/v1/sites/{site_id}/plan:apply
```

## Authorizations

- `Authorization` (bearer, in header, required)

## Path parameters

- `site_id` (`string`, required): L’identifiant du site ou son slug (l’adresse avant .atelier201.page).

## Body

`application/json`, required

- `name` (`string`, length: `1–80 chars`): Le nom du site dans Atelier201 (le nom de l’entreprise).
- `singletons` (`Record<string, Record<string, object>>`): business, theme, navigation... : chaque groupe est fusionné avec le contenu du brouillon (clés de premier niveau ; un groupe imbriqué fourni ici remplace ce groupe). Les champs sont ceux définis par get_content_model.
- `entries` (`object[]`, items: `1–200 items`): Entrées à créer, modifier ou supprimer (delete: true), au format accepté par save_entries, jusqu’à 200.
- `entries.collection` (`string`, required)
- `entries.slug` (`string`, required): Lettres minuscules, chiffres et traits d’union.
- `entries.data` (`Record<string, object>`): Les champs définis par le schéma de la collection (à omettre en cas de suppression).
- `entries.body` (`string`, length: `≤ 500000 chars`): Corps en Markdown, pour les collections de contenu.
- `entries.delete` (`boolean`): true pour supprimer cette entrée.
- `images` (`object[]`, items: `≤ 12 items`): Images à renseigner dans les champs image, au format attendu par place_image (target, alt et l’un des champs query, stock_id ou media_path). Si une image est introuvable, un avertissement est renvoyé ; les autres modifications sont tout de même appliquées.
- `images.target` (`string`, required, length: `3–200 chars`): Le champ image : business:/hero/image pour les informations de l’entreprise, ou <collection>/<slug>:/image pour une entrée (services/sourdough:/image). get_content_model indique les champs image.
- `images.alt` (`string`, required, length: `1–300 chars`): Description de l’image pour les personnes qui ne peuvent pas la voir, dans la langue du site. Elle est enregistrée dans le champ alt, à côté de l’image, lorsqu’il existe.
- `images.query` (`string`, length: `≤ 100 chars`): Description à rechercher dans la bibliothèque d’images libres de droits, en anglais et avec des termes concrets ("minimalist concrete house at dusk") : le premier résultat est importé.
- `images.stock_id` (`string`, length: `≤ 20 chars`): ID d’un résultat de search_stock_media, si vous avez choisi l’image vous-même.
- `images.media_path` (`string`, length: `≤ 200 chars`): Fichier déjà présent dans les médias du site (/media/storefront.jpg), par exemple une photo du propriétaire.
- `images.orientation` (`enum<string>`, one of: `landscape, portrait, square`): Avec query : format de l’image à rechercher. Landscape convient à une image hero.
- `keep_samples` (`boolean`): Conservez les entrées d’exemple du modèle de départ (service-one, service-two). Par défaut, elles sont supprimées, sauf si le plan les crée.
- `summary` (`string`, length: `≤ 200 chars`): Une phrase pour l’historique.

## Response

**200**: Appliquer un forfait à un site

- `data` (`Record<string, object>`, required)
- `data.renamed` (`string,null`, required)
- `data.singletons` (`string[]`, required): Les éléments singleton enregistrés.
- `data.saved` (`integer`, required, range: `-9007199254740991–9007199254740991`)
- `data.deleted` (`integer`, required, range: `-9007199254740991–9007199254740991`)
- `data.images` (`object[]`, required)
- `data.images.target` (`string`, required)
- `data.images.image` (`string,null`, required)
- `data.images.credit` (`string,null`, required)
- `data.images.warning` (`string,null`, required)
- `data.revision` (`string | null`, required)
- `data.changed` (`boolean`, required)
- `data.build` (`object | null`, required): La génération démarrée (ou rejointe) par cette modification : l’aperçu la suit. Aucun appel à build_site n’est nécessaire.
- `data.build.id` (`string`, required)
- `data.build.state` (`string`, required)
- `data.build.next_action` (`string`, required)
- `data.next_action` (`string`, required)
- `request_id` (`string`, required)

```json
{
  "data": {
    "renamed": null,
    "singletons": [
      "<string>"
    ],
    "saved": 123,
    "deleted": 123,
    "images": [
      {
        "target": "<string>",
        "image": null,
        "credit": null,
        "warning": null
      }
    ],
    "revision": "<string>",
    "changed": true,
    "build": {
      "id": "<string>",
      "state": "<string>",
      "next_action": "<string>"
    },
    "next_action": "<string>"
  },
  "request_id": "<string>"
}
```

**400**: Codes possibles : invalid_request, unknown_field, invalid_parameter, invalid_cursor

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**401**: Codes possibles : authentication_required, invalid_api_key, api_key_expired, api_key_revoked

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**402**: Codes possibles : insufficient_credits

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**403**: Codes possibles : insufficient_scope, feature_not_available, admin_required

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**404**: Codes possibles : resource_not_found

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**409**: Codes possibles : conflict, result_not_ready, idempotency_key_reused

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**410**: Codes possibles : result_expired

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**413**: Codes possibles : request_too_large

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**422**: Codes possibles : request_too_large_for_plan

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**429**: Codes possibles : rate_limited

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**500**: Codes possibles : internal_error

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**503**: Codes possibles : service_unavailable

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**Example request**

```bash
curl --request POST \
  --url 'https://api.atelier201.com/v1/sites/<site_id>/plan:apply' \
  --header 'Authorization: <api-key>' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "<string>",
  "singletons": {},
  "entries": [
    {
      "collection": "<string>",
      "slug": "<string>"
    }
  ],
  "images": [
    {
      "target": "<string>",
      "alt": "<string>"
    }
  ],
  "keep_samples": true,
  "summary": "<string>"
}'
```
