> ## Documentation Index
> Fetch the complete documentation index at: https://docs.moda.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Validate Canvas Edit

> Validate the current Main Edit or a proposed operation batch without writing.



## OpenAPI

````yaml /openapi/moda-public-api.yaml post /canvases/{canvas_ref}/edit/validate
openapi: 3.1.0
info:
  title: Moda Public API
  description: >
    Programmatic access to Moda's canvas design platform. Create designs, export
    assets, manage brand kits, and run AI design tasks.


    ## Versioning


    Pin response shapes with a calendar-dated `Moda-Version` header (e.g.
    `2026-05-01`). **The pin is global** — it applies to every endpoint in the
    request, not just the one you adopted it for, so raising it to use a new
    endpoint also moves your other responses to that version's shapes.


    ### Migrating `2026-04-12` → `2026-05-01`


    - **Tasks** move from the flat `JobResponse` (`job_id`, `canvas_url`,
    `can_export`) to the canonical `Task` envelope. The export artifact is now
    under `result.export` as `{url, format, page_count}`; update any code that
    read the export URL from the old top-level fields.

    - **Multi-page PNG/JPEG exports are delivered as a single `.zip`** of
    per-page files (`page-1.png`, …), so `result.export.format` is `zip`. For
    one bundled document instead, request `format=pdf` or `pptx`; for a single
    image, pass `page_number`.
  version: 1.0.0
  x-moda-api-version: '2026-05-01'
servers:
  - url: https://api.moda.app/v1
    description: Production
security: []
tags:
  - name: canvases
    description: List, search, read, export, and share canvases
  - name: tasks
    description: Start and monitor AI design tasks
  - name: organizations
    description: List organizations and teams
  - name: credits
    description: Check credit balance and usage
  - name: brand-kits
    description: Manage brand kits
  - name: remix
    description: Duplicate and edit canvases
  - name: share-links
    description: Resolve share URLs to canvas identifiers
  - name: uploads
    description: Upload files for use as attachments
  - name: usage
    description: Aggregate API usage stats for the caller's team
  - name: embed
    description: Signed iframe embed sessions
  - name: web
    description: 'Metered web research: search and page reading'
  - name: websites
    description: >-
      Create, update, publish, screenshot, and manage hosted multi-page static
      sites
  - name: drive
    description: >-
      Organize the workspace: folders, the folder tree, and item
      move/rename/visibility/delete for folders, canvases, and files
paths:
  /canvases/{canvas_ref}/edit/validate:
    post:
      tags:
        - canvas-actions
      summary: Validate Canvas Edit
      description: >-
        Validate the current Main Edit or a proposed operation batch without
        writing.
      operationId: editValidate
      parameters:
        - name: canvas_ref
          in: path
          required: true
          schema:
            type: string
            title: Canvas Ref
        - $ref: '#/components/parameters/ModaVersion'
      requestBody:
        content:
          application/json:
            schema:
              anyOf:
                - $ref: '#/components/schemas/EditValidateRequest'
                - type: 'null'
              title: Body
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
                title: Response Editvalidate
        '401':
          description: Authentication required.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '402':
          description: Insufficient credits for a metered operation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '403':
          description: Permission denied for this scope.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '404':
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '409':
          description: Conflict (idempotency / resource state).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '422':
          description: Request validation failed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '429':
          description: Rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '500':
          description: Internal error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
      security:
        - API Key: []
