openapi: 3.1.0
info:
  title: ApostropheCMS REST API
  description: |
    **🚀 Developer freedom. Editor happiness. It just works.**

    **For production use:** Download this YAML file and update the server URL
    and cookie names to match your setup.

    The ApostropheCMS REST API allows you to create, read, update, and delete content programmatically.
    Perfect for building modern websites, mobile apps, and any digital experience that needs flexible content management.

    ## Quick Start Guide
    1. **Authentication**: Use the login endpoint to get a bearer token or session cookie
    2. **Get Content**: Start with `/@apostrophecms/page` to fetch your page structure
    3. **Media Files**: Upload files via `/@apostrophecms/attachment/upload`
    4. **Internationalization**: Use `/@apostrophecms/i18n` to localize your content

    ## Content Architecture
    ApostropheCMS uses a flexible "pieces" system for content types. While the core system provides
    essential pieces like users and global content, most projects define custom piece types like
    articles, events, or products using the `@apostrophecms/piece-type` module.

    ## Built-in Piece Types
    - `@apostrophecms/user` - User accounts and profiles
    - `@apostrophecms/global` - Site-wide content (customizable with additional fields)
    - `@apostrophecms/image` - Image file management
    - `@apostrophecms/file` - General file management (PDFs, documents, etc.)

    ## Built-in Tag Types
    - `@apostrophecms/image-tag` - Tags for organizing images
    - `@apostrophecms/file-tag` - Tags for organizing files

    ## Authentication Methods
    - **Bearer Token**: Recommended for API clients and SPAs
    - **Session Cookie**: For traditional web applications
    - **API Key**: For server-to-server communication

    ## Rate Limiting
    API requests are rate-limited to prevent abuse. See response headers for current limits.

  version: 1.0.0
  contact:
    name: ApostropheCMS Support
    url: https://apostrophecms.com
    email: support@apostrophecms.com
  license:
    name: MIT
    url: https://github.com/apostrophecms/apostrophe/blob/main/packages/apostrophe/LICENSE.md

externalDocs:
  description: Full Documentation
  url: "https://docs.apostrophecms.org"

x-apostrophe:
  cmsVersion: ">=4.20.0"
  notes: |
    Spec versioning follows semver independently of CMS releases.
  isCore: true

  # Used by the expander to control localization flags & nicer names.
  pieceTypes:
    standard:
      - '@apostrophecms/image'
      - '@apostrophecms/file'
      - '@apostrophecms/image-tag'
      - '@apostrophecms/file-tag'
      - '@apostrophecms/submitted-draft'

    nonLocalizable:
      - '@apostrophecms/user'
      - '@apostrophecms/global'

  marketingTags:
    '@apostrophecms/image': Media
    '@apostrophecms/file': Media
    '@apostrophecms/image-tag': Media
    '@apostrophecms/file-tag': Media
    '@apostrophecms/user': Users
    '@apostrophecms/global': Global Content
    '@apostrophecms/submitted-draft': Submitted Draft

  # 👇 fallback for any piece not listed above
  defaultPieceMarketingTag: Custom

  # adds the module name as a second tag
  includeTechnicalTag: true

security:
  # adds session authentication as the default
  - SessionAuth: []

servers:
  - url: http://localhost:3000/api/v1
    description: Development server
  - url: https://your-site.com/api/v1
    description: Production server (not for online use)

tags:
  - name: Authentication
    description: 🚀 Login, logout, and session management for API access - start here!
  - name: Pages
    description: 🚀 Essential for headless sites - page structure, content, and navigation
  - name: Users
    description: Built-in user management and authentication
  - name: Global Content
    description: Site-wide settings and content that appears across pages
  - name: Submitted Drafts
    description: Draft submission workflow and review queue management
  - name: Media
    description: File uploads, image management, and media organization
  - name: Attachments
    description: File upload utilities and image processing
  - name: Internationalization
    description: Multi-language support and locale management
  - name: Custom
    description: Project-defined piece types (your own content models)

