---
title: "Aplicar un plan de sitio"
description: "Escribe en una sola llamada los datos del negocio, el tema, la navegación, las entradas y las imágenes de un sitio, como una única entrada del historial."
canonical: "https://atelier201.com/docs/es/api/sites/apply-plan"
updated: "2026-11-06"
---

# Aplicar un plan de sitio

Requiere `sites:write`. No cuesta créditos: las imágenes de stock son gratuitas. La ruta termina en `/plan:apply`. Solo modifica el borrador. Los visitantes no verán nada hasta que [publiques](/docs/api/publishing/publish).

La forma más rápida de crear la primera versión de un sitio o rehacer uno: todo lo que necesita una primera versión, en una sola solicitud. Lee primero el [modelo de contenido](/docs/api/content/model) para consultar los campos.

- **`name`**: el nombre del sitio en Atelier201.
- **`singletons`**: `business`, `theme`, `navigation`... Cada elemento se combina con lo que ya hay en el borrador, clave por clave en el nivel superior; los grupos anidados que envíes, como `hero` o `colors`, sustituyen al grupo correspondiente.
- **`entries`**: hasta 200 entradas para crear, actualizar o eliminar, con el formato que acepta [Guardar varias entradas](/docs/api/content/save-entries).
- **`images`**: hasta 12 imágenes, con el formato que acepta [Añadir una imagen a un campo de imagen](/docs/api/media/place): `target`, `alt` y uno de estos campos: `query`, `stock_id` o `media_path`. Si no se encuentra una imagen, se devuelve una `warning` y el resto del plan se aplica igualmente.
- **`keep_samples`**: las entradas de ejemplo de la plantilla inicial (`service-one`, `service-two`) se eliminan, salvo que el plan las incluya o que este valor sea `true`.

Todo se valida antes de escribir nada. Si se rechaza alguna parte, no se guarda nada y la respuesta `400` enumera todas las partes que hay que corregir para que puedas solucionarlas de una vez. Si la operación se completa correctamente, se crea una sola entrada del historial y se inicia la compilación: la respuesta incluye `build`. Después, [revisa la publicación](/docs/api/publishing/review): se rechazará mientras quede algún texto de ejemplo de la plantilla inicial.

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

## Authorizations

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

## Path parameters

- `site_id` (`string`, required): El ID del sitio o su slug (la dirección antes de .atelier201.page).

## Body

`application/json`, required

- `name` (`string`, length: `1–80 chars`): El nombre del sitio en Atelier201 (el nombre del negocio).
- `singletons` (`Record<string, Record<string, object>>`): business, theme, navigation...: cada grupo se combina con lo que contiene el borrador (claves de nivel superior; si se proporciona un grupo anidado, sustituye a ese grupo). Los campos se definen en get_content_model.
- `entries` (`object[]`, items: `1–200 items`): Entradas que se deben crear, actualizar o eliminar (delete: true), con el formato que acepta save_entries, hasta 200.
- `entries.collection` (`string`, required)
- `entries.slug` (`string`, required): Letras minúsculas, dígitos y guiones.
- `entries.data` (`Record<string, object>`): Los campos definidos en el esquema de la colección (no se aplica a delete).
- `entries.body` (`string`, length: `≤ 500000 chars`): Cuerpo en Markdown, para colecciones de contenido.
- `entries.delete` (`boolean`): true para eliminar esta entrada.
- `images` (`object[]`, items: `≤ 12 items`): Imágenes que se asignan a campos de imagen, con el formato que acepta place_image (target, alt y uno de estos valores: query, stock_id, media_path). Si no se encuentra una imagen, se muestra una advertencia; el resto se aplica igualmente.
- `images.target` (`string`, required, length: `3–200 chars`): El campo de imagen: business:/hero/image para los datos de la empresa o <collection>/<slug>:/image para una entrada (services/sourdough:/image). get_content_model muestra los campos de imagen.
- `images.alt` (`string`, required, length: `1–300 chars`): Qué muestra la imagen, para las personas que no pueden verla, en el idioma del sitio. Se guarda en el campo alt junto a la imagen, si lo hay.
- `images.query` (`string`, length: `≤ 100 chars`): Descripción para buscar en la biblioteca de imágenes gratuitas. Escríbela en inglés con términos concretos ("minimalist concrete house at dusk"). Se importa el primer resultado.
- `images.stock_id` (`string`, length: `≤ 20 chars`): ID de un resultado de search_stock_media, si has elegido la imagen manualmente.
- `images.media_path` (`string`, length: `≤ 200 chars`): Archivo que ya está en la carpeta de medios del sitio (/media/storefront.jpg), por ejemplo, una foto del propietario.
- `images.orientation` (`enum<string>`, one of: `landscape, portrait, square`): Con query: la orientación que se debe buscar. El formato apaisado es adecuado para una imagen principal.
- `keep_samples` (`boolean`): Conserva las entradas de ejemplo del Starter (service-one, service-two). De forma predeterminada, se eliminan salvo que el plan las incluya.
- `summary` (`string`, length: `≤ 200 chars`): Una frase para el historial.

## Response

**200**: Aplicar un plan a un sitio

- `data` (`Record<string, object>`, required)
- `data.renamed` (`string,null`, required)
- `data.singletons` (`string[]`, required): Los elementos únicos escritos.
- `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 compilación que inició este cambio (o a la que se incorporó): la vista previa la sigue. No hace falta llamar a build_site.
- `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**: Códigos posibles: 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**: Códigos posibles: 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**: Códigos posibles: 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**: Códigos posibles: 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**: Códigos posibles: 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**: Códigos posibles: 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**: Códigos posibles: 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**: Códigos posibles: 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**: Códigos posibles: 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**: Códigos posibles: 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**: Códigos posibles: 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**: Códigos posibles: 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>"
}'
```
