{
  "openapi": "3.1.0",
  "info": {
    "title": "ButterCMS Write API",
    "version": "2.0.0",
    "description": "Write endpoints for the ButterCMS API — create, update, and delete Pages, Collections, and Blog Posts.\n",
    "contact": {
      "email": "support@buttercms.com"
    },
    "license": {
      "name": "ButterCMS Terms of Service",
      "url": "https://buttercms.com/terms/"
    }
  },
  "servers": [
    {
      "url": "https://api.buttercms.com/v2",
      "description": "ButterCMS API v2"
    }
  ],
  "tags": [
    {
      "name": "Pages",
      "description": "Create new pages using ButterCMS Write API. Programmatically create content to enable powerful use cases and scale your content faster.\n\nNote: For Pages, PUT behaves like PATCH (partial update). Use either method to perform partial updates.\n"
    },
    {
      "name": "Collections",
      "description": "Create, update, and delete Collection items using ButterCMS Write API. Collections are user-defined content structures with completely customizable field schemas.\n"
    },
    {
      "name": "Blog posts",
      "description": "Create, update, and delete blog posts using ButterCMS Write API. Blog posts support rich content including HTML body, categories, tags, featured images, and SEO metadata.\n"
    }
  ],
  "paths": {
    "/pages/": {
      "post": {
        "tags": [
          "Pages"
        ],
        "summary": "Create Page via Write API",
        "description": "Create a new page using the ButterCMS Write API with support for multiple locales and automatic media uploads. This endpoint allows you to programmatically generate content that follows your predefined page type structure.\n\n**Page Type Requirement**: The page type schema must already exist in your ButterCMS account before creating pages. Page types define the structure and field requirements for your content. You cannot create new Page Types through the API - they must be configured through the dashboard first.\n\n**Field Requirements**: When creating a page, all field keys defined in your page type schema must be included in the request, even if they're marked as optional in your schema. For optional fields that you don't want to populate, provide empty strings (e.g., `\"hero_image\": \"\"`). This ensures your content structure remains consistent.\n\n**Locale Formats**: Define all page content inside of a single `fields` object for accounts that do not have localization set up. For accounts with localization, all page content for each individual language should be defined inside of an object whose key is the locale slug. Nest these objects inside of the `fields` object. The locale codes must match those configured in your account.\n\n**Media Upload**: If `Media` is the field_type for a chosen field, any URL can be provided as the field's value. The media corresponding to this URL will be automatically downloaded and uploaded to your ButterCMS media library. This ensures your media is hosted reliably and integrates with ButterCMS's CDN for optimal performance.\n\n**Publication & Scheduling**: Pages are created as `draft` by default. You can set `status=published` to publish immediately. Scheduling future publication is not supported via the Write API.\n",
        "x-mint": {
          "metadata": {
            "description": "Create a new page via the Write API with support for multiple locales, media uploads, and draft status."
          },
          "content": "Create a new page using the ButterCMS Write API with support for multiple locales and automatic media uploads. This endpoint allows you to programmatically generate content that follows your predefined page type structure.\n\n**Page Type Requirement**: The page type schema must already exist in your ButterCMS account before creating pages. Page types define the structure and field requirements for your content. You cannot create new Page Types through the API - they must be configured through the dashboard first.\n\n**Field Requirements**: When creating a page, all field keys defined in your page type schema must be included in the request, even if they're marked as optional in your schema. For optional fields that you don't want to populate, provide empty strings (e.g., `\"hero_image\": \"\"`). This ensures your content structure remains consistent.\n\n**Locale Formats**: Define all page content inside of a single `fields` object for accounts that do not have localization set up. For accounts with localization, all page content for each individual language should be defined inside of an object whose key is the locale slug. Nest these objects inside of the `fields` object. The locale codes must match those configured in your account.\n\n**Media Upload**: If `Media` is the field_type for a chosen field, any URL can be provided as the field's value. The media corresponding to this URL will be automatically downloaded and uploaded to your ButterCMS media library. This ensures your media is hosted reliably and integrates with ButterCMS's CDN for optimal performance.\n\n**Publication & Scheduling**: Pages are created as `draft` by default. You can set `status=published` to publish immediately. Scheduling future publication is not supported via the Write API.\n"
        },
        "operationId": "createPage",
        "security": [
          {
            "writeTokenAuth": []
          }
        ],
        "parameters": [
          {
            "name": "locale",
            "in": "query",
            "description": "Set to the API slug of a pre-configured locale (e.g., 'en' or 'fr').\n\n**Usage:** Only applicable when using the single-locale request format (WITHOUT Locales format).\nIf you are using the single-locale format to create only a single locale's version of a page, you must specify the locale via this query param, e.g., `?locale=en`.\n\n**Not applicable** when using the multi-locale format (WITH Locales format), as locale codes are specified within the request body under the `fields` object.\n\nWhen omitted and using single-locale format, defaults to your organization's default locale.\n",
            "required": false,
            "schema": {
              "type": "string",
              "example": "en"
            },
            "examples": {
              "english": {
                "value": "en",
                "description": "English locale"
              },
              "spanish": {
                "value": "es",
                "description": "Spanish locale"
              },
              "french": {
                "value": "fr",
                "description": "French locale"
              }
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Page data in either single-locale or multi-locale format.\n\n**Request Body Formats**:\n- **WITHOUT Locales or Single Locale**: If you don't have locales, or if you are only creating a single locale's version of a page, format your request body as a JSON object where `fields` is an object with each property representing a content field. Note: if creating only a single locale's version, you must specify the locale via query param, e.g., `?locale=en`.\n- **WITH Locales (Multi-Locale)**: The multi-locale format can be used to create one or more locales of a page at the same time. In this format, the `fields` object has an extra level and must be first mapped to the locale code. The locale codes must already be configured in your account; however, you can pick and choose which locales to create.\n",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePageRequest"
              },
              "examples": {
                "without_locales": {
                  "summary": "Create Page WITHOUT Locales or with a Single Locale",
                  "description": "Example of creating a page without locale support or for a single locale.\n\nIf you don't have locales, or if you are only creating a single locale's version of a page, you can format your request body into a JSON object where `fields` is an object in which each property represents a content field with its key and value.\n\nNote: If you are using this format to create only a single locale's version of a page, you must specify the locale via query param, e.g., `?locale=en`.\n",
                  "value": {
                    "title": "Frequently Asked Questions",
                    "slug": "faq",
                    "page_type": "questions",
                    "status": "draft",
                    "fields": {
                      "headline": "Frequently Asked Questions",
                      "hero_image": "",
                      "body": "<p class=\"content\">We love questions</p>",
                      "questions": [
                        {
                          "question": "Are dogs allowed?",
                          "answer": "Leashed dogs are allowed.",
                          "picture": "https://farm1.staticflickr.com/836/42903355654_8faa21171a_m_d.jpg"
                        },
                        {
                          "question": "Are wallabies allowed?",
                          "answer": "Yes, leashed wallabies are allowed",
                          "picture": "https://farm2.staticflickr.com/1840/29120307158_a9586a58b1_m_d.jpg"
                        }
                      ]
                    }
                  }
                },
                "with_locales": {
                  "summary": "Create Page WITH Locales",
                  "description": "Example of creating a page with multiple locales at the same time.\n\nThis is our multi-locale format, which can be used to create one or more locales of a page at the same time. In this format, the `fields` object has an extra level and must be first mapped to the locale code to use. The locale codes must already be configured in your account; however, you can pick and choose which locales to create.\n",
                  "value": {
                    "title": "Frequently Asked Questions",
                    "slug": "faq",
                    "page_type": "questions",
                    "status": "draft",
                    "fields": {
                      "en": {
                        "headline": "Frequently Asked Questions",
                        "body": "<p class=\"content\">We love questions</p>",
                        "questions": [
                          {
                            "question": "Are dogs allowed?",
                            "answer": "Leashed dogs are allowed.",
                            "picture": "https://farm1.staticflickr.com/836/42903355654_8faa21171a_m_d.jpg"
                          }
                        ]
                      },
                      "es": {
                        "headline": "Preguntas frecuentes",
                        "body": "<p class=\"content\">Nos encantan las preguntas</p>",
                        "questions": [
                          {
                            "question": "Se admiten perros?",
                            "answer": "Se permiten perros con correa.",
                            "picture": "https://farm1.staticflickr.com/836/42903355654_8faa21171a_m_d.jpg"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "**Accepted - Page creation started successfully**\n\nThe request has been accepted for processing. Full page creation occurs asynchronously,\nmeaning the successfully created page may not show immediately. Pages are validated\nprior to returning this response, but it is possible that page creation may fail\nafter returning a `202` response. If this happens, please contact support.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                },
                "example": {
                  "status": "pending"
                }
              }
            }
          },
          "400": {
            "description": "**Bad Request - Validation Error**\n\nYour data did not pass the initial validation stage. This may happen if you are:\n- Missing a required field\n- Missing a field that's required in your page type\n- Providing a remote URL for a media field that returns a 404\n\nError explanations will be returned in a JSON array.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "examples": {
                  "missing_page_type": {
                    "summary": "Missing page type",
                    "value": {
                      "page_type": [
                        "You must specify a page type."
                      ]
                    }
                  },
                  "invalid_page_type": {
                    "summary": "Invalid page type",
                    "value": {
                      "page_type": [
                        "The write API cannot be used to create single pages."
                      ]
                    }
                  },
                  "missing_title": {
                    "summary": "Missing title",
                    "value": {
                      "title": [
                        "You must specify a page title."
                      ]
                    }
                  },
                  "missing_slug": {
                    "summary": "Missing slug",
                    "value": {
                      "slug": [
                        "You must specify a page slug."
                      ]
                    }
                  },
                  "slug_already_exists": {
                    "summary": "Slug already exists",
                    "value": {
                      "slug": [
                        "A page with slug 'faq' already exists."
                      ]
                    }
                  },
                  "invalid_status": {
                    "summary": "Invalid status",
                    "value": {
                      "status": [
                        "Valid status values are 'draft' and 'published'"
                      ]
                    }
                  },
                  "scheduling_not_supported": {
                    "summary": "Scheduling not supported",
                    "value": {
                      "scheduled": [
                        "Scheduling a page during page creation is not supported by the write API at this time."
                      ]
                    }
                  },
                  "locale_validation_error": {
                    "summary": "Locale validation error",
                    "value": {
                      "fields": [
                        "You must specify one or more locales from your account."
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedWriteResponse"
          },
          "403": {
            "description": "**Forbidden - Page Creation Limit Exceeded**\n\nThe organization has exceeded its page creation limit. This can happen when you've reached\nthe maximum number of pages allowed for your plan.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LimitErrorResponse"
                },
                "example": {
                  "error": "Page creation limit is over"
                }
              }
            }
          }
        }
      }
    },
    "/pages/{page_type}/{page_slug}/": {
      "patch": {
        "tags": [
          "Pages"
        ],
        "summary": "Update Page via Write API",
        "description": "Update existing pages using PATCH requests with support for partial updates and multi-locale content. This endpoint provides flexible page modification capabilities while preserving unchanged content.\n\n**PUT Support**: PUT requests are supported for backwards compatibility. PATCH is the recommended method going forward. Both methods perform partial updates — only the fields you include in the request body will be modified.\n\n**Page Type Flexibility**: Use `*` to update pages across all page types when you know the slug but not the specific type, or specify the particular page type slug for optimized queries.\n\n**Partial Update Behavior**: Include only the fields you want to modify in your request body. All other fields will retain their current values, making this ideal for targeted content updates without affecting the entire page structure.\nNote: PUT behaves like PATCH (partial update) for Pages. Use either method to perform partial updates.\n\n**Locale Handling**: For single-locale updates, use the direct field format. For multi-locale organizations, nest your field changes under the appropriate locale codes. You can update specific locales without affecting others.\n\n**Status Control**: Control page visibility by setting `status` to \"draft\" (keeps the page unpublished) or \"published\" (makes changes live immediately). Draft status is useful for staging content changes.\n\n**Immutable Fields**: Page `title` and `slug` cannot be modified via PATCH requests to maintain URL consistency and prevent broken links. These core identifiers must remain stable after page creation.\n\n**Repeater Field Behavior**: When updating repeater fields, you must include the complete array contents in your request. Partial repeater updates are not supported - the entire repeater will be replaced with your provided data.\n\n**Scheduling Limitation**: Page scheduling is not available through the Write API. Any scheduled parameters in your request will be ignored, allowing you to safely update pages that are currently scheduled without affecting their publication timing.\n",
        "x-mint": {
          "metadata": {
            "description": "Update an existing page via PATCH request with support for locale handling and status control."
          },
          "content": "Update existing pages using PATCH requests with support for partial updates and multi-locale content. This endpoint provides flexible page modification capabilities while preserving unchanged content.\n\n**PUT Support**: PUT requests are supported for backwards compatibility. PATCH is the recommended method going forward. Both methods perform partial updates — only the fields you include in the request body will be modified.\n\n**Page Type Flexibility**: Use `*` to update pages across all page types when you know the slug but not the specific type, or specify the particular page type slug for optimized queries.\n\n**Partial Update Behavior**: Include only the fields you want to modify in your request body. All other fields will retain their current values, making this ideal for targeted content updates without affecting the entire page structure.\nNote: PUT behaves like PATCH (partial update) for Pages. Use either method to perform partial updates.\n\n**Locale Handling**: For single-locale updates, use the direct field format. For multi-locale organizations, nest your field changes under the appropriate locale codes. You can update specific locales without affecting others.\n\n**Status Control**: Control page visibility by setting `status` to \"draft\" (keeps the page unpublished) or \"published\" (makes changes live immediately). Draft status is useful for staging content changes.\n\n**Immutable Fields**: Page `title` and `slug` cannot be modified via PATCH requests to maintain URL consistency and prevent broken links. These core identifiers must remain stable after page creation.\n\n**Repeater Field Behavior**: When updating repeater fields, you must include the complete array contents in your request. Partial repeater updates are not supported - the entire repeater will be replaced with your provided data.\n\n**Scheduling Limitation**: Page scheduling is not available through the Write API. Any scheduled parameters in your request will be ignored, allowing you to safely update pages that are currently scheduled without affecting their publication timing.\n"
        },
        "operationId": "updatePage",
        "security": [
          {
            "writeTokenAuth": []
          }
        ],
        "parameters": [
          {
            "name": "page_type",
            "in": "path",
            "description": "The type of page to update.\n\n- Use `*` to search across all page types\n- Use a specific page type slug to limit search to that type\n",
            "required": true,
            "schema": {
              "type": "string"
            },
            "examples": {
              "wildcard": {
                "value": "*",
                "description": "Update page across all page types"
              },
              "specific_type": {
                "value": "news",
                "description": "Update page within news page type only"
              }
            }
          },
          {
            "name": "page_slug",
            "in": "path",
            "description": "The slug of the page to update.\n",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "faq"
          },
          {
            "name": "locale",
            "in": "query",
            "description": "Set to the API slug of a pre-configured locale (e.g., 'en' or 'fr').\n\n**Usage:** Only applicable when using the single-locale request format (WITHOUT Locales format).\nIf you are using the single-locale format to update only a single locale's version of a page, you can specify the locale via this query param, e.g., `?locale=en`.\n\n**Not applicable** when using the multi-locale format (WITH Locales format), as locale codes are specified within the request body under the `fields` object.\n\nWhen omitted and using single-locale format, updates the organization's default locale.\n",
            "required": false,
            "schema": {
              "type": "string",
              "example": "en"
            },
            "examples": {
              "english": {
                "value": "en",
                "description": "English locale"
              },
              "spanish": {
                "value": "es",
                "description": "Spanish locale"
              },
              "french": {
                "value": "fr",
                "description": "French locale"
              }
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Page update data in either single-locale or multi-locale format.\n\n**Partial Updates**: Unlike creating pages, you only need to specify the fields you want to update. You don't need to include all fields.\n\n**Format Flexibility**: The API accepts data wrapped in a top-level \"data\" key (Read API format). For example: `{\"data\": {\"status\": \"draft\", \"fields\": {...}}}` will be automatically unwrapped. You can use either `title` or `name` - both are accepted and `name` will be automatically converted to `title`.\n\n**Request Body Formats**:\n- **WITHOUT Locales or Single Locale**: One format mirrors the read API response and can be used for pages without locales or updating a single, specified locale.\n- **WITH Locales (Multi-Locale)**: The second format can be used for updating multiple locales at once. In this format, the `fields` object has an extra level and must be first mapped to the locale code to use.\n",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePageRequest"
              },
              "examples": {
                "without_locales": {
                  "summary": "Update Page WITHOUT Locales or with a Single Locale",
                  "description": "Example of updating a page without locale support or for a single locale.\n\nNote: You only need to specify the fields you want to update, not all fields.\n",
                  "value": {
                    "status": "draft",
                    "fields": {
                      "headline": "Frequently Asked Questions Updated",
                      "questions": [
                        {
                          "question": "Are dogs allowed?",
                          "answer": "Leashed dogs are allowed.",
                          "picture": "https://farm1.staticflickr.com/836/42903355654_8faa21171a_m_d.jpg"
                        },
                        {
                          "question": "Another dog question",
                          "answer": "Another dog answer",
                          "picture": "https://farm1.staticflickr.com/836/42903355654_8faa21171a_m_d.jpg"
                        }
                      ]
                    }
                  }
                },
                "with_locales": {
                  "summary": "Update Page WITH Locales",
                  "description": "Example of updating a page with multiple locales at the same time.\n\nNote: You only need to specify the fields you want to update for each locale.\n",
                  "value": {
                    "status": "draft",
                    "fields": {
                      "en": {
                        "headline": "Frequently Asked Questions Updated",
                        "questions": [
                          {
                            "question": "Are dogs allowed?",
                            "answer": "Leashed dogs are allowed.",
                            "picture": "https://farm1.staticflickr.com/836/42903355654_8faa21171a_m_d.jpg"
                          },
                          {
                            "question": "Another dog question",
                            "answer": "Another dog answer",
                            "picture": "https://farm1.staticflickr.com/836/42903355654_8faa21171a_m_d.jpg"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "**Accepted - Page update started successfully**\n\nThe request has been accepted for processing. Full page update occurs asynchronously,\nmeaning the successfully updated page may not show changes immediately. Page updates are validated\nprior to returning this response, but it is possible that page update may fail\nafter returning a `202` response. If this happens, please contact support.\n\n**Warning Messages**: If you include fields that cannot be updated (like `scheduled` timestamp or `scheduled` status),\nthe API will return warning messages explaining which fields were ignored.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdateSuccessResponse"
                },
                "examples": {
                  "basic_success": {
                    "summary": "Standard successful update",
                    "value": {
                      "status": "pending"
                    }
                  },
                  "success_with_warnings": {
                    "summary": "Successful update with ignored fields",
                    "value": {
                      "status": "pending",
                      "warning: scheduled field": "Scheduled timestamps cannot be created or altered via write API. This field will be ignored.",
                      "warning: status field": "A page's status cannot be set as `scheduled` via write API at this time. This field will be ignored."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "**Bad Request - Validation Error**\n\nYour data did not pass the initial validation stage. This may happen if you are:\n- Missing a required field for the specific page type\n- Providing a remote URL for a media field that returns a 404\n- Trying to update immutable fields (title, slug)\n- Providing invalid field values\n\nError explanations will be returned in a JSON array.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "examples": {
                  "missing_required_field": {
                    "summary": "Missing required field",
                    "value": {
                      "headline": [
                        "This field is required for this page type."
                      ]
                    }
                  },
                  "invalid_status": {
                    "summary": "Invalid status",
                    "value": {
                      "status": [
                        "Valid status values are 'draft' and 'published'"
                      ]
                    }
                  },
                  "immutable_field_attempt": {
                    "summary": "Attempted to update immutable field",
                    "value": {
                      "title": [
                        "Page title cannot be updated via PATCH."
                      ]
                    }
                  },
                  "locale_validation_error": {
                    "summary": "Locale validation error",
                    "value": {
                      "fields": [
                        "You must specify one or more locales from your account."
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedWriteResponse"
          },
          "403": {
            "description": "**Forbidden - Permission Denied**\n\nYou don't have permission to update this page. This could be due to:\n- Page update limits exceeded\n- Insufficient permissions for the page type\n- Organization-level restrictions\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "detail": "Permission denied"
                }
              }
            }
          },
          "404": {
            "description": "**Not Found - Page Does Not Exist**\n\nThe requested page doesn't exist, or you don't have access to it. This could be because:\n- The page slug doesn't exist\n- The page type doesn't exist\n- The page exists but not in the specified page type\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "page_not_found": {
                    "summary": "Page not found",
                    "value": {
                      "detail": "Page not found."
                    }
                  },
                  "page_type_not_found": {
                    "summary": "Page type not found",
                    "value": {
                      "detail": "Page type not found."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/content/": {
      "post": {
        "tags": [
          "Collections"
        ],
        "summary": "Create Collection Item",
        "description": "Create new items within a Collection using the Write API. Collections support completely dynamic schemas and multi-locale content, making them ideal for flexible content types like team members, products, or testimonials.\n\n**Dynamic Schema Flexibility**: Collection fields are entirely user-defined through your dashboard configuration. The field structure in your request must match the schema you've configured for the specific collection, including field types, validation rules, and any required fields.\n\n**Locale Structure**: For organizations without locales configured, provide field values directly in a flat structure. For multi-locale organizations, nest your field data under the appropriate locale codes (e.g., \"en\", \"es\") to create content in multiple languages simultaneously.\n\n**Media Integration**: If `Media` is the field_type for a chosen field, any URL can be provided as the field's value. The media corresponding to this URL will be automatically downloaded and uploaded to your ButterCMS media library, ensuring reliable hosting and CDN integration.\n\n**Asynchronous Processing**: This endpoint returns `202 Accepted` immediately to ensure fast response times for your application. The actual item creation, including media uploads, validation, and any configured webhooks, happens in the background processing queue.\nSee also: Architecture & Performance for guidance on `levels`, pagination, and performance best practices.\n",
        "x-mint": {
          "metadata": {
            "description": "Create a new item within a Collection via the Write API with support for locales and media uploads."
          },
          "content": "Create new items within a Collection using the Write API. Collections support completely dynamic schemas and multi-locale content, making them ideal for flexible content types like team members, products, or testimonials.\n\n**Dynamic Schema Flexibility**: Collection fields are entirely user-defined through your dashboard configuration. The field structure in your request must match the schema you've configured for the specific collection, including field types, validation rules, and any required fields.\n\n**Locale Structure**: For organizations without locales configured, provide field values directly in a flat structure. For multi-locale organizations, nest your field data under the appropriate locale codes (e.g., \"en\", \"es\") to create content in multiple languages simultaneously.\n\n**Media Integration**: If `Media` is the field_type for a chosen field, any URL can be provided as the field's value. The media corresponding to this URL will be automatically downloaded and uploaded to your ButterCMS media library, ensuring reliable hosting and CDN integration.\n\n**Asynchronous Processing**: This endpoint returns `202 Accepted` immediately to ensure fast response times for your application. The actual item creation, including media uploads, validation, and any configured webhooks, happens in the background processing queue.\nSee also: Architecture & Performance for guidance on `levels`, pagination, and performance best practices.\n"
        },
        "operationId": "createCollectionItem",
        "security": [
          {
            "writeTokenAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Collection item data with dynamic field structure based on collection configuration and locale settings.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCollectionItemRequest"
              },
              "examples": {
                "without_locales": {
                  "summary": "Create item without locales (single language)",
                  "description": "Use this format when your organization has no locales configured",
                  "value": {
                    "key": "team_members",
                    "status": "published",
                    "fields": [
                      {
                        "name": "John Doe",
                        "position": "Software Engineer",
                        "bio": "Experienced developer with expertise in web technologies",
                        "profile_image": "https://example.com/images/john-doe.jpg",
                        "years_experience": 5
                      }
                    ]
                  }
                },
                "with_locales": {
                  "summary": "Create item with locales (multi-language)",
                  "description": "Use this format when your organization has locales configured (e.g., English and Spanish)",
                  "value": {
                    "key": "team_members",
                    "status": "published",
                    "fields": [
                      {
                        "en": {
                          "name": "John Doe",
                          "position": "Software Engineer",
                          "bio": "Experienced developer with expertise in web technologies",
                          "profile_image": "https://example.com/images/john-doe.jpg",
                          "years_experience": 5
                        },
                        "es": {
                          "name": "John Doe",
                          "position": "Ingeniero de Software",
                          "bio": "Desarrollador experimentado con experiencia en tecnologías web",
                          "profile_image": "https://example.com/images/john-doe.jpg",
                          "years_experience": 5
                        }
                      }
                    ]
                  }
                },
                "media_upload_example": {
                  "summary": "Create item with remote media URLs",
                  "description": "Demonstrates automatic media upload from remote URLs",
                  "value": {
                    "key": "products",
                    "status": "draft",
                    "fields": [
                      {
                        "name": "Premium Widget",
                        "description": "High-quality widget for professional use",
                        "main_image": "https://cdn.example.com/products/widget-main.jpg",
                        "gallery_images": [
                          "https://cdn.example.com/products/widget-1.jpg",
                          "https://cdn.example.com/products/widget-2.jpg"
                        ],
                        "price": 99.99
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "**Accepted - Collection Item Creation Queued**\n\nThe collection item has passed initial validation and creation has been queued for asynchronous processing.\n\n**Important**: The item may not be immediately available in collection queries. Background processing includes:\n\n- Field validation against collection schema\n- Media download and upload to Butter Media Library\n- Reference field resolution\n- Search index updates\n\nIf creation fails during background processing, contact support for assistance.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateCollectionItemResponse"
                },
                "example": {
                  "status": "pending"
                }
              }
            }
          },
          "400": {
            "description": "**Bad Request - Validation Failed**\n\nThe request failed initial validation. Common causes:\n\n- **Missing Required Fields**: `key` or `fields` not provided\n- **Invalid Status**: Status must be 'published' or 'draft'\n- **Invalid Collection Key**: Collection doesn't exist or access denied\n- **Field Validation**: Missing required fields or invalid field values\n- **Invalid Media URLs**: Remote URLs are not accessible or return 404\n- **Locale Errors**: Invalid locale codes or mismatched locale format\n- **Organization Limits**: Collection item limit reached for subscription plan\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "examples": {
                  "missing_fields": {
                    "summary": "Missing required fields",
                    "value": {
                      "key": [
                        "Missing parameter"
                      ],
                      "fields": [
                        "Missing parameter"
                      ]
                    }
                  },
                  "invalid_status": {
                    "summary": "Invalid status value",
                    "value": {
                      "status": [
                        "Valid status values are 'draft' and 'published'"
                      ]
                    }
                  },
                  "invalid_media_url": {
                    "summary": "Invalid remote media URL",
                    "value": {
                      "fields": [
                        "Remote URL for media field is not a valid URL"
                      ]
                    }
                  },
                  "unsupported_media_type": {
                    "summary": "Unsupported media file type",
                    "value": {
                      "fields": [
                        "We don't support 'text/plain' files, please contact us about possible support."
                      ]
                    }
                  },
                  "video_enterprise_required": {
                    "summary": "Video uploads require enterprise plan",
                    "value": {
                      "fields": [
                        "Video upload is not allowed with your current plan. Please contact support."
                      ]
                    }
                  },
                  "svg_security_error": {
                    "summary": "SVG security validation failed",
                    "value": {
                      "fields": [
                        "We don't allow <script> tag in the SVG files."
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedWriteResponse"
          },
          "403": {
            "description": "**Forbidden - Insufficient Permissions or Subscription Limits**\n\nThis error occurs when the provided token doesn't have write permissions or the collection item limit has been reached for your subscription plan.\n",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "$ref": "#/components/schemas/LimitErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "write_permission": {
                    "summary": "Token lacks write permissions",
                    "value": {
                      "detail": "Token does not have write permissions"
                    }
                  },
                  "organization_limit": {
                    "summary": "Collection item limit reached",
                    "value": {
                      "error": "Cannot create a new Collection Item. Collection Item Limit Reached."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/content/{collection_key}/{item_id}/": {
      "put": {
        "tags": [
          "Collections"
        ],
        "summary": "Update Collection Item (Full)",
        "description": "Perform a full update (PUT) of an existing Collection item, completely replacing the item with the provided data. This operation is ideal when you need to ensure all fields are synchronized with your source data or when making comprehensive changes.\n\n**Update Method**: PUT replaces the entire item with your request data, similar to recreating the item from scratch. This differs from PATCH operations, which only update specific fields. Use PUT when you want to ensure complete data consistency or when your workflow involves regenerating entire items.\n\n> **Important**: The URL must include a trailing slash after the item ID (e.g., `/v2/content/my-collection/123/`). This is required for the endpoint to function correctly.\n\n**Item Identification**: The unique item ID can be found in the `meta` field of any collection item when retrieved through GET requests. This identifier remains constant throughout the item's life cycle and is required for all update and delete operations.\n\n**Reference Field Updates**: When updating reference fields, use page slugs for Page references and item IDs for Collection references. To remove existing references, provide empty strings (`\"\"`), empty arrays (`[]`), or `null` values depending on the field type and whether it's a single or multi-reference field.\n\n**Asynchronous Processing**: This endpoint returns `202 Accepted` immediately to ensure fast response times. The actual update processing, including media uploads, reference resolution, validation, and webhook triggers, happens in the background processing queue.\n",
        "x-mint": {
          "metadata": {
            "description": "Fully replace an existing Collection item via PUT request, overwriting all fields with the provided data."
          },
          "content": "Perform a full update (PUT) of an existing Collection item, completely replacing the item with the provided data. This operation is ideal when you need to ensure all fields are synchronized with your source data or when making comprehensive changes.\n\n**Update Method**: PUT replaces the entire item with your request data, similar to recreating the item from scratch. This differs from PATCH operations, which only update specific fields. Use PUT when you want to ensure complete data consistency or when your workflow involves regenerating entire items.\n\n> **Important**: The URL must include a trailing slash after the item ID (e.g., `/v2/content/my-collection/123/`). This is required for the endpoint to function correctly.\n\n**Item Identification**: The unique item ID can be found in the `meta` field of any collection item when retrieved through GET requests. This identifier remains constant throughout the item's life cycle and is required for all update and delete operations.\n\n**Reference Field Updates**: When updating reference fields, use page slugs for Page references and item IDs for Collection references. To remove existing references, provide empty strings (`\"\"`), empty arrays (`[]`), or `null` values depending on the field type and whether it's a single or multi-reference field.\n\n**Asynchronous Processing**: This endpoint returns `202 Accepted` immediately to ensure fast response times. The actual update processing, including media uploads, reference resolution, validation, and webhook triggers, happens in the background processing queue.\n"
        },
        "operationId": "updateCollectionItem",
        "parameters": [
          {
            "name": "collection_key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 100
            },
            "description": "The unique identifier/slug of the Collection containing the item to update.\n\nMust match an existing collection in your organization.\n",
            "example": "team_members"
          },
          {
            "name": "item_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 50
            },
            "description": "The unique identifier of the collection item to update.\n\n**Important**: The URL must end with a trailing slash after this parameter.\n\nThis ID can be found in the `meta` field of collection items returned by GET operations.\n",
            "example": "123"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCollectionItemRequest"
              },
              "examples": {
                "without_locales_full_update": {
                  "summary": "Full update without locales",
                  "description": "Complete replacement of collection item fields",
                  "value": {
                    "status": "published",
                    "fields": {
                      "field1_key": "Updated field value",
                      "field2_key": "Another updated value",
                      "contact_email": "updated@example.com"
                    }
                  }
                },
                "with_locales_full_update": {
                  "summary": "Full update with locales",
                  "description": "Complete replacement with multi-locale support",
                  "value": {
                    "status": "published",
                    "fields": {
                      "en": {
                        "field1_key": "Updated English value",
                        "field2_key": "Another English value"
                      },
                      "es": {
                        "field1_key": "Valor actualizado en español",
                        "field2_key": "Otro valor en español"
                      }
                    }
                  }
                },
                "reference_fields_update": {
                  "summary": "Reference field updates",
                  "description": "Updating relationships to pages and other collections",
                  "value": {
                    "status": "published",
                    "fields": {
                      "related_page": "updated-page-slug",
                      "tags": [
                        4,
                        5,
                        6
                      ],
                      "category": null
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "$ref": "#/components/responses/CollectionItemAcceptedResponse"
          },
          "400": {
            "description": "Bad Request - Validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "examples": {
                  "validation_errors": {
                    "summary": "Field validation errors",
                    "value": {
                      "field1_key": [
                        "This field is required."
                      ],
                      "status": [
                        "Valid status values are 'draft' and 'published'"
                      ]
                    }
                  },
                  "invalid_references": {
                    "summary": "Reference field errors",
                    "value": {
                      "related_page": [
                        "Page with slug 'nonexistent-page' not found."
                      ],
                      "tags": [
                        "Collection item with ID 999 not found."
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "missing_token": {
                    "summary": "Missing API token",
                    "value": {
                      "detail": "Authentication credentials were not provided"
                    }
                  },
                  "invalid_token": {
                    "summary": "Invalid API token",
                    "value": {
                      "detail": "Invalid token"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Forbidden - Insufficient permissions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "write_permission": {
                    "summary": "Token lacks write permissions",
                    "value": {
                      "detail": "Token does not have write permissions"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not Found - Collection or item not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "collection_not_found": {
                    "summary": "Collection not found",
                    "value": {
                      "detail": "Collection not found"
                    }
                  },
                  "item_not_found": {
                    "summary": "Collection item not found",
                    "value": {
                      "detail": "Collection item not found"
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "writeTokenAuth": []
          }
        ]
      },
      "patch": {
        "tags": [
          "Collections"
        ],
        "summary": "Update Collection Item (Partial)",
        "description": "Perform a partial update (PATCH) of an existing Collection item, updating only the fields you specify while preserving all other content. This method is ideal for targeted updates without affecting the entire item structure.\n\n**Update Method**: PATCH updates only the fields included in your request body, leaving all other fields unchanged. This differs from PUT operations, which replace the entire item. Use PATCH when you want to modify specific fields while preserving existing content, relationships, and metadata.\n\n**Partial Update Intelligence**: Reference fields, status, timestamps, and any omitted content fields automatically retain their current values. This allows you to safely update specific content without worrying about accidentally clearing other important data.\n\n> **Important**: The URL must include a trailing slash after the item ID (e.g., `/v2/content/my-collection/123/`). This is required for the endpoint to function correctly.\n\n**Item Identification**: The unique item ID can be found in the `meta` field of any collection item when retrieved through GET requests. This identifier remains constant throughout the item's life cycle.\n\n**Reference Field Handling**: When updating reference fields, use page slugs for Page references and item IDs for Collection references. If you omit reference fields from your request, existing references remain completely unchanged, making it safe to update other content without affecting relationships.\n\n**Asynchronous Processing**: This endpoint returns `202 Accepted` immediately to ensure fast response times. The actual update processing, including media uploads, reference validation, and webhook triggers, happens in the background processing queue.\n",
        "x-mint": {
          "metadata": {
            "description": "Partially update an existing Collection item via PATCH request, modifying only the specified fields."
          },
          "content": "Perform a partial update (PATCH) of an existing Collection item, updating only the fields you specify while preserving all other content. This method is ideal for targeted updates without affecting the entire item structure.\n\n**Update Method**: PATCH updates only the fields included in your request body, leaving all other fields unchanged. This differs from PUT operations, which replace the entire item. Use PATCH when you want to modify specific fields while preserving existing content, relationships, and metadata.\n\n**Partial Update Intelligence**: Reference fields, status, timestamps, and any omitted content fields automatically retain their current values. This allows you to safely update specific content without worrying about accidentally clearing other important data.\n\n> **Important**: The URL must include a trailing slash after the item ID (e.g., `/v2/content/my-collection/123/`). This is required for the endpoint to function correctly.\n\n**Item Identification**: The unique item ID can be found in the `meta` field of any collection item when retrieved through GET requests. This identifier remains constant throughout the item's life cycle.\n\n**Reference Field Handling**: When updating reference fields, use page slugs for Page references and item IDs for Collection references. If you omit reference fields from your request, existing references remain completely unchanged, making it safe to update other content without affecting relationships.\n\n**Asynchronous Processing**: This endpoint returns `202 Accepted` immediately to ensure fast response times. The actual update processing, including media uploads, reference validation, and webhook triggers, happens in the background processing queue.\n"
        },
        "operationId": "patchCollectionItem",
        "parameters": [
          {
            "name": "collection_key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 100
            },
            "description": "The unique identifier/slug of the Collection containing the item to update.\n\nMust match an existing collection in your organization.\n",
            "example": "team_members"
          },
          {
            "name": "item_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 50
            },
            "description": "The unique identifier of the collection item to update.\n\n**Important**: The URL must end with a trailing slash after this parameter.\n\nThis ID can be found in the `meta` field of collection items returned by GET operations.\n",
            "example": "123"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCollectionItemRequest"
              },
              "examples": {
                "without_locales_partial": {
                  "summary": "Partial update without locales",
                  "description": "Update only specific fields, others remain unchanged",
                  "value": {
                    "status": "published",
                    "fields": {
                      "field2_key": "Only this field gets updated"
                    }
                  }
                },
                "with_locales_partial": {
                  "summary": "Partial update with locales",
                  "description": "Update only specific locales and fields",
                  "value": {
                    "status": "published",
                    "fields": {
                      "en": {
                        "field2_key": "Updated English field"
                      },
                      "es": {
                        "field1_key": "Campo actualizado en español"
                      }
                    }
                  }
                },
                "reference_partial_update": {
                  "summary": "Partial reference field update",
                  "description": "Update only reference relationships, preserve other fields",
                  "value": {
                    "fields": {
                      "related_page": "new-page-slug",
                      "tags": [
                        7,
                        8
                      ]
                    }
                  }
                },
                "status_only_update": {
                  "summary": "Status change only",
                  "description": "Change only the publication status",
                  "value": {
                    "status": "draft"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "$ref": "#/components/responses/CollectionItemAcceptedResponse"
          },
          "400": {
            "description": "Bad Request - Validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "examples": {
                  "validation_errors": {
                    "summary": "Field validation errors",
                    "value": {
                      "field1_key": [
                        "This field is required."
                      ],
                      "status": [
                        "Valid status values are 'draft' and 'published'"
                      ]
                    }
                  },
                  "invalid_references": {
                    "summary": "Reference field errors",
                    "value": {
                      "related_page": [
                        "Page with slug 'nonexistent-page' not found."
                      ],
                      "tags": [
                        "Collection item with ID 999 not found."
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/paths/~1content~1%7Bcollection_key%7D~1%7Bitem_id%7D~1/put/responses/401"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "write_permission": {
                    "summary": "Token lacks write permissions",
                    "value": {
                      "detail": "Token does not have write permissions"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not Found - Collection or item not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "collection_not_found": {
                    "summary": "Collection not found",
                    "value": {
                      "detail": "Collection not found"
                    }
                  },
                  "item_not_found": {
                    "summary": "Collection item not found",
                    "value": {
                      "detail": "Collection item not found"
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "writeTokenAuth": []
          }
        ]
      },
      "delete": {
        "tags": [
          "Collections"
        ],
        "summary": "Delete Collection Item",
        "description": "Delete an existing Collection item using a soft delete operation, which marks the item as deleted while preserving the data for potential recovery. This approach ensures data safety while removing items from public API responses.\n\n**Soft Delete Behavior**: The item is marked as deleted in the system and will no longer appear in collection listings, search results, or standard API responses. However, the actual data is preserved in the database, allowing for potential recovery through support channels if needed.\n\n> **Important**: The URL must include a trailing slash after the item ID (e.g., `/v2/content/my-collection/123/`). This is required for the endpoint to function correctly.\n\n**Item Identification**: The unique item ID can be found in the `meta` field of any collection item when retrieved through GET requests. This identifier is required to specify which item to delete.\n\n**Request Body**: DELETE requests should not include any request body data - send an empty body or omit the body entirely. The item ID in the URL path is sufficient to identify the target item.\n\n**Asynchronous Processing**: This endpoint returns `204 No Content` immediately upon successful request validation. The actual deletion processing, including webhook notifications and reference cleanup, happens in the background processing queue.\n",
        "x-mint": {
          "metadata": {
            "description": "Soft-delete an existing Collection item via the Write API. The item is marked as deleted but data is preserved."
          },
          "content": "Delete an existing Collection item using a soft delete operation, which marks the item as deleted while preserving the data for potential recovery. This approach ensures data safety while removing items from public API responses.\n\n**Soft Delete Behavior**: The item is marked as deleted in the system and will no longer appear in collection listings, search results, or standard API responses. However, the actual data is preserved in the database, allowing for potential recovery through support channels if needed.\n\n> **Important**: The URL must include a trailing slash after the item ID (e.g., `/v2/content/my-collection/123/`). This is required for the endpoint to function correctly.\n\n**Item Identification**: The unique item ID can be found in the `meta` field of any collection item when retrieved through GET requests. This identifier is required to specify which item to delete.\n\n**Request Body**: DELETE requests should not include any request body data - send an empty body or omit the body entirely. The item ID in the URL path is sufficient to identify the target item.\n\n**Asynchronous Processing**: This endpoint returns `204 No Content` immediately upon successful request validation. The actual deletion processing, including webhook notifications and reference cleanup, happens in the background processing queue.\n"
        },
        "operationId": "deleteCollectionItem",
        "parameters": [
          {
            "name": "collection_key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 100
            },
            "description": "The unique identifier/slug of the Collection containing the item to delete.\n\nMust match an existing collection in your organization.\n",
            "example": "team_members"
          },
          {
            "name": "item_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 50
            },
            "description": "The unique identifier of the collection item to delete.\n\n**Important**: The URL must end with a trailing slash after this parameter.\n\nThis ID can be found in the `meta` field of collection items returned by GET operations.\n",
            "example": "123"
          }
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/NoContentResponse"
          },
          "401": {
            "$ref": "#/paths/~1content~1%7Bcollection_key%7D~1%7Bitem_id%7D~1/put/responses/401"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "write_permission": {
                    "summary": "Token lacks write permissions",
                    "value": {
                      "detail": "Token does not have write permissions"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not Found - Collection or item not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "collection_not_found": {
                    "summary": "Collection not found",
                    "value": {
                      "detail": "Collection not found"
                    }
                  },
                  "item_not_found": {
                    "summary": "Collection item not found",
                    "value": {
                      "detail": "Collection item not found"
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "writeTokenAuth": []
          }
        ]
      }
    },
    "/posts/": {
      "post": {
        "tags": [
          "Blog posts"
        ],
        "summary": "Create Blog Post via Write API",
        "description": "Create a new blog post using the Write API with support for rich media, categorization, and automatic author assignment. This endpoint enables programmatic content creation for blogs, news sites, and content management workflows.\n\n**Required Fields**: Every blog post must include a `title` (post title) and `slug` (URL-friendly identifier). The slug must be unique across all posts in your organization and will become part of the post's permanent URL.\n\n**Author Management**: The author must already exist in your ButterCMS account before creating posts. You can specify the author by email address or slug. If no author is specified, the post will be automatically assigned to your organization owner, ensuring every post has proper attribution.\n\n**Dynamic Categorization**: Categories and tags can be provided as string arrays in your request. If you specify categories or tags that don't exist yet, they will be automatically created in your account, making it easy to expand your content taxonomy organically.\n\n**Media Integration**: Featured images are always uploaded to your ButterCMS media library for reliable hosting. For images within the post body content, set `upload_images_to_media_library=true` to automatically download and host external images through ButterCMS's CDN infrastructure.\n\n**Localization**: Use the `locale` query parameter to assign a locale to the post (e.g. `?locale=es`). When omitted, the post is created in your organization's default locale. To create a translated version of an existing post, use the Update endpoint with the desired locale instead.\n\n**Publication & Scheduling**: Blog posts default to `draft` unless `status=published` is provided. Scheduling future publication is not supported via the Write API; scheduling-related fields will result in validation errors.\n\n**Asynchronous Processing**: This endpoint returns `202 Accepted` immediately to ensure fast response times for your application. The actual post creation, including media processing, category creation, and webhook notifications, happens in the background processing queue.\n",
        "x-mint": {
          "metadata": {
            "description": "Create a new blog post via the Write API with support for draft status, author assignment, category tagging, and media integration."
          },
          "content": "Create a new blog post using the Write API with support for rich media, categorization, and automatic author assignment. This endpoint enables programmatic content creation for blogs, news sites, and content management workflows.\n\n**Required Fields**: Every blog post must include a `title` (post title) and `slug` (URL-friendly identifier). The slug must be unique across all posts in your organization and will become part of the post's permanent URL.\n\n**Author Management**: The author must already exist in your ButterCMS account before creating posts. You can specify the author by email address or slug. If no author is specified, the post will be automatically assigned to your organization owner, ensuring every post has proper attribution.\n\n**Dynamic Categorization**: Categories and tags can be provided as string arrays in your request. If you specify categories or tags that don't exist yet, they will be automatically created in your account, making it easy to expand your content taxonomy organically.\n\n**Media Integration**: Featured images are always uploaded to your ButterCMS media library for reliable hosting. For images within the post body content, set `upload_images_to_media_library=true` to automatically download and host external images through ButterCMS's CDN infrastructure.\n\n**Localization**: Use the `locale` query parameter to assign a locale to the post (e.g. `?locale=es`). When omitted, the post is created in your organization's default locale. To create a translated version of an existing post, use the Update endpoint with the desired locale instead.\n\n**Publication & Scheduling**: Blog posts default to `draft` unless `status=published` is provided. Scheduling future publication is not supported via the Write API; scheduling-related fields will result in validation errors.\n\n**Asynchronous Processing**: This endpoint returns `202 Accepted` immediately to ensure fast response times for your application. The actual post creation, including media processing, category creation, and webhook notifications, happens in the background processing queue.\n"
        },
        "operationId": "createBlogPost",
        "security": [
          {
            "writeTokenAuth": []
          }
        ],
        "parameters": [
          {
            "name": "locale",
            "in": "query",
            "description": "Assign a locale to the new post (e.g. `en`, `es`). When omitted, the post is created in your organization's default locale.\n",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 10
            },
            "example": "es"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateBlogPostRequest"
              },
              "examples": {
                "complete_blog_post": {
                  "summary": "Complete blog post with all fields",
                  "value": {
                    "title": "This is a blog post",
                    "slug": "this-is-a-blog-post",
                    "status": "published",
                    "author": {
                      "email": "your@author.com"
                    },
                    "categories": [
                      "Recipes",
                      "Meals"
                    ],
                    "tags": [
                      "Butter",
                      "Sushi",
                      "Really Good Recipes"
                    ],
                    "featured_image": "https://farm1.staticflickr.com/836/42903355654_8faa21171a_m_d.jpg",
                    "featured_image_alt": "Featured image alt text example.",
                    "body": "<h1>Butter</h1><p>I am so hungry!</p>",
                    "summary": "This is a blog post summary.",
                    "seo_title": "This is a blog post",
                    "meta_description": "This is a blog post to test the API.",
                    "upload_images_to_media_library": false
                  }
                },
                "minimal_blog_post": {
                  "summary": "Minimal blog post with required fields only",
                  "value": {
                    "title": "My First Blog Post",
                    "slug": "my-first-blog-post"
                  }
                },
                "draft_with_author_slug": {
                  "summary": "Draft post with author specified by slug",
                  "value": {
                    "title": "Draft Post Example",
                    "slug": "draft-post-example",
                    "author": {
                      "slug": "firstname-lastname"
                    },
                    "body": "<p>This is a draft post.</p>",
                    "summary": "A draft post example."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "**Accepted - Post Creation Initiated**\n\nA validated POST request will return a response with HTTP status code 202. Full post creation occurs asynchronously, meaning a successfully created post may not show immediately.\n\nPosts are validated prior to returning the API response but it is also possible that post creation may fail after returning a 202 response. If this happens please contact support.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogPostCreateSuccessResponse"
                },
                "example": {
                  "status": "pending"
                }
              }
            }
          },
          "400": {
            "description": "**Bad Request - Validation Error**\n\nThe API will return HTTP status code 400 if your data does not pass the initial validation stage. This may happen if:\n\n- You are missing a required field (title or slug)\n- The slug is already in use\n- The remote URL for a media field returns a 404\n- You attempt to schedule a blog post (not supported)\n- Invalid author email or slug provided\n\nError explanations will be returned in a single JSON array.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "examples": {
                  "missing_title": {
                    "summary": "Missing required title field",
                    "value": {
                      "title": [
                        "This field is required."
                      ]
                    }
                  },
                  "missing_slug": {
                    "summary": "Missing required slug field",
                    "value": {
                      "slug": [
                        "This field is required."
                      ]
                    }
                  },
                  "duplicate_slug": {
                    "summary": "Slug already exists",
                    "value": {
                      "slug": [
                        "Blog post with this slug already exists."
                      ]
                    }
                  },
                  "scheduling_not_supported": {
                    "summary": "Scheduling attempt during creation",
                    "value": {
                      "scheduled": [
                        "Scheduling a blog post during creation is not supported by the write API at this time."
                      ]
                    }
                  },
                  "scheduling_status_not_supported": {
                    "summary": "Scheduled status not supported",
                    "value": {
                      "status_field": [
                        "Scheduling a blog post during creation is not supported by the write API at this time."
                      ]
                    }
                  },
                  "invalid_featured_image": {
                    "summary": "Invalid featured image URL",
                    "value": {
                      "featured_image": [
                        "Could not retrieve image from URL."
                      ]
                    }
                  },
                  "unsupported_file_type": {
                    "summary": "Unsupported media file type",
                    "value": {
                      "featured_image": [
                        "We don't support 'application/x-unknown' files, please contact us about possible support."
                      ]
                    }
                  },
                  "video_enterprise_only": {
                    "summary": "Video upload requires enterprise plan",
                    "value": {
                      "featured_image": [
                        "Video upload is not allowed with your current plan. Please contact support."
                      ]
                    }
                  },
                  "svg_security_violation": {
                    "summary": "SVG contains security risk",
                    "value": {
                      "featured_image": [
                        "We don't allow <script> tag in the SVG files."
                      ]
                    }
                  },
                  "invalid_author_email": {
                    "summary": "Author with email not found",
                    "value": {
                      "author": [
                        "Author with email 'nonexistent@email.com' not found."
                      ]
                    }
                  },
                  "invalid_author_slug": {
                    "summary": "Author with slug not found",
                    "value": {
                      "author": [
                        "Author with slug 'nonexistent-author' not found."
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedWriteResponse"
          },
          "403": {
            "description": "**Forbidden - Blog Post Limit Exceeded or Insufficient Permissions**\n\nThis can happen when:\n- Your organization has reached the blog post limit for your plan\n- Your API token does not have write permissions\n",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "$ref": "#/components/schemas/LimitErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "blog_post_limit": {
                    "summary": "Blog post limit exceeded",
                    "value": {
                      "error": "Blog post limit is over"
                    }
                  },
                  "write_permission_denied": {
                    "summary": "API token lacks write permissions",
                    "value": {
                      "detail": "Your API token does not allow writes."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "**Not Found - Organization Blog Missing or Invalid Pagination**\n\n- Could not find this organization's blog. This is a rare error that typically indicates a configuration issue.\n- Invalid pagination parameters (page number out of range).\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "blog_missing": {
                    "summary": "Organization blog missing",
                    "value": {
                      "detail": "Could not find this organization's blog"
                    }
                  },
                  "invalid_pagination": {
                    "summary": "Invalid pagination",
                    "value": {
                      "detail": "Invalid Page."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/posts/{slug}/": {
      "patch": {
        "tags": [
          "Blog posts"
        ],
        "summary": "Update Blog Post via Write API",
        "description": "Update an existing blog post using partial updates, allowing you to modify specific fields while preserving all other content. This endpoint is perfect for content updates, SEO optimization, or adding new media to existing posts.\n\n**Partial Update Flexibility**: All fields in the request body are optional - include only the fields you want to modify. Any omitted fields will retain their current values, making it safe to update specific content without affecting the entire post structure.\n\n> **Important**: The URL must append a trailing slash to the blog post slug in the URL path (`/v2/posts/your-post-slug/`). This is required for the endpoint to function correctly.\n\n**Localization**: Use the `locale` query parameter to target a specific locale variant (e.g. `?locale=es`). When omitted, updates the post in its current locale. If the locale variant does not yet exist, a new locale variant is created and linked to the original post — this is the primary way to create translations of existing blog posts.\n\n**Scheduling Limitations**: Blog post scheduling is not available through the Write API. Any scheduled parameters in your request will be silently ignored (not treated as errors), allowing you to safely update posts that are currently scheduled without affecting their publication timing.\n\n**Media Integration**: Include `upload_images_to_media_library=true` in your request to automatically download and upload any image URLs within the post body to your ButterCMS media library. This ensures reliable hosting and CDN performance for your content images.\n\n**Asynchronous Processing**: This endpoint returns `202 Accepted` immediately to ensure fast response times for your application. The actual update processing, including media uploads, content validation, and webhook notifications, happens in the background processing queue.\n",
        "x-mint": {
          "metadata": {
            "description": "Partially update an existing blog post via the Write API with support for flexible field modification and status changes."
          },
          "content": "Update an existing blog post using partial updates, allowing you to modify specific fields while preserving all other content. This endpoint is perfect for content updates, SEO optimization, or adding new media to existing posts.\n\n**Partial Update Flexibility**: All fields in the request body are optional - include only the fields you want to modify. Any omitted fields will retain their current values, making it safe to update specific content without affecting the entire post structure.\n\n> **Important**: The URL must append a trailing slash to the blog post slug in the URL path (`/v2/posts/your-post-slug/`). This is required for the endpoint to function correctly.\n\n**Localization**: Use the `locale` query parameter to target a specific locale variant (e.g. `?locale=es`). When omitted, updates the post in its current locale. If the locale variant does not yet exist, a new locale variant is created and linked to the original post — this is the primary way to create translations of existing blog posts.\n\n**Scheduling Limitations**: Blog post scheduling is not available through the Write API. Any scheduled parameters in your request will be silently ignored (not treated as errors), allowing you to safely update posts that are currently scheduled without affecting their publication timing.\n\n**Media Integration**: Include `upload_images_to_media_library=true` in your request to automatically download and upload any image URLs within the post body to your ButterCMS media library. This ensures reliable hosting and CDN performance for your content images.\n\n**Asynchronous Processing**: This endpoint returns `202 Accepted` immediately to ensure fast response times for your application. The actual update processing, including media uploads, content validation, and webhook notifications, happens in the background processing queue.\n"
        },
        "operationId": "updateBlogPost",
        "security": [
          {
            "writeTokenAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "The slug of the blog post to update.\n\n**Important**: The URL must end with a trailing slash (`/v2/posts/your-slug/`).\n",
            "schema": {
              "type": "string",
              "maxLength": 100
            },
            "example": "this-is-a-blog-post"
          },
          {
            "name": "locale",
            "in": "query",
            "description": "Target a specific locale variant (e.g. `en`, `es`). When omitted, updates the post in its current locale. If the locale variant does not exist, a new one is created and linked to the original post.\n",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 10
            },
            "example": "en"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateBlogPostRequest"
              },
              "examples": {
                "partial_update": {
                  "summary": "Partial update (only specified fields changed)",
                  "value": {
                    "slug": "the-new-post-slug",
                    "body": "<h1>Updated</h1><p>This blog post was updated via API</p>"
                  }
                },
                "content_update": {
                  "summary": "Update content and SEO fields",
                  "value": {
                    "title": "Updated Blog Post Title",
                    "body": "<h1>Fresh Content</h1><p>Completely new content for this post.</p>",
                    "summary": "Updated summary of the post.",
                    "seo_title": "Updated SEO Title",
                    "meta_description": "Updated meta description for better SEO."
                  }
                },
                "category_tag_update": {
                  "summary": "Update categories and tags",
                  "value": {
                    "categories": [
                      "Updated Category",
                      "New Category"
                    ],
                    "tags": [
                      "updated",
                      "refresh",
                      "api"
                    ]
                  }
                },
                "status_update": {
                  "summary": "Change post status",
                  "value": {
                    "status": "published"
                  }
                },
                "media_library_update": {
                  "summary": "Update with media library upload",
                  "value": {
                    "body": "<h1>Updated with Images</h1><p><img src='https://example.com/new-image.jpg' alt='New image'></p>",
                    "upload_images_to_media_library": true
                  }
                },
                "scheduled_ignored": {
                  "summary": "Scheduled fields ignored (with warnings)",
                  "value": {
                    "title": "Updated Title",
                    "scheduled": "2024-12-25T10:00:00Z",
                    "status": "scheduled"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "**Accepted - Post Update Initiated**\n\nThe update request has been accepted and will be processed asynchronously. The response may include warning messages if certain fields were ignored (such as scheduling-related fields).\n\n**Warning Messages**: If you provided `scheduled` timestamp or `status: \"scheduled\"`, these will be ignored and warning messages will be included in the response.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogPostUpdateSuccessResponse"
                },
                "examples": {
                  "simple_update": {
                    "summary": "Simple update without warnings",
                    "value": {
                      "status": "pending"
                    }
                  },
                  "update_with_scheduled_warning": {
                    "summary": "Update with scheduled field ignored",
                    "value": {
                      "status": "pending",
                      "warning: scheduled field": "Scheduled timestamps cannot be created or altered via write API. This field will be ignored."
                    }
                  },
                  "update_with_status_warning": {
                    "summary": "Update with scheduled status ignored",
                    "value": {
                      "status": "pending",
                      "warning: status field": "A blog post's status cannot be set as `scheduled` via write API at this time. This field will be ignored."
                    }
                  },
                  "update_with_both_warnings": {
                    "summary": "Update with both scheduling warnings",
                    "value": {
                      "status": "pending",
                      "warning: scheduled field": "Scheduled timestamps cannot be created or altered via write API. This field will be ignored.",
                      "warning: status field": "A blog post's status cannot be set as `scheduled` via write API at this time. This field will be ignored."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "**Bad Request - Validation Error**\n\nThe API will return HTTP status code 400 if your data does not pass validation. This may happen if:\n\n- Invalid field values provided\n- The remote URL for a media field returns a 404\n- Invalid author email or slug provided\n- Malformed request data\n\nError explanations will be returned in a single JSON array.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "examples": {
                  "invalid_featured_image": {
                    "summary": "Invalid featured image URL",
                    "value": {
                      "featured_image": [
                        "Could not retrieve image from URL."
                      ]
                    }
                  },
                  "invalid_author_email": {
                    "summary": "Author with email not found",
                    "value": {
                      "author": [
                        "Author with email 'nonexistent@email.com' not found."
                      ]
                    }
                  },
                  "invalid_status": {
                    "summary": "Invalid status value",
                    "value": {
                      "status": [
                        "Select a valid choice. 'invalid_status' is not one of the available choices."
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedWriteResponse"
          },
          "403": {
            "description": "**Forbidden - Insufficient Permissions**\n\nYour API token does not have write permissions or you don't have permission to update this blog post.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "detail": "Your API token does not allow writes."
                }
              }
            }
          },
          "404": {
            "description": "**Not Found - Blog Post Does Not Exist**\n\nThe blog post with the specified slug was not found or you don't have access to it.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "detail": "Not found."
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Blog posts"
        ],
        "summary": "Delete Blog Post via Write API",
        "description": "Delete an existing blog post using a soft delete operation that marks the post as deleted while preserving the content for potential recovery. This approach ensures data safety while removing posts from public visibility.\n\n> **Important**: You must append a trailing slash to the end of the blog post slug in the URL path: `/v2/posts/your-post-slug/`. This is required for the endpoint to function correctly.\n\n**Soft Delete Behavior**: The post is marked as deleted in the system and will no longer appear in blog listings, search results, RSS feeds, or other public endpoints. However, the actual content and metadata are preserved in the database, allowing for potential recovery through support channels if needed.\n\n**Localization**: Use the `locale` query parameter to specify which locale variant to delete (e.g. `?locale=es`). When omitted, the post's current locale is used. If the specified locale variant does not exist, a 404 Not Found response is returned.\n\n**Access Control**: You can only delete blog posts that belong to your organization. Attempting to delete posts from other organizations will result in a 404 Not Found response, ensuring proper data isolation and security.\n",
        "x-mint": {
          "metadata": {
            "description": "Soft-delete an existing blog post via the Write API. The post is marked as deleted but its data is preserved."
          },
          "content": "Delete an existing blog post using a soft delete operation that marks the post as deleted while preserving the content for potential recovery. This approach ensures data safety while removing posts from public visibility.\n\n> **Important**: You must append a trailing slash to the end of the blog post slug in the URL path: `/v2/posts/your-post-slug/`. This is required for the endpoint to function correctly.\n\n**Soft Delete Behavior**: The post is marked as deleted in the system and will no longer appear in blog listings, search results, RSS feeds, or other public endpoints. However, the actual content and metadata are preserved in the database, allowing for potential recovery through support channels if needed.\n\n**Localization**: Use the `locale` query parameter to specify which locale variant to delete (e.g. `?locale=es`). When omitted, the post's current locale is used. If the specified locale variant does not exist, a 404 Not Found response is returned.\n\n**Access Control**: You can only delete blog posts that belong to your organization. Attempting to delete posts from other organizations will result in a 404 Not Found response, ensuring proper data isolation and security.\n"
        },
        "operationId": "deleteBlogPost",
        "security": [
          {
            "writeTokenAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "The slug of the blog post to delete.\n\n**Important**: The URL must end with a trailing slash (`/v2/posts/your-slug/`).\n",
            "schema": {
              "type": "string",
              "maxLength": 100
            },
            "example": "this-is-a-blog-post"
          },
          {
            "name": "locale",
            "in": "query",
            "description": "Delete this locale variant of the post (e.g. `en`, `es`). When omitted, deletes the post in its current locale. Returns 404 if the locale variant does not exist.\n",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 10
            },
            "example": "en"
          }
        ],
        "responses": {
          "204": {
            "description": "**No Content - Blog Post Successfully Deleted**\n\nThe blog post has been successfully deleted (soft delete). The response body is empty.\n\n**Note**: This is a soft delete operation. The post is marked as deleted but not physically removed from the system.\n"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedWriteResponse"
          },
          "403": {
            "description": "**Forbidden - Insufficient Permissions**\n\nYour API token does not have write permissions. Only write-enabled API tokens can delete blog posts.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "detail": "Your API token does not allow writes."
                }
              }
            }
          },
          "404": {
            "description": "**Not Found - Blog Post Does Not Exist or Already Deleted**\n\nThe blog post with the specified slug was not found. This can happen if:\n\n- The blog post doesn't exist\n- The blog post belongs to a different organization\n- The blog post has already been deleted\n- You don't have access to the blog post\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "detail": "Not found."
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "readTokenAuthQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "auth_token",
        "description": "Pass your API token via the `auth_token` parameter on every request: `?auth_token=your_read_api_token`.\n\nYou can access your API token from your settings page.\n\nRequests made with a missing or invalid token will get a 401 Unauthorized response. All requests must be made over HTTPS.\n"
      },
      "readTokenAuthHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "Authorization",
        "description": "Set the `Authorization` header to `Token your_read_api_token`.\n\nExample: `Authorization: Token abc123def456`\n\nNote: The header value includes the `Token` prefix.\n\nYou can access your API token from your settings page.\n"
      },
      "writeTokenAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "Authorization",
        "description": "Write-enabled API token required for creating content.\n\nThe API token you use for reading from the ButterCMS API will not allow you to create content in the API. For this you will need to use a different write-enabled token. Chat or email support@buttercms.com to get yours.\n\nSet the `Authorization` header to `Token your_write_api_token`.\n\nExample: `Authorization: Token abc123def456`\n\nYour write-enabled token should never be used anywhere it would be exposed, e.g. in client-side JavaScript.\n"
      }
    },
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "detail": {
            "type": "string",
            "description": "Error message describing what went wrong",
            "example": "Authentication credentials were not provided"
          }
        }
      },
      "SuccessResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "pending"
            ],
            "description": "Indicates that the page creation request has been accepted and is being processed asynchronously",
            "example": "pending"
          }
        }
      },
      "ValidationErrorResponse": {
        "type": "object",
        "description": "Response for validation errors (400 Bad Request) - supports both field-specific errors and general error messages",
        "oneOf": [
          {
            "type": "object",
            "description": "Field-specific validation errors (used by Pages, Blog Posts, and Collections)",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "example": {
              "title": [
                "You must specify a page title."
              ],
              "slug": [
                "You must specify a page slug."
              ]
            }
          },
          {
            "type": "object",
            "description": "General error message (used for organization limits, etc.)",
            "properties": {
              "error": {
                "type": "string",
                "description": "Error message"
              }
            },
            "example": {
              "error": "Cannot create a new Collection Item. Collection Item Limit Reached."
            }
          }
        ]
      },
      "LimitErrorResponse": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Error message when subscription plan limits are exceeded",
            "example": "Page creation limit is over"
          }
        }
      },
      "CreatePageRequest": {
        "type": "object",
        "required": [
          "title",
          "slug",
          "page_type",
          "fields"
        ],
        "description": "**Flexible request schema for creating pages - supports both single-locale and multi-locale formats.**\n\nSystem automatically detects the format based on the structure of the `fields` object:\n\n**Single-Locale Format**: `fields` contains field names as keys (e.g., `headline`, `questions`)\n**Multi-Locale Format**: `fields` contains locale codes as keys (e.g., `en`, `es`, `fr`)\n\n**Request Body Formats**:\n- **WITHOUT Locales or Single Locale**: Use when you don't have locales, or when creating a single locale's version of a page. Format `fields` as a direct object with field names as keys. Note: if creating only a single locale's version, you must specify the locale via query param, e.g., `?locale=en`.\n- **WITH Locales (Multi-Locale)**: Use to create one or more locales of a page at the same time. Format `fields` with locale codes as top-level keys. The locale codes must already be configured in your account.\n",
        "properties": {
          "title": {
            "type": "string",
            "description": "The title of the page.",
            "example": "Frequently Asked Questions"
          },
          "slug": {
            "type": "string",
            "description": "The slug of the page.",
            "example": "faq"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "published"
            ],
            "default": "draft",
            "description": "Status of the page. Can be 'draft' or 'published'. Defaults to 'draft'.\nNote that you cannot create a page with a status of 'scheduled' via the write API.\n",
            "example": "draft"
          },
          "page_type": {
            "type": "string",
            "description": "The key of the page type. The page type must already exist in your Butter account.",
            "example": "questions"
          },
          "fields": {
            "type": "object",
            "description": "**Flexible Fields Object - Two Supported Formats**\n- **Format 1: Single-locale/direct fields**\n  - `fields` contains field names as keys (e.g., `headline`, `questions`).\n\n- **Format 2: Multi-locale**\n  - `fields` contains locale codes as keys (e.g., `en`, `es`, `fr`).\n\n- **Detection**: The system automatically detects the format based on whether the\n  top-level keys are locale codes or field names.\n\n- **Field requirements**\n  - All field keys are required for each locale/format you include. If a field is not\n    required in your page type, set it to an empty string.\n  - Repeater fields must be JSON arrays of the repeater groups. For optional repeater\n    fields, use an empty array (`[]`).\n  - Providing a remote URL in any Media field triggers automatic download and upload\n    to your ButterCMS media library.\n\n- **Examples**: See the Examples section for sample request bodies.\n"
          }
        }
      },
      "UpdatePageRequest": {
        "type": "object",
        "description": "**Flexible request schema for updating pages - supports both single-locale and multi-locale formats.**\n\nSystem automatically detects the format based on the structure of the `fields` object:\n\n**Single-Locale Format**: `fields` contains field names as keys (e.g., `headline`, `questions`)\n**Multi-Locale Format**: `fields` contains locale codes as keys (e.g., `en`, `es`, `fr`)\n\n**Partial Updates**: You only need to specify the fields you want to update.\nNote: Pages accept both PATCH and PUT; PUT behaves like PATCH (partial update).\n\n**Immutable Fields**: Cannot update `title` or `slug` via PATCH.\n\n**Field Name Flexibility**: You can use either `title` or `name` in the request - both are accepted and `name` will be automatically converted to `title`.\n",
        "properties": {
          "title": {
            "type": "string",
            "description": "The title of the page. Note: This field cannot be updated via PATCH - it's included here for documentation completeness only.\n\n**Alternative**: You can also use `name` which will be automatically converted to `title`.\n"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "published"
            ],
            "description": "Status of the update. Can be 'draft' or 'published'. Defaults to 'draft'. Setting to 'published' will make your update live immediately.\n\nNote: If `scheduled` timestamp or status is passed, these fields will be ignored to allow updating already scheduled pages.\n",
            "example": "draft"
          },
          "fields": {
            "type": "object",
            "description": "**Flexible Fields Object - Two Supported Formats**\n- **Format 1: Single-locale/direct fields**\n  - `fields` contains field names as keys (e.g., `headline`, `questions`).\n\n- **Format 2: Multi-locale**\n  - `fields` contains locale codes as keys (e.g., `en`, `es`, `fr`).\n\n- **Detection**: The system automatically detects the format based on whether the\n  top-level keys are locale codes or field names.\n\n- **Partial update behavior**\n  - Only specify the fields you want to update; omitted fields remain unchanged.\n  - Repeater fields must be replaced in full; delta changes are not supported. If you need\n    to clear a repeater, provide an empty array (`[]`).\n  - Images and media can be updated by providing remote URLs.\n\n- **Examples**: See the Examples section below for sample request bodies.\n"
          }
        }
      },
      "CreateCollectionItemRequest": {
        "type": "object",
        "required": [
          "key",
          "fields"
        ],
        "properties": {
          "key": {
            "type": "string",
            "description": "The unique identifier/slug of the Collection to create an item in.\n\nMust match an existing collection in your organization.\n",
            "example": "team_members"
          },
          "status": {
            "type": "string",
            "enum": [
              "published",
              "draft"
            ],
            "default": "draft",
            "description": "Status of the collection item:\n\n- **draft**: Item is saved but not publicly available\n- **published**: Item is live and publicly accessible\n\nDefaults to \"draft\" if not specified.\n",
            "example": "published"
          },
          "fields": {
            "type": "array",
            "description": "Array of collection item data. Structure varies based on locale configuration:\n\n- **Without Locales**: Array of objects with direct field key-value pairs\n- **With Locales**: Array of objects with locale codes as keys, containing field data\n\n**Dynamic Nature**: Field names and types are defined by your collection schema and can vary completely between collections.\n",
            "items": {
              "type": "object",
              "description": "**Flexible collection item data - supports both single-locale and multi-locale formats.**\n\nSystem automatically detects the format based on the structure of the object:\n\n**Without Locales Format**: Direct field properties (e.g., `name`, `position`, `bio`)\n**With Locales Format**: Locale codes as keys (e.g., `en`, `es`, `fr`)\n\n**Dynamic Schema**: Field names and types are completely user-defined based on your collection configuration.\n",
              "additionalProperties": true
            },
            "minItems": 1,
            "example": [
              {
                "name": "John Smith",
                "position": "Senior Developer",
                "email": "john@company.com"
              }
            ]
          }
        }
      },
      "UpdateCollectionItemRequest": {
        "type": "object",
        "description": "**Flexible request schema for updating collection items - supports both single-locale and multi-locale formats.**\n\n**Update Types**:\n- **PUT**: Requires `fields` for full replacement\n- **PATCH**: `fields` is optional for partial updates (e.g., status-only updates)\n",
        "properties": {
          "status": {
            "$ref": "#/components/schemas/CreateCollectionItemRequest/properties/status",
            "description": "Publication status of the collection item.\n\n- If omitted in PATCH requests, the current status is preserved\n- If provided in PUT/PATCH requests, the status will be updated\n"
          },
          "fields": {
            "type": "object",
            "description": "**Optional for PATCH, Required for PUT**. Collection item field data with flexible format support.\n\nSystem automatically detects the format based on the structure of the object:\n\n**Without Locales Format**: Direct field properties (e.g., `name`, `position`, `bio`)\n**With Locales Format**: Locale codes as keys (e.g., `en`, `es`, `fr`)\n\n**Update Behavior**:\n- **PUT**: All fields should be provided (full replacement)\n- **PATCH**: Only provided fields are updated, others remain unchanged\n\n**Dynamic Schema**: Field names and types are completely user-defined based on your collection configuration.\n\n**Reference Fields**: Support updating relationships to Pages and other Collections\n- Page references: Use page slugs (e.g., `\"related_page\": \"example-slug\"`)\n- Collection references: Use collection item IDs (e.g., `\"tags\": [1, 2, 3]`)\n- Remove references: Use `\"\"`, `[]`, or `null`\n\n**Media Fields**: Support remote URL upload - content is automatically uploaded to ButterCMS\n",
            "additionalProperties": true,
            "example": {
              "name": "Updated Team Member Name",
              "position": "Lead Developer",
              "bio": "Updated biography content"
            }
          }
        }
      },
      "CreateCollectionItemResponse": {
        "type": "object",
        "description": "Response for successful collection item creation (202 Accepted)",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "pending"
            ],
            "description": "Indicates that the collection item creation is being processed asynchronously",
            "example": "pending"
          }
        }
      },
      "UpdateSuccessResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "pending"
            ],
            "description": "Indicates that the collection item update request has been accepted and is being processed asynchronously",
            "example": "pending"
          }
        },
        "example": {
          "status": "pending"
        }
      },
      "CreateBlogPostRequest": {
        "type": "object",
        "description": "Request schema for creating a new blog post",
        "required": [
          "title"
        ],
        "properties": {
          "title": {
            "type": "string",
            "description": "The title of the blog post",
            "maxLength": 200,
            "example": "This is a blog post"
          },
          "slug": {
            "type": "string",
            "description": "The slug of the blog post (must be unique).\n\n**Auto-Generation**: If not provided, the slug will be automatically generated from the title using unicode slugification. You can provide a custom slug or let the API generate one for you.\n",
            "maxLength": 100,
            "example": "this-is-a-blog-post"
          },
          "status": {
            "type": "string",
            "description": "The status of the post. Defaults to 'draft'. Cannot be 'scheduled'.",
            "enum": [
              "draft",
              "published"
            ],
            "default": "draft",
            "example": "published"
          },
          "author": {
            "type": "object",
            "description": "Author reference for blog posts. Author must exist in your account prior to POST.\n\nYou can specify the author either by email or by slug. If no author is specified, defaults to the organization owner.\n",
            "oneOf": [
              {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "description": "Email address of the existing author",
                    "example": "your@author.com"
                  }
                }
              },
              {
                "type": "object",
                "required": [
                  "slug"
                ],
                "properties": {
                  "slug": {
                    "type": "string",
                    "description": "Slug of the existing author",
                    "example": "firstname-lastname"
                  }
                }
              }
            ]
          },
          "categories": {
            "type": "array",
            "description": "Array of category names. Categories will be created if they don't exist.",
            "items": {
              "type": "string"
            },
            "example": [
              "Recipes",
              "Meals"
            ]
          },
          "tags": {
            "type": "array",
            "description": "Array of tag names. Tags will be created if they don't exist.",
            "items": {
              "type": "string"
            },
            "example": [
              "Butter",
              "Sushi",
              "Really Good Recipes"
            ]
          },
          "featured_image": {
            "type": "string",
            "format": "uri",
            "description": "Can be a remote URL to an image.\n\nThe image will always be uploaded to the media library (the value of `upload_images_to_media_library` is ignored for featured images).\n",
            "example": "https://farm1.staticflickr.com/836/42903355654_8faa21171a_m_d.jpg"
          },
          "featured_image_alt": {
            "type": "string",
            "description": "Alt text for the featured image",
            "maxLength": 250,
            "example": "Featured image alt text example."
          },
          "body": {
            "type": "string",
            "description": "Should be a string of escaped HTML.\n\nIn case it contains any remote URLs to images, the `upload_images_to_media_library` flag controls the behavior.\n",
            "example": "<h1>Butter</h1><p>I am so hungry!</p>"
          },
          "summary": {
            "type": "string",
            "description": "Plain-text summary of the blog post",
            "maxLength": 2000,
            "example": "This is a blog post summary."
          },
          "seo_title": {
            "type": "string",
            "description": "SEO title for HTML title tag",
            "maxLength": 100,
            "example": "This is a blog post"
          },
          "meta_description": {
            "type": "string",
            "description": "Meta description for SEO and social sharing",
            "example": "This is a blog post to test the API."
          },
          "upload_images_to_media_library": {
            "type": "boolean",
            "description": "Defaults to `false`.\n\nIf set to `true`, any image URLs in the `body` property will be uploaded to the Butter Media Library and the original URL will be replaced with the media library URL.\n\n**Note**: Featured images are always uploaded regardless of this setting.\n",
            "default": false,
            "example": false
          }
        }
      },
      "UpdateBlogPostRequest": {
        "type": "object",
        "description": "Request schema for updating an existing blog post. All fields are optional for partial updates.\n\n**Note**: If `scheduled` timestamp or `status: \"scheduled\"` are provided, they will be ignored and warning messages will be included in the response.\n",
        "properties": {
          "title": {
            "type": "string",
            "description": "The title of the blog post",
            "maxLength": 200,
            "example": "Updated Blog Post Title"
          },
          "slug": {
            "type": "string",
            "description": "The slug of the blog post.\n\n**Auto-Slugification**: The API automatically converts your input to a valid slug format using unicode slugification.\n",
            "maxLength": 100,
            "example": "updated-blog-post-slug"
          },
          "status": {
            "type": "string",
            "description": "The status of the post.\n\n**Note**: `\"scheduled\"` status will be ignored and a warning message will be included in the response.\n",
            "enum": [
              "draft",
              "published",
              "scheduled"
            ],
            "example": "published"
          },
          "author": {
            "$ref": "#/components/schemas/CreateBlogPostRequest/properties/author"
          },
          "categories": {
            "type": "array",
            "description": "Array of category names. Categories will be created if they don't exist.",
            "items": {
              "type": "string"
            },
            "example": [
              "Updated Category",
              "New Category"
            ]
          },
          "tags": {
            "type": "array",
            "description": "Array of tag names. Tags will be created if they don't exist.",
            "items": {
              "type": "string"
            },
            "example": [
              "updated",
              "refresh",
              "api"
            ]
          },
          "featured_image": {
            "type": "string",
            "format": "uri",
            "description": "Can be a remote URL to an image.\n\nThe image will always be uploaded to the media library (the value of `upload_images_to_media_library` is ignored for featured images).\n",
            "example": "https://example.com/updated-featured-image.jpg"
          },
          "featured_image_alt": {
            "type": "string",
            "description": "Alt text for the featured image",
            "maxLength": 250,
            "example": "Updated featured image alt text."
          },
          "body": {
            "type": "string",
            "description": "Should be a string of escaped HTML.\n\nIn case it contains any remote URLs to images, the `upload_images_to_media_library` flag controls the behavior.\n",
            "example": "<h1>Updated Content</h1><p>This blog post was updated via API</p>"
          },
          "summary": {
            "type": "string",
            "description": "Plain-text summary of the blog post",
            "maxLength": 2000,
            "example": "Updated summary of the blog post."
          },
          "seo_title": {
            "type": "string",
            "description": "SEO title for HTML title tag",
            "maxLength": 100,
            "example": "Updated SEO Title"
          },
          "meta_description": {
            "type": "string",
            "description": "Meta description for SEO and social sharing",
            "example": "Updated meta description for better SEO."
          },
          "upload_images_to_media_library": {
            "type": "boolean",
            "description": "Defaults to `false`.\n\nIf set to `true`, any image URLs in the `body` property will be uploaded to the Butter Media Library and the original URL will be replaced with the media library URL.\n\n**Note**: Featured images are always uploaded regardless of this setting.\n",
            "default": false,
            "example": true
          },
          "scheduled": {
            "type": "string",
            "format": "date-time",
            "description": "**Note**: This field will be ignored - scheduled timestamps cannot be created or altered via write API.\n\nIf provided, this field will be removed from the request and a warning message will be included in the response.\n",
            "example": "2024-12-25T10:00:00Z"
          }
        }
      },
      "BlogPostCreateSuccessResponse": {
        "type": "object",
        "description": "Success response for blog post creation (202 Accepted)",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "pending"
            ],
            "description": "Indicates that the blog post creation is being processed asynchronously",
            "example": "pending"
          }
        }
      },
      "BlogPostUpdateSuccessResponse": {
        "type": "object",
        "description": "Success response for blog post updates (202 Accepted). May include warning messages for ignored fields.\n",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "pending"
            ],
            "description": "Indicates that the blog post update is being processed asynchronously",
            "example": "pending"
          },
          "warning: scheduled field": {
            "type": "string",
            "description": "Warning message when scheduled field is ignored",
            "example": "Scheduled timestamps cannot be created or altered via write API. This field will be ignored."
          },
          "warning: status field": {
            "type": "string",
            "description": "Warning message when scheduled status is ignored",
            "example": "A blog post's status cannot be set as `scheduled` via write API at this time. This field will be ignored."
          }
        },
        "additionalProperties": {
          "type": "string",
          "description": "Additional warning messages for other ignored fields"
        }
      }
    },
    "responses": {
      "UnauthorizedWriteResponse": {
        "description": "**Unauthorized - Invalid or Missing Write API Token**\n\nNo valid write API key provided. The API token you use for reading from the ButterCMS API\nwill not allow you to create content. You need a different write-enabled token.\nContact support@buttercms.com to get yours.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "detail": "Authentication credentials were not provided"
            }
          }
        }
      },
      "NoContentResponse": {
        "description": "Operation completed successfully - No content returned"
      },
      "CollectionItemAcceptedResponse": {
        "description": "Collection item operation accepted for async processing",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "string",
                  "enum": [
                    "pending"
                  ],
                  "description": "Indicates the request was accepted and is being processed asynchronously",
                  "example": "pending"
                }
              }
            },
            "example": {
              "status": "pending"
            }
          }
        }
      }
    },
    "parameters": {
      "auth_token": {
        "name": "auth_token",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string"
        },
        "description": "Your ButterCMS read API token\n",
        "example": "your_api_token"
      },
      "locale": {
        "name": "locale",
        "in": "query",
        "description": "Set to the api slug of your configured locale (e.g. `en` or `fr`). When omitted, this query parameter will default to your organization's default locale.\n",
        "required": false,
        "schema": {
          "type": "string",
          "maxLength": 10,
          "example": "en"
        },
        "examples": {
          "english": {
            "value": "en",
            "description": "English locale"
          },
          "spanish": {
            "value": "es",
            "description": "Spanish locale"
          },
          "french": {
            "value": "fr",
            "description": "French locale"
          }
        }
      }
    }
  },
  "security": [
    {
      "writeTokenAuth": []
    }
  ]
}