x-tagGroups:
  - name: Start Here
    tags: [Authentication]
  - name: Content & Media
    tags: [Pages, Global Content, Submitted Draft, Media, Attachments]
  - name: People
    tags: [Users]
  - name: Internationalization
    tags: [Internationalization]
  - name: Custom
    tags: [Custom]

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: query
      name: apikey
      description: |
        **Server-to-server authentication** - API key for server-to-server communication.
        Use as query parameter: ?apikey=your-api-key-here

        Configure in app.js:
        ```javascript
        '@apostrophecms/express': {
          options: {
            apiKeys: {
              'myapikey1029384756': { role: 'admin' }
            }
          }
        }
        ```

    BearerAuth:
      type: http
      scheme: bearer
      description: |
        Bearer token authentication (recommended for API clients).

        **Step 1:** Close this dialog box and generate a bearer token using the `POST /@apostrophecms/login/login` endpoint below with:
        ```json
        {
          "username": "your-username",
          "password": "your-password"
        }
        ```

        **Step 2:** Copy **only the token value** from the response (not the full JSON)
        Example: if response is `{"token": "abc123"}`, paste only `abc123`
        The token will be sent as: Authorization: Bearer {your-token}

        **Step 3:** Reopen this dialog and paste the token value into the value field.

    SessionAuth:
      type: apiKey
      in: cookie
      name: project-shortname.sid
      description: |
        ⚠️ **For testing after download only:** Change "project-shortname" in the `SessionAuth` to your actual ApostropheCMS shortname (e.g., "myapp.sid").

        💡 This authentication won't work when testing in the online ApostropheCMS sandbox. However, you can use the login route to set a cookie you can examine in your browser DevTools.
        It will be named `project-shortname.sid`.

        **Step 1:** Close this dialog and use the `POST /@apostrophecms/login/login` endpoint below with:
        ```json
        {
          "username": "your-username",
          "password": "your-password",
          "session": true
        }
        ```

        **Step 2:** Copy the session cookie value from your browser's dev tools
        and paste it into the "Value" field.

  parameters:
    Page:
      name: page
      in: query
      description: Page number for pagination (1-based)
      required: false
      schema:
        type: integer
        minimum: 1
        default: 1
      example: 2

    PerPage:
      name: perPage
      in: query
      description: Number of items per page
      required: false
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 10
      example: 25

    Search:
      name: search
      in: query
      description: Search term for filtering results
      required: false
      schema:
        type: string
      example: "headless cms"

    Autocomplete:
      name: autocomplete
      in: query
      description: Partial word search for autocomplete functionality
      required: false
      schema:
        type: string
      example: "apost"

    AposMode:
      name: aposMode
      in: query
      description: Request draft or published version of content
      required: false
      schema:
        type: string
        enum: [draft, published]
        default: published
      example: "published"

    AposLocale:
      name: aposLocale
      in: query
      description: Locale for internationalization (e.g., 'en', 'fr', 'es')
      required: false
      schema:
        type: string
        example: "fr"

    ToLocale:
      name: toLocale
      in: path
      required: true
      description: Target locale code (e.g., en:us:published)
      schema:
        type: string
        pattern: '^[a-z]{2}(-[A-Z]{2})?$'
        example: en

    RenderAreas:
      name: render-areas
      in: query
      description: 💡 Render widget areas as HTML instead of returning raw widget data - useful for hybrid architectures
      required: false
      schema:
        type: boolean
        default: false
      example: true

    DocumentId:
      name: _id
      in: path
      required: true
      description: Computed document ID (can optionally include mode and locale, e.g., id:en:published)
      schema:
        type: string
        pattern: '^\S+$'
        example: "ckitdo5oq004pu69kr6oxo6fr:en:published"

    AposDocId:
      name: aposDocId
      in: path
      required: true
      description: ApostropheCMS document identifier
      schema:
        type: string
        pattern: '^[a-zA-Z0-9]+$'
        example: "ckitdo5oq004pu69kr6oxo6fr"

    ImageDocId:
      name: imageId
      in: path
      required: true
      description: ApostropheCMS document identifier for an image
      schema:
        type: string
        pattern: '^[a-zA-Z0-9]+$'
        example: "ck9x8v7w2000001l6h8q9d5f0"

    AllPages:
      name: all
      in: query
      description: Return all pages the requester can see (system/orphan pages included). Use with caution for large sites. Default is 0.
      schema:
        type: integer
        enum: [0,1]
        default: 0
      example: 1

    FlatResponse:
      name: flat
      in: query
      description: 💡 Return pages in flat array instead of tree structure - easier for some use cases. Default is 0 (nested).
      schema:
        type: integer
        enum: [0,1]
        default: 0
      example: 1

    ChildrenParam:
      name: children
      in: query
      description: Include children array in response (set to 'false' to exclude). Default is true.
      schema:
        type: boolean
        default: true
      example: false

  schemas:
    _Overview_Fields:
      type: object
      description: |
        # Field Types (editor-facing)

        - `StringField` — basic text
        - `IntegerField`, `FloatField` — numbers
        - `SelectField`, `RadioField`, `CheckboxesField` — choices
        - `AreaField`, `ArrayField`, `ObjectField`
        - `AttachmentField`, `RelationshipField`, `RelationshipReverseField`

        👉 See also: **FieldDefinition** (discriminator: `type`).
      externalDocs:
        description: ApostropheCMS Field Guide
        url: https://docs.apostrophecms.org/reference/field-types/
      title: _Overview_Fields
    _Overview_Primitives:
      type: object
      description: |
        # Content Primitives (payload-level)

        These are the “data atoms” for requests and responses.

        - `AposString`, `AposSlug`, `AposUrl`, `AposEmail`
        - `AposDateTime`, `AposDate`, `AposTime`
        - Arrays: `AposStringArray`, `AposIntegerArray`, etc.

        👉 Defined under **AposPrimitives**.
      title: _Overview_Primitives
    _Overview_Advanced:
      type: object
      description: |
        # Advanced / Internal

        Used by OpenAPI for schema defs:
        - `UiCondition` (for `if`/`requiredIf`)
        - `OperatorObject` (query operators)
        - `AreaOptions`, `ArrayOptions`, and other config helpers
      title: _Overview_Advanced
    AreaField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - type: object
        additionalProperties: false
        properties:
          type:
            type: string
            enum:
            - area
            description: Apostrophe field type id.
          options:
            $ref: '#/components/schemas/AreaOptions'
          if:
            $ref: '#/components/schemas/UiCondition'
          requiredIf:
            $ref: '#/components/schemas/UiCondition'
        required:
        - type
        - label
        - options
        examples:
        - type: area
          label: Main content
          options:
            max: 3
            expanded: true
            widgets:
              '@apostrophecms/image': {}
              '@apostrophecms/rich-text':
                toolbar:
                - bold
                - italic
              '@apostrophecms/video': {}
              '@apostrophecms/html': {}
            groups:
              basics:
                label: Basic Content
                columns: 3
                widgets:
                  '@apostrophecms/rich-text':
                    toolbar:
                    - bold
                  '@apostrophecms/image': {}
              embeds:
                label: Embeds
                columns: 2
                widgets:
                  '@apostrophecms/video': {}
                  '@apostrophecms/html': {}
      title: AreaField
    AreaOptions:
      type: object
      additionalProperties: false
      properties:
        widgets:
          description: |
            Allowed widget types for this area. Keys are widget module names (e.g., "@apostrophecms/rich-text"). Values are per-widget options that apply *only* in this area.
          type: object
          additionalProperties:
            type: object
        groups:
          description: |
            Organize widgets into groups for the expanded preview menu.
            Each group has a label, optional columns (1–4, default 3), and its own widgets map (same shape as `widgets`).
          type: object
          additionalProperties:
            $ref: '#/components/schemas/AreaWidgetGroup'
        max:
          type: integer
          description: Maximum number of widgets allowed in this area.
        expanded:
          type: boolean
          description: Use the expanded preview menu UX.
      required:
      - widgets
      title: AreaOptions
    AreaWidgetGroup:
      type: object
      additionalProperties: false
      properties:
        label:
          type: string
        columns:
          type: integer
          minimum: 1
          maximum: 4
          description: Number of widget previews per row (default 3).
        widgets:
          type: object
          additionalProperties:
            type: object
      required:
      - label
      - widgets
      title: AreaWidgetGroup
    ArrayField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - type: object
        additionalProperties: false
        description: A repeatable list of objects, each with its own field schema.
        properties:
          type:
            type: string
            enum:
            - array
            description: Apostrophe field type id.
          fields:
            $ref: '#/components/schemas/Fieldset'
          min:
            type: integer
            description: Minimum number of items (inclusive).
          max:
            type: integer
            description: Maximum number of items (inclusive).
          titleField:
            type: string
            description: Field name in each item used as the item label in the UI.
          if:
            $ref: '#/components/schemas/UiCondition'
          requiredIf:
            $ref: '#/components/schemas/UiCondition'
        required:
        - type
        - label
        - fields
        examples:
        - type: array
          label: Tasks
          min: 0
          max: 50
          titleField: title
          items:
            type: object
            properties:
              title:
                type: string
              priority:
                type: string
          fields:
            add:
              title:
                type: string
                label: Task Title
              priority:
                type: select
                label: Priority
                choices:
                - label: Low
                  value: low
                - label: High
                  value: high
      title: ArrayField
    AttachmentField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - type: object
        additionalProperties: false
        description: |
          Lets editors upload a single file (image, PDF, etc.).
          Use an ArrayField of AttachmentField if you need multiple files.
        properties:
          type:
            type: string
            enum:
            - attachment
            description: Apostrophe field type id.
          accept:
            oneOf:
            - type: string
              description: HTML "accept" string (e.g., "image/*,.pdf"). Use to limitby MIME type and/or extension.
            - type: array
              items:
                type: string
              description: List of MIME types and/or extensions (e.g., ["image/*",
                ".pdf"]).
          maxSize:
            type: integer
            description: Optional max file size in bytes (documentation-only hint).
          if:
            $ref: '#/components/schemas/UiCondition'
          requiredIf:
            $ref: '#/components/schemas/UiCondition'
        required:
        - type
        - label
        examples:
        - type: attachment
          label: Resume (PDF)
          accept:
          - .pdf
          required: true
        - type: attachment
          label: Hero Image
          accept: image/*
      title: AttachmentField
    BooleanField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - type: object
        additionalProperties: false
        properties:
          type:
            type: string
            enum:
            - boolean
            description: Apostrophe field type id.
          def:
            type: boolean
            description: Default value shown in the editor UI.
          toggle:
            oneOf:
            - type: boolean
              description: |
                If true, use the alternate "toggle" UI. 
                Labels default to the field label and standard true/false text.
            - type: object
              additionalProperties: false
              description: Configure custom labels for the toggle UI.
              properties:
                'true':
                  type: string
                  description: Label to display when value is true.
                'false':
                  type: string
                  description: Label to display when value is false.
        required:
        - type
        - label
        examples:
        - type: boolean
          label: Is this a special item?
          def: false
        - type: boolean
          label: Show related articles?
          toggle:
            'true': Show related articles
            'false': Hide related articles
      title: BooleanField
    CheckboxesField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - type: object
        additionalProperties: false
        properties:
          type:
            type: string
            enum:
            - checkboxes
            description: Apostrophe field type id.
          def:
            type: array
            items:
              oneOf:
              - type: string
              - type: number
              - type: boolean
            description: Default selected values.
          choices:
            oneOf:
            - type: array
              description: Static choices for the checkboxes.
              items:
                $ref: '#/components/schemas/SelectChoice'
            - type: string
              description: Method name that provides choices dynamically.
          following:
            oneOf:
            - type: string
            - type: array
              items:
                type: string
            description: Populate dynamically based on other fields (supports `<` parent prefixes).
          followingIgnore:
            oneOf:
            - type: boolean
            - type: array
              items:
                type: string
            description: Ignore some or all followed fields when generating values.
          if:
            $ref: '#/components/schemas/UiCondition'
          requiredIf:
            $ref: '#/components/schemas/UiCondition'
        required:
        - type
        - label
        - choices
        examples:
        - type: checkboxes
          label: Tags
          choices:
          - label: News
            value: news
          - label: Blog
            value: blog
          - label: Events
            value: events
          def:
          - news
          - events
      title: CheckboxesField
    ColorField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - type: object
        additionalProperties: false
        properties:
          type:
            type: string
            enum:
            - color
            description: Apostrophe field type id.
          def:
            type: string
            pattern: ^#(?:[0-9a-fA-F]{3}){1,2}$
            description: Default hex color (e.g. "#ff0000").
          if:
            $ref: '#/components/schemas/UiCondition'
          requiredIf:
            $ref: '#/components/schemas/UiCondition'
        required:
        - type
        - label
        examples:
        - type: color
          label: Theme Color
          def: '#336699'
      title: ColorField
    DateField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - $ref: '#/components/schemas/DateBoundaryOptions'
      - type: object
        additionalProperties: false
        properties:
          type:
            type: string
            enum:
            - date
            description: Apostrophe field type id.
          def:
            type: string
            format: date
            description: Default date shown in the editor UI (YYYY-MM-DD).
          if:
            $ref: '#/components/schemas/UiCondition'
          requiredIf:
            $ref: '#/components/schemas/UiCondition'
        required:
        - type
        - label
        examples:
        - type: date
          label: Publish Date
          def: '2025-01-01'
          min: '2020-01-01'
          max: '2030-12-31'
        - type: date
          label: Event Date
          if:
            status:
              $eq: scheduled
      title: DateField
    DateAndTimeField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - $ref: '#/components/schemas/DateTimeBoundaryOptions'
      - type: object
        additionalProperties: false
        properties:
          type:
            type: string
            enum:
            - dateAndTime
            description: Apostrophe field type id.
          def:
            type: string
            format: date-time
            description: Default timestamp in RFC 3339 format (e.g., 2025-08-29T13:00:00Z).
          if:
            $ref: '#/components/schemas/UiCondition'
          requiredIf:
            $ref: '#/components/schemas/UiCondition'
        required:
        - type
        - label
        examples:
        - type: dateAndTime
          label: Starts At
          def: '2025-08-29T13:00:00Z'
          min: '2024-01-01T00:00:00Z'
          max: '2026-12-31T23:59:59Z'
        - type: dateAndTime
          label: Reminder At
          requiredIf:
            remindersEnabled: true
      title: DateAndTimeField
    EmailField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - type: object
        additionalProperties: false
        properties:
          type:
            type: string
            enum:
            - email
            description: Apostrophe field type id.
          def:
            type: string
            format: email
            description: Default email address shown in the editor UI.
          pattern:
            type: string
            description: Optional regex for stricter validation (in addition to HTML5
              email validation).
          autocomplete:
            type: string
            description: Value for the HTML autocomplete attribute. Common values are
              "email" or "off".
          if:
            $ref: '#/components/schemas/UiCondition'
          requiredIf:
            $ref: '#/components/schemas/UiCondition'
        required:
        - type
        - label
        examples:
        - type: email
          label: Contact Email
          def: info@example.com
        - type: email
          label: Support Email
          autocomplete: email
          requiredIf:
            supportEnabled: true
      title: EmailField
    FloatField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - $ref: '#/components/schemas/NumericRangeOptions'
      - type: object
        additionalProperties: false
        properties:
          type:
            type: string
            enum:
            - float
          format:
            type: string
            enum:
            - float
            description: OpenAPI hint for tooling; always "float".
          def:
            type: number
            format: float
            description: Default decimal value.
        examples:
        - type: float
          label: Price (USD)
          help: Enter a decimal price.
          def: 0.0
          min: 0
          max: 99999.99
          required: true
      title: FloatField
    IntegerField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - $ref: '#/components/schemas/NumericRangeOptions'
      - type: object
        additionalProperties: false
        properties:
          type:
            type: string
            enum:
            - integer
            description: Apostrophe field type id.
          def:
            type: integer
            description: Default integer value shown in the editor UI.
        required:
        - type
        - label
        examples:
        - type: integer
          label: Age
          min: 0
          max: 120
          def: 18
        - type: integer
          label: Estimated Hours
          min: 1
          max: 999
      title: IntegerField
    ObjectField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - type: object
        additionalProperties: false
        description: A nested object with its own field schema.
        properties:
          type:
            type: string
            enum:
            - object
          fields:
            $ref: '#/components/schemas/Fieldset'
          if:
            $ref: '#/components/schemas/UiCondition'
          requiredIf:
            $ref: '#/components/schemas/UiCondition'
        required:
        - type
        - label
        - fields
      title: ObjectField
    OembedField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - type: object
        additionalProperties: false
        properties:
          type:
            type: string
            enum:
            - oembed
            description: Apostrophe field type id.
          if:
            $ref: '#/components/schemas/UiCondition'
          requiredIf:
            $ref: '#/components/schemas/UiCondition'
        required:
        - type
        - label
        description: |
          Lets editors paste a media URL from an oEmbed-compatible host.
          The editor shows an immediate preview once a valid URL is entered.
          Stored value is an object snapshot (url/title/thumbnail).
        examples:
        - type: oembed
          label: Featured video
      title: OembedField
    PasswordField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - type: object
        additionalProperties: false
        properties:
          type:
            type: string
            enum:
            - password
            description: Apostrophe field type id.
          def:
            type: string
            description: Default password value (generally not used).
          min:
            type: integer
            description: Minimum number of characters required.
          max:
            type: integer
            description: Maximum number of characters allowed.
          pattern:
            type: string
            description: Regex to enforce password rules (e.g., at least one number).
          autocomplete:
            type: string
            description: HTML autocomplete attribute, usually "new-password" or "current-password".
          if:
            $ref: '#/components/schemas/UiCondition'
          requiredIf:
            $ref: '#/components/schemas/UiCondition'
        required:
        - type
        - label
        examples:
        - type: password
          label: Account Password
          min: 8
          autocomplete: new-password
      title: PasswordField
    RadioField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - type: object
        additionalProperties: false
        properties:
          type:
            type: string
            enum:
            - radio
            description: Apostrophe field type id.
          def:
            oneOf:
            - type: string
            - type: number
            - type: boolean
            description: Default selected value.
          choices:
            oneOf:
            - type: array
              description: Static choices to render as radio buttons.
              items:
                $ref: '#/components/schemas/SelectChoice'
            - type: string
              description: Method name that provides choices (e.g. "statusChoices").
          following:
            oneOf:
            - type: string
            - type: array
              items:
                type: string
            description: Populate dynamically based on other fields (supports `<` parent prefixes).
          followingIgnore:
            oneOf:
            - type: boolean
            - type: array
              items:
                type: string
            description: Ignore some or all followed fields when generating values.
          if:
            $ref: '#/components/schemas/UiCondition'
          requiredIf:
            $ref: '#/components/schemas/UiCondition'
        required:
        - type
        - label
        - choices
        examples:
        - type: radio
          label: Priority
          choices:
          - label: Low
            value: low
          - label: High
            value: high
          def: low
        - type: radio
          label: Status
          choices: statusChoices
      title: RadioField
    RangeField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - $ref: '#/components/schemas/NumericRangeOptions'
      - type: object
        additionalProperties: false
        properties:
          type:
            type: string
            enum:
            - range
            description: Apostrophe field type id.
          def:
            type: number
            description: Default slider value in the editor UI.
          step:
            type: number
            description: Increment step for the slider. If omitted, defaults to 1.
          min:
            type: number
            description: Minimum value for the slider.
          max:
            type: number
            description: Maximum value for the slider.
          if:
            $ref: '#/components/schemas/UiCondition'
          requiredIf:
            $ref: '#/components/schemas/UiCondition'
        required:
        - type
        - label
        examples:
        - type: range
          label: Satisfaction
          min: 1
          max: 10
          step: 1
          def: 5
        - type: range
          label: Volume
          min: 0
          max: 100
          step: 5
          def: 50
      title: RangeField
    RelationshipField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - type: object
        additionalProperties: false
        description: |
          Relate this document to one or more docs of another type (pieces/pages).
          Use `max: 1` for a single-select join; omit `max` (or set >1) for multi-select.
        properties:
          type:
            type: string
            enum:
            - relationship
            description: Apostrophe field type id.
          withType:
            type: string
            description: Module name of the related doc type (e.g., "article", "@apostrophecms/image").
          min:
            type: integer
            description: Minimum number of related docs required (inclusive).
          max:
            type: integer
            description: Maximum number of related docs allowed (inclusive).
          fields:
            $ref: '#/components/schemas/Fieldset'
          builders:
            type: object
            additionalProperties: true
            description: |
              Apostrophe cursor builders for the related query (e.g., {project: { title: 1 }, sort: { title: 1 } }).
          if:
            $ref: '#/components/schemas/UiCondition'
          requiredIf:
            $ref: '#/components/schemas/UiCondition'
        required:
        - type
        - label
        - withType
        examples:
        - type: relationship
          label: Author
          withType: person
          max: 1
          builders:
            project:
              title: 1
              _url: 1
        - type: relationship
          label: Related Articles
          withType: article
          min: 0
          max: 5
          fields:
            add:
              relationshipRole:
                type: select
                label: Role
                choices:
                - label: Primary
                  value: primary
                - label: Secondary
                  value: secondary
          builders:
            project:
              title: 1
              _url: 1
            sort:
              title: 1
      title: RelationshipField
    RelationshipReverseField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - type: object
        additionalProperties: false
        description: |
          Read-only reverse side of a forward `relationship` field defined on another type.
          Use this to show “referenced by” links without storing ids here.
        properties:
          type:
            type: string
            enum:
            - relationshipReverse
            description: Apostrophe field type id.
          withType:
            type: string
            description: Module name that holds the forward relationship.
          reverseOf:
            type: string
            description: |
              Name of the forward relationship field on `withType` (e.g.,"_authors" on "article").
          builders:
            type: object
            additionalProperties: true
            description: Cursor builders applied when populating the reverse join.
          if:
            $ref: '#/components/schemas/UiCondition'
          requiredIf:
            $ref: '#/components/schemas/UiCondition'
        required:
        - type
        - label
        - withType
        - reverseOf
        examples:
        - type: relationshipReverse
          label: Articles referencing this person
          withType: article
          reverseOf: _authors
          builders:
            project:
              title: 1
              _url: 1
      title: RelationshipReverseField
    SelectField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - type: object
        additionalProperties: false
        properties:
          type:
            type: string
            enum:
            - select
            description: Apostrophe field type id.
          def:
            oneOf:
            - type: string
            - type: number
            - type: boolean
            - type: array
              items:
                oneOf:
                - type: string
                - type: number
                - type: boolean
            description: |
              Default value. If `multiple: true`, this should be an array.
          multiple:
            type: boolean
            description: Allow selecting multiple values (stores an array).
          choices:
            oneOf:
            - type: array
              description: Static choices for the select dropdown.
              items:
                $ref: '#/components/schemas/SelectChoice'
            - type: string
              description: |
                Name of a method that returns choices (e.g. "sponsorNames").
                May be "module:method" to reference another module.
          following:
            oneOf:
            - type: string
            - type: array
              items:
                type: string
            description: Populate dynamically based on other fields’ values (supports `<` parent prefixes).
          followingIgnore:
            oneOf:
            - type: boolean
            - type: array
              items:
                type: string
            description: Ignore some or all followed fields when generating values.
        required:
        - type
        - label
        examples:
        - type: select
          label: Task Priority
          choices:
          - label: Low
            value: low
          - label: Medium
            value: medium
          - label: High
            value: high
          - label: Critical
            value: critical
          def: medium
        - type: select
          label: Tags
          multiple: true
          choices:
          - label: News
            value: news
          - label: Blog
            value: blog
          - label: Events
            value: events
          def:
          - news
          - events
        - type: select
          label: Sponsor
          choices: sponsorNames
          following:
          - <projectType
      title: SelectField
    SelectChoice:
      type: object
      additionalProperties: false
      properties:
        label:
          type: string
          description: Human-friendly label shown in UI.
        value:
          oneOf:
          - type: string
          - type: number
          - type: boolean
          description: The stored value for this choice.
        disabled:
          type: boolean
          description: If true, show but disable this option.
      required:
      - label
      - value
      title: SelectChoice
    SlugField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - type: object
        additionalProperties: false
        properties:
          type:
            type: string
            enum:
            - slug
            description: Apostrophe field type id.
          def:
            type: string
            description: Default slug value shown in the editor UI.
          prefix:
            type: string
            description: Optional prefix automatically prepended when generating the slug.
          source:
            type: string
            description: |
              Name of the field this slug should follow (usually "title").
              Works with `following`/`followingIgnore`.
          unique:
            type: boolean
            description: If true, ensures slug is unique across docs of this type.
          pattern:
            type: string
            description: Optional regex to further constrain allowed slugs.
          if:
            $ref: '#/components/schemas/UiCondition'
          requiredIf:
            $ref: '#/components/schemas/UiCondition'
        required:
        - type
        - label
        examples:
        - type: slug
          label: URL Slug
          source: title
          unique: true
          prefix: blog/
        - type: slug
          label: Custom Slug
          def: my-custom-page
      title: SlugField
    StringField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - type: object
        additionalProperties: false
        properties:
          type:
            type: string
            enum:
            - string
            description: Apostrophe field type id.
          def:
            type: string
            description: Default value shown in the editor UI.
          textarea:
            type: boolean
            description: If true, renders a multiline textarea UI.
          min:
            type: integer
            description: Minimum number of characters allowed.
          max:
            type: integer
            description: Maximum number of characters allowed.
          pattern:
            type: string
            description: |
              Regular expression (string form) to validate the input.
              Only matching values are allowed.
          autocomplete:
            type: string
            description: |
              Value of the HTML autocomplete attribute (see MDN). Use `"off"` to disable autocomplete.
          following:
            oneOf:
            - type: string
            - type: array
              items:
                type: string
            description: Field(s) to follow for automatic value generation. Supports `<` prefixes to access parent fields.
          followingIgnore:
            oneOf:
            - type: boolean
            - type: array
              items:
                type: string
            description: Controls which `following` values are ignored.
          sortify:
            type: boolean
            description: If true, creates a parallel “sortified” version of this field for case- and punctuation-insensitive sorting.
        required:
        - type
        - label
        examples:
        - type: string
          label: Dog Name
          def: Fido
        - type: string
          label: Biography
          textarea: true
          max: 800
        - type: string
          label: Meta Description
          following:
          - title
          - featured
          followingIgnore:
          - featured
          if:
            featured: true
      title: StringField
    TimeField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - type: object
        additionalProperties: false
        properties:
          type:
            type: string
            enum:
            - time
            description: Apostrophe field type id.
          def:
            type: string
            pattern: ^(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d$
            description: |
              Default value in HH:MM:SS (24-hour).
              If not set and not required, defaults to the current time.
          if:
            $ref: '#/components/schemas/UiCondition'
          requiredIf:
            $ref: '#/components/schemas/UiCondition'
        required:
        - type
        - label
        examples:
        - type: time
          label: Event Time
          def: '14:30:00'
        - type: time
          label: Reminder Time
      title: TimeField
    UrlField:
      allOf:
      - $ref: '#/components/schemas/BaseField'
      - type: object
        additionalProperties: false
        properties:
          type:
            type: string
            enum:
            - url
            description: Apostrophe field type id.
          def:
            type: string
            format: uri
            description: Default URL shown in the editor UI.
          pattern:
            type: string
            description: Optional regex for stricter validation of allowed URLs (in addition to standard URI syntax).
          autocomplete:
            type: string
            description: Value for the HTML autocomplete attribute. Common values include "url" or "off".
          if:
            $ref: '#/components/schemas/UiCondition'
          requiredIf:
            $ref: '#/components/schemas/UiCondition'
        required:
        - type
        - label
        examples:
        - type: url
          label: Website
          def: https://example.com
        - type: url
          label: LinkedIn Profile
          autocomplete: url
          requiredIf:
            hasLinkedIn: true
      title: UrlField
    Page:
      type: object
      description: An ApostropheCMS page document with hierarchical structure and content
        areas
      properties:
        _id:
          type: string
          description: Unique document identifier, may include mode and locale (e.g.,
            "id:en:published")
          example: ckhdscx5900054z9k88uqs16w:en:published
        aposDocId:
          type: string
          description: Base document ID without mode/locale qualifiers
          example: ckhdscx5900054z9k88uqs16w
        aposLocale:
          type: string
          description: Document locale code
          example: en
        aposMode:
          type: string
          description: Document mode (draft or published)
          enum:
          - draft
          - published
          example: published
        archived:
          type: boolean
          description: Whether the page is archived
          default: false
        createdAt:
          type: string
          format: date-time
          description: Page creation timestamp
          example: '2023-01-15T10:30:00.000Z'
        updatedAt:
          type: string
          format: date-time
          description: Page last update timestamp
          example: '2024-12-18T14:20:00.000Z'
        titleSortified:
          type: string
          description: Sortable version of the page title
          example: about us
        slug:
          type: string
          description: URL slug for the page
          example: /about-us
        path:
          type: string
          description: Full hierarchical path in the page tree
          example: /about-us
        rank:
          type: integer
          description: Sort order within parent page
          example: 0
        level:
          type: integer
          description: Depth level in the page tree (0 = root level)
          example: 1
        orphan:
          type: boolean
          description: Whether page is orphaned (not in tree structure)
          default: false
        parked:
          type: array
          description: Array of parking lot configurations if page is parked
          items:
            type: string
          example: []
        visibility:
          type: string
          description: Page visibility setting
          enum:
          - public
          - loginRequired
          - private
          default: public
          example: public
        type:
          type: string
          description: Page type module name
          example: '@apostrophecms/page'
        title:
          type: string
          description: Page title
          example: About Us
          maxLength: 100
        main:
          type: object
          description: Main content area with rich content widgets
          properties:
            metaType:
              type: string
              example: area
            items:
              type: array
              items:
                type: object
                properties:
                  metaType:
                    type: string
                    example: widget
                  type:
                    type: string
                    example: '@apostrophecms/rich-text'
                  aposPlaceholder:
                    type: boolean
                    default: false
                  content:
                    type: string
                    description: Widget content (varies by widget type)
                    example: <p>Welcome to our website!</p>
                  _id:
                    type: string
                    example: widget-id-123
        seoFields:
          type: object
          description: SEO metadata for the page
          properties:
            metaDescription:
              type: string
              description: Meta description for search engines
              maxLength: 160
              example: Learn about our company, mission, and values
            metaKeywords:
              type: string
              description: Meta keywords (legacy, rarely used)
              example: about, company, mission
            ogTitle:
              type: string
              description: Open Graph title for social sharing
              example: About Our Company
            ogDescription:
              type: string
              description: Open Graph description for social sharing
              example: Discover our story and what drives us forward
            ogImage:
              type: object
              description: Open Graph image for social sharing
              properties:
                _id:
                  type: string
                  example: image-id-456
                title:
                  type: string
                  example: Company Photo
                attachment:
                  type: object
                  properties:
                    _id:
                      type: string
                      example: attachment-789
                    name:
                      type: string
                      example: company-photo
                    extension:
                      type: string
                      example: jpg
                    _url:
                      type: string
                      example: /uploads/attachments/company-photo.jpg
        _ancestors:
          type: array
          description: Array of ancestor page IDs in the page tree hierarchy
          items:
            type: string
          example:
          - root-page-id
        _children:
          type: array
          description: Array of child pages (when requested with children parameter)
          items:
            $ref: '#/components/schemas/Page'
          example: []
        _url:
          type: string
          description: Full URL to the page
          example: https://example.com/about-us
          format: uri
        _edit:
          type: boolean
          description: Whether current user can edit this page
          example: true
        _publish:
          type: boolean
          description: Whether current user can publish this page
          example: true
        _publishedDoc:
          allOf:
          - $ref: '#/components/schemas/Page'
          - description: Published version of the page (when viewing drafts)
        _draftDoc:
          allOf:
          - $ref: '#/components/schemas/Page'
          - description: Draft version of the page (when viewing published)
      required:
      - _id
      - aposDocId
      - type
      - title
      - slug
      - path
      - level
      additionalProperties: true
      example:
        _id: ckhdscx5900054z9k88uqs16w:en:published
        aposDocId: ckhdscx5900054z9k88uqs16w
        aposLocale: en
        aposMode: published
        archived: false
        createdAt: '2023-01-15T10:30:00.000Z'
        updatedAt: '2024-12-18T14:20:00.000Z'
        titleSortified: about us
        slug: /about-us
        path: /about-us
        rank: 0
        level: 1
        orphan: false
        parked: []
        visibility: public
        type: '@apostrophecms/page'
        title: About Us
        main:
          metaType: area
          items:
          - metaType: widget
            type: '@apostrophecms/rich-text'
            aposPlaceholder: false
            content: <p>Welcome to our company! We've been serving customers since 2020.</p>
            _id: widget-123
        seoFields:
          metaDescription: Learn about our company, mission, and values
          ogTitle: About Our Company
          ogDescription: Discover our story and what drives us forward
        _ancestors:
        - root-page-id
        _children: []
        _url: https://example.com/about-us
        _edit: true
        _publish: true
      title: Page
    User:
      type: object
      description: |
        Built-in user piece type for account management.

        **Base Properties**: Inherited from @apostrophecms/piece-type
        **User-Specific Properties**: title, username, email, role, disabled

        💡 Developers can add custom fields to the user piece type in their project configuration.
      properties:
        _id:
          type: string
          description: Unique identifier
          example: clx1234567890abcdef
        title:
          type: string
          description: User's display name
          example: John Developer
        username:
          type: string
          description: Login username (must be unique)
          example: johndeveloper
        email:
          type: string
          format: email
          description: User's email address
          example: john@example.com
        role:
          type: string
          description: User role - determines permissions
          enum:
          - guest
          - contributor
          - editor
          - admin
          example: editor
        disabled:
          type: boolean
          description: Whether the user account is disabled
          default: false
        archived:
          type: boolean
          description: Whether the user is archived
          default: false
        visibility:
          type: string
          description: Visibility setting
          enum:
          - public
          - loginRequired
          default: loginRequired
        type:
          type: string
          example: '@apostrophecms/user'
        slug:
          type: string
          example: user-johndeveloper
        createdAt:
          type: string
          format: date-time
          description: Account creation date
        updatedAt:
          type: string
          format: date-time
          description: Last update date
      title: User
    Global:
      type: object
      description: |
        'Built-in global content piece type for site-wide settings.

        💡 Developers can add custom fields to the global piece type in their project
        configuration.
      properties:
        _id:
          type: string
          description: Unique identifier
          example: global
        title:
          type: string
          description: Default title field
          readOnly: true
          example: global
        slug:
          type: string
          description: Default slug field
          readOnly: true
          example: global
        type:
          type: string
          example: '@apostrophecms/global'
          readOnly: true
      additionalProperties: true
      title: Global
    GlobalPatch:
      type: object
      description: |
        Allows for patching of costom user added fields.
        It blocks the modification of the title, slu, and type fields.
      properties:
        title:
          type: string
          description: Default title field
          readOnly: true
          example: global
        slug:
          type: string
          description: Default slug field
          readOnly: true
          example: global
        type:
          type: string
          example: '@apostrophecms/global'
          readOnly: true
      additionalProperties: true
    Attachment:
      type: object
      description: File attachment information from upload endpoint
      properties:
        _id:
          type: string
          description: Unique attachment identifier
          example: ckj0akbxa003vp39kfbxgb8zg
        _url:
          type: string
          description: URL to the original file
          example: https://example.net/uploads/attachments/ckj0akbxa003vp39kfbxgb8zg-blue-box.png
        _urls:
          type: object
          description: URLs for different image sizes (images only)
          additionalProperties:
            type: string
        name:
          type: string
          description: Slugified filename
          example: blue-box
        title:
          type: string
          description: Sortified filename
          example: blue box
        extension:
          type: string
          description: File extension
          example: png
        type:
          type: string
          example: attachment
        group:
          type: string
          description: File group type
          example: images
        length:
          type: integer
          description: File size in bytes
          example: 10497
        md5:
          type: string
          description: MD5 checksum
          example: 630eeaaecd0bdc07c4a82eeca4c07588
        width:
          type: integer
          description: Image width in pixels (images only)
          example: 600
        height:
          type: integer
          description: Image height in pixels (images only)
          example: 106
        landscape:
          type: boolean
          description: Whether image is landscape orientation (images only)
        portrait:
          type: boolean
          description: Whether image is portrait orientation (images only)
        docIds:
          type: array
          items:
            type: string
          description: IDs of documents using this attachment
        archivedDocIds:
          type: array
          items:
            type: string
          description: IDs of archived documents using this attachment
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      title: Attachment
    Image:
      type: object
      description: Built-in image/media piece type for managing photos and graphics
      properties:
        _id:
          type: string
          description: Unique identifier
          example: clx1234567890abcdef
        title:
          type: string
          description: Image title/alt text
          example: Hero banner image
        slug:
          type: string
          example: hero-banner-image
        type:
          type: string
          example: '@apostrophecms/image'
        archived:
          type: boolean
          default: false
        visibility:
          type: string
          enum:
          - public
          - loginRequired
          default: public
        attachment:
          type: object
          description: File attachment information
          properties:
            _id:
              type: string
            name:
              type: string
              example: hero-banner
            extension:
              type: string
              example: jpg
            length:
              type: integer
              description: File size in bytes
            url:
              type: string
              description: Public URL to access the image
              example: /uploads/attachments/clx123/hero-banner.jpg
        credit:
          type: string
          description: Image credit or attribution
        tags:
          type: array
          items:
            type: string
          description: Image tags for organization
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      title: Image
    FileObject:
      type: object
      description: Built-in file piece type for general file uploads (PDFs, documents,
        etc.)
      properties:
        _id:
          type: string
          description: Unique identifier
          example: clx1234567890abcdef
        title:
          type: string
          description: File title/description
          example: Company Brochure
        slug:
          type: string
          example: company-brochure
        type:
          type: string
          example: '@apostrophecms/file'
        archived:
          type: boolean
          default: false
        visibility:
          type: string
          enum:
          - public
          - loginRequired
          default: public
        attachment:
          type: object
          description: File attachment information
          properties:
            _id:
              type: string
            name:
              type: string
              example: company-brochure
            extension:
              type: string
              example: pdf
            length:
              type: integer
              description: File size in bytes
            url:
              type: string
              description: Public URL to access the file
              example: /uploads/attachments/clx123/company-brochure.pdf
        description:
          type: string
          description: File description
        tags:
          type: array
          items:
            type: string
          description: File tags for organization
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      title: File
    ImageTag:
      type: object
      description: Built-in image tag piece type for organizing images
      properties:
        _id:
          type: string
          example: clx1234567890abcdef
        title:
          type: string
          description: Tag name
          example: Hero Images
        slug:
          type: string
          description: URL-friendly tag name
          example: hero-images
        type:
          type: string
          example: '@apostrophecms/image-tag'
        archived:
          type: boolean
          default: false
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      title: ImageTag
    FileTag:
      type: object
      description: Built-in file tag piece type for organizing files
      properties:
        _id:
          type: string
          example: clx1234567890abcdef
        title:
          type: string
          description: Tag name
          example: Marketing Materials
        slug:
          type: string
          description: URL-friendly tag name
          example: marketing-materials
        type:
          type: string
          example: '@apostrophecms/file-tag'
        archived:
          type: boolean
          default: false
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      title: FileTag
    SubmittedDraft:
      type: object
      properties:
        _id:
          type: string
          description: Unique identifier for the submitted draft
          example: clh123abc456def789
        type:
          type: string
          description: Document type identifier
          example: '@apostrophecms/submitted-draft'
        title:
          type: string
          description: Title of the submitted draft
          example: New Article Draft
        slug:
          type: string
          description: URL-friendly version of the title
          example: new-article-draft
        content:
          type: string
          description: Content of the submitted draft
          example: This is the draft content awaiting review.
        author:
          type: string
          description: Author of the submitted draft
          example: John Doe
        authorId:
          type: string
          description: ID of the user who created the draft
          example: clh456def789abc123
        submissionNotes:
          type: string
          description: Notes from the submitter about the draft
          example: Please review for accuracy and tone.
        priority:
          type: string
          enum:
          - low
          - normal
          - high
          - urgent
          description: Priority level for review
          example: normal
        category:
          type: string
          description: Category or type of content being submitted
          example: blog-post
        status:
          type: string
          enum:
          - draft
          - submitted
          - under-review
          - approved
          - rejected
          - published
          description: Current status of the submitted draft
          example: submitted
        submittedAt:
          type: string
          format: date-time
          description: When the draft was submitted for review
          example: '2024-03-15T10:30:00Z'
        reviewedAt:
          type: string
          format: date-time
          description: When the draft was last reviewed
          example: '2024-03-16T14:20:00Z'
        reviewedBy:
          type: string
          description: ID of the user who reviewed the draft
          example: clh789ghi012jkl345
        reviewNotes:
          type: string
          description: Notes from the reviewer
          example: Approved with minor suggestions for improvement.
        publishedAt:
          type: string
          format: date-time
          description: When the draft was published (if applicable)
          example: '2024-03-17T09:00:00Z'
        archived:
          type: boolean
          description: Whether the submitted draft is archived
          default: false
        createdAt:
          type: string
          format: date-time
          description: When the submitted draft was created
          example: '2024-03-15T09:15:00Z'
        updatedAt:
          type: string
          format: date-time
          description: When the submitted draft was last updated
          example: '2024-03-15T10:30:00Z'
        aposLocale:
          type: string
          description: Locale for this version of the content
          example: en
        aposMode:
          type: string
          enum:
          - draft
          - published
          description: Content mode (draft or published)
          example: draft
      required:
      - _id
      - type
      - title
      - content
      - author
      - status
      - createdAt
      - updatedAt
      title: SubmittedDraft
    PieceResponse:
      type: object
      properties:
        success:
          type: boolean
          description: Whether the request was successful
        data:
          type: object
          description: The piece data
        error:
          type: string
          description: Error message if success is false
      title: PieceResponse
    PaginatedResponse:
      type: object
      description: Standard response format for list endpoints
      properties:
        success:
          type: boolean
        data:
          type: object
          properties:
            results:
              type: array
              items:
                type: object
                description: Array of pieces (type depends on endpoint)
            pages:
              type: integer
              description: Total number of pages
            currentPage:
              type: integer
              description: Current page number (1-based)
            total:
              type: integer
              description: Total number of items across all pages
      title: PaginatedResponse
    CreatePieceRequest:
      type: object
      description: Generic structure for creating any piece type
      required:
      - title
      properties:
        title:
          type: string
          description: Piece title (required for all piece types)
        slug:
          type: string
          description: URL slug (auto-generated from title if not provided)
        visibility:
          type: string
          enum:
          - public
          - loginRequired
          description: Visibility setting
          default: public
        archived:
          type: boolean
          description: Whether the piece is archived
          default: false
      title: CreatePieceRequest
    ApiError:
      type: object
      properties:
        status:
          type: integer
          description: HTTP status code, e.g., 401
        code:
          type: string
          description: Application error code (optional)
        message:
          type: string
          description: Human-readable error message
        details:
          type: object
          additionalProperties: true
          description: Extra context about the error
      required:
      - message
      title: Error
    LocalesResponse:
      type: object
      description: Object containing all configured locales
      additionalProperties:
        type: object
        properties:
          label:
            type: string
            description: Human-readable locale name
            example: English
          _edit:
            type: boolean
            description: Whether current user can edit content in this locale
            example: true
      example:
        en:
          label: English
          _edit: true
        fr:
          label: French
          _edit: false
      title: LocalesResponse
    LocaleRequest:
      type: object
      required:
      - locale
      properties:
        locale:
          type: string
          description: Target locale code
          example: fr
        contextDocId:
          type: string
          description: Optional document ID for the path
          example: cloydg3ka0005qcls5vmg8sb9
        clipboard:
          type: string
          description: Optional clipboard content for cross-domain situations
          example: exampleClipboardContent
      title: LocaleRequest
    PageLocaleResult:
      type: object
      properties:
        _id:
          type: string
          description: |
          Document ID with locale and mode (format: docId:locale:mode)
          example: "s9gjqtw1ok7wxvewdu78xnes:en:published"
        aposLocale:
          type: string
          description: |
          Locale identifier with mode (format: locale:mode)
          example: "en:published"
      required:
        - _id
        - aposLocale
    PageLocalesResponse:
      type: object
      properties:
        results:
          type: array
          items:
            $ref: '#/components/schemas/PageLocaleResult'
      required:
        - results
    SameHostnameResponse:
      type: object
      additionalProperties: false
      required:
      - redirectTo
      properties:
        redirectTo:
          type: string
          description: Path to redirect to within same hostname
          pattern: ^/(?!/).*
          example: /fr/page-slug
      title: SameHostnameResponse
    DifferentHostnameResponse:
      type: object
      additionalProperties: false
      required:
      - redirectTo
      properties:
        redirectTo:
          type: string
          format: uri
          description: Full URL to redirect to with cross-domain session token
          pattern: ^[A-Za-z][A-Za-z0-9+.-]*://
          example: https://fr.example.com/french-example-page?aposCrossDomainSessionToken=generated_token
      title: DifferentHostnameResponse
    ExistInLocaleRequest:
      type: object
      required:
      - ids
      - locale
      - mode
      properties:
        ids:
          type: array
          items:
            type: string
          description: Array of document IDs to check
          example:
          - cloydg3ka0005qcls5vmg8sb9
          - cloydg3ka0005qcls5vmg8sb8
        locale:
          type: string
          description: Locale to check documents in
          example: fr
        mode:
          type: string
          enum:
          - draft
          - published
          description: Mode to check documents in
          example: published
      title: ExistInLocaleRequest
    ExistInLocaleResponse:
      type: object
      properties:
        originalLocaleIds:
          type: array
          items:
            type: string
          description: Array of document IDs in the original locale and mode
          example:
          - cloydg3ka0005qcls5vmg8sb9:en:published
          - cloydg3ka0005qcls5vmg8sb8:en:published
        newLocaleIds:
          type: array
          items:
            type: string
          description: Array of document IDs in the new locale
          example:
          - cloydg3ka0005qcls5vmg8sb9:fr:published
          - cloydg3ka0005qcls5vmg8sb8:fr:published
        aposDocIds:
          type: array
          items:
            type: string
          description: Array of aposDocId values for the documents
          example:
          - cloydg3ka0005qcls5vmg8sb9
          - cloydg3ka0005qcls5vmg8sb8
      title: ExistInLocaleResponse
    PageTreeResponse:
      type: object
      description: Complete page data with nested children structure - perfect for building
        navigation
      properties:
        _id:
          type: string
          description: Unique document identifier
          example: ckhdscx5900054z9k88uqs16w
        orphan:
          type: boolean
          description: Whether page is excluded from navigation menus
          example: false
        visibility:
          type: string
          enum:
          - public
          - loginRequired
          - private
          description: Page visibility setting - controls who can view this page
          example: public
        type:
          type: string
          description: Page type identifier (configured in your project)
          example: '@apostrophecms/home-page'
        title:
          type: string
          description: Page title - used for navigation and SEO
          example: Home Page
        slug:
          type: string
          description: URL slug for the page
          example: /
        rank:
          type: integer
          description: Order among sibling pages (for navigation sorting)
          example: 0
        level:
          type: integer
          description: Page tree depth level (0 = home page)
          example: 0
        path:
          type: string
          description: Ancestor path of page IDs
          example: ckhdscx5900054z9k88uqs16w
        _url:
          type: string
          format: uri
          description: Complete page URL - use this for links
          example: http://localhost:3000/
        _ancestors:
          type: array
          items:
            $ref: '#/components/schemas/PageSummary'
          description: Array of ancestor pages (for breadcrumbs)
        _children:
          type: array
          items:
            $ref: '#/components/schemas/PageTreeResponse'
          description: Array of child pages (nested structure)
        createdAt:
          type: string
          format: date-time
          description: ISO date of creation
        updatedAt:
          type: string
          format: date-time
          description: ISO date of last update
        archived:
          type: boolean
          description: Whether page is archived (hidden from normal views)
          example: false
        historicUrls:
          type: array
          items:
            type: string
          description: Previous URLs that redirect to this page (SEO preservation)
        metaType:
          type: string
          example: doc
        titleSortified:
          type: string
          description: Sortable version of title
        updatedBy:
          $ref: '#/components/schemas/User'
        _edit:
          type: boolean
          description: Whether current user can edit this page
      title: PageTreeResponse
    FlatPageResponse:
      type: object
      description: Pages returned as flat array instead of tree structure
      properties:
        results:
          type: array
          items:
            allOf:
            - $ref: '#/components/schemas/PageTreeResponse'
            - type: object
              properties:
                _children:
                  type: array
                  items:
                    type: string
                  description: Array of child page IDs (in flat response)
                _ancestors:
                  type: array
                  items:
                    type: string
                  description: Array of ancestor page IDs (in flat response)
      title: FlatPageResponse
    PageSummary:
      type: object
      description: Abbreviated page information for ancestors/references
      properties:
        _id:
          type: string
        title:
          type: string
        slug:
          type: string
        type:
          type: string
        _url:
          type: string
          format: uri
        level:
          type: integer
        rank:
          type: integer
      title: PageSummary
    PageCreateRequest:
      type: object
      required:
      - _targetId
      - _position
      - title
      properties:
        _targetId:
          type: string
          description: ID of target page for positioning (_home and _archive are convenience
            values)
          example: ckhdscx5900054z9k88uqs16w
        _position:
          oneOf:
          - type: string
            enum:
            - before
            - after
            - firstChild
            - lastChild
          - type: integer
            minimum: 0
          description: Position relative to target (string values) or child index (number)
          example: firstChild
        _copyingId:
          type: string
          description: Optional ID of existing page to copy properties from
        title:
          type: string
          description: Page title
          example: My New Page
        slug:
          type: string
          description: URL slug (auto-generated if not provided)
          example: /my-new-page
        type:
          type: string
          description: Page type (must be configured in your project)
          example: default-page
        visibility:
          type: string
          enum:
          - public
          - loginRequired
          - private
          default: public
          description: Who can view this page
      title: PageCreateRequest
    PageUpdateRequest:
      type: object
      properties:
        _targetId:
          type: string
          description: ID of target page for repositioning (required if moving page)
        _position:
          oneOf:
          - type: string
            enum:
            - before
            - after
            - firstChild
            - lastChild
          - type: integer
            minimum: 0
          description: New position (required if moving page)
        title:
          type: string
          description: Updated page title
        slug:
          type: string
          description: Updated URL slug
        visibility:
          type: string
          enum:
          - public
          - loginRequired
          - private
          description: Updated visibility setting
        updatedBy:
          $ref: '#/components/schemas/User'
      title: PageUpdateRequest
    Widget:
      type: object
      description: Content widget within an area - represents a piece of structured
        content
      properties:
        _id:
          type: string
        metaType:
          type: string
          enum:
          - widget
        type:
          type: string
          description: Widget type (e.g., rich-text, image, custom widgets)
          example: '@apostrophecms/rich-text'
        _edit:
          type: boolean
        _docId:
          type: string
        content:
          type: string
          description: HTML content for rich text widgets (filtered based on widget
            configuration)
          example: <p>Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum
            <strong>nibh, ut fermentum massa justo sit amet risus.</strong></p>
        import:
          type: object
          description: Import configuration for external content (used during creation/update)
          properties:
            baseUrl:
              type: string
              format: uri
              description: Base URL for resolving relative image URLs
              example: https://myoldsite.com
            html:
              type: string
              description: HTML content to import (images will be automatically imported)
              example: '<p>Here is some text.</p>

                <img src="/my-image.jpg" />'
            imageTags:
              type: array
              items:
                type: string
              description: Array of existing @apostrophecms/image-tag piece _ids to
                apply to imported images
              example:
              - tag-piece-id-1
              - tag-piece-id-2
      title: Widget
    PageDotNotationUpdate:
      type: object
      description: Keys may use Apostrophe dot notation to target nested content.
      propertyNames:
        pattern: ^[a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+|\.\d+)+$
      additionalProperties:
        oneOf:
        - type: string
        - type: number
        - type: boolean
        - type: object
        - type: array
          items: {}
        - type: 'null'
      title: PageDotNotationUpdate
    BaseField:
      type: object
      additionalProperties: false
      properties:
        type:
          type: string
          description: Apostrophe field type id (e.g., "float", "string", "boolean").
        label:
          type: string
          description: Human-readable label for editors.
        help:
          type: string
          description: Short helper text shown in the UI.
        htmlHelp:
          type: string
          description: Rich helper text (HTML allowed by Apostrophe).
        def:
          description: Default value for this field (type varies by field).
        required:
          type: boolean
          description: If true, value must be provided.
        readOnly:
          type: boolean
          description: If true, UI should render as read-only (Apostrophe option).
        hidden:
          type: boolean
          description: If true, hide in editor UI.
        if:
          $ref: '#/components/schemas/UiCondition'
        requiredIf:
          $ref: '#/components/schemas/UiCondition'
      required:
      - type
      - label
      title: BaseField
    UiCondition:
      type: object
      additionalProperties: false
      description: |
        'Apostrophe conditional used by `if` and `requiredIf`.
        Keys are field paths (including `<` parent access and dot notation) or method calls with `()`.
        Values are either simple equality (primitive) or an operator object. Supports `$or` / `$and` groups. See OperatorObject.
      properties:
        $or:
          type: array
          description: Any condition group may pass. :contentReference[oaicite:1]{index=1}
          items:
            $ref: '#/components/schemas/UiCondition'
        $and:
          type: array
          description: All condition groups must pass. (Redundant at the same level,
            but useful when nested with `$or`.) :contentReference[oaicite:2]{index=2}
          items:
            $ref: '#/components/schemas/UiCondition'
      patternProperties:
        ^[A-Za-z_][\\w-]*(?:\\.(?:length|\\d+|[A-Za-z_][\\w-]*))*$:
          $ref: '#/components/schemas/FieldPredicate'
        ^<+[A-Za-z_][\\w-]*(?:\\.(?:length|\\d+|[A-Za-z_][\\w-]*))*$:
          $ref: '#/components/schemas/FieldPredicate'
        ^(?:[A-Za-z0-9_-]+:)?[A-Za-z0-9_-]+\\(\\)$:
          $ref: '#/components/schemas/FieldPredicate'
      examples:
      - priority:
          $in:
          - high
          - critical
        estimatedHours:
          $gte: 20
        assignee.length:
          $gt: 0
      - $or:
        - seenMovie: true
        - featuredMovie(): true
      title: UiCondition
    FieldPredicate:
      description: A simple equality (primitive) or an OperatorObject. :contentReference[oaicite:5]{index=5}
      oneOf:
      - type: string
      - type: number
      - type: boolean
      - type: 'null'
      - $ref: '#/components/schemas/OperatorObject'
      title: FieldPredicate
    OperatorObject:
      type: object
      additionalProperties: false
      description: |
        MongoDB-style operators supported by Apostrophe conditions.
        Note:
          `$eq` has special handling with arrays (see docs).
          `$exists: true` means not null/undefined; empty string is truthy so use `$ne: ''''` or check `.length`.
      properties:
        $eq: {}
        $ne: {}
        $gt:
          type: number
        $gte:
          type: number
        $lt:
          type: number
        $lte:
          type: number
        $in:
          type: array
          items: {}
        $nin:
          type: array
          items: {}
        $exists:
          type: boolean
      example:
        $in:
        - high
        - critical
      title: OperatorObject
    NumericRangeOptions:
      type: object
      additionalProperties: false
      properties:
        min:
          type: number
          description: Minimum allowed value (inclusive).
        max:
          type: number
          description: Maximum allowed value (inclusive)
      title: NumericRangeOptions
    DateBoundaryOptions:
      type: object
      additionalProperties: false
      properties:
        min:
          type: string
          format: date
          description: Minimum allowed date (inclusive), ISO-8601 (YYYY-MM-DD).
        max:
          type: string
          format: date
          description: Maximum allowed date (inclusive), ISO-8601 (YYYY-MM-DD).
      title: DateBoundaryOptions
    DateTimeBoundaryOptions:
      type: object
      additionalProperties: false
      properties:
        min:
          type: string
          format: date-time
          description: Minimum allowed timestamp (inclusive), RFC 3339.
        max:
          type: string
          format: date-time
          description: Maximum allowed timestamp (inclusive), RFC 3339.
      title: DateTimeBoundaryOptions
    RelationshipEntry:
      type: object
      description: |
        One relationship entry. Always includes the related document `_id`.
        If you declared per-relationship `fields`, those values are stored alongside `_id` here.
      properties:
        _id:
          type: string
          description: Id of the related document.
      required:
      - _id
      additionalProperties: true
      title: RelationshipEntry
    BulkOperationRequest:
      type: object
      properties:
        _ids:
          type: array
          items:
            type: string
          description: Array of document IDs to operate on
          example: ["doc1:en:draft", "doc2:en:published"]
      required:
        - _ids
    BulkOperationResponse:
      type: object
      properties:
        success:
          type: boolean
        modified:
          type: integer
          description: Number of documents affected
        errors:
          type: array
          items:
            type: string
    Fieldset:
      type: object
      additionalProperties: false
      properties:
        add:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/FieldDefinition'
      required:
      - add
      title: Fieldset
    FieldDefinition:
      oneOf:
      - $ref: '#/components/schemas/BooleanField'
      - $ref: '#/components/schemas/StringField'
      - $ref: '#/components/schemas/IntegerField'
      - $ref: '#/components/schemas/FloatField'
      - $ref: '#/components/schemas/SelectField'
      - $ref: '#/components/schemas/RadioField'
      - $ref: '#/components/schemas/CheckboxesField'
      - $ref: '#/components/schemas/PasswordField'
      - $ref: '#/components/schemas/ColorField'
      - $ref: '#/components/schemas/DateField'
      - $ref: '#/components/schemas/DateAndTimeField'
      - $ref: '#/components/schemas/TimeField'
      - $ref: '#/components/schemas/EmailField'
      - $ref: '#/components/schemas/UrlField'
      - $ref: '#/components/schemas/SlugField'
      - $ref: '#/components/schemas/OembedField'
      - $ref: '#/components/schemas/RangeField'
      - $ref: '#/components/schemas/ObjectField'
      - $ref: '#/components/schemas/ArrayField'
      - $ref: '#/components/schemas/AreaField'
      - $ref: '#/components/schemas/AttachmentField'
      - $ref: '#/components/schemas/RelationshipField'
      - $ref: '#/components/schemas/RelationshipReverseField'
      discriminator:
        propertyName: type
        mapping:
          boolean: '#/components/schemas/BooleanField'
          string: '#/components/schemas/StringField'
          integer: '#/components/schemas/IntegerField'
          float: '#/components/schemas/FloatField'
          select: '#/components/schemas/SelectField'
          radio: '#/components/schemas/RadioField'
          checkboxes: '#/components/schemas/CheckboxesField'
          password: '#/components/schemas/PasswordField'
          color: '#/components/schemas/ColorField'
          date: '#/components/schemas/DateField'
          dateAndTime: '#/components/schemas/DateAndTimeField'
          time: '#/components/schemas/TimeField'
          email: '#/components/schemas/EmailField'
          url: '#/components/schemas/UrlField'
          slug: '#/components/schemas/SlugField'
          oembed: '#/components/schemas/OembedField'
          range: '#/components/schemas/RangeField'
          object: '#/components/schemas/ObjectField'
          array: '#/components/schemas/ArrayField'
          area: '#/components/schemas/AreaField'
          attachment: '#/components/schemas/AttachmentField'
          relationship: '#/components/schemas/RelationshipField'
          relationshipReverse: '#/components/schemas/RelationshipReverseField'
      title: FieldDefinition
    AposPrimitives:
      $id: https://example.com/apostrophe/primitives
      $schema: https://json-schema.org/draft/2020-12/schema
      description: |
        Reusable primitive data shapes for ApostropheCMS document payloads.
        Use these in content models; keep field-definition objects separate.
      $defs:
        AposString:
          type: string
        AposStringArray:
          type: array
          items:
            $ref: '#/components/schemas/AposPrimitives/$defs/AposString'
        AposSlug:
          type: string
          pattern: ^[a-z0-9][a-z0-9-]*$
          description: Slug string stored in the document, usually lowercase and URL-safe (e.g. "my-article", "blog/my-custom-page").
        AposEmail:
          type: string
          format: email
          description: A valid email address per RFC 5322, as stored in documents and returned via the API.
        AposURI:
          type: string
          format: uri
          description: |
            A valid absolute URL (RFC 3986).
            Usually stored with protocol, e.g., "https://example.com".
        AposPassword:
          type: string
          description: Password string as entered. Apostrophe typically hashes thisbefore storage; API usage depends on context.
        AposDateTime:
          type: string
          format: date-time
          description: ISO-8601 calendar date (YYYY-MM-DD).
        AposDate:
          type: string
          format: date
          description: RFC 3339 timestamp (e.g., 2025-08-29T13:00:00Z).
        AposTime:
          type: string
          pattern: ^(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d$
          description: Time string stored in documents, always in HH:MM:SS (24-hour).
        AposInteger:
          type: integer
        AposIntegerArray:
          type: array
          items:
            $ref: '#/components/schemas/AposPrimitives/$defs/AposInteger'
        AposFloat:
          type: number
        AposFloatArray:
          type: array
          items:
            $ref: '#/components/schemas/AposPrimitives/$defs/AposFloat'
        AposRange:
          type: number
          description: Stored numeric value selected via the slider (integer or float, depending on configuration).
        AposBoolean:
          type: boolean
        AposBooleanArray:
          type: array
          items:
            $ref: '#/components/schemas/AposPrimitives/$defs/AposBoolean'
        AposRadio:
          oneOf:
          - type: string
          - type: number
          - type: boolean
          description: The stored value for a radio field (one of the choice values).
        AposCheckboxes:
          type: array
          items:
            oneOf:
            - type: string
            - type: number
            - type: boolean
          description: The stored values for a checkboxes field. Each item is one of the configured choice values.
        AposOembed:
          type: object
          additionalProperties: false
          properties:
            url:
              type: string
              format: uri
              description: Original media URL saved by the editor.
            title:
              type: string
              description: Title snapshot from the oEmbed response at save time.
            thumbnail:
              type: string
              format: uri
              description: Thumbnail URL snapshot from the oEmbed response at save time.
          required:
          - url
          description: |
            Data stored on the document: a snapshot of the oEmbed resource.
            Fetch full embed HTML at runtime via GET `/api/v1/@apostrophecms/oembed/query?url=<media-url>`.
        AposArea:
          type: object
          additionalProperties: false
          properties:
            items:
              type: array
              items:
                $ref: '#/components/schemas/Widget'
          required:
          - items
          description: |
            The value saved on the doc: an object with an `items` array of widgets.
              # --- Data value (what’s stored on the doc) ---
        AposAttachment:
          type: object
          description: |
            Attachment metadata saved on the document.
            Extra fields maybe present depending on project config and file type (e.g., image dimensions).
          additionalProperties: true
          properties:
            _id:
              type: string
              description: Internal id of the uploaded file.
            name:
              type: string
              description: Basename without extension.
            extension:
              type: string
              description: File extension (e.g., "pdf", "png").
            mimeType:
              type: string
              description: MIME type (e.g., "application/pdf", "image/png").
            group:
              type: string
              description: Broad file group (e.g., "images", "office", "video", "audio",
                "generic").
            size:
              type: integer
              description: File size in bytes.
            width:
              type: integer
              description: Image width in pixels (if applicable).
            height:
              type: integer
              description: Image height in pixels (if applicable).
          required:
          - _id
        AposRelationship:
          description: |
            The stored value of a relationship field. For multi-select joins,this is an array of entries.
            For `max: 1`, treat it as either a single entry or null.
            An entry always contains at least the related `_id`; additional keys may appear if `fields` were defined.
          oneOf:
          - $ref: '#/components/schemas/RelationshipEntry'
          - type: 'null'
          - type: array
            items:
              $ref: '#/components/schemas/RelationshipEntry'
        AposRelationshipReverse:
          type: array
          items:
            $ref: '#/components/schemas/RelationshipEntry'
          description: Populated reverse relationships at read time. Not persistedon this document; useful in responses.
        AposObjectId:
          type: string
          pattern: ^[a-fA-F0-9]{24}$
          description: MongoDB ObjectId (24 hex chars)
        AposObjectIdArray:
          type: array
          items:
            $ref: '#/components/schemas/AposPrimitives/$defs/AposObjectId'
        AposJSON:
          type: object
          additionalProperties: true
        AposJSONArray:
          type: array
          items:
            $ref: '#/components/schemas/AposPrimitives/$defs/AposJSON'
        NullableString:
          type:
          - string
          - 'null'
        NullableInteger:
          type:
          - integer
          - 'null'
        NullableNumber:
          type:
          - number
          - 'null'
        NullableBoolean:
          type:
          - boolean
          - 'null'
        NullableObjectId:
          type:
          - string
          - 'null'
          pattern: ^[a-fA-F0-9]{24}$
      title: AposPrimitives

  responses:
    BadRequest:
      description: Bad request - invalid input parameters
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: string
                example: "Invalid request parameters"
              message:
                type: string
                example: "The request could not be processed due to invalid input"

    Unauthorized:
      description: Authentication required
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: string
                example: "Unauthorized"
              message:
                type: string
                example: "Authentication is required to access this resource"

    Forbidden:
      description: Access forbidden - insufficient permissions
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: string
                example: "Forbidden"
              message:
                type: string
                example: "You do not have permission to perform this action"

    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: string
                example: "Not Found"
              message:
                type: string
                example: "The requested resource could not be found"

    InternalServerError:
      description: Internal server error
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: string
                example: "Internal Server Error"
              message:
                type: string
                example: "An unexpected error occurred while processing the request"

    PieceOperationSuccess:
      description: Operation completed successfully
      content:
        application/json:
          schema:
            type: object
            properties:
              success:
                type: boolean
                example: true
              message:
                type: string
                example: "Operation completed successfully"

paths:
  # Authentication endpoints
  /@apostrophecms/login/login:
    post:
      tags:
        - Authentication
      summary: "Login to get authentication token"
      description: |
        🚀 **Start here!** Authenticate and receive either a bearer token or session cookie for subsequent API requests.

        **Perfect for:**
        - Getting started with the API
        - Setting up authentication for your app
        - Testing API access

        **Choose your authentication method:**
        - **Bearer Token** (recommended): omit `session` field or set to `false`
        - **Session Cookie**: set `session` to `true` and include `credentials: 'include'` in fetch
      operationId: AuthLogin
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - username
                - password
              properties:
                username:
                  type: string
                  description: User's login username
                  example: "admin"
                password:
                  type: string
                  format: password
                  description: User's password
                session:
                  type: boolean
                  description: Set to true to receive session cookie instead of bearer token
                  default: false
                  example: false
            examples:
              bearer_token:
                summary: "Request bearer token (recommended)"
                value:
                  username: "admin"
                  password: "your-password"
              session_cookie:
                summary: "Request session cookie"
                value:
                  username: "admin"
                  password: "your-password"
                  session: true
      responses:
        '200':
          description: Login successful
          content:
            application/json:
              schema:
                type: object
                properties:
                  token:
                    type: string
                    description: Bearer token (only present when session is false/omitted)
                    example: "random123Token456xyz"
              examples:
                bearer_response:
                  summary: "Bearer token response"
                  value:
                    token: "random123Token456xyz"
                session_response:
                  summary: "Session cookie response (token field not present)"
                  value: {}
          headers:
            Set-Cookie:
              description: Session cookie (only when session=true)
              schema:
                type: string
                example: "apostrophe.sid=s%3A...; Path=/; HttpOnly"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security: []

  /@apostrophecms/login/logout:
    post:
      tags:
        - Authentication
      summary: "Logout and invalidate session"
      description: |
        End the current session or invalidate the bearer token.

        **For bearer token**: include Authorization header
        **For session cookie**: include credentials in request
      operationId: AuthLogout
      responses:
        '200':
          description: Logout successful
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/login/reset-request:
    post:
      tags:
        - Authentication
      summary: "Request password reset"
      description: |
        Initiates a password reset process by sending a reset link to the user's email address.

        **⚠️ Note:** This endpoint is only available when `passwordReset` is enabled in the login module configuration.

        **Security feature:** The user will not be notified if the email check fails or if the email fails to send.
        However, debug information will be output in the server terminal.
      operationId: AuthResetRequest
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - email
              properties:
                email:
                  type: string
                  format: email
                  description: Email address of the user requesting password reset
                  example: "user@example.com"
      responses:
        '200':
          description: Password reset request processed (always returns success for security)
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                    example: "If an account with that email exists, a password reset link has been sent."
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security: []

  /@apostrophecms/login/reset:
    post:
      tags:
        - Authentication
      summary: "Complete password reset"
      description: |
        Completes a password reset using the token provided in the reset email.

        **⚠️ Note:** This endpoint is only available when `passwordReset` is enabled in the login module configuration.

        Reset tokens are valid for the number of hours specified in `passwordResetHours` (default: 48 hours).
      operationId: AuthReset
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - token
                - password
              properties:
                token:
                  type: string
                  description: Reset token from the password reset email
                  example: "reset-token-from-email"
                password:
                  type: string
                  format: password
                  description: New password for the user account
                  example: "new-secure-password"
      responses:
        '200':
          description: Password reset completed successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                    example: "Password has been reset successfully"
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'
        '410':
          description: Reset token expired
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: "Reset token has expired"
        '500':
          $ref: '#/components/responses/InternalServerError'
      security: []

  /@apostrophecms/login/whoami:
    get:
      tags:
        - Authentication
      summary: "Get current user information"
      deprecated: true
      description: |
        **⚠️ DEPRECATED:** This GET endpoint is deprecated due to caching issues.
        Use the POST method instead.

        Returns information about the currently authenticated user.

        **Security note:** Only explicitly configured fields are returned,
        never the complete user object. This prevents accidental exposure
        of sensitive user data.
      operationId: AuthWhoAmI
      responses:
        '200':
          description: Current user information retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  _id:
                    type: string
                    description: User's unique identifier
                    example: "user123"
                  username:
                    type: string
                    description: User's login username
                    example: "john-doe"
                  title:
                    type: string
                    description: User's display name
                    example: "John Doe"
                  email:
                    type: string
                    format: email
                    description: User's email address (if configured in whoamiFields)
                    example: "john@example.com"
                additionalProperties: true
                description: Additional fields based on whoamiFields configuration
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

    post:
      tags:
        - Authentication
      summary: "Get current user information"
      description: |
        Returns information about the currently authenticated user.

        **Note:** POST method is recommended for this endpoint to avoid caching issues.

        **Perfect for:**
        - Checking if authentication is working
        - Getting user details for your app
        - Validating permissions

        **Security note:** Only explicitly configured fields are returned, 
        never the complete user object. This prevents accidental exposure 
        of sensitive user data.
      operationId: AuthWhoAmIPost
      responses:
        '200':
          description: Current user information retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  _id:
                    type: string
                    description: User's unique identifier
                    example: "user123"
                  username:
                    type: string
                    description: User's login username
                    example: "john-doe"
                  title:
                    type: string
                    description: User's display name
                    example: "John Doe"
                  email:
                    type: string
                    format: email
                    description: User's email address (if configured in whoamiFields)
                    example: "john@example.com"
                additionalProperties: true
                description: Additional fields based on whoamiFields configuration
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/login/context:
    get:
      tags:
        - Authentication
      summary: "Get login context information"
      deprecated: true
      description: |
        **⚠️ DEPRECATED:** This GET endpoint is deprecated due to caching issues.
        Use the POST method instead.

        Returns login context information including environment and requirements.
        This endpoint provides information about the login system configuration.

        **Useful for:**
        - Understanding available login methods
        - Checking if password reset is enabled
        - Getting login system configuration
      operationId: AuthContext
      responses:
        '200':
          description: Login context retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  localLogin:
                    type: boolean
                    description: Whether local login is enabled
                    example: true
                  passwordReset:
                    type: boolean
                    description: Whether password reset is enabled
                    example: false
                  loginUrl:
                    type: string
                    description: The configured login URL
                    example: "/login"
                additionalProperties: true
                description: Additional context based on configuration
        '400':
          $ref: '#/components/responses/BadRequest'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

    post:
      tags:
        - Authentication
      summary: "Get login context information"
      description: |
        Returns login context information including environment and requirements.
        This endpoint provides information about the login system configuration.

        **Note:** POST method is recommended for this endpoint to avoid caching issues.

        **Useful for:**
        - Understanding available login methods
        - Checking if password reset is enabled
        - Getting login system configuration
      operationId: AuthContextPost
      responses:
        '200':
          description: Login context retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  localLogin:
                    type: boolean
                    description: Whether local login is enabled
                    example: true
                  passwordReset:
                    type: boolean
                    description: Whether password reset is enabled
                    example: false
                  loginUrl:
                    type: string
                    description: The configured login URL
                    example: "/login"
                additionalProperties: true
                description: Additional context based on configuration"
        '400':
          $ref: '#/components/responses/BadRequest'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  # Page endpoints
  /@apostrophecms/page:
    get:
      tags:
        - Pages
      summary: Get page tree
      description: |
        🚀 **Essential for headless sites!** Fetch your site's complete page structure and content.

        **Perfect for:**
        - Building navigation menus
        - Getting all pages for static site generation
        - Fetching content for SPA routing
        - Understanding your site structure

        Returns the complete page hierarchy starting from the home page. Use `flat=1` to get pages in a flat array instead of nested structure.
      operationId: PageGet
      parameters:
        - $ref: '#/components/parameters/AllPages'
        - $ref: '#/components/parameters/FlatResponse'
        - $ref: '#/components/parameters/ChildrenParam'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      responses:
        '200':
          description: Page tree retrieved successfully
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/PageTreeResponse'
                  - $ref: '#/components/schemas/FlatPageResponse'
              examples:
                tree_response:
                  summary: Nested page tree (default)
                  value:
                    _id: "ckhdscx5900054z9k88uqs16w"
                    title: "Home Page"
                    slug: "/"
                    type: "@apostrophecms/home-page"
                    _children: []
                flat_response:
                  summary: Flat array response (with flat=1)
                  value:
                    results: []
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []
        - {}

    post:
      tags:
        - Pages
      summary: Create new page
      description: |
        Insert a new page at the specified position in the page tree.

        **Perfect for:**
        - Programmatically creating pages
        - Building page management interfaces
        - Migrating content from other systems

        Requires `_targetId` and `_position` to determine placement in the page tree.
      operationId: PagePost
      parameters:
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PageCreateRequest'
            examples:
              new_page:
                summary: Create new page as first child
                value:
                  title: "New Page"
                  _targetId: "ckhdscx5900054z9k88uqs16w"
                  _position: "firstChild"
              copy_page:
                summary: Create page by copying existing one
                value:
                  title: "Copied Page"
                  _targetId: "_home"
                  _position: "lastChild"
                  _copyingId: "existing-page-id"
      responses:
        '200':
          description: Page created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Page'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/page/archive:
    post:
      tags:
        - Pages
      summary: Archive pages
      description: Archive pages in bulk, making them inactive while preserving their data in the page tree
      operationId: PageArchive
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                _ids:
                  type: array
                  items:
                    type: string
                  description: Array of page IDs to archive
                  example: ["page1-id", "page2-id"]
      responses:
        '200':
          description: Archive job started successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  jobId:
                    type: string
                    description: ID of the background job processing the archive operation
                    example: "b4kef9mgstbi5trzsw5dyfqm"
                required:
                  - jobId
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/page/localize:
    post:
      tags:
        - Pages
      summary: Localize pages
      description: Create or update localized versions of pages in bulk for different languages/regions
      operationId: PageLocalize
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                _ids:
                  type: array
                  items:
                    type: string
                  description: Array of page IDs to localize
                  example: ["page1-id", "page2-id"]
                toLocale:
                  type: string
                  description: Target locale for localization
                  example: "es"
      responses:
        '200':
          description: Pages localized successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Page'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/page/publish:
    post:
      tags:
        - Pages
      summary: Publish pages
      description: Publish pages in bulk, making them live and visible to end users in the page tree
      operationId: PagePublish
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                _ids:
                  type: array
                  items:
                    type: string
                  description: Array of page IDs to publish
                  example: ["page1-id", "page2-id"]
      responses:
        '200':
          description: Pages published successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Page'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/page/restore:
    post:
      tags:
        - Pages
      summary: Restore pages
      description: Restore previously archived pages in bulk, making them active again in the page tree
      operationId: PageRestore
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkOperationRequest'
      responses:
        '200':
          description: Pages restored successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Page'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/page/{_id}:
    delete:
      tags:
        - Pages
      summary: Delete page
      description: |
        ⚠️ **Permanently delete a page document.** This cannot be undone.

        **Important**: This endpoint should be used to delete the draft version of a page. If the page has been published, you should unpublish it first using the unpublish endpoint
        to ensure complete removal.

        **Recommended deletion workflow**:
        1. Unpublish the page (removes published version)
        2. Delete the page (removes draft version)

        **Restrictions:**
        - Cannot delete home page
        - Cannot delete pages with children (delete children first)
        - Cannot delete draft if published version exists
        ⚠️ **Permanently delete a page document.** This cannot be undone.

        **Use with caution!**
      operationId: PageDeleteById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      responses:
        '200':
          description: Page deleted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Page'
        '400':
          description: Deletion not allowed
          content:
            application/json:
              schema:
                type: object
                properties:
                  name:
                    type: string
                    example: "invalid"
                  data:
                    type: object
                  message:
                    type: string
                    example: "You must delete the children of this page first."
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

    get:
      tags:
        - Pages
      summary: Get page by ID
      description: |
        Fetch a single page document by ID for detailed content access.

        **Perfect for:**
        - Getting page content for rendering
        - Fetching specific page data
        - Building page detail views

        The ID can include mode and locale (e.g., `id:en:published`) or use query parameters to specify them.
      operationId: PageGetById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
        - $ref: '#/components/parameters/RenderAreas'
      responses:
        '200':
          description: Page retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Page'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []
        - {}

    patch:
      tags:
        - Pages
      summary: Update page
      description: |
        Partially update a page document.

        **Perfect for:**
        - Updating page titles or content
        - Moving pages within the tree
        - Making incremental changes

        Can use MongoDB-style operators and dot notation for nested properties. Include `_targetId` and `_position` to move the page within the tree.
      operationId: PagePatchById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              anyOf:
                - $ref: '#/components/schemas/PageUpdateRequest'
                - $ref: '#/components/schemas/PageDotNotationUpdate'
            examples:
              update_title:
                summary: Update page title only
                value:
                  title: "Updated Page Title"
              move_page:
                summary: Move page to new position
                value:
                  _targetId: "target-page-id"
                  _position: "after"
              archive_page:
                summary: Move page to archive
                value:
                  _targetId: "_archive"
                  _position: "lastChild"
              dot_notation:
                summary: Update nested content with dot notation
                value:
                  "description.items.0.content": "<p>Updated content</p>"
      responses:
        '200':
          description: Page updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Page'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

    put:
      tags:
        - Pages
      summary: Replace page
      description: |
        Completely replace a page document.

        **Use cases:**
        - Complete page updates
        - Moving pages in the tree structure
        - Replacing page content entirely

        Requires `_targetId` and `_position` for page tree positioning.
      operationId: PagePutById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
        - $ref: '#/components/parameters/RenderAreas'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/PageCreateRequest'
                - type: object
                  required:
                    - _targetId
                    - _position
      responses:
        '200':
          description: Page replaced successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Page'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/page/{_id}/dismiss-submission:
    post:
      tags:
        - Pages
      summary: Dismiss page submission
      description: Dismiss a pending submission for the specified page, removing it from the review queue
      operationId: PageDismissSubmissionById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Page submission dismissed successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Page'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/page/{_id}/locale/{toLocale}:
    get:
      tags:
        - Pages
      summary: Get page in specific locale
      description: Retrieve the specified page in a specific locale
      operationId: PageGetLocaleById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/ToLocale'
      responses:
        '200':
          description: Page locale retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Page'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/page/{_id}/locales:
    get:
      tags:
        - Pages
      summary: Get page locales
      description: Retrieve all available locales for the specified page
      operationId: PageGetLocalesById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Page locales retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  results:
                    type: array
                    items:
                      type: object
                      properties:
                        _id:
                          type: string
                          description: Document ID with locale and mode
                          example: "s9gjqtw1ok7wxvewdu78xnes:en:published"
                        aposLocale:
                          type: string
                          description: Locale identifier with mode
                          example: "en:published"
                      required:
                        - _id
                        - aposLocale
                required:
                  - results
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/page/{_id}/localize:
    post:
      tags:
        - Pages
      summary: Localize page
      description: Create a localized version of the specified page for a specific language/region
      operationId: PageLocalizeById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                toLocale:
                  type: string
                  description: Target locale for localization
                  example: "es"
      responses:
        '200':
          description: Page localized successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Page'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/page/{_id}/publish:
    post:
      tags:
        - Pages
      summary: Publish page
      description: |
        **Advanced Feature**: Publish a draft page to make it live.

        Moves a page from draft mode to published mode, making it visible
        to public users. Essential for content workflows where editors
        create drafts before publishing.

        **Use cases:**
        - Content approval workflows
        - Scheduled publishing systems
        - Editorial review processes

        The `_id` can be from either the draft or published version, 
        or you can use the `aposDocId` to reference the document.
      operationId: PagePublishById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposLocale'
      responses:
        '200':
          description: Page published successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Page'
              examples:
                published_page:
                  summary: Successfully published page
                  value:
                    _id: "ckhdscx5900054z9k88uqs16w:en:published"
                    title: "My Published Page"
                    slug: "/my-published-page"
                    type: "default-page"
                    _url: "https://example.com/my-published-page"
                    updatedAt: "2024-12-18T10:30:00.000Z"
        '400':
          description: Bad request - cannot publish (e.g., validation errors)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
              examples:
                validation_error:
                  summary: Page validation failed
                  value:
                    error: "Validation failed"
                    message: "Page title is required before publishing"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: Forbidden - insufficient permissions to publish pages
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        '404':
          description: Page not found or no draft version exists
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
              examples:
                no_draft:
                  summary: No draft version to publish
                  value:
                    error: "Not Found"
                    message: "No draft version of this page exists"
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/page/{_id}/revert-draft-to-published:
    post:
      tags:
        - Pages
      summary: Revert draft to published
      description: Revert the draft version of the specified page back to its published state
      operationId: PageRevertDraftToPublishedById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Page draft reverted to published successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Page'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/page/{_id}/revert-published-to-previous:
    post:
      tags:
        - Pages
      summary: Revert published to previous
      description: Revert the published version of the specified page to its previous published state
      operationId: PageRevertPublishedToPreviousById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Page published version reverted to previous successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Page'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/page/{_id}/share:
    post:
      tags:
        - Pages
      summary: Share page
      description: Generate a sharing link or configure sharing permissions for the specified page
      operationId: PageShareById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Page shared successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Page'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/page/{_id}/submit:
    post:
      tags:
        - Pages
      summary: Submit page
      description: Submit the specified page for review and approval workflow
      operationId: PageSubmitById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Page submitted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Page'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/page/{_id}/unpublish:
    post:
      tags:
        - Pages
      summary: Unpublish page
      description: Unpublish the specified page, removing it from public visibility while preserving the content
      operationId: PageUnpublishById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      responses:
        '200':
          description: Page unpublished successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Page'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  # Built-in piece types
  # User
  /@apostrophecms/user:
    get:
      tags:
        - Users
      summary: List users
      description: Retrieve a list of users with optional filtering, sorting, and pagination
      operationId: UserList
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: object
                properties:
                  results:
                    type: array
                    items:
                      $ref: '#/components/schemas/User'
                  pages:
                    type: integer
                    description: Total number of pages
                  currentPage:
                    type: integer
                    description: Current page number
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

    post:
      tags:
        - Users
      summary: Create user
      description: Create a new user account with the specified properties
      operationId: UserCreate
      parameters:
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - title
                - username
                - email
              properties:
                title:
                  type: string
                  description: Display name for the user
                  example: "John Doe"
                username:
                  type: string
                  description: Unique username for login
                  example: "johndoe"
                email:
                  type: string
                  format: email
                  description: User's email address
                  example: "john.doe@example.com"
                password:
                  type: string
                  format: password
                  description: User's password
                  example: "securePassword123"
                firstName:
                  type: string
                  description: User's first name
                  example: "John"
                lastName:
                  type: string
                  description: User's last name
                  example: "Doe"
                role:
                  type: string
                  description: User's role/permission level
                  example: "editor"
                disabled:
                  type: boolean
                  description: Whether the user account is disabled
                  default: false
      responses:
        '200':
          description: User created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: Conflict - username or email already exists
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/user/archive:
    post:
      tags:
        - Users
      summary: Archive users
      description: Archive multiple users, making them inactive while preserving their data
      operationId: UserArchive
      responses:
        '200':
          description: Archive job started successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  jobId:
                    type: string
                    description: ID of the background job processing the archive operation
                    example: "b4kef9mgstbi5trzsw5dyfqm"
                required:
                  - jobId
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/user/localize:
    post:
      tags:
        - Users
      summary: Localize users
      description: Create or update localized versions of users for different languages/regions
      operationId: UserLocalize
      responses:
        '200':
          description: Users localized successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/user/publish:
    post:
      tags:
        - Users
      summary: Publish users
      description: Publish multiple users, making them live and visible
      operationId: UserPublish
      responses:
        '200':
          description: Users published successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/user/restore:
    post:
      tags:
        - Users
      summary: Restore users
      description: Restore previously archived users, making them active again
      operationId: UserRestore
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkOperationRequest'
      responses:
        '200':
          description: Users restored successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/user/{_id}:
    delete:
      tags:
        - Users
      summary: Delete user
      description: Permanently delete a specific user by ID (requires appropriate permissions)
      operationId: UserDeleteById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: User deleted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

    get:
      tags:
        - Users
      summary: Get user
      description: Retrieve a specific user by ID
      operationId: UserGetById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
        - $ref: '#/components/parameters/RenderAreas'
      responses:
        '200':
          description: User retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

    patch:
      tags:
        - Users
      summary: Update user
      description: Partially update a specific user by ID using PATCH semantics
      operationId: UserPatchById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                  description: Display name for the user
                  example: "John Doe"
                email:
                  type: string
                  format: email
                  description: User's email address
                  example: "john.doe@example.com"
                firstName:
                  type: string
                  description: User's first name
                  example: "John"
                lastName:
                  type: string
                  description: User's last name
                  example: "Doe"
                role:
                  type: string
                  description: User's role/permission level
                  example: "editor"
                disabled:
                  type: boolean
                  description: Whether the user account is disabled
      responses:
        '200':
          description: User updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

    put:
      tags:
        - Users
      summary: Replace user
      description: Completely replace a specific user by ID using PUT semantics
      operationId: UserPutById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - title
                - username
                - email
              properties:
                title:
                  type: string
                  description: Display name for the user
                  example: "John Doe"
                username:
                  type: string
                  description: Unique username for login
                  example: "johndoe"
                email:
                  type: string
                  format: email
                  description: User's email address
                  example: "john.doe@example.com"
                firstName:
                  type: string
                  description: User's first name
                  example: "John"
                lastName:
                  type: string
                  description: User's last name
                  example: "Doe"
                role:
                  type: string
                  description: User's role/permission level
                  example: "editor"
                disabled:
                  type: boolean
                  description: Whether the user account is disabled
                  default: false
      responses:
        '200':
          description: User replaced successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/user/{_id}/dismiss-submission:
    post:
      tags:
        - Users
      summary: Dismiss user submission
      description: Dismiss a pending submission for the specified user, removing it from the review queue
      operationId: UserDismissSubmissionById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: User submission dismissed successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/user/{_id}/locale/{toLocale}:
    get:
      tags:
        - Users
      summary: Get user locale
      description: Retrieve the specified user in a specific locale
      operationId: UserGetLocaleById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/ToLocale'
      responses:
        '200':
          description: User locale retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/user/{_id}/locales:
    get:
      tags:
        - Users
      summary: Get user locales
      description: Retrieve all available locales for the specified user
      operationId: UserGetLocalesById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: User locales retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string
                example: ["en", "es", "fr", "de"]
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/user/{_id}/localize:
    post:
      tags:
        - Users
      summary: Localize user
      description: Create a localized version of the specified user for a specific language/region
      operationId: UserLocalizeById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: User localized successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/user/{_id}/publish:
    post:
      tags:
        - Users
      summary: Publish user
      description: Publish the specified user, making them live and visible
      operationId: UserPublishById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: User published successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/user/{_id}/revert-draft-to-published:
    post:
      tags:
        - Users
      summary: Revert draft to published
      description: Revert the draft version of the specified user back to its published state
      operationId: UserRevertDraftToPublishedById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: User draft reverted to published successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/user/{_id}/revert-published-to-previous:
    post:
      tags:
        - Users
      summary: Revert published to previous
      description: Revert the published version of the specified user to its previous published state
      operationId: UserRevertPublishedToPreviousById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: User published version reverted to previous successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/user/{_id}/share:
    post:
      tags:
        - Users
      summary: Share user
      description: Generate a sharing link or configure sharing permissions for the specified user
      operationId: UserShareById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: User shared successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/user/{_id}/submit:
    post:
      tags:
        - Users
      summary: Submit user
      description: Submit the specified user for review and approval workflow
      operationId: UserSubmitById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: User submitted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/user/{_id}/unpublish:
    post:
      tags:
        - Users
      summary: Unpublish user
      description: Unpublish the specified user, removing them from public visibility while preserving the content
      operationId: UserUnpublishById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: User unpublished successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  # Global
  /@apostrophecms/global:
    get:
      tags:
        - Global Content
      summary: Get global content
      description: Retrieve global site configuration and content that appears across all pages
      operationId: GlobalGet
      parameters:
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/PaginatedResponse'
                  - type: object
                    properties:
                      results:
                        type: array
                        items:
                          $ref: '#/components/schemas/Global'

        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

    post:
      tags:
        - Global Content
      summary: Update global content
      description: Update global site configuration and content (requires editor permissions or higher)
      operationId: GlobalPost
      parameters:
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                  description: Global content title
                  example: "Site Global Settings"
                footerContent:
                  type: string
                  description: Footer content that appears on all pages
                  example: "© 2024 My Website. All rights reserved."
                contactInfo:
                  type: object
                  description: Site-wide contact information
                  properties:
                    email:
                      type: string
                      format: email
                      example: "contact@example.com"
                    phone:
                      type: string
                      example: "+1 (555) 123-4567"
                    address:
                      type: string
                      example: "123 Main St, City, State 12345"
                socialMedia:
                  type: object
                  description: Social media links
                  properties:
                    facebook:
                      type: string
                      format: uri
                      example: "https://facebook.com/mysite"
                    twitter:
                      type: string
                      format: uri
                      example: "https://twitter.com/mysite"
                    linkedin:
                      type: string
                      format: uri
                      example: "https://linkedin.com/company/mysite"
                siteSettings:
                  type: object
                  description: Global site configuration
                  properties:
                    siteName:
                      type: string
                      example: "My Website"
                    tagline:
                      type: string
                      example: "Welcome to our amazing site"
                    maintenanceMode:
                      type: boolean
                      default: false
      responses:
        '200':
          description: Global content updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Global'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/global/archive:
    post:
      tags:
        - Global Content
      summary: Archive global document
      description: Archive the global document, making it inactive while preserving its data
      operationId: GlobalArchive
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkOperationRequest'
      responses:
        '200':
          description: Archive job started successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  jobId:
                    type: string
                    description: ID of the background job processing the archive operation
                    example: "b4kef9mgstbi5trzsw5dyfqm"
                required:
                  - jobId
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/global/localize:
    post:
      tags:
        - Global Content
      summary: Localize global document
      description: Create or update localized versions of the global document for different languages/regions
      operationId: GlobalLocalize
      responses:
        '200':
          description: Global localized successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Global'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/global/publish:
    post:
      tags:
        - Global Content
      summary: Publish global document
      description: Publish the global document, making it live and visible to end users
      operationId: GlobalPublish
      responses:
        '200':
          description: Global published successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Global'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/global/restore:
    post:
      tags:
        - Global Content
      summary: Restore global document
      description: Restore a previously archived global document, making it active again
      operationId: GlobalRestore
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkOperationRequest'
      responses:
        '200':
          description: Global restored successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Global'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/global/{_id}:
    delete:
      tags:
        - Global Content
      summary: Delete global document
      description: Permanently delete a specific global document by ID (requires appropriate permissions)
      operationId: GlobalDeleteById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Global deleted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Global'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

    get:
      tags:
        - Global Content
      summary: Get global document
      description: Retrieve a specific global document by ID (requires appropriate permissions)
      operationId: GlobalGetById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Global retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Global'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

    patch:
      tags:
        - Global Content
      summary: Update global document
      description: |
        Partially update a specific global document by ID using PATCH semantics.
        Writes must target the draft mode.
      operationId: GlobalPatchById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/GlobalPatch'
      responses:
        '200':
          description: Global updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Global'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

    put:
      tags:
        - Global Content
      summary: Replace global document
      description: Completely replace a specific global document by ID using PUT semantics
      operationId: GlobalPutById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Global replaced successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Global'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/global/{_id}/dismiss-submission:
    post:
      tags:
        - Global Content
      summary: Dismiss global submission
      description: Dismiss a pending submission for the specified global document, removing it from the review queue
      operationId: GlobalDismissSubmissionById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Global submission dismissed successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Global'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/global/{_id}/locale/{toLocale}:
    get:
      tags:
        - Global Content
      summary: Get global document locale
      description: Retrieve the specified global document in a specific locale
      operationId: GlobalGetLocaleById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/ToLocale'
      responses:
        '200':
          description: Global locale retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Global'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/global/{_id}/locales:
    get:
      tags:
        - Global Content
      summary: Get global document locales
      description: Retrieve all available locales for the specified global document
      operationId: GlobalGetLocalesById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Global locales retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string
                example: ["en", "es", "fr", "de"]
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/global/{_id}/localize:
    post:
      tags:
        - Global Content
      summary: Localize global document
      description: Create a localized version of the specified global document for a specific language/region
      operationId: GlobalLocalizeById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Global localized successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Global'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/global/{_id}/publish:
    post:
      tags:
        - Global Content
      summary: Publish global document
      description: Publish the specified global document, making it live and visible to end users
      operationId: GlobalPublishById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Global published successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Global'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/global/{_id}/revert-draft-to-published:
    post:
      tags:
        - Global Content
      summary: Revert draft to published
      description: Revert the draft version of the specified global document back to its published state
      operationId: GlobalRevertDraftToPublishedById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Global draft reverted to published successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Global'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/global/{_id}/revert-published-to-previous:
    post:
      tags:
        - Global Content
      summary: Revert published to previous
      description: Revert the published version of the specified global document to its previous published state
      operationId: GlobalRevertPublishedToPreviousById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Global published version reverted to previous successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Global'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/global/{_id}/share:
    post:
      tags:
        - Global Content
      summary: Share global document
      description: Generate a sharing link or configure sharing permissions for the specified global document
      operationId: GlobalShareById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Global shared successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Global'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/global/{_id}/submit:
    post:
      tags:
        - Global Content
      summary: Submit global document
      description: Submit the specified global document for review and approval workflow
      operationId: GlobalSubmitById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Global submitted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Global'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/global/{_id}/unpublish:
    post:
      tags:
        - Global Content
      summary: Unpublish global document
      description: Unpublish the specified global document, removing it from public visibility while preserving the content
      operationId: GlobalUnpublishById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Global unpublished successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Global'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  # Image
  /@apostrophecms/image:
    get:
      tags:
        - Media
      summary: Get images
      description: |
        Retrieve images from the media library. 
        Authentication is required for all requests other than GET requests 
        for images with defined publicApiProjection.
      operationId: ImageGet
      parameters:
        - $ref: '#/components/parameters/Page'
        - $ref: '#/components/parameters/PerPage'
        - $ref: '#/components/parameters/Search'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
        - $ref: '#/components/parameters/RenderAreas'
      responses:
        '200':
          description: Images retrieved successfully
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/PaginatedResponse'
                  - type: object
                    properties:
                      results:
                        type: array
                        items:
                          $ref: '#/components/schemas/Image'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []
        - {} # Allows unauthenticated access if publicApiProjection is defined

    post:
      tags:
        - Media
      summary: Create image
      description: Create a new image document (requires prior attachment upload)
      operationId: ImagePost
      parameters:
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - title
                - attachment
              properties:
                title:
                  type: string
                  example: "Beautiful Landscape"
                attachment:
                  $ref: '#/components/schemas/Attachment'
                  description: Attachment object from upload endpoint
                alt:
                  type: string
                  description: Alt text for accessibility
                  example: "A beautiful mountain landscape at sunset"
                credit:
                  type: string
                  description: Photo credit
                  example: "Photo by John Doe"
      responses:
        '200':
          description: Image created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Image'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image/archive:
    post:
      tags:
        - Media
      summary: Archive images
      description: Archive multiple images, making them inactive while preserving their data
      operationId: ImageArchive
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkOperationRequest'
      responses:
        '200':
          description: Archive job started successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  jobId:
                    type: string
                    description: ID of the background job processing the archive operation
                    example: "b4kef9mgstbi5trzsw5dyfqm"
                required:
                  - jobId
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image/autocrop:
    post:
      tags:
        - Media
      summary: Auto-crop images
      description: Automatically crop uploaded images using intelligent cropping algorithms
      operationId: ImageAutocrop
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                _ids:
                  type: array
                  items:
                    type: string
                  description: Array of image IDs to auto-crop
                cropRatio:
                  type: string
                  description: Desired aspect ratio for cropping
                  example: "16:9"
      responses:
        '200':
          description: Images auto-cropped successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Image'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image/localize:
    post:
      tags:
        - Media
      summary: Localize images
      description: Create or update localized versions of images for different languages/regions
      operationId: ImageLocalize
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                _ids:
                  type: array
                  items:
                    type: string
                  description: Array of image IDs to localize
                toLocale:
                  type: string
                  description: Target locale for localization
                  example: "es"
      responses:
        '200':
          description: Images localized successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Image'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image/publish:
    post:
      tags:
        - Media
      summary: Publish images
      description: Bulk publish multiple images, making them live and visible to end users
      operationId: ImagePublish
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                _ids:
                  type: array
                  items:
                    type: string
                  description: Array of image IDs to publish
      responses:
        '200':
          description: Images published successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Image'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image/restore:
    post:
      tags:
        - Media
      summary: Restore images
      description: Restore previously archived images, making them active again
      operationId: ImageRestore
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkOperationRequest'
      responses:
        '200':
          description: Images restored successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Image'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image/tag:
    post:
      tags:
        - Media
      summary: Tag images
      description: Add tags to multiple images for better organization and searchability
      operationId: ImageTag
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                _ids:
                  type: array
                  items:
                    type: string
                  description: Array of image IDs to tag
                tags:
                  type: array
                  items:
                    type: string
                  description: Array of tags to add to the images
                  example: ["landscape", "nature", "sunset"]
      responses:
        '200':
          description: Images tagged successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Image'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image/{_id}:
    get:
      tags:
        - Media
      summary: Get image document
      description: |
        Retrieve a specific image by ID from the media library.
        Authentication is required for all requests other than GET requests 
        for images with defined publicApiProjection.
      operationId: ImageGetById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
        - $ref: '#/components/parameters/RenderAreas'
      responses:
        '200':
          description: Image retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Image'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []
        - {} # Allows unauthenticated access if publicApiProjection is defined

    put:
      tags:
        - Media
      summary: Replace image document
      description: Completely replace an image document by ID using PUT semantics
      operationId: ImagePutById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - title
                - attachment
              properties:
                title:
                  type: string
                  example: "Beautiful Landscape"
                attachment:
                  $ref: '#/components/schemas/Attachment'
                  description: Attachment object from upload endpoint
                alt:
                  type: string
                  description: Alt text for accessibility
                  example: "A beautiful mountain landscape at sunset"
                credit:
                  type: string
                  description: Photo credit
                  example: "Photo by John Doe"
      responses:
        '200':
          description: Image replaced successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Image'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

    patch:
      tags:
        - Media
      summary: Update image document
      description: Partially update a specific image document by ID using PATCH semantics
      operationId: ImagePatchById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                  example: "Beautiful Landscape"
                alt:
                  type: string
                  description: Alt text for accessibility
                  example: "A beautiful mountain landscape at sunset"
                credit:
                  type: string
                  description: Photo credit
                  example: "Photo by John Doe"
              description: Only include fields to update
      responses:
        '200':
          description: Image updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Image'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

    delete:
      tags:
        - Media
      summary: Delete image document
      description: Permanently delete a specific image document by ID (requires appropriate permissions)
      operationId: ImageDeleteById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Image deleted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Image'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image/{_id}/dismiss-submission:
    post:
      tags:
        - Media
      summary: Dismiss image submission
      description: Dismiss a pending submission for the specified image document, removing it from the review queue
      operationId: ImageDismissSubmissionById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Image submission dismissed successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Image'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image/{_id}/locale/{toLocale}:
    get:
      tags:
        - Media
      summary: Get image document locale
      description: Retrieve the specified image document in a specific locale
      operationId: ImageGetLocaleById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/ToLocale'
      responses:
        '200':
          description: Image locale retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Image'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image/{_id}/locales:
    get:
      tags:
        - Media
      summary: Get image document locales
      description: Retrieve all available locales for the specified image document
      operationId: ImageGetLocalesById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Image locales retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string
                example: ["en", "es", "fr", "de"]
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image/{_id}/localize:
    post:
      tags:
        - Media
      summary: Localize image document
      description: Create a localized version of the specified image document for a specific language/region
      operationId: ImageLocalizeById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                toLocale:
                  type: string
                  description: Target locale for localization
                  example: "es"
      responses:
        '200':
          description: Image localized successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Image'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image/{_id}/publish:
    post:
      tags:
        - Media
      summary: Publish image document
      description: Publish the specified image document, making it live and visible to end users
      operationId: ImagePublishById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Image published successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Image'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image/{_id}/revert-draft-to-published:
    post:
      tags:
        - Media
      summary: Revert image draft to published
      description: Revert the draft version of the specified image document back to its published state
      operationId: ImageRevertDraftToPublishedById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Image draft reverted to published successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Image'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image/{_id}/revert-published-to-previous:
    post:
      tags:
        - Media
      summary: Revert image published to previous
      description: Revert the published version of the specified image document to its previous published state
      operationId: ImageRevertPublishedToPreviousById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Image published version reverted to previous successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Image'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image/{_id}/share:
    post:
      tags:
        - Media
      summary: Share image document
      description: Generate a sharing link or configure sharing permissions for the specified image document
      operationId: ImageShareById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Image shared successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Image'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image/{imageId}/src:
    get:
      tags:
        - Media
      summary: Get image source URL
      description: Retrieve the source URL for a specific image, with optional size and format parameters
      operationId: ImageGetSrcById
      parameters:
        - $ref: '#/components/parameters/ImageDocId'
        - name: size
          in: query
          description: Image size variant
          schema:
            type: string
            enum: [thumbnail, small, medium, large, original]
            default: original
        - name: format
          in: query
          description: Image format
          schema:
            type: string
            enum: [jpg, jpeg, png, webp, avif]
        - name: quality
          in: query
          description: Image quality (1-100)
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 80
      responses:
        '200':
          description: Image source URL retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  url:
                    type: string
                    format: uri
                    description: Direct URL to the image file
                    example: "https://example.com/uploads/images/landscape-large.jpg"
                  width:
                    type: integer
                    description: Image width in pixels
                    example: 1920
                  height:
                    type: integer
                    description: Image height in pixels
                    example: 1080
                  format:
                    type: string
                    description: Image format
                    example: "jpg"
                  size:
                    type: integer
                    description: File size in bytes
                    example: 245760
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []
        - {} # Allows unauthenticated access for public images

  /@apostrophecms/image/{_id}/submit:
    post:
      tags:
        - Media
      summary: Submit image document
      description: Submit the specified image document for review and approval workflow
      operationId: ImageSubmitById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Image submitted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Image'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image/{_id}/unpublish:
    post:
      tags:
        - Media
      summary: Unpublish image document
      description: Unpublish the specified image document, removing it from public visibility while preserving the content
      operationId: ImageUnpublishById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Image unpublished successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Image'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  # Files
  /@apostrophecms/file:
    get:
      tags:
        - Media
      summary: List files
      description: Retrieve a paginated list of files from the media library
      operationId: FileGet
      parameters:
        - $ref: '#/components/parameters/Page'
        - $ref: '#/components/parameters/PerPage'
        - $ref: '#/components/parameters/Search'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
        - $ref: '#/components/parameters/RenderAreas'
      responses:
        '200':
          description: Files retrieved successfully
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/PaginatedResponse'
                  - type: object
                    properties:
                      results:
                        type: array
                        items:
                          $ref: '#/components/schemas/FileObject'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []
        - {} # Allows unauthenticated access if publicApiProjection is defined

    post:
      tags:
        - Media
      summary: Create file
      description: Create a new file document (requires prior attachment upload)
      operationId: FilePost
      parameters:
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - title
                - attachment
              properties:
                title:
                  type: string
                  example: "Important Document"
                attachment:
                  $ref: '#/components/schemas/Attachment'
                  description: Attachment object from upload endpoint
                description:
                  type: string
                  description: File description
                  example: "Quarterly report PDF"
      responses:
        '200':
          description: File created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileObject'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file/archive:
    post:
      tags:
        - Media
      summary: Archive files
      description: Archive multiple files, making them inactive while preserving their data
      operationId: FileArchive
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkOperationRequest'
      responses:
        '200':
          description: Archive job started successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  jobId:
                    type: string
                    description: ID of the background job processing the archive operation
                    example: "b4kef9mgstbi5trzsw5dyfqm"
                required:
                  - jobId
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file/localize:
    post:
      tags:
        - Media
      summary: Localize files
      description: Create or update localized versions of files for different languages/regions
      operationId: FileLocalize
      responses:
        '200':
          description: Files localized successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/FileObject'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file/publish:
    post:
      tags:
        - Media
      summary: Publish files
      description: Bulk publish multiple files, making them live and visible to end users
      operationId: FilePublish
      responses:
        '200':
          description: Files published successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/FileObject'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file/restore:
    post:
      tags:
        - Media
      summary: Restore files
      description: Restore previously archived files, making them active again
      operationId: FileRestore
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkOperationRequest'
      responses:
        '200':
          description: Files restored successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/FileObject'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file/{_id}:
    delete:
      tags:
        - Media
      summary: Delete file
      description: Permanently delete a specific file by ID (requires appropriate permissions)
      operationId: FileDeleteById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      responses:
        '200':
          description: File deleted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileObject'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

    get:
      tags:
        - Media
      summary: Get file by ID
      description: Retrieve a specific file by ID from the media library
      operationId: FileGetById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
        - $ref: '#/components/parameters/RenderAreas'
      responses:
        '200':
          description: File retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileObject'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []
        - {} # Allows unauthenticated access if publicApiProjection is defined

    patch:
      tags:
        - Media
      summary: Update file
      description: Partially update a specific file by ID using PATCH semantics
      operationId: FilePatchById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                  description: File title
                  example: "Important Document"
                description:
                  type: string
                  description: File description
                  example: "Quarterly report PDF"
              description: Only include fields to update
      responses:
        '200':
          description: File updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileObject'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

    put:
      tags:
        - Media
      summary: Replace file
      description: Completely replace a specific file by ID using PUT semantics
      operationId: FilePutById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - title
                - attachment
              properties:
                title:
                  type: string
                  example: "Important Document"
                attachment:
                  $ref: '#/components/schemas/Attachment'
                  description: Attachment object from upload endpoint
                description:
                  type: string
                  description: File description
                  example: "Quarterly report PDF"
      responses:
        '200':
          description: File replaced successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileObject'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file/{_id}/dismiss-submission:
    post:
      tags:
        - Media
      summary: Dismiss file submission
      description: Dismiss a pending submission for the specified file, removing it from the review queue
      operationId: FileDismissSubmissionById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: File submission dismissed successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileObject'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file/{_id}/locale/{toLocale}:
    get:
      tags:
        - Media
      summary: Get file locale
      description: Retrieve the specified file in a specific locale
      operationId: FileGetLocaleById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/ToLocale'
      responses:
        '200':
          description: File locale retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileObject'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file/{_id}/locales:
    get:
      tags:
        - Media
      summary: Get file locales
      description: Retrieve all available locales for the specified file
      operationId: FileGetLocalesById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: File locales retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string
                example: ["en", "es", "fr", "de"]
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file/{_id}/localize:
    post:
      tags:
        - Media
      summary: Localize file
      description: Create a localized version of the specified file for a specific language/region
      operationId: FileLocalizeById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: File localized successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileObject'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file/{_id}/publish:
    post:
      tags:
        - Media
      summary: Publish file
      description: Publish the specified file, making it live and visible to end users
      operationId: FilePublishById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: File published successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileObject'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file/{_id}/revert-draft-to-published:
    post:
      tags:
        - Media
      summary: Revert file draft to published
      description: Revert the draft version of the specified file back to its published state
      operationId: FileRevertDraftToPublishedById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: File draft reverted to published successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileObject'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file/{_id}/revert-published-to-previous:
    post:
      tags:
        - Media
      summary: Revert file published to previous
      description: Revert the published version of the specified file to its previous published state
      operationId: FileRevertPublishedToPreviousById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: File published version reverted to previous successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileObject'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file/{_id}/share:
    post:
      tags:
        - Media
      summary: Share file
      description: Generate a sharing link or configure sharing permissions for the specified file
      operationId: FileShareById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: File shared successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileObject'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file/{_id}/submit:
    post:
      tags:
        - Media
      summary: Submit file
      description: Submit the specified file for review and approval workflow
      operationId: FileSubmitById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: File submitted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileObject'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file/{_id}/unpublish:
    post:
      tags:
        - Media
      summary: Unpublish file
      description: Unpublish the specified file, removing it from public visibility while preserving the content
      operationId: FileUnpublishById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: File unpublished successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileObject'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  # Image-tags
  /@apostrophecms/image-tag:
    get:
      tags:
        - Media
      summary: Get image tags
      description: Retrieve image tags for organizing images
      operationId: ImageTagGet
      parameters:
        - $ref: '#/components/parameters/Page'
        - $ref: '#/components/parameters/PerPage'
        - $ref: '#/components/parameters/Search'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
        - $ref: '#/components/parameters/RenderAreas'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/PaginatedResponse'
                  - type: object
                    properties:
                      results:
                        type: array
                        items:
                          $ref: '#/components/schemas/ImageTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []
        - {} # Allows unauthenticated access if publicApiProjection is defined

    post:
      tags:
        - Media
      summary: Create image tag
      description: Create a new image tag for organizing images
      operationId: ImageTagPost
      parameters:
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - title
              properties:
                title:
                  type: string
                  example: "Hero Images"
                  description: Tag name
                slug:
                  type: string
                  example: "hero-images"
                  description: URL-friendly identifier (auto-generated if not provided)
      responses:
        '200':
          description: Image tag created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImageTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image-tag/archive:
    post:
      tags:
        - Media
      summary: Archive image tags
      description: Archive multiple image tags, making them inactive while preserving their data
      operationId: ImageTagArchive
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkOperationRequest'
      responses:
        '200':
          description: Archive job started successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  jobId:
                    type: string
                    description: ID of the background job processing the archive operation
                    example: "b4kef9mgstbi5trzsw5dyfqm"
                required:
                  - jobId
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image-tag/localize:
    post:
      tags:
        - Media
      summary: Localize image tags
      description: Create or update localized versions of image tags for different languages/regions
      operationId: ImageTagLocalize
      responses:
        '200':
          description: Image tags localized successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ImageTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image-tag/publish:
    post:
      tags:
        - Media
      summary: Publish image tags
      description: Publish multiple image tags, making them live and visible to end users
      operationId: ImageTagPublish
      responses:
        '200':
          description: Image tags published successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ImageTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image-tag/restore:
    post:
      tags:
        - Media
      summary: Restore image tags
      description: Restore previously archived image tags, making them active again
      operationId: ImageTagRestore
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkOperationRequest'
      responses:
        '200':
          description: Image tags restored successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ImageTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image-tag/{_id}:
    delete:
      tags:
        - Media
      summary: Delete image tag
      description: Permanently delete a specific image tag by ID (requires appropriate permissions)
      operationId: ImageTagDeleteById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Image tag deleted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImageTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

    get:
      tags:
        - Media
      summary: Get image tag
      description: Retrieve a specific image tag by ID
      operationId: ImageTagGetById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
        - $ref: '#/components/parameters/RenderAreas'
      responses:
        '200':
          description: Image tag retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImageTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []
        - {} # Allows unauthenticated access if publicApiProjection is defined

    patch:
      tags:
        - Media
      summary: Update image tag
      description: Partially update a specific image tag by ID using PATCH semantics
      operationId: ImageTagPatchById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                  example: "Hero Images"
                  description: Tag name
                slug:
                  type: string
                  example: "hero-images"
                  description: URL-friendly identifier
              description: Only include fields to update
      responses:
        '200':
          description: Image tag updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImageTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

    put:
      tags:
        - Media
      summary: Replace image tag
      description: Completely replace a specific image tag by ID using PUT semantics
      operationId: ImageTagPutById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - title
              properties:
                title:
                  type: string
                  example: "Hero Images"
                  description: Tag name
                slug:
                  type: string
                  example: "hero-images"
                  description: URL-friendly identifier (auto-generated if not provided)
      responses:
        '200':
          description: Image tag replaced successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImageTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image-tag/{_id}/dismiss-submission:
    post:
      tags:
        - Media
      summary: Dismiss image tag submission
      description: Dismiss a pending submission for the specified image tag, removing it from the review queue
      operationId: ImageTagDismissSubmissionById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Image tag submission dismissed successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImageTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image-tag/{_id}/locale/{toLocale}:
    get:
      tags:
        - Media
      summary: Get image tag locale
      description: Retrieve the specified image tag in a specific locale
      operationId: ImageTagGetLocaleById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/ToLocale'
      responses:
        '200':
          description: Image tag locale retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImageTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image-tag/{_id}/locales:
    get:
      tags:
        - Media
      summary: Get image tag locales
      description: Retrieve all available locales for the specified image tag
      operationId: ImageTagGetLocalesById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Image tag locales retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string
                example: ["en", "es", "fr", "de"]
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image-tag/{_id}/localize:
    post:
      tags:
        - Media
      summary: Localize image tag
      description: Create a localized version of the specified image tag for a specific language/region
      operationId: ImageTagLocalizeById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Image tag localized successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImageTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image-tag/{_id}/publish:
    post:
      tags:
        - Media
      summary: Publish image tag
      description: Publish the specified image tag, making it live and visible to end users
      operationId: ImageTagPublishById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Image tag published successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImageTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image-tag/{_id}/revert-draft-to-published:
    post:
      tags:
        - Media
      summary: Revert draft to published
      description: Revert the draft version of the specified image tag back to its published state
      operationId: ImageTagRevertDraftToPublishedById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Image tag draft reverted to published successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImageTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image-tag/{_id}/revert-published-to-previous:
    post:
      tags:
        - Media
      summary: Revert published to previous
      description: Revert the published version of the specified image tag to its previous published state
      operationId: ImageTagRevertPublishedToPreviousById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Image tag published version reverted to previous successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImageTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image-tag/{_id}/share:
    post:
      tags:
        - Media
      summary: Share image tag
      description: Generate a sharing link or configure sharing permissions for the specified image tag
      operationId: ImageTagShareById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Image tag shared successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImageTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image-tag/{_id}/submit:
    post:
      tags:
        - Media
      summary: Submit image tag
      description: Submit the specified image tag for review and approval workflow
      operationId: ImageTagSubmitById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Image tag submitted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImageTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/image-tag/{_id}/unpublish:
    post:
      tags:
        - Media
      summary: Unpublish image tag
      description: Unpublish the specified image tag, removing it from public visibility while preserving the content
      operationId: ImageTagUnpublishById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Image tag unpublished successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImageTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  # File-tags
  /@apostrophecms/file-tag:
    get:
      tags:
        - Media
      summary: List file tags
      description: Retrieve a list of file tags used for organizing and categorizing uploaded files
      operationId: FileTagGet
      parameters:
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
        - $ref: '#/components/parameters/RenderAreas'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: object
                properties:
                  results:
                    type: array
                    items:
                      $ref: '#/components/schemas/FileTag'
                  pages:
                    type: integer
                    description: Total number of pages
                  currentPage:
                    type: integer
                    description: Current page number
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []
        - {}  # Allows unauthenticated access to file tags

    post:
      tags:
        - Media
      summary: Create file tag
      description: Create a new file tag for organizing uploaded files (requires editor permissions or higher)
      operationId: FileTagPost
      parameters:
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - title
              properties:
                title:
                  type: string
                  description: File tag name
                  example: "Documents"
                description:
                  type: string
                  description: Optional description of the file tag
                  example: "For organizing PDF documents and text files"
                color:
                  type: string
                  description: Color code for visual organization
                  pattern: "^#[0-9A-Fa-f]{6}$"
                  example: "#3498db"
      responses:
        '200':
          description: File tag created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file-tag/archive:
    post:
      tags:
        - Media
      summary: Archive file tags
      description: Archive multiple file tags, making them inactive while preserving their data
      operationId: FileTagArchive
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkOperationRequest'
      responses:
        '200':
          description: File tags archived successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/FileTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file-tag/localize:
    post:
      tags:
        - Media
      summary: Localize file tags
      description: Create or update localized versions of file tags for different languages/regions
      operationId: FileTagLocalize
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                _ids:
                  type: array
                  items:
                    type: string
                  description: Array of file tag IDs to localize
                toLocale:
                  type: string
                  description: Target locale for localization
                  example: "es"
      responses:
        '200':
          description: File tags localized successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/FileTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file-tag/publish:
    post:
      tags:
        - Media
      summary: Publish file tags
      description: Publish multiple file tags, making them live and visible to end users
      operationId: FileTagPublish
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                _ids:
                  type: array
                  items:
                    type: string
                  description: Array of file tag IDs to publish
      responses:
        '200':
          description: File tags published successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/FileTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file-tag/restore:
    post:
      tags:
        - Media
      summary: Restore file tags
      description: Restore previously archived file tags, making them active again
      operationId: FileTagRestore
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkOperationRequest'
      responses:
        '200':
          description: File tags restored successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/FileTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file-tag/{_id}:
    delete:
      tags:
        - Media
      summary: Delete file tag
      description: Permanently delete a specific file tag by ID (requires appropriate permissions)
      operationId: FileTagDeleteById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: File tag deleted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

    get:
      tags:
        - Media
      summary: Get file tag
      description: Retrieve a specific file tag by ID
      operationId: FileTagGetById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      responses:
        '200':
          description: File tag retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []
        - {}  # Allows unauthenticated access to file tags

    patch:
      tags:
        - Media
      summary: Update file tag
      description: Partially update a specific file tag by ID using PATCH semantics
      operationId: FileTagPatchById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                  description: File tag name
                  example: "Updated Documents"
                description:
                  type: string
                  description: Optional description of the file tag
                  example: "Updated description for organizing files"
                color:
                  type: string
                  description: Color code for visual organization
                  pattern: "^#[0-9A-Fa-f]{6}$"
                  example: "#e74c3c"
      responses:
        '200':
          description: File tag updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

    put:
      tags:
        - Media
      summary: Replace file tag
      description: Completely replace a specific file tag by ID using PUT semantics
      operationId: FileTagPutById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - title
              properties:
                title:
                  type: string
                  description: File tag name
                  example: "Replaced Documents"
                description:
                  type: string
                  description: Optional description of the file tag
                  example: "Completely replaced file tag description"
                color:
                  type: string
                  description: Color code for visual organization
                  pattern: "^#[0-9A-Fa-f]{6}$"
                  example: "#9b59b6"
      responses:
        '200':
          description: File tag replaced successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file-tag/{_id}/dismiss-submission:
    post:
      tags:
        - Media
      summary: Dismiss file tag submission
      description: Dismiss a pending submission for the specified file tag, removing it from the review queue
      operationId: FileTagDismissSubmissionById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: File tag submission dismissed successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file-tag/{_id}/locale/{toLocale}:
    get:
      tags:
        - Media
      summary: Get file tag locale
      description: Retrieve the specified file tag in a specific locale
      operationId: FileTagGetLocaleById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/ToLocale'
      responses:
        '200':
          description: File tag locale retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file-tag/{_id}/locales:
    get:
      tags:
        - Media
      summary: Get file tag locales
      description: Retrieve all available locales for the specified file tag
      operationId: FileTagGetLocalesById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: File tag locales retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string
                example: ["en", "es", "fr", "de"]
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file-tag/{_id}/localize:
    post:
      tags:
        - Media
      summary: Localize file tag
      description: Create a localized version of the specified file tag for a specific language/region
      operationId: FileTagLocalizeById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                toLocale:
                  type: string
                  description: Target locale for localization
                  example: "es"
      responses:
        '200':
          description: File tag localized successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file-tag/{_id}/publish:
    post:
      tags:
        - Media
      summary: Publish file tag
      description: Publish the specified file tag, making it live and visible to end users
      operationId: FileTagPublishById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: File tag published successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file-tag/{_id}/revert-draft-to-published:
    post:
      tags:
        - Media
      summary: Revert file tag draft to published
      description: Revert the draft version of the specified file tag back to its published state
      operationId: FileTagRevertDraftToPublishedById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: File tag draft reverted to published successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file-tag/{_id}/revert-published-to-previous:
    post:
      tags:
        - Media
      summary: Revert file tag published to previous
      description: Revert the published version of the specified file tag to its previous published state
      operationId: FileTagRevertPublishedToPreviousById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: File tag published version reverted to previous successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file-tag/{_id}/share:
    post:
      tags:
        - Media
      summary: Share file tag
      description: Generate a sharing link or configure sharing permissions for the specified file tag
      operationId: FileTagShareById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: File tag shared successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file-tag/{_id}/submit:
    post:
      tags:
        - Media
      summary: Submit file tag
      description: Submit the specified file tag for review and approval workflow
      operationId: FileTagSubmitById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: File tag submitted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/file-tag/{_id}/unpublish:
    post:
      tags:
        - Media
      summary: Unpublish file tag
      description: Unpublish the specified file tag, removing it from public visibility while preserving the content
      operationId: FileTagUnpublishById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: File tag unpublished successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileTag'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  # Submitted-draft
  /@apostrophecms/submitted-draft:
    get:
      tags:
        - Submitted Drafts
      summary: List submitted drafts
      description: Retrieve a list of all submitted drafts in the review queue
      operationId: SubmittedDraftGet
      parameters:
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
        - $ref: '#/components/parameters/RenderAreas'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: object
                properties:
                  results:
                    type: array
                    items:
                      $ref: '#/components/schemas/SubmittedDraft'
                  pages:
                    type: integer
                    description: Total number of pages available
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

    post:
      tags:
        - Submitted Drafts
      summary: Create submitted draft
      description: Create a new submitted draft for review workflow (requires contributor permissions or higher)
      operationId: SubmittedDraftPost
      parameters:
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                  description: Title of the submitted draft
                  example: "New Article Draft"
                content:
                  type: string
                  description: Content of the submitted draft
                  example: "This is the draft content awaiting review."
                author:
                  type: string
                  description: Author of the submitted draft
                  example: "John Doe"
                submissionNotes:
                  type: string
                  description: Notes from the submitter about the draft
                  example: "Please review for accuracy and tone."
                priority:
                  type: string
                  enum: [low, normal, high, urgent]
                  default: normal
                  description: Priority level for review
                category:
                  type: string
                  description: Category or type of content being submitted
                  example: "blog-post"
      responses:
        '200':
          description: Submitted draft created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubmittedDraft'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/submitted-draft/archive:
    post:
      tags:
        - Submitted Drafts
      summary: Archive submitted drafts
      description: Archive multiple submitted drafts, removing them from active review queues while preserving data
      operationId: SubmittedDraftArchive
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkOperationRequest'
      responses:
        '200':
          description: Submitted drafts archived successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  archived:
                    type: array
                    items:
                      $ref: '#/components/schemas/SubmittedDraft'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /@apostrophecms/submitted-draft/localize:
    post:
      tags:
        - Submitted Drafts
      summary: Localize submitted drafts
      description: Create or update localized versions of submitted drafts for different languages/regions
      operationId: SubmittedDraftLocalize
      responses:
        '200':
          description: Submitted drafts localized successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  localized:
                    type: array
                    items:
                      $ref: '#/components/schemas/SubmittedDraft'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /@apostrophecms/submitted-draft/publish:
    post:
      tags:
        - Submitted Drafts
      summary: Publish submitted drafts
      description: Bulk publish multiple submitted drafts, moving them from draft status to published content
      operationId: SubmittedDraftPublish
      responses:
        '200':
          description: Submitted drafts published successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  published:
                    type: array
                    items:
                      $ref: '#/components/schemas/SubmittedDraft'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /@apostrophecms/submitted-draft/restore:
    post:
      tags:
        - Submitted Drafts
      summary: Restore submitted drafts
      description: Restore previously archived submitted drafts, returning them to active review queues
      operationId: SubmittedDraftRestore
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkOperationRequest'
      responses:
        '200':
          description: Submitted drafts restored successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  restored:
                    type: array
                    items:
                      $ref: '#/components/schemas/SubmittedDraft'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /@apostrophecms/submitted-draft/{_id}:
    delete:
      tags:
        - Submitted Drafts
      summary: Delete submitted draft
      description: Permanently delete a specific submitted draft by ID (requires appropriate permissions)
      operationId: SubmittedDraftDeleteById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Submitted draft deleted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubmittedDraft'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

    get:
      tags:
        - Submitted Drafts
      summary: Get submitted draft
      description: Retrieve a specific submitted draft by ID (requires appropriate permissions)
      operationId: SubmittedDraftGetById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Submitted draft retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubmittedDraft'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

    patch:
      tags:
        - Submitted Drafts
      summary: Update submitted draft
      description: Partially update a specific submitted draft by ID using PATCH semantics
      operationId: SubmittedDraftPatchById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                  description: Updated title of the submitted draft
                content:
                  type: string
                  description: Updated content of the submitted draft
                submissionNotes:
                  type: string
                  description: Updated notes about the submission
                priority:
                  type: string
                  enum: [low, normal, high, urgent]
                  description: Updated priority level for review
      responses:
        '200':
          description: Submitted draft updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubmittedDraft'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

    put:
      tags:
        - Submitted Drafts
      summary: Replace submitted draft
      description: Completely replace a specific submitted draft by ID using PUT semantics
      operationId: SubmittedDraftPutById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                  description: Title of the submitted draft
                  example: "Updated Article Draft"
                content:
                  type: string
                  description: Content of the submitted draft
                  example: "This is the updated draft content."
                author:
                  type: string
                  description: Author of the submitted draft
                  example: "John Doe"
                submissionNotes:
                  type: string
                  description: Notes about the submission
                  example: "Updated after initial feedback."
                priority:
                  type: string
                  enum: [low, normal, high, urgent]
                  default: normal
                  description: Priority level for review
              required:
                - title
                - content
      responses:
        '200':
          description: Submitted draft replaced successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubmittedDraft'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /@apostrophecms/submitted-draft/{_id}/dismiss-submission:
    post:
      tags:
        - Submitted Drafts
      summary: Dismiss submission
      description: Dismiss a pending submission for the specified draft, removing it from the review queue
      operationId: SubmittedDraftDismissSubmissionById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Submission dismissed successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubmittedDraft'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /@apostrophecms/submitted-draft/{_id}/locale/{toLocale}:
    get:
      tags:
        - Submitted Drafts
      summary: Get submitted draft locale
      description: Retrieve the specified submitted draft in a specific locale
      operationId: SubmittedDraftGetLocaleById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
        - $ref: '#/components/parameters/ToLocale'
      responses:
        '200':
          description: Submitted draft locale retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubmittedDraft'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /@apostrophecms/submitted-draft/{_id}/locales:
    get:
      tags:
        - Submitted Drafts
      summary: Get submitted draft locales
      description: Retrieve all available locales for the specified submitted draft
      operationId: SubmittedDraftGetLocalesById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Submitted draft locales retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string
                example: ["en", "es", "fr", "de"]
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /@apostrophecms/submitted-draft/{_id}/localize:
    post:
      tags:
        - Submitted Drafts
      summary: Localize submitted draft
      description: Create a localized version of the specified submitted draft for a specific language/region
      operationId: SubmittedDraftLocalizeById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Submitted draft localized successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubmittedDraft'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /@apostrophecms/submitted-draft/{_id}/publish:
    post:
      tags:
        - Submitted Drafts
      summary: Publish submitted draft
      description: Publish the specified submitted draft, moving it from draft status to published content
      operationId: SubmittedDraftPublishById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Submitted draft published successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubmittedDraft'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /@apostrophecms/submitted-draft/{_id}/revert-draft-to-published:
    post:
      tags:
        - Submitted Drafts
      summary: Revert draft to published
      description: Revert the draft version of the specified submitted draft back to its published state
      operationId: SubmittedDraftRevertDraftToPublishedById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Draft reverted to published successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubmittedDraft'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /@apostrophecms/submitted-draft/{_id}/revert-published-to-previous:
    post:
      tags:
        - Submitted Drafts
      summary: Revert published to previous
      description: Revert the published version of the specified submitted draft to its previous published state
      operationId: SubmittedDraftRevertPublishedToPreviousById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Published version reverted to previous successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubmittedDraft'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /@apostrophecms/submitted-draft/{_id}/share:
    post:
      tags:
        - Submitted Drafts
      summary: Share submitted draft
      description: Generate a sharing link or configure sharing permissions for the specified submitted draft
      operationId: SubmittedDraftShareById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Submitted draft shared successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubmittedDraft'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /@apostrophecms/submitted-draft/{_id}/submit:
    post:
      tags:
        - Submitted Drafts
      summary: Submit draft
      description: Submit the specified draft for review and approval workflow
      operationId: SubmittedDraftSubmitById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Draft submitted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubmittedDraft'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /@apostrophecms/submitted-draft/{_id}/unpublish:
    post:
      tags:
        - Submitted Drafts
      summary: Unpublish submitted draft
      description: Unpublish the specified submitted draft, removing it from public visibility while preserving the content
      operationId: SubmittedDraftUnpublishById
      parameters:
        - $ref: '#/components/parameters/DocumentId'
      responses:
        '200':
          description: Submitted draft unpublished successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubmittedDraft'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

  #Attachments
  /@apostrophecms/attachment/upload:
    post:
      tags:
        - Attachments
      summary: Upload media file
      description: |
        Upload a media file to create an attachment. The uploaded file can then be used
        to create image or file documents. Uses multipart/form-data encoding with the
        file uploaded under the name 'file'.
      operationId: AttachmentUpload
      parameters:
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - file
              properties:
                file:
                  type: string
                  format: binary
                  description: The file to upload
            encoding:
              file:
                contentType: image/*, application/pdf, application/*, text/*
      responses:
        '200':
          description: File uploaded successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Attachment'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '413':
          description: File too large
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        '415':
          description: Unsupported file type
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/attachment/crop:
    post:
      tags:
        - Attachments
      summary: Crop image attachment
      description: |
        Create a cropped version of an existing image attachment. The crop object
        is appended to the crops array property of the attachment document.
        The newly uploaded image file will be stored with a filename using the
        crop properties: {_id}-{name}.{top}.{left}.{width}.{height}.{extension}
      operationId: AttachmentCrop
      parameters:
        - $ref: '#/components/parameters/AposMode'
        - $ref: '#/components/parameters/AposLocale'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - _id
                - crop
              properties:
                _id:
                  type: string
                  description: The _id property of an existing image attachment document
                  example: "ckj0akbxa003vp39kfbxgb8zg"
                crop:
                  type: object
                  description: Crop coordinates and dimensions
                  required:
                    - top
                    - left
                    - width
                    - height
                  properties:
                    top:
                      type: integer
                      description: Top coordinate of the crop area (pixels)
                      example: 10
                      minimum: 0
                    left:
                      type: integer
                      description: Left coordinate of the crop area (pixels)
                      example: 15
                      minimum: 0
                    width:
                      type: integer
                      description: Width of the crop area (pixels)
                      example: 300
                      minimum: 1
                    height:
                      type: integer
                      description: Height of the crop area (pixels)
                      example: 200
                      minimum: 1
      responses:
        '200':
          description: Image cropped successfully
          content:
            application/json:
              schema:
                type: boolean
                example: true
                description: Returns true on successful crop
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          description: Unprocessable entity - crop coordinates exceed image bounds
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  # i18n
  /@apostrophecms/i18n/locales:
    get:
      tags:
        - Internationalization
      summary: Get all configured locales
      description: |
        Returns information about all configured locales including labels and edit permissions.
        Authentication is required to access locale configuration data.
      operationId: I18nLocalesGet
      responses:
        '200':
          description: Locales retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LocalesResponse'
              example:
                en:
                  label: "English"
                  _edit: true
                fr:
                  label: "French"
                  _edit: false
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/i18n/locale:
    post:
      tags:
        - Internationalization
      summary: Get locale path and manage clipboard
      description: |
        Returns the path to a locale home-page or optional document and makes the clipboard 
        available in the given locale. Used for cross-locale navigation.
      parameters:
        - name: contextDocId
          in: query
          description: Optional document ID for the path, defaults to locale home-page
          required: false
          schema:
            type: string
            example: "cloydg3ka0005qcls5vmg8sb9"
        - name: locale
          in: query
          description: Required. The locale for the desired path
          required: true
          schema:
            type: string
            example: "fr"
        - name: clipboard
          in: query
          description: Optional clipboard content for cross-domain situations
          required: false
          schema:
            type: string
            example: "exampleClipboardContent"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LocaleRequest'
            examples:
              basic_locale_switch:
                summary: Basic locale switch to home page
                value:
                  locale: "fr"
              with_context_doc:
                summary: Switch locale for specific document
                value:
                  locale: "fr"
                  contextDocId: "cloydg3ka0005qcls5vmg8sb9"
              with_clipboard:
                summary: Cross-domain switch with clipboard
                value:
                  locale: "fr"
                  contextDocId: "cloydg3ka0005qcls5vmg8sb9"
                  clipboard: "exampleClipboardContent"
      operationId: I18nLocalePost
      responses:
        '200':
          description: Locale path retrieved successfully
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/SameHostnameResponse'
                  - $ref: '#/components/schemas/DifferentHostnameResponse'
              examples:
                same_hostname:
                  summary: Same hostname response
                  value:
                    redirectTo: "/fr/page-slug"
                different_hostname:
                  summary: Different hostname response
                  value:
                    redirectTo: "https://fr.example.com/french-example-page?aposCrossDomainSessionToken=generated_token"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []

  /@apostrophecms/i18n/exist-in-locale:
    post:
      tags:
        - Internationalization
      summary: Check document existence in locale
      description: |
        Returns arrays of original document IDs, new locale IDs, and aposDocIds 
        for an array of document IDs in a specified locale and mode.
      parameters:
        - name: ids
          in: query
          description: Required. Array of document IDs to check in the specified locale
          required: true
          schema:
            type: array
            items:
              type: string
            example: ["cloydg3ka0005qcls5vmg8sb9", "cloydg3ka0005qcls5vmg8sb8"]
        - name: locale
          in: query
          description: Required. The locale in which to check for the document IDs
          required: true
          schema:
            type: string
            example: "fr"
        - name: mode
          in: query
          description: Required. The mode (draft or published) in which to check for the document IDs
          required: true
          schema:
            type: string
            enum: [draft, published]
            example: "published"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExistInLocaleRequest'
            example:
              ids: ["cloydg3ka0005qcls5vmg8sb9", "cloydg3ka0005qcls5vmg8sb8"]
              locale: "fr"
              mode: "published"
      operationId: I18nExistsPost
      responses:
        '200':
          description: Document existence check completed successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExistInLocaleResponse'
              example:
                originalLocaleIds: ["cloydg3ka0005qcls5vmg8sb9:en:published", "cloydg3ka0005qcls5vmg8sb8:en:published"]
                newLocaleIds: ["cloydg3ka0005qcls5vmg8sb9:fr:published", "cloydg3ka0005qcls5vmg8sb8:fr:published"]
                aposDocIds: ["cloydg3ka0005qcls5vmg8sb9", "cloydg3ka0005qcls5vmg8sb8"]
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - SessionAuth: []
