{
  "openapi": "3.1.0",
  "info": {
    "title": "Vunoblade Preview API",
    "version": "1.0.0-preview",
    "description": "Account-scoped native projects, source media, and revision-aware edits in an open editor. The current server is a development preview. Managed cloud renders, team invitations and provider generation are not implemented."
  },
  "servers": [
    {
      "url": "/api/v1",
      "description": "This Vunoblade server"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/projects": {
      "get": {
        "operationId": "listProjects",
        "summary": "List your projects",
        "description": "Requires projects:read. At most 100 projects, newest updates first.",
        "responses": {
          "200": {
            "description": "Projects",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "projects": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ProjectSummary"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient scope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honor the Retry-After header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "saveProject",
        "summary": "Create or update a native project",
        "description": "Requires projects:write. Supply expectedRevision to prevent overwriting a newer revision. Maximum JSON request: 16 MiB. General API traffic is bounded at 240 requests/minute per account; source media uses a separate 1200 requests/minute bucket.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProjectWrite"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "project": {
                      "$ref": "#/components/schemas/ProjectSummary"
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "project": {
                      "$ref": "#/components/schemas/ProjectSummary"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient scope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Project request exceeds 16 MiB",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honor the Retry-After header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/projects/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]+$"
          }
        }
      ],
      "get": {
        "operationId": "getProject",
        "summary": "Read the native document and asset manifest",
        "description": "Requires projects:read.",
        "responses": {
          "200": {
            "description": "Native source",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "project": {
                      "$ref": "#/components/schemas/NativeProject"
                    },
                    "revision": {
                      "type": "integer"
                    },
                    "assets": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient scope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honor the Retry-After header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteProject",
        "summary": "Permanently delete this account’s project and server media",
        "description": "Requires projects:write. Device-local copies are separate.",
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient scope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honor the Retry-After header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/projects/{id}/assets/{assetId}/meta": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]+$"
          }
        },
        {
          "name": "assetId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]+$"
          }
        }
      ],
      "put": {
        "operationId": "setAssetMetadata",
        "summary": "Declare an original source upload",
        "description": "Requires projects:write. Account storage limit depends on the plan: 350 MiB on Free, 5 GiB on Creator, 20 GiB on Pro. Metadata payload is limited to 25,000 bytes.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AssetMeta"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Metadata saved",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient scope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Storage quota or payload exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honor the Retry-After header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/projects/{id}/assets/{assetId}/chunks/{part}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]+$"
          }
        },
        {
          "name": "assetId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]+$"
          }
        },
        {
          "name": "part",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 0
          }
        }
      ],
      "put": {
        "operationId": "uploadChunk",
        "summary": "Upload a binary source chunk",
        "description": "Requires projects:write. Exactly 786432 bytes per part, except the final remainder. The final completed source is SHA-256 verified. PUT is idempotent for identical bytes.",
        "requestBody": {
          "required": true,
          "content": {
            "application/octet-stream": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Chunk saved",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient scope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Checksum mismatch; chunks discarded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honor the Retry-After header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "getChunk",
        "summary": "Read a source chunk",
        "description": "Requires projects:read.",
        "responses": {
          "200": {
            "description": "Original bytes",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient scope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honor the Retry-After header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/editor/sessions": {
      "get": {
        "operationId": "listEditorSessions",
        "summary": "Find native artwork open in your studio",
        "description": "Requires editor:read. Sessions expire from discovery after 45 seconds without a heartbeat.",
        "responses": {
          "200": {
            "description": "Active sessions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "sessions": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient scope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honor the Retry-After header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/editor/sessions/{sessionId}": {
      "parameters": [
        {
          "name": "sessionId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]+$"
          }
        }
      ],
      "get": {
        "operationId": "getEditorContext",
        "summary": "Read geometry, selection, revision, and playhead",
        "description": "Requires editor:read. The current editor is the authority for document state.",
        "responses": {
          "200": {
            "description": "Native document context",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient scope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honor the Retry-After header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/editor/sessions/{sessionId}/commands": {
      "parameters": [
        {
          "name": "sessionId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]+$"
          }
        }
      ],
      "post": {
        "operationId": "submitEdit",
        "summary": "Queue a revision-aware native edit batch",
        "description": "Requires editor:write. Read current context first. Use a stable command id and identical payload for retries. Only an applied receipt confirms completion.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EditBatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Previously acknowledged command",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Receipt"
                }
              }
            }
          },
          "202": {
            "description": "Queued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Receipt"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient scope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honor the Retry-After header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/editor/sessions/{sessionId}/commands/{commandId}": {
      "parameters": [
        {
          "name": "sessionId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]+$"
          }
        },
        {
          "name": "commandId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]+$"
          }
        }
      ],
      "get": {
        "operationId": "getEditReceipt",
        "summary": "Read the queued, applied, or rejected result",
        "description": "Requires editor:read. In-memory receipts expire after one hour or server restart. API keys cannot publish editor context or applied receipts.",
        "responses": {
          "200": {
            "description": "Receipt",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Receipt"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient scope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honor the Retry-After header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "vb_…",
        "description": "Create and revoke scoped keys in Account → API keys. Keep the secret on your server."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "requestId": {
            "type": "string"
          }
        }
      },
      "NativeProject": {
        "type": "object",
        "required": [
          "tracks",
          "clips",
          "assets"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "ratio": {
            "type": "string",
            "enum": [
              "landscape",
              "portrait",
              "square"
            ]
          },
          "tracks": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "type": "object"
            }
          },
          "clips": {
            "type": "array",
            "maxItems": 2000,
            "items": {
              "type": "object"
            }
          },
          "assets": {
            "type": "array",
            "maxItems": 500,
            "items": {
              "type": "object"
            }
          },
          "bible": {
            "type": "object"
          },
          "customVisualizers": {
            "type": "array",
            "items": {
              "type": "object"
            }
          }
        },
        "additionalProperties": true
      },
      "ProjectSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "ratio": {
            "type": "string"
          },
          "revision": {
            "type": "integer"
          },
          "createdAt": {
            "type": "integer"
          },
          "touchedAt": {
            "type": "integer"
          },
          "clips": {
            "type": "integer"
          },
          "duration": {
            "type": "number"
          },
          "template": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "ProjectWrite": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{1,100}$"
          },
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "ratio": {
            "type": "string",
            "enum": [
              "landscape",
              "portrait",
              "square"
            ]
          },
          "data": {
            "$ref": "#/components/schemas/NativeProject"
          },
          "template": {
            "type": "string",
            "enum": [
              "afterimage",
              "chromatic",
              "signal"
            ]
          },
          "expectedRevision": {
            "type": "integer",
            "minimum": 0,
            "description": "Send the last read revision for updates, or zero for create-only semantics. Legacy clients may omit it, but then have no conflict protection."
          }
        }
      },
      "AssetMeta": {
        "type": "object",
        "required": [
          "name",
          "kind",
          "mime",
          "size",
          "chunkCount",
          "digest"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 200
          },
          "kind": {
            "type": "string",
            "enum": [
              "image",
              "video",
              "audio"
            ]
          },
          "mime": {
            "type": "string",
            "pattern": "^(video|audio|image)/[a-zA-Z0-9.+-]+$"
          },
          "size": {
            "type": "integer",
            "minimum": 1,
            "maximum": 367001600
          },
          "duration": {
            "type": "number",
            "minimum": 0
          },
          "chunkCount": {
            "type": "integer",
            "minimum": 1,
            "description": "ceil(size / 786432)"
          },
          "digest": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$"
          },
          "thumbnail": {
            "type": "string",
            "maxLength": 18000,
            "description": "Optional base64 PNG, JPEG, or WebP data URI"
          }
        }
      },
      "EditBatch": {
        "type": "object",
        "required": [
          "id",
          "documentId",
          "expectedRevision",
          "actions"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{8,100}$"
          },
          "documentId": {
            "type": "string"
          },
          "expectedRevision": {
            "type": "integer",
            "minimum": 0
          },
          "actions": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "items": {
              "type": "object",
              "required": [
                "op"
              ],
              "properties": {
                "op": {
                  "type": "string",
                  "enum": [
                    "add_svg",
                    "set",
                    "path",
                    "keys",
                    "gradient",
                    "corner",
                    "effect",
                    "remove",
                    "pathfinder",
                    "outline_stroke",
                    "width_profile",
                    "brush",
                    "erase",
                    "gradient_mesh",
                    "fire",
                    "render"
                  ]
                },
                "objectId": {
                  "type": "string"
                },
                "values": {
                  "type": "object"
                },
                "at": {
                  "type": "number"
                },
                "svg": {
                  "type": "string"
                },
                "d": {
                  "type": "string"
                },
                "property": {
                  "type": "string"
                },
                "keys": {
                  "type": "array",
                  "items": {
                    "type": "object"
                  }
                },
                "stopIndex": {
                  "type": "integer"
                },
                "radius": {
                  "type": "number"
                }
              },
              "additionalProperties": true
            }
          }
        }
      },
      "Receipt": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "applied",
              "rejected"
            ]
          },
          "created": {
            "type": "integer"
          },
          "revision": {
            "type": "integer"
          },
          "message": {
            "type": "string"
          },
          "batch": {
            "$ref": "#/components/schemas/EditBatch"
          }
        }
      }
    }
  }
}