components:
  parameters:
    ModaVersion:
      name: Moda-Version
      in: header
      required: false
      description: >-
        Calendar-dated API version pin. New integrations should pin `2026-05-01`
        to opt into the newest response shapes. For back-compat the server also
        accepts requests with no header and resolves them to the current default
        (today: `2026-04-12`); that default advances on each [sunset
        date](/api-reference/versioning). Any unsupported value returns 400
        `unsupported_version`.
      example: '2026-05-01'
      schema:
        type: string
        enum:
          - '2026-04-12'
          - '2026-05-01'
        default: '2026-05-01'
        example: '2026-05-01'
  schemas:
    EditValidateRequest:
      properties:
        operations:
          anyOf:
            - items:
                oneOf:
                  - $ref: '#/components/schemas/EditInsertClipRequest'
                  - $ref: '#/components/schemas/EditMoveClipRequest'
                  - $ref: '#/components/schemas/EditTrimClipRequest'
                  - $ref: '#/components/schemas/EditRemoveClipRequest'
                  - $ref: '#/components/schemas/EditReorderClipRequest'
                discriminator:
                  propertyName: op
                  mapping:
                    insert_clip:
                      $ref: '#/components/schemas/EditInsertClipRequest'
                    move_clip:
                      $ref: '#/components/schemas/EditMoveClipRequest'
                    remove_clip:
                      $ref: '#/components/schemas/EditRemoveClipRequest'
                    reorder_clip:
                      $ref: '#/components/schemas/EditReorderClipRequest'
                    trim_clip:
                      $ref: '#/components/schemas/EditTrimClipRequest'
              type: array
              maxItems: 100
              minItems: 1
            - type: 'null'
          title: Operations
      additionalProperties: false
      type: object
      title: EditValidateRequest
    ErrorEnvelope:
      properties:
        type:
          $ref: '#/components/schemas/ErrorType'
        code:
          type: string
          title: Code
          description: >-
            Stable machine string keyed to doc_url. Never changes once
            published.
        message:
          type: string
          title: Message
          description: >-
            Human-readable message, for developers. Not localized, not
            user-facing.
        doc_url:
          type: string
          title: Doc Url
          description: Permalink to the docs page for this code.
        request_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Request Id
          description: Correlator for logs/Sentry/audit.
        causes:
          anyOf:
            - items:
                $ref: '#/components/schemas/ErrorEnvelope'
              type: array
            - type: 'null'
          title: Causes
          description: Aggregated upstream failures (e.g. per-page export errors).
        details:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          title: Details
          description: >-
            Code-specific detail payload (e.g. validation field list). Callers
            should pass ``None`` rather than ``{}`` to omit the key from the
            response.
        retry_after_ms:
          anyOf:
            - type: integer
            - type: 'null'
          title: Retry After Ms
          description: Hint for rate-limited or transient errors.
        retryable:
          anyOf:
            - type: boolean
            - type: 'null'
          title: Retryable
          description: >-
            Explicit retryability for this code, from the error-code registry:
            ``false`` means retrying the same request cannot succeed (fix the
            input / resource first); ``true`` means the condition is transient
            and a retry (with backoff / after the blocker clears) can succeed.
            Omitted for codes whose retryability is context-dependent — do not
            derive it from ``type`` or the HTTP status when this field is
            present.
      type: object
      required:
        - type
        - code
        - message
        - doc_url
      title: ErrorEnvelope
      description: >-
        Canonical error payload, nested under the top-level ``{"error": ...}``
        key.
    EditInsertClipRequest:
      properties:
        op:
          type: string
          const: insert_clip
          title: Op
        track_id:
          type: string
          minLength: 1
          title: Track Id
        clip:
          $ref: '#/components/schemas/EditClipRequest'
      additionalProperties: false
      type: object
      required:
        - op
        - track_id
        - clip
      title: EditInsertClipRequest
    EditMoveClipRequest:
      properties:
        op:
          type: string
          const: move_clip
          title: Op
        clip_id:
          type: string
          minLength: 1
          title: Clip Id
        track_id:
          type: string
          minLength: 1
          title: Track Id
        start:
          $ref: '#/components/schemas/EditTimeValueRequest'
      additionalProperties: false
      type: object
      required:
        - op
        - clip_id
        - track_id
        - start
      title: EditMoveClipRequest
    EditTrimClipRequest:
      properties:
        op:
          type: string
          const: trim_clip
          title: Op
        clip_id:
          type: string
          minLength: 1
          title: Clip Id
        edge:
          type: string
          enum:
            - start
            - end
          title: Edge
        time:
          $ref: '#/components/schemas/EditTimeValueRequest'
      additionalProperties: false
      type: object
      required:
        - op
        - clip_id
        - edge
        - time
      title: EditTrimClipRequest
    EditRemoveClipRequest:
      properties:
        op:
          type: string
          const: remove_clip
          title: Op
        clip_id:
          type: string
          minLength: 1
          title: Clip Id
      additionalProperties: false
      type: object
      required:
        - op
        - clip_id
      title: EditRemoveClipRequest
    EditReorderClipRequest:
      properties:
        op:
          type: string
          const: reorder_clip
          title: Op
        track_id:
          type: string
          minLength: 1
          title: Track Id
        clip_id:
          type: string
          minLength: 1
          title: Clip Id
        before_clip_id:
          anyOf:
            - type: string
              minLength: 1
            - type: 'null'
          title: Before Clip Id
      additionalProperties: false
      type: object
      required:
        - op
        - track_id
        - clip_id
      title: EditReorderClipRequest
    ErrorType:
      type: string
      enum:
        - invalid_request
        - authentication
        - permission
        - not_found
        - conflict
        - rate_limited
        - idempotency_conflict
        - unprocessable
        - upstream_error
        - internal_error
      title: ErrorType
      description: Closed set of high-level categories SDKs branch on.
    EditClipRequest:
      properties:
        id:
          type: string
          minLength: 1
          title: Id
        source:
          oneOf:
            - $ref: '#/components/schemas/EditCompositionSourceRequest'
            - $ref: '#/components/schemas/EditMediaSourceRequest'
            - $ref: '#/components/schemas/EditMediaStreamSourceRequest'
            - $ref: '#/components/schemas/EditCompositionAudioSourceRequest'
          title: Source
          discriminator:
            propertyName: kind
            mapping:
              composition:
                $ref: '#/components/schemas/EditCompositionSourceRequest'
              composition-audio:
                $ref: '#/components/schemas/EditCompositionAudioSourceRequest'
              media:
                $ref: '#/components/schemas/EditMediaSourceRequest'
              media-stream:
                $ref: '#/components/schemas/EditMediaStreamSourceRequest'
        start:
          $ref: '#/components/schemas/EditTimeValueRequest'
        duration:
          $ref: '#/components/schemas/EditTimeValueRequest'
        source_start:
          anyOf:
            - $ref: '#/components/schemas/EditTimeValueRequest'
            - type: 'null'
        rate:
          anyOf:
            - $ref: '#/components/schemas/EditPlaybackRateRequest'
            - type: 'null'
        end_behavior:
          anyOf:
            - type: string
              enum:
                - hold
                - loop
                - transparent
                - stop
            - type: 'null'
          title: End Behavior
        enabled:
          anyOf:
            - type: boolean
            - type: 'null'
          title: Enabled
        name:
          anyOf:
            - type: string
            - type: 'null'
          title: Name
        audio:
          anyOf:
            - $ref: '#/components/schemas/EditAudioPolicyRequest'
            - type: 'null'
        preserve_pitch:
          anyOf:
            - type: boolean
            - type: 'null'
          title: Preserve Pitch
        gain_db:
          anyOf:
            - type: number
            - type: 'null'
          title: Gain Db
        pan:
          anyOf:
            - type: number
              maximum: 1
              minimum: -1
            - type: 'null'
          title: Pan
        channel_map:
          anyOf:
            - type: string
              enum:
                - stereo
                - left
                - right
                - mono
            - type: 'null'
          title: Channel Map
        fade_in:
          anyOf:
            - $ref: '#/components/schemas/EditFadeRequest'
            - type: 'null'
        fade_out:
          anyOf:
            - $ref: '#/components/schemas/EditFadeRequest'
            - type: 'null'
      additionalProperties: false
      type: object
      required:
        - id
        - source
        - start
        - duration
      title: EditClipRequest
      description: >-
        Clip envelope; P1 rejects non-composition/audio fields with named
        capabilities.
    EditTimeValueRequest:
      properties:
        value:
          type: string
          pattern: ^-?\d+$
          title: Value
          description: Exact integer numerator encoded as a decimal string.
        timescale:
          type: integer
          maximum: 2147483647
          minimum: 1
          title: Timescale
      additionalProperties: false
      type: object
      required:
        - value
        - timescale
      title: EditTimeValueRequest
    EditCompositionSourceRequest:
      properties:
        kind:
          type: string
          const: composition
          title: Kind
        composition_id:
          type: string
          minLength: 1
          title: Composition Id
      additionalProperties: false
      type: object
      required:
        - kind
        - composition_id
      title: EditCompositionSourceRequest
    EditMediaSourceRequest:
      properties:
        kind:
          type: string
          const: media
          title: Kind
        asset_id:
          type: string
          minLength: 1
          title: Asset Id
      additionalProperties: false
      type: object
      required:
        - kind
        - asset_id
      title: EditMediaSourceRequest
    EditMediaStreamSourceRequest:
      properties:
        kind:
          type: string
          const: media-stream
          title: Kind
        asset_id:
          type: string
          minLength: 1
          title: Asset Id
        stream:
          $ref: '#/components/schemas/EditMediaStreamRequest'
      additionalProperties: false
      type: object
      required:
        - kind
        - asset_id
        - stream
      title: EditMediaStreamSourceRequest
    EditCompositionAudioSourceRequest:
      properties:
        kind:
          type: string
          const: composition-audio
          title: Kind
        composition_id:
          type: string
          minLength: 1
          title: Composition Id
      additionalProperties: false
      type: object
      required:
        - kind
        - composition_id
      title: EditCompositionAudioSourceRequest
    EditPlaybackRateRequest:
      properties:
        numerator:
          type: integer
          minimum: 1
          title: Numerator
        denominator:
          type: integer
          minimum: 1
          title: Denominator
      additionalProperties: false
      type: object
      required:
        - numerator
        - denominator
      title: EditPlaybackRateRequest
    EditAudioPolicyRequest:
      properties:
        mode:
          type: string
          enum:
            - follow-source
            - muted
            - detached
          title: Mode
        gain_db:
          anyOf:
            - type: number
            - type: 'null'
          title: Gain Db
        preserve_pitch:
          anyOf:
            - type: boolean
            - type: 'null'
          title: Preserve Pitch
      additionalProperties: false
      type: object
      required:
        - mode
      title: EditAudioPolicyRequest
    EditFadeRequest:
      properties:
        duration:
          $ref: '#/components/schemas/EditTimeValueRequest'
        curve:
          anyOf:
            - type: string
              enum:
                - linear
                - equal-power
                - ease-in
                - ease-out
            - type: 'null'
          title: Curve
      additionalProperties: false
      type: object
      required:
        - duration
      title: EditFadeRequest
    EditMediaStreamRequest:
      properties:
        kind:
          type: string
          const: audio
          title: Kind
        index:
          type: integer
          minimum: 0
          title: Index
      additionalProperties: false
      type: object
      required:
        - kind
        - index
      title: EditMediaStreamRequest
  securitySchemes:
    API Key:
      type: http
      description: API key from Settings > Developer > REST API
      scheme: bearer

````