# Gavana > Gavana is a collaborative visual canvas with a stable API and CLI for scoped canvas, asset, Recipe, deterministic Image Action, and AI image automation through one shared Run resource. ## Developer references - [Canvas API V1 reference](https://app.gavana.ai/openapi/canvas-agent-v1.md): Compact endpoint, scope, and CLI command index. - [Canvas API V1 OpenAPI](https://app.gavana.ai/openapi/canvas-agent-v1.json): Authoritative OpenAPI 3.1 contract for client generation. ## Optional - [Full API and CLI context](https://app.gavana.ai/llms-full.txt): Complete OpenAPI schemas plus CLI pagination and output guidance. # Gavana Canvas API V1.0.0 > Generated from the stable OpenAPI contract. Use the JSON document for code generation and this page for a compact human- and agent-readable index. Base URL: `https://app.gavana.ai/api/canvas-agent/v1` Authentication: `Authorization: Bearer cba_...` Every response includes `X-Request-ID`. The active Canvas, Recipe, asset, Action, model, and provider list endpoints preserve their named array and include `page.limit`, `page.hasMore`, and opaque `page.nextCursor` fields. ## Operations | Method | Path | Summary | Required scopes | CLI | | --- | --- | --- | --- | --- | | GET | `/auth/status` | Verify the current Agent Access token | none | `gavana auth status` | | GET | `/actions` | List deterministic Image Actions | `canvas:read` | `gavana action list` | | GET | `/actions/{actionKey}` | Read one Image Action schema | `canvas:read` | `gavana action get` | | POST | `/actions/{actionKey}/runs` | Run a deterministic Image Action | `canvas:read`, `canvas:write`, `asset:read` | `gavana action run` | | GET | `/assets` | List accessible assets | `asset:read` | `gavana asset list` | | POST | `/assets` | Upload a durable raster reference | `asset:read`; plus one of `image:generate` or `video:generate`; additionally when canvasId query parameter is present: `canvas:read`, `canvas:write` | `gavana asset upload` | | GET | `/assets/{assetId}` | Get an accessible asset | `asset:read` | `gavana asset get` | | GET | `/assets/preview` | Read a short-lived scoped image preview | none | — | | GET | `/campaigns` | List legacy campaign runs (deprecated) | `canvas:read`, `canvas:write`, `asset:read`, `image:generate`, `job:manage` | — | | GET | `/campaigns/{runId}` | Get a legacy campaign run (deprecated) | `canvas:read`, `canvas:write`, `asset:read`, `image:generate`, `job:manage` | — | | DELETE | `/campaigns/{runId}` | Cancel a legacy campaign run (deprecated) | `canvas:read`, `canvas:write`, `asset:read`, `image:generate`, `job:manage` | — | | POST | `/campaigns/{runId}/review` | Review a legacy campaign run (deprecated) | `canvas:read`, `canvas:write`, `asset:read`, `image:generate`, `job:manage` | — | | POST | `/campaigns/plan` | Plan a legacy campaign (deprecated) | `canvas:read`, `canvas:write`, `asset:read` | — | | POST | `/campaigns/start` | Start a legacy campaign (deprecated) | `canvas:read`, `canvas:write`, `asset:read`, `image:generate`, `job:manage` | — | | GET | `/canvases` | List accessible canvases | `canvas:read` | `gavana canvas list` | | POST | `/canvases` | Create a canvas or resolve Agent Canvas | `canvas:read`, `canvas:write` | `gavana canvas create` | | GET | `/canvases/{canvasId}` | Get a complete canvas and its current revision | `canvas:read` | `gavana canvas get` | | GET | `/canvases/{canvasId}/nodes/{nodeId}` | Get one node with incoming and outgoing connections | `canvas:read` | `gavana node get` | | POST | `/canvases/{canvasId}/operations` | Validate or apply one revision-safe operation batch | `canvas:read`; additionally when validateOnly is not true: `canvas:write` | `gavana canvas apply` | | POST | `/canvases/{canvasId}/workflows` | Create a private reusable workflow without running it | `canvas:read`, `canvas:write` | — | | GET | `/canvases/{canvasId}/render` | Render a canvas as SVG | `canvas:read` | `gavana canvas render` | | POST | `/images/edit` | Queue an image edit | `canvas:read`, `canvas:write`, `asset:read`, `image:generate` | `gavana image edit` | | POST | `/images/generate` | Queue image generation | `canvas:read`, `canvas:write`, `asset:read`, `image:generate` | `gavana image generate` | | POST | `/images/import` | Import a public HTTPS image as a durable canvas node | `canvas:read`, `canvas:write`, `asset:read`, `image:generate` | — | | POST | `/images/variations` | Queue image variations | `canvas:read`, `canvas:write`, `asset:read`, `image:generate` | `gavana image variations` | | POST | `/videos/generate` | Queue video generation | `canvas:read`, `asset:read`, `video:generate` | `gavana video generate` | | GET | `/jobs/{jobId}` | Read or finalize an image, Action, or video job | `job:manage` | `gavana job get` | | DELETE | `/jobs/{jobId}` | Cancel an image, Action, or video job | `job:manage` | `gavana job cancel` | | GET | `/jobs/{jobId}/output` | Download completed video output | `job:manage` | `gavana video download` | | GET | `/models` | List runnable image and video models | one of `image:generate` or `video:generate` | `gavana model list` | | GET | `/models/{modelKey}` | Read an image or video model schema | one of `image:generate` or `video:generate` | `gavana model get` | | GET | `/providers` | List saved image and video provider connections | one of `image:generate` or `video:generate` | `gavana provider list` | | GET | `/recipes` | Search approved Recipes | `canvas:read` | `gavana recipe search` | | GET | `/recipes/{recipeId}` | Get an approved Recipe | `canvas:read` | `gavana recipe get` | | POST | `/recipes/{recipeId}/fork` | Fork a Recipe into a canvas without running it | `canvas:read`, `canvas:write` | `gavana recipe fork` | | POST | `/recipes/{recipeId}/runs` | Run a Recipe explicitly | `canvas:read`, `canvas:write`, `asset:read`, `image:generate` | `gavana recipe run` | | GET | `/runs/{runId}` | Read or advance a shared Run | `job:manage` | `gavana run get` | | DELETE | `/runs/{runId}` | Cancel a shared Run | `job:manage` | `gavana run cancel` | ## Machine-readable contract - [OpenAPI 3.1 JSON](https://app.gavana.ai/openapi/canvas-agent-v1.json) - [LLM index](https://app.gavana.ai/llms.txt) - [Complete API and CLI context](https://app.gavana.ai/llms-full.txt) Do not put Agent Access tokens in URLs, screenshots, logs, or support messages. Share the response request ID when asking for support. ## CLI automation contract The canonical command is `gavana`; `gavana-canvas` is its descriptive alias, while `craftboard` and `craftboard-canvas` remain backward-compatible aliases. Commands return `{"ok":true,"result":...}` JSON on stdout by default. Errors and progress go to stderr. Active Canvas, Recipe, asset, Action, model, and provider lists accept `--limit` and `--cursor`. Use `--jq '.canvases[].handle' -r` for raw selected values, `--output jsonl` for one selected array item per line, or `--output markdown` for chat-ready output. The built-in selector supports property paths, non-negative array indexes, and `[]` projections; it does not execute arbitrary jq programs. Recipe, image, and Action starts return `run:`; use `gavana run get|wait|cancel` to reconnect to any of them. ## Complete OpenAPI 3.1 contract ```json { "openapi": "3.1.0", "info": { "title": "Gavana Canvas API", "version": "1.0.0", "description": "The stable V1 API used by the Gavana browser, CLI, and MCP adapter to read canvases, apply revision-safe edits, manage durable assets, run Recipes and deterministic Image Actions, generate images and videos, and observe asynchronous work.", "x-craftboard-stability": "stable" }, "servers": [ { "url": "/api/canvas-agent/v1", "description": "Current Gavana origin" } ], "security": [ { "agentToken": [] } ], "tags": [ { "name": "Authentication", "description": "Verify an Agent Access token without requiring an unrelated product scope." }, { "name": "Canvases", "description": "Read canvases and apply revision-safe graph operations." }, { "name": "Recipes", "description": "Discover, fork, and explicitly run approved or private Recipe workflows." }, { "name": "Assets", "description": "Read durable assets and upload raster references." }, { "name": "Actions", "description": "Discover and run deterministic, credit-free image transformations." }, { "name": "Images", "description": "Queue image generation, editing, and variation jobs." }, { "name": "Videos", "description": "Queue video generation from prompts, first and last frames, or reference images." }, { "name": "Jobs", "description": "Observe or cancel image, Action, and video jobs and download completed video output." }, { "name": "Runs", "description": "Read, resume, or cancel Recipe, image, and Action execution through one shared resource." }, { "name": "Models", "description": "Discover runnable image and video models, capabilities, parameter schemas, and duration estimates." }, { "name": "Providers", "description": "Discover saved image and video provider connections." }, { "name": "Legacy campaigns", "description": "Deprecated compatibility endpoints. New integrations should use Recipes plus explicit canvas and image operations." } ], "paths": { "/auth/status": { "get": { "operationId": "getAuthStatus", "tags": [ "Authentication" ], "summary": "Verify the current Agent Access token", "description": "Authenticates the token and reports its granted scopes without requiring canvas, asset, image, or job access.", "x-craftboard-required-scopes": [], "x-craftboard-cli-command": "gavana auth status", "responses": { "200": { "$ref": "#/components/responses/AuthStatus" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/actions": { "get": { "operationId": "listImageActions", "tags": [ "Actions" ], "summary": "List deterministic Image Actions", "description": "Returns typed schemas for the eight deterministic, credit-free raster transformations available in the browser, CLI, API, and MCP adapter.", "x-craftboard-required-scopes": [ "canvas:read" ], "x-craftboard-cli-command": "gavana action list", "parameters": [ { "$ref": "#/components/parameters/ActionQuery" }, { "$ref": "#/components/parameters/ListLimit100" }, { "$ref": "#/components/parameters/ListCursor" } ], "responses": { "200": { "$ref": "#/components/responses/ActionList" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/actions/{actionKey}": { "get": { "operationId": "getImageAction", "tags": [ "Actions" ], "summary": "Read one Image Action schema", "description": "Returns the exact ordered image inputs, typed parameters, defaults, limits, output contract, and cost behavior for one Action.", "x-craftboard-required-scopes": [ "canvas:read" ], "x-craftboard-cli-command": "gavana action get", "parameters": [ { "$ref": "#/components/parameters/ActionKey" } ], "responses": { "200": { "$ref": "#/components/responses/Action" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/actions/{actionKey}/runs": { "post": { "operationId": "startImageAction", "tags": [ "Actions" ], "summary": "Run a deterministic Image Action", "description": "Queues a credit-free raster transform against one or two durable node or asset handles. The result is stored as a durable asset and materialized in the selected target image node.", "x-craftboard-required-scopes": [ "canvas:read", "canvas:write", "asset:read" ], "x-craftboard-cli-command": "gavana action run", "parameters": [ { "$ref": "#/components/parameters/ActionKey" } ], "requestBody": { "$ref": "#/components/requestBodies/ImageActionRun" }, "callbacks": { "imageJobTerminal": { "$ref": "#/components/callbacks/ImageJobTerminal" } }, "responses": { "202": { "$ref": "#/components/responses/Job" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/assets": { "get": { "operationId": "listAssets", "tags": [ "Assets" ], "summary": "List accessible assets", "description": "Assets are ordered by updatedAt descending, then handle descending.", "x-craftboard-required-scopes": [ "asset:read" ], "x-craftboard-cli-command": "gavana asset list", "parameters": [ { "$ref": "#/components/parameters/CanvasIdQuery" }, { "$ref": "#/components/parameters/OwnerUidQuery" }, { "$ref": "#/components/parameters/ListLimit200" }, { "$ref": "#/components/parameters/ListCursor" } ], "responses": { "200": { "$ref": "#/components/responses/AssetList" }, "default": { "$ref": "#/components/responses/Error" } } }, "post": { "operationId": "uploadAsset", "tags": [ "Assets" ], "summary": "Upload a durable raster reference", "description": "Uploads a private raster reference for image or video generation. When canvasId is supplied, canvas read/write scopes are also required and the upload is stored inside that canvas.", "x-craftboard-required-scopes": [ "asset:read" ], "x-craftboard-any-of-scopes": [ "image:generate", "video:generate" ], "x-craftboard-conditional-scopes": [ { "when": "canvasId query parameter is present", "scopes": [ "canvas:read", "canvas:write" ] } ], "x-craftboard-cli-command": "gavana asset upload", "parameters": [ { "$ref": "#/components/parameters/CanvasIdQuery" }, { "$ref": "#/components/parameters/OwnerUidQuery" }, { "$ref": "#/components/parameters/FileNameHeader" }, { "$ref": "#/components/parameters/LegacyFileNameHeader" } ], "requestBody": { "required": true, "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } }, "image/png": { "schema": { "type": "string", "format": "binary" } }, "image/jpeg": { "schema": { "type": "string", "format": "binary" } }, "image/webp": { "schema": { "type": "string", "format": "binary" } }, "image/gif": { "schema": { "type": "string", "format": "binary" } } } }, "responses": { "201": { "$ref": "#/components/responses/Asset" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/assets/{assetId}": { "get": { "operationId": "getAsset", "tags": [ "Assets" ], "summary": "Get an accessible asset", "description": "For a shared asset, pass the ownerUid encoded in its owner-qualified handle. The CLI does this automatically.", "x-craftboard-required-scopes": [ "asset:read" ], "x-craftboard-cli-command": "gavana asset get", "parameters": [ { "$ref": "#/components/parameters/AssetId" }, { "$ref": "#/components/parameters/OwnerUidQuery" } ], "responses": { "200": { "$ref": "#/components/responses/Asset" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/assets/preview": { "get": { "operationId": "previewAsset", "tags": [ "Assets" ], "summary": "Read a short-lived scoped image preview", "description": "The encrypted preview token is the authorization grant for this endpoint. Agent bearer tokens are not accepted or required.", "security": [], "x-craftboard-required-scopes": [], "parameters": [ { "$ref": "#/components/parameters/PreviewToken" } ], "responses": { "200": { "$ref": "#/components/responses/BinaryImage" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/campaigns": { "get": { "operationId": "listLegacyCampaignRuns", "tags": [ "Legacy campaigns" ], "summary": "List legacy campaign runs", "deprecated": true, "x-craftboard-required-scopes": [ "canvas:read", "canvas:write", "asset:read", "image:generate", "job:manage" ], "parameters": [ { "$ref": "#/components/parameters/CanvasIdQuery" } ], "responses": { "200": { "$ref": "#/components/responses/CampaignList" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/campaigns/{runId}": { "get": { "operationId": "getLegacyCampaignRun", "tags": [ "Legacy campaigns" ], "summary": "Get a legacy campaign run", "deprecated": true, "x-craftboard-required-scopes": [ "canvas:read", "canvas:write", "asset:read", "image:generate", "job:manage" ], "parameters": [ { "$ref": "#/components/parameters/RunId" } ], "responses": { "200": { "$ref": "#/components/responses/Campaign" }, "default": { "$ref": "#/components/responses/Error" } } }, "delete": { "operationId": "cancelLegacyCampaignRun", "tags": [ "Legacy campaigns" ], "summary": "Cancel a legacy campaign run", "description": "Retired mutation surface. Returns 410 unless legacy compatibility is explicitly enabled by the server operator.", "deprecated": true, "x-craftboard-runtime": "legacy-compatibility", "x-craftboard-required-scopes": [ "canvas:read", "canvas:write", "asset:read", "image:generate", "job:manage" ], "parameters": [ { "$ref": "#/components/parameters/RunId" } ], "responses": { "200": { "$ref": "#/components/responses/Campaign" }, "410": { "$ref": "#/components/responses/Error" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/campaigns/{runId}/review": { "post": { "operationId": "reviewLegacyCampaignRun", "tags": [ "Legacy campaigns" ], "summary": "Review a legacy campaign run", "description": "Retired mutation surface. Returns 410 unless legacy compatibility is explicitly enabled by the server operator.", "deprecated": true, "x-craftboard-runtime": "legacy-compatibility", "x-craftboard-required-scopes": [ "canvas:read", "canvas:write", "asset:read", "image:generate", "job:manage" ], "parameters": [ { "$ref": "#/components/parameters/RunId" } ], "requestBody": { "$ref": "#/components/requestBodies/LegacyCampaign" }, "responses": { "200": { "$ref": "#/components/responses/Campaign" }, "202": { "$ref": "#/components/responses/Campaign" }, "410": { "$ref": "#/components/responses/Error" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/campaigns/plan": { "post": { "operationId": "planLegacyCampaign", "tags": [ "Legacy campaigns" ], "summary": "Plan a legacy campaign", "description": "Retired mutation surface. Returns 410 unless legacy compatibility is explicitly enabled by the server operator.", "deprecated": true, "x-craftboard-runtime": "legacy-compatibility", "x-craftboard-required-scopes": [ "canvas:read", "canvas:write", "asset:read" ], "requestBody": { "$ref": "#/components/requestBodies/LegacyCampaign" }, "responses": { "200": { "$ref": "#/components/responses/Campaign" }, "201": { "$ref": "#/components/responses/Campaign" }, "410": { "$ref": "#/components/responses/Error" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/campaigns/start": { "post": { "operationId": "startLegacyCampaign", "tags": [ "Legacy campaigns" ], "summary": "Start a legacy campaign", "description": "Retired mutation surface. Returns 410 unless legacy compatibility is explicitly enabled by the server operator.", "deprecated": true, "x-craftboard-runtime": "legacy-compatibility", "x-craftboard-required-scopes": [ "canvas:read", "canvas:write", "asset:read", "image:generate", "job:manage" ], "requestBody": { "$ref": "#/components/requestBodies/LegacyCampaign" }, "responses": { "200": { "$ref": "#/components/responses/Campaign" }, "202": { "$ref": "#/components/responses/Campaign" }, "410": { "$ref": "#/components/responses/Error" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/canvases": { "get": { "operationId": "listCanvases", "tags": [ "Canvases" ], "summary": "List accessible canvases", "description": "Owned and shared canvases are merged and ordered by updatedAt descending, then handle descending.", "x-craftboard-required-scopes": [ "canvas:read" ], "x-craftboard-cli-command": "gavana canvas list", "parameters": [ { "$ref": "#/components/parameters/ListLimit25" }, { "$ref": "#/components/parameters/ListCursor" } ], "responses": { "200": { "$ref": "#/components/responses/CanvasList" }, "default": { "$ref": "#/components/responses/Error" } } }, "post": { "operationId": "createCanvas", "tags": [ "Canvases" ], "summary": "Create a canvas or resolve Agent Canvas", "x-craftboard-required-scopes": [ "canvas:read", "canvas:write" ], "x-craftboard-cli-command": "gavana canvas create", "requestBody": { "$ref": "#/components/requestBodies/CanvasCreate" }, "responses": { "201": { "$ref": "#/components/responses/Canvas" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/canvases/{canvasId}": { "get": { "operationId": "getCanvas", "tags": [ "Canvases" ], "summary": "Get a complete canvas and its current revision", "x-craftboard-required-scopes": [ "canvas:read" ], "x-craftboard-cli-command": "gavana canvas get", "parameters": [ { "$ref": "#/components/parameters/CanvasId" }, { "$ref": "#/components/parameters/OwnerUidQuery" } ], "responses": { "200": { "$ref": "#/components/responses/Canvas" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/canvases/{canvasId}/nodes/{nodeId}": { "get": { "operationId": "getCanvasNode", "tags": [ "Canvases" ], "summary": "Get one node with incoming and outgoing connections", "x-craftboard-required-scopes": [ "canvas:read" ], "x-craftboard-cli-command": "gavana node get", "parameters": [ { "$ref": "#/components/parameters/CanvasId" }, { "$ref": "#/components/parameters/NodeId" }, { "$ref": "#/components/parameters/OwnerUidQuery" } ], "responses": { "200": { "$ref": "#/components/responses/GenericObject" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/canvases/{canvasId}/operations": { "post": { "operationId": "applyCanvasOperations", "tags": [ "Canvases" ], "summary": "Validate or apply one revision-safe operation batch", "description": "Set validateOnly to true to run the canonical operation engine and graph validator without writing, consuming an idempotency key, or requiring canvas:write. For mutation, read the canvas first, pass its revision as baseRevision, and provide an idempotencyKey. A 409 response includes the current revision when another actor changed the canvas.", "x-craftboard-required-scopes": [ "canvas:read" ], "x-craftboard-conditional-scopes": [ { "when": "validateOnly is not true", "scopes": [ "canvas:write" ] } ], "x-craftboard-cli-command": "gavana canvas apply", "parameters": [ { "$ref": "#/components/parameters/CanvasId" }, { "$ref": "#/components/parameters/OwnerUidQuery" } ], "requestBody": { "$ref": "#/components/requestBodies/CanvasOperations" }, "responses": { "200": { "$ref": "#/components/responses/CanvasOperationsResult" }, "409": { "$ref": "#/components/responses/Error" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/canvases/{canvasId}/workflows": { "post": { "operationId": "createCanvasWorkflow", "tags": [ "Recipes" ], "summary": "Create a private reusable workflow without running it", "description": "Creates the workflow graph, a private Recipe draft, and a compact runnable Recipe instance. Inputs marked useAsDefault reuse their saved source on later runs, so callers only need to provide changing inputs. This operation does not start generation or consume provider credits.", "x-craftboard-required-scopes": [ "canvas:read", "canvas:write" ], "parameters": [ { "$ref": "#/components/parameters/CanvasId" }, { "$ref": "#/components/parameters/OwnerUidQuery" } ], "requestBody": { "$ref": "#/components/requestBodies/CanvasWorkflowCreate" }, "responses": { "200": { "$ref": "#/components/responses/WorkflowMutation" }, "201": { "$ref": "#/components/responses/WorkflowMutation" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/canvases/{canvasId}/render": { "get": { "operationId": "renderCanvasSvg", "tags": [ "Canvases" ], "summary": "Render a canvas as SVG", "x-craftboard-required-scopes": [ "canvas:read" ], "x-craftboard-cli-command": "gavana canvas render", "parameters": [ { "$ref": "#/components/parameters/CanvasId" }, { "$ref": "#/components/parameters/OwnerUidQuery" } ], "responses": { "200": { "$ref": "#/components/responses/Svg" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/images/edit": { "post": { "operationId": "startImageEdit", "tags": [ "Images" ], "summary": "Queue an image edit", "x-craftboard-required-scopes": [ "canvas:read", "canvas:write", "asset:read", "image:generate" ], "x-craftboard-cli-command": "gavana image edit", "requestBody": { "$ref": "#/components/requestBodies/ImageEdit" }, "callbacks": { "imageJobTerminal": { "$ref": "#/components/callbacks/ImageJobTerminal" } }, "responses": { "202": { "$ref": "#/components/responses/Job" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/images/generate": { "post": { "operationId": "startImageGeneration", "tags": [ "Images" ], "summary": "Queue image generation", "x-craftboard-required-scopes": [ "canvas:read", "canvas:write", "asset:read", "image:generate" ], "x-craftboard-cli-command": "gavana image generate", "requestBody": { "$ref": "#/components/requestBodies/ImageGeneration" }, "callbacks": { "imageJobTerminal": { "$ref": "#/components/callbacks/ImageJobTerminal" } }, "responses": { "202": { "$ref": "#/components/responses/Job" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/images/import": { "post": { "operationId": "importImageToCanvas", "tags": [ "Images" ], "summary": "Import a public HTTPS image as a durable canvas node", "description": "Downloads a bounded raster image through Gavana's SSRF-safe fetcher, stores it as a canvas-scoped asset, and adds one deterministic image node. Reuse the idempotency key only for the exact same import.", "x-craftboard-required-scopes": [ "canvas:read", "canvas:write", "asset:read", "image:generate" ], "requestBody": { "$ref": "#/components/requestBodies/ImageImport" }, "responses": { "200": { "$ref": "#/components/responses/ImageImport" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/images/variations": { "post": { "operationId": "startImageVariations", "tags": [ "Images" ], "summary": "Queue image variations", "x-craftboard-required-scopes": [ "canvas:read", "canvas:write", "asset:read", "image:generate" ], "x-craftboard-cli-command": "gavana image variations", "requestBody": { "$ref": "#/components/requestBodies/ImageVariations" }, "callbacks": { "imageJobTerminal": { "$ref": "#/components/callbacks/ImageJobTerminal" } }, "responses": { "202": { "$ref": "#/components/responses/Job" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/videos/generate": { "post": { "operationId": "startVideoGeneration", "tags": [ "Videos" ], "summary": "Queue video generation", "description": "Starts a retry-safe video job using a connected video model. First, last, and reference frames may be stable image node or asset handles, or public HTTPS image URLs.", "x-craftboard-required-scopes": [ "canvas:read", "asset:read", "video:generate" ], "x-craftboard-cli-command": "gavana video generate", "requestBody": { "$ref": "#/components/requestBodies/VideoGeneration" }, "responses": { "202": { "$ref": "#/components/responses/Job" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/jobs/{jobId}": { "get": { "operationId": "getJob", "tags": [ "Jobs" ], "summary": "Read or finalize an image, Action, or video job", "x-craftboard-required-scopes": [ "job:manage" ], "x-craftboard-cli-command": "gavana job get", "parameters": [ { "$ref": "#/components/parameters/JobId" } ], "responses": { "200": { "$ref": "#/components/responses/Job" }, "202": { "$ref": "#/components/responses/Job" }, "default": { "$ref": "#/components/responses/Error" } } }, "delete": { "operationId": "cancelJob", "tags": [ "Jobs" ], "summary": "Cancel an image, Action, or video job", "x-craftboard-required-scopes": [ "job:manage" ], "x-craftboard-cli-command": "gavana job cancel", "parameters": [ { "$ref": "#/components/parameters/JobId" } ], "responses": { "200": { "$ref": "#/components/responses/Job" }, "202": { "$ref": "#/components/responses/Job" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/jobs/{jobId}/output": { "get": { "operationId": "downloadVideoJobOutput", "tags": [ "Jobs", "Videos" ], "summary": "Download completed video output", "x-craftboard-required-scopes": [ "job:manage" ], "x-craftboard-cli-command": "gavana video download", "parameters": [ { "$ref": "#/components/parameters/JobId" } ], "responses": { "200": { "$ref": "#/components/responses/VideoOutput" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/models": { "get": { "operationId": "listModels", "tags": [ "Models" ], "summary": "List runnable image and video models", "description": "Returns models Gavana can invoke through the managed runtime or the actor's saved connections.", "x-craftboard-required-scopes": [], "x-craftboard-any-of-scopes": [ "image:generate", "video:generate" ], "x-craftboard-cli-command": "gavana model list", "parameters": [ { "$ref": "#/components/parameters/ModelQuery" }, { "$ref": "#/components/parameters/ModelProviderQuery" }, { "$ref": "#/components/parameters/ModelCapabilityQuery" }, { "$ref": "#/components/parameters/ListLimit100" }, { "$ref": "#/components/parameters/ListCursor" } ], "responses": { "200": { "$ref": "#/components/responses/ModelList" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/models/{modelKey}": { "get": { "operationId": "getModel", "tags": [ "Models" ], "summary": "Read an image or video model schema", "x-craftboard-required-scopes": [], "x-craftboard-any-of-scopes": [ "image:generate", "video:generate" ], "x-craftboard-cli-command": "gavana model get", "parameters": [ { "$ref": "#/components/parameters/ModelKey" } ], "responses": { "200": { "$ref": "#/components/responses/Model" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/providers": { "get": { "operationId": "listProviders", "tags": [ "Providers" ], "summary": "List saved image and video provider connections", "x-craftboard-required-scopes": [], "x-craftboard-any-of-scopes": [ "image:generate", "video:generate" ], "x-craftboard-cli-command": "gavana provider list", "parameters": [ { "$ref": "#/components/parameters/ListLimit100" }, { "$ref": "#/components/parameters/ListCursor" } ], "responses": { "200": { "$ref": "#/components/responses/ProviderList" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/recipes": { "get": { "operationId": "searchRecipes", "tags": [ "Recipes" ], "summary": "Search approved Recipes", "x-craftboard-required-scopes": [ "canvas:read" ], "x-craftboard-cli-command": "gavana recipe search", "parameters": [ { "$ref": "#/components/parameters/RecipeQuery" }, { "$ref": "#/components/parameters/ListLimit100" }, { "$ref": "#/components/parameters/ListCursor" } ], "responses": { "200": { "$ref": "#/components/responses/RecipeList" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/recipes/{recipeId}": { "get": { "operationId": "getRecipe", "tags": [ "Recipes" ], "summary": "Get an approved Recipe", "x-craftboard-required-scopes": [ "canvas:read" ], "x-craftboard-cli-command": "gavana recipe get", "parameters": [ { "$ref": "#/components/parameters/RecipeId" }, { "$ref": "#/components/parameters/RecipeVersionQuery" } ], "responses": { "200": { "$ref": "#/components/responses/Recipe" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/recipes/{recipeId}/fork": { "post": { "operationId": "forkRecipe", "tags": [ "Recipes" ], "summary": "Fork a Recipe into a canvas without running it", "x-craftboard-required-scopes": [ "canvas:read", "canvas:write" ], "x-craftboard-cli-command": "gavana recipe fork", "parameters": [ { "$ref": "#/components/parameters/RecipeId" } ], "requestBody": { "$ref": "#/components/requestBodies/RecipeFork" }, "responses": { "200": { "$ref": "#/components/responses/Mutation" }, "201": { "$ref": "#/components/responses/Mutation" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/recipes/{recipeId}/runs": { "post": { "operationId": "startRecipeRun", "tags": [ "Recipes", "Runs" ], "summary": "Run a Recipe explicitly", "description": "Creates or reuses a private Recipe instance, binds typed inputs, materializes declared output nodes, and queues sequential text or image work. Forking a Recipe never calls this operation automatically.", "x-craftboard-required-scopes": [ "canvas:read", "canvas:write", "asset:read", "image:generate" ], "x-craftboard-cli-command": "gavana recipe run", "parameters": [ { "$ref": "#/components/parameters/RecipeId" } ], "requestBody": { "$ref": "#/components/requestBodies/RecipeRun" }, "callbacks": { "recipeRunTerminal": { "$ref": "#/components/callbacks/RecipeRunTerminal" } }, "responses": { "202": { "$ref": "#/components/responses/RecipeRun" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/runs/{runId}": { "get": { "operationId": "getRun", "tags": [ "Runs" ], "summary": "Read or advance a shared Run", "description": "Returns Recipe, image, or Action Run state. Reading a completed image child also finalizes its durable asset and canvas node.", "x-craftboard-required-scopes": [ "job:manage" ], "x-craftboard-cli-command": "gavana run get", "parameters": [ { "$ref": "#/components/parameters/RunId" } ], "responses": { "200": { "$ref": "#/components/responses/Run" }, "202": { "$ref": "#/components/responses/Run" }, "default": { "$ref": "#/components/responses/Error" } } }, "delete": { "operationId": "cancelRun", "tags": [ "Runs" ], "summary": "Cancel a shared Run", "x-craftboard-required-scopes": [ "job:manage" ], "x-craftboard-cli-command": "gavana run cancel", "parameters": [ { "$ref": "#/components/parameters/RunId" } ], "responses": { "200": { "$ref": "#/components/responses/Run" }, "202": { "$ref": "#/components/responses/Run" }, "default": { "$ref": "#/components/responses/Error" } } } } }, "components": { "securitySchemes": { "agentToken": { "type": "http", "scheme": "bearer", "bearerFormat": "cba_.", "description": "Create a scoped Agent Access Token in Gavana settings. Never place the token in a URL or support message." } }, "parameters": { "ActionKey": { "name": "actionKey", "in": "path", "required": true, "description": "An Action slug or action: handle returned by GET /actions.", "schema": { "type": "string", "pattern": "^(?:action:)?(?:resize|crop|change-aspect-ratio|side-by-side-composite|add-text-to-image|overlay-image|color-grade|rotate)$" } }, "ActionQuery": { "name": "q", "in": "query", "required": false, "description": "Free-text Action slug, title, or summary search.", "schema": { "type": "string", "maxLength": 240 } }, "AssetId": { "name": "assetId", "in": "path", "required": true, "schema": { "type": "string", "pattern": "^(?:asset:)?[A-Za-z0-9_-]{1,180}$" } }, "CanvasId": { "name": "canvasId", "in": "path", "required": true, "schema": { "$ref": "#/components/schemas/StableId" } }, "CanvasIdQuery": { "name": "canvasId", "in": "query", "required": false, "description": "Optional plain canvas id used to filter or scope the request.", "schema": { "$ref": "#/components/schemas/StableId" } }, "FileNameHeader": { "name": "X-Gavana-File-Name", "in": "header", "required": false, "schema": { "type": "string", "maxLength": 255 } }, "LegacyFileNameHeader": { "name": "X-Craftboard-File-Name", "in": "header", "required": false, "deprecated": true, "description": "Legacy alias for X-Gavana-File-Name.", "schema": { "type": "string", "maxLength": 255 } }, "JobId": { "name": "jobId", "in": "path", "required": true, "schema": { "type": "string", "pattern": "^(?:job:)?[0-9a-fA-F-]{36}$" } }, "ListCursor": { "name": "cursor", "in": "query", "required": false, "description": "Opaque continuation cursor from page.nextCursor. Reuse it with the same list filters.", "schema": { "type": "string", "maxLength": 8192 } }, "ListLimit100": { "name": "limit", "in": "query", "required": false, "description": "Maximum number of items in this page.", "schema": { "type": "integer", "minimum": 1, "maximum": 100 } }, "ListLimit25": { "name": "limit", "in": "query", "required": false, "description": "Maximum number of canvases in this page. Canvas pages are capped at 25 because summaries are derived from complete graph documents.", "schema": { "type": "integer", "minimum": 1, "maximum": 25, "default": 25 } }, "ListLimit200": { "name": "limit", "in": "query", "required": false, "description": "Maximum number of items in this page.", "schema": { "type": "integer", "minimum": 1, "maximum": 200 } }, "ModelCapabilityQuery": { "name": "capability", "in": "query", "required": false, "schema": { "type": "string", "enum": [ "image.generate", "image.edit", "image.variations", "video.generate", "video.generate.fromImage", "video.generate.fromFrames", "video.generate.fromReferences" ] } }, "ModelKey": { "name": "modelKey", "in": "path", "required": true, "description": "Opaque key from a model: handle.", "schema": { "type": "string", "pattern": "^[A-Za-z0-9_-]{8,600}$" } }, "ModelProviderQuery": { "name": "provider", "in": "query", "required": false, "schema": { "type": "string", "maxLength": 80 } }, "ModelQuery": { "name": "q", "in": "query", "required": false, "description": "Free-text model, provider, connection, or capability search.", "schema": { "type": "string", "maxLength": 240 } }, "NodeId": { "name": "nodeId", "in": "path", "required": true, "schema": { "type": "string", "pattern": "^(?:node:)?[A-Za-z0-9_-]{1,180}$" } }, "OwnerUidQuery": { "name": "ownerUid", "in": "query", "required": false, "description": "Identifies the owner of a shared canvas or asset. Owner-qualified handles let the CLI supply it automatically.", "schema": { "$ref": "#/components/schemas/StableId" } }, "PreviewToken": { "name": "token", "in": "query", "required": true, "schema": { "type": "string", "minLength": 1 } }, "RecipeId": { "name": "recipeId", "in": "path", "required": true, "schema": { "$ref": "#/components/schemas/StableId" } }, "RecipeQuery": { "name": "q", "in": "query", "required": false, "description": "Free-text Recipe Library search.", "schema": { "type": "string", "maxLength": 500 } }, "RecipeVersionQuery": { "name": "version", "in": "query", "required": false, "description": "Optional immutable Recipe version.", "schema": { "type": "string", "maxLength": 80 } }, "RunId": { "name": "runId", "in": "path", "required": true, "schema": { "type": "string", "pattern": "^(?:run:)?[A-Za-z0-9_-]{1,180}$" } } }, "headers": { "RequestId": { "description": "Safe correlation id for support and server logs.", "schema": { "type": "string", "format": "uuid" } } }, "callbacks": { "ImageJobTerminal": { "{$request.body#/webhook/url}": { "post": { "summary": "Receive a signed terminal image-job event", "description": "Gavana signs `${timestamp}.${rawBody}` with HMAC-SHA256 and the caller-owned secret. Return any 2xx response to acknowledge delivery. Delivery uses four total attempts. Retryable network failures and 408, 425, 429, or 5xx responses back off for 10 seconds, 60 seconds, then 5 minutes; redirects and other 4xx responses stop delivery. Successful Image and Action callbacks already contain durable asset and node handles in `data.run.images`, so callback-only clients do not need a follow-up GET. A caller with `job:manage` may read the shared Run later for inspection. Successful image and Action results retain their temporary observation record for 24 hours before the first successful server finalization and 15 minutes after it; an authenticated Run GET or pre-callback worker finalization both count. Failed and canceled records keep the normal 24-hour window.", "parameters": [ { "in": "header", "name": "Gavana-Webhook-Id", "required": true, "schema": { "type": "string", "pattern": "^webhook:" } }, { "in": "header", "name": "Gavana-Webhook-Timestamp", "required": true, "schema": { "type": "string", "pattern": "^\\d{10,13}$" } }, { "in": "header", "name": "Gavana-Webhook-Signature", "required": true, "schema": { "type": "string", "pattern": "^t=\\d{10,13},v1=[0-9a-f]{64}$" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImageJobWebhookEvent" } } } }, "responses": { "2XX": { "description": "The event was accepted. Any 2xx response acknowledges delivery." } } } } }, "RecipeRunTerminal": { "{$request.body#/webhook/url}": { "post": { "summary": "Receive a signed terminal Recipe Run event", "description": "Gavana signs `${timestamp}.${rawBody}` with HMAC-SHA256 and the caller-owned secret. Return any 2xx response to acknowledge delivery. Delivery uses four total attempts. Retryable network failures and 408, 425, 429, or 5xx responses back off for 10 seconds, 60 seconds, then 5 minutes; redirects and other 4xx responses stop delivery. Private-network destinations are blocked.", "parameters": [ { "in": "header", "name": "Gavana-Webhook-Id", "required": true, "schema": { "type": "string", "pattern": "^webhook:" } }, { "in": "header", "name": "Gavana-Webhook-Timestamp", "required": true, "schema": { "type": "string", "pattern": "^\\d{10,13}$" } }, { "in": "header", "name": "Gavana-Webhook-Signature", "required": true, "schema": { "type": "string", "pattern": "^t=\\d{10,13},v1=[0-9a-f]{64}$" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RecipeRunWebhookEvent" } } } }, "responses": { "2XX": { "description": "The event was accepted. Any 2xx response acknowledges delivery." } } } } } }, "requestBodies": { "CanvasCreate": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CanvasCreateInput" } } } }, "CanvasOperations": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CanvasOperationsInput" } } } }, "CanvasWorkflowCreate": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CanvasWorkflowCreateInput" } } } }, "ImageActionRun": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImageActionRunInput" } } } }, "ImageEdit": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImageEditInput" } } } }, "ImageGeneration": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImageGenerationInput" } } } }, "ImageImport": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImageImportInput" } } } }, "ImageVariations": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImageVariationsInput" } } } }, "VideoGeneration": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VideoGenerationInput" } } } }, "LegacyCampaign": { "required": true, "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true } } } }, "RecipeFork": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RecipeForkInput" } } } }, "RecipeRun": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RecipeRunInput" } } } } }, "responses": { "Action": { "description": "One deterministic Image Action with its typed input and parameter schema.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "type": "object", "required": [ "action" ], "properties": { "action": { "$ref": "#/components/schemas/ImageAction" } }, "additionalProperties": false } } } }, "ActionList": { "description": "Deterministic Image Actions with typed schemas and pagination.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "type": "object", "required": [ "actions", "page" ], "properties": { "actions": { "type": "array", "items": { "$ref": "#/components/schemas/ImageAction" } }, "page": { "$ref": "#/components/schemas/CursorPage" } }, "additionalProperties": false } } } }, "AuthStatus": { "description": "The authenticated identity and Agent Access scopes. No token secret is returned.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthStatus" } } } }, "Asset": { "description": "A durable asset.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "type": "object", "required": [ "asset" ], "properties": { "asset": { "$ref": "#/components/schemas/Asset" } } } } } }, "AssetList": { "description": "Accessible durable assets.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "type": "object", "required": [ "assets", "page" ], "properties": { "assets": { "type": "array", "items": { "$ref": "#/components/schemas/Asset" } }, "page": { "$ref": "#/components/schemas/CursorPage" } } } } } }, "BinaryImage": { "description": "A proxied PNG, JPEG, WebP, or GIF image.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "image/png": { "schema": { "type": "string", "format": "binary" } }, "image/jpeg": { "schema": { "type": "string", "format": "binary" } }, "image/webp": { "schema": { "type": "string", "format": "binary" } }, "image/gif": { "schema": { "type": "string", "format": "binary" } } } }, "Campaign": { "description": "A deprecated campaign compatibility result.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true } } } }, "CampaignList": { "description": "Deprecated campaign compatibility results.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "type": "object", "required": [ "runs" ], "properties": { "runs": { "type": "array", "items": { "type": "object", "additionalProperties": true } } } } } } }, "Canvas": { "description": "A complete canvas with its current revision.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CanvasResponse" } } } }, "CanvasList": { "description": "Accessible canvas summaries.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "type": "object", "required": [ "canvases", "page" ], "properties": { "canvases": { "type": "array", "items": { "$ref": "#/components/schemas/CanvasSummary" } }, "page": { "$ref": "#/components/schemas/CursorPage" } } } } } }, "Error": { "description": "A stable machine-readable error. The response always includes X-Request-ID.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "GenericObject": { "description": "A successful JSON response.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true } } } }, "ImageImport": { "description": "A durable canvas image import result.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImageImportResponse" } } } }, "Job": { "description": "An image, Action, or video job state or finalized result. Image and Action results follow the documented Run retention policy. Video records are retained for 30 days and expose a protected download URL after completion.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "oneOf": [ { "$ref": "#/components/schemas/ImageJob" }, { "$ref": "#/components/schemas/VideoJob" } ] } } } }, "Model": { "description": "One runnable image or video model with its connection-specific schema.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "type": "object", "required": [ "model" ], "properties": { "model": { "$ref": "#/components/schemas/ImageModel" } }, "additionalProperties": false } } } }, "ModelList": { "description": "Runnable image and video models with typed schemas and pagination.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "type": "object", "required": [ "models", "page" ], "properties": { "models": { "type": "array", "items": { "$ref": "#/components/schemas/ImageModel" } }, "page": { "$ref": "#/components/schemas/CursorPage" } }, "additionalProperties": false } } } }, "Mutation": { "description": "A revision-safe canvas mutation result.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MutationResponse" } } } }, "CanvasOperationsResult": { "description": "A canonical read-only validation result when validateOnly is true, otherwise a revision-safe mutation result.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "anyOf": [ { "$ref": "#/components/schemas/CanvasValidationResponse" }, { "$ref": "#/components/schemas/MutationResponse" } ] } } } }, "WorkflowMutation": { "description": "A private reusable workflow creation or idempotent replay result.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CanvasWorkflowMutationResponse" } } } }, "ProviderList": { "description": "Saved image-provider connections with masked credentials.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "type": "object", "required": [ "connections", "page" ], "properties": { "connections": { "type": "array", "items": { "$ref": "#/components/schemas/ProviderConnection" } }, "page": { "$ref": "#/components/schemas/CursorPage" } } } } } }, "Recipe": { "description": "An approved Recipe Library workflow.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "type": "object", "required": [ "recipe" ], "properties": { "recipe": { "$ref": "#/components/schemas/Recipe" } } } } } }, "RecipeList": { "description": "Approved Recipe Library search results.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "type": "object", "required": [ "recipes", "page" ], "properties": { "recipes": { "type": "array", "items": { "$ref": "#/components/schemas/Recipe" } }, "page": { "$ref": "#/components/schemas/CursorPage" } } } } } }, "RecipeRun": { "description": "A durable Recipe Run with typed input bindings and declared output state.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RecipeRun" } } } }, "Run": { "description": "A shared Recipe, image, or Action Run.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Run" } } } }, "Svg": { "description": "An SVG rendering of the canvas.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "image/svg+xml": { "schema": { "type": "string" } } } }, "VideoOutput": { "description": "The generated video stream. The concrete Content-Type is the provider result, such as video/mp4 or video/webm.", "headers": { "X-Request-ID": { "$ref": "#/components/headers/RequestId" } }, "content": { "video/mp4": { "schema": { "type": "string", "format": "binary" } } } } }, "schemas": { "AuthStatus": { "type": "object", "required": [ "authenticated", "authType", "email", "scopes" ], "properties": { "authenticated": { "const": true }, "authType": { "type": "string", "enum": [ "agent", "firebase" ] }, "email": { "type": "string", "format": "email" }, "scopes": { "anyOf": [ { "type": "array", "uniqueItems": true, "items": { "type": "string", "enum": [ "canvas:read", "canvas:write", "asset:read", "image:generate", "video:generate", "job:manage" ] } }, { "type": "null" } ] }, "agentTokenId": { "type": "string", "format": "uuid" }, "agentLabel": { "type": "string", "maxLength": 80 } }, "additionalProperties": false }, "CursorPage": { "type": "object", "required": [ "limit", "hasMore", "nextCursor" ], "properties": { "limit": { "type": "integer", "minimum": 1, "maximum": 200 }, "hasMore": { "type": "boolean" }, "nextCursor": { "type": [ "string", "null" ], "maxLength": 8192 } }, "additionalProperties": false }, "Asset": { "type": "object", "required": [ "id", "handle", "name" ], "properties": { "id": { "$ref": "#/components/schemas/StableId" }, "handle": { "type": "string", "description": "Shared assets include their owner: asset::.", "pattern": "^asset:(?:[A-Za-z0-9_-]{1,180}:)?[A-Za-z0-9_-]{1,180}$" }, "ownerUid": { "$ref": "#/components/schemas/StableId" }, "kind": { "type": "string", "enum": [ "image", "prompt" ] }, "name": { "type": "string" }, "mimeType": { "type": "string" }, "width": { "type": "integer", "minimum": 0 }, "height": { "type": "integer", "minimum": 0 }, "bytes": { "type": "integer", "minimum": 0 }, "previewUrl": { "type": "string", "format": "uri" }, "previewExpiresInSeconds": { "type": "integer", "minimum": 1 }, "node": { "type": "string", "pattern": "^node:" } }, "additionalProperties": true }, "Canvas": { "type": "object", "required": [ "id", "handle", "ownerUid", "title", "createdAt", "updatedAt", "revision", "nodes", "connections" ], "properties": { "id": { "$ref": "#/components/schemas/StableId" }, "canvasType": { "type": "string", "enum": [ "agent" ] }, "handle": { "type": "string", "pattern": "^canvas:[A-Za-z0-9_-]+:[A-Za-z0-9_-]+$" }, "ownerUid": { "$ref": "#/components/schemas/StableId" }, "title": { "type": "string", "maxLength": 160 }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" }, "revision": { "type": "string", "minLength": 1 }, "nodes": { "type": "array", "items": { "$ref": "#/components/schemas/CanvasNode" } }, "connections": { "type": "array", "items": { "$ref": "#/components/schemas/CanvasConnection" } } }, "additionalProperties": true }, "CanvasConnection": { "type": "object", "required": [ "id", "handle", "fromNodeId", "toNodeId", "from", "to" ], "properties": { "id": { "$ref": "#/components/schemas/StableId" }, "handle": { "type": "string", "pattern": "^connection:" }, "fromNodeId": { "$ref": "#/components/schemas/StableId" }, "toNodeId": { "$ref": "#/components/schemas/StableId" }, "from": { "type": "string", "pattern": "^node:" }, "to": { "type": "string", "pattern": "^node:" } }, "additionalProperties": true }, "CanvasCreateInput": { "type": "object", "properties": { "id": { "$ref": "#/components/schemas/StableId" }, "title": { "type": "string", "maxLength": 160 }, "canvasType": { "type": "string", "enum": [ "agent" ] }, "destination": { "type": "string", "enum": [ "agent-canvas" ] } }, "additionalProperties": false }, "CanvasNode": { "type": "object", "required": [ "id", "handle", "type", "title", "position", "width", "height" ], "properties": { "id": { "$ref": "#/components/schemas/StableId" }, "handle": { "type": "string", "pattern": "^node:" }, "type": { "type": "string", "enum": [ "image", "video", "text", "sticky" ] }, "title": { "type": "string" }, "position": { "$ref": "#/components/schemas/Position" }, "width": { "type": "number", "exclusiveMinimum": 0 }, "height": { "type": "number", "exclusiveMinimum": 0 }, "metadata": { "type": "object", "additionalProperties": true }, "asset": { "type": "string", "pattern": "^asset:" } }, "additionalProperties": true }, "BatchNodeReference": { "type": "string", "pattern": "^(?:(?:node|client):)?[A-Za-z0-9_-]{1,180}$" }, "CanvasConnectionInput": { "type": "object", "required": [ "fromNodeId", "toNodeId" ], "properties": { "id": { "$ref": "#/components/schemas/StableId" }, "fromNodeId": { "$ref": "#/components/schemas/BatchNodeReference" }, "toNodeId": { "$ref": "#/components/schemas/BatchNodeReference" }, "mode": { "type": "string", "enum": [ "list", "reference", "first-frame", "last-frame" ] } }, "additionalProperties": false }, "PublicNodeMetadata": { "type": "object", "description": "Publicly writable node metadata. Null removes a field during update. The serialized metadata object must be no larger than 64 KiB. Server-owned provenance, upload, storage, and generation-job fields are intentionally excluded.", "properties": { "content": { "type": [ "string", "null" ], "description": "Text and sticky nodes only. A non-empty value is rejected when the target node is an image or video; use a generation or asset operation instead.", "maxLength": 8000 }, "composerContent": { "type": [ "string", "null" ], "maxLength": 8000 }, "assetName": { "type": [ "string", "null" ], "maxLength": 600 }, "prompt": { "type": [ "string", "null" ], "maxLength": 8000 }, "errorDetails": { "type": [ "string", "null" ], "maxLength": 600 }, "model": { "type": [ "string", "null" ], "maxLength": 600 }, "size": { "type": [ "string", "null" ], "maxLength": 600 }, "quality": { "type": [ "string", "null" ], "maxLength": 600 }, "aspectRatio": { "type": [ "string", "null" ], "maxLength": 600 }, "resolution": { "type": [ "string", "null" ], "maxLength": 600 }, "posterUrl": { "type": [ "string", "null" ], "maxLength": 8000 }, "variationSourceId": { "type": [ "string", "null" ], "maxLength": 600 }, "primaryImageId": { "type": [ "string", "null" ], "maxLength": 600 }, "stickyColor": { "type": [ "string", "null" ], "maxLength": 600 }, "sceneRole": { "type": [ "string", "null" ], "maxLength": 600 }, "videoPrompt": { "type": [ "string", "null" ], "maxLength": 600 }, "fontSize": { "type": [ "number", "null" ] }, "count": { "type": [ "number", "null" ] }, "variationIndex": { "type": [ "number", "null" ] }, "generationBatchIndex": { "type": [ "number", "null" ] }, "sceneIndex": { "type": [ "number", "null" ] }, "durationSeconds": { "type": [ "number", "null" ] }, "freeResize": { "type": [ "boolean", "null" ] }, "isList": { "type": [ "boolean", "null" ] }, "isGeneratedOutputList": { "type": [ "boolean", "null" ] }, "isBatchRoot": { "type": [ "boolean", "null" ] }, "batchUsesReferenceImages": { "type": [ "boolean", "null" ] }, "imageBatchExpanded": { "type": [ "boolean", "null" ] }, "isSection": { "type": [ "boolean", "null" ] }, "generateAudio": { "type": [ "boolean", "null" ] }, "status": { "type": [ "string", "null" ], "enum": [ "idle", "success", "loading", "error", null ] }, "generationMode": { "type": [ "string", "null" ], "enum": [ "text", "image", "video", null ] }, "generationType": { "type": [ "string", "null" ], "enum": [ "generation", "edit", null ] }, "videoGenerationType": { "type": [ "string", "null" ], "enum": [ "text-to-video", "image-to-video", "frames-to-video", null ] }, "listType": { "type": [ "string", "null" ], "enum": [ "prompt", "image", null ] }, "listViewMode": { "type": [ "string", "null" ], "enum": [ "grid", "list", null ] }, "listExecutionMode": { "type": [ "string", "null" ], "enum": [ "batch", "reference-set", null ] }, "listRunStatus": { "type": [ "string", "null" ], "enum": [ "idle", "running", "complete", null ] }, "generatedOutputSourceListType": { "type": [ "string", "null" ], "enum": [ "prompt", "image", null ] }, "listSourceId": { "type": [ "string", "null" ], "pattern": "^(?:node:)?[A-Za-z0-9_-]{1,180}$" }, "listGeneratorId": { "type": [ "string", "null" ], "pattern": "^(?:node:)?[A-Za-z0-9_-]{1,180}$" }, "listRunId": { "type": [ "string", "null" ], "pattern": "^(?:node:)?[A-Za-z0-9_-]{1,180}$" }, "listItemId": { "type": [ "string", "null" ], "pattern": "^(?:node:)?[A-Za-z0-9_-]{1,180}$" }, "listOutputId": { "type": [ "string", "null" ], "pattern": "^(?:node:)?[A-Za-z0-9_-]{1,180}$" }, "batchRootId": { "type": [ "string", "null" ], "pattern": "^(?:node:)?[A-Za-z0-9_-]{1,180}$" }, "firstFrameNodeId": { "type": [ "string", "null" ], "pattern": "^(?:node:)?[A-Za-z0-9_-]{1,180}$" }, "lastFrameNodeId": { "type": [ "string", "null" ], "pattern": "^(?:node:)?[A-Za-z0-9_-]{1,180}$" }, "listRunTargetIds": { "anyOf": [ { "type": "array", "maxItems": 200, "items": { "type": "string", "pattern": "^(?:node:)?[A-Za-z0-9_-]{1,180}$" } }, { "type": "null" } ] }, "generatedOutputChildIds": { "anyOf": [ { "type": "array", "maxItems": 200, "items": { "type": "string", "pattern": "^(?:node:)?[A-Za-z0-9_-]{1,180}$" } }, { "type": "null" } ] }, "batchChildIds": { "anyOf": [ { "type": "array", "maxItems": 200, "items": { "type": "string", "pattern": "^(?:node:)?[A-Za-z0-9_-]{1,180}$" } }, { "type": "null" } ] }, "references": { "anyOf": [ { "type": "array", "maxItems": 32, "items": { "type": "string", "pattern": "^(?:node|asset):[A-Za-z0-9_-]{1,180}$" } }, { "type": "null" } ] }, "crop": { "anyOf": [ { "type": "object", "required": [ "offsetX", "offsetY", "scale" ], "properties": { "offsetX": { "type": "number" }, "offsetY": { "type": "number" }, "scale": { "type": "number" } }, "additionalProperties": false }, { "type": "null" } ] }, "promptHistory": { "anyOf": [ { "type": "array", "maxItems": 20, "items": { "type": "object", "required": [ "prompt" ], "properties": { "id": { "type": "string", "maxLength": 180 }, "prompt": { "type": "string", "maxLength": 8000 }, "createdAt": { "type": "string", "maxLength": 80 }, "source": { "type": "string", "enum": [ "agent", "manual" ] }, "instruction": { "type": "string", "maxLength": 1200 } }, "additionalProperties": false } }, { "type": "null" } ] }, "listItems": { "anyOf": [ { "type": "array", "maxItems": 200, "items": { "type": "object", "required": [ "value" ], "properties": { "id": { "type": "string", "maxLength": 180 }, "value": { "type": "string", "maxLength": 8000 }, "checked": { "type": "boolean" }, "sourceNodeId": { "type": "string", "pattern": "^[A-Za-z0-9_-]{1,180}$" }, "referenceBindings": { "type": "array", "maxItems": 16, "items": { "type": "object", "required": [ "nodeId", "role" ], "properties": { "nodeId": { "type": "string", "pattern": "^(?:node:)?[A-Za-z0-9_-]{1,180}$" }, "role": { "type": "string", "enum": [ "product", "style" ] } }, "additionalProperties": false } } }, "additionalProperties": false } }, { "type": "null" } ] } }, "x-craftboard-node-type-rules": { "content": "Non-empty content is writable only on text and sticky nodes." }, "additionalProperties": false }, "CanvasNodeInput": { "type": "object", "properties": { "id": { "$ref": "#/components/schemas/StableId" }, "type": { "type": "string", "enum": [ "image", "video", "text", "sticky" ] }, "title": { "type": "string", "maxLength": 160 }, "position": { "$ref": "#/components/schemas/Position" }, "width": { "type": "number", "minimum": 40, "maximum": 10000 }, "height": { "type": "number", "minimum": 40, "maximum": 10000 }, "metadata": { "$ref": "#/components/schemas/PublicNodeMetadata" } }, "allOf": [ { "if": { "required": [ "type" ], "properties": { "type": { "const": "image" } } }, "then": { "properties": { "metadata": { "properties": { "content": { "anyOf": [ { "type": "string", "maxLength": 0 }, { "type": "null" } ] } } } } } } ], "additionalProperties": false }, "CanvasNodePatch": { "type": "object", "description": "Patch for an existing node. A non-empty metadata.content value is rejected when the existing node is an image or video, even when type is omitted.", "properties": { "type": { "type": "string", "enum": [ "image", "video", "text", "sticky" ] }, "title": { "type": "string", "maxLength": 160 }, "position": { "$ref": "#/components/schemas/Position" }, "width": { "type": "number", "minimum": 40, "maximum": 10000 }, "height": { "type": "number", "minimum": 40, "maximum": 10000 }, "metadata": { "$ref": "#/components/schemas/PublicNodeMetadata" } }, "allOf": [ { "if": { "required": [ "type" ], "properties": { "type": { "const": "image" } } }, "then": { "properties": { "metadata": { "properties": { "content": { "anyOf": [ { "type": "string", "maxLength": 0 }, { "type": "null" } ] } } } } } } ], "additionalProperties": false }, "CanvasUpdateOperation": { "type": "object", "required": [ "type" ], "properties": { "type": { "const": "canvas.update" }, "title": { "type": "string", "maxLength": 160 }, "backgroundMode": { "type": "string", "enum": [ "dots", "lines", "blank" ] }, "showImageInfo": { "type": "boolean" }, "viewport": { "$ref": "#/components/schemas/Viewport" } }, "additionalProperties": false }, "NodeCreateOperation": { "type": "object", "required": [ "type", "node" ], "properties": { "type": { "const": "node.create" }, "clientId": { "type": "string", "pattern": "^(?:client:)?[A-Za-z0-9_-]{1,100}$" }, "node": { "$ref": "#/components/schemas/CanvasNodeInput" } }, "additionalProperties": false }, "NodeUpdateOperation": { "type": "object", "required": [ "type", "nodeId", "patch" ], "properties": { "type": { "const": "node.update" }, "nodeId": { "$ref": "#/components/schemas/BatchNodeReference" }, "patch": { "$ref": "#/components/schemas/CanvasNodePatch" } }, "additionalProperties": false }, "NodeMoveOperation": { "type": "object", "required": [ "type", "nodeId", "position" ], "properties": { "type": { "const": "node.move" }, "nodeId": { "$ref": "#/components/schemas/BatchNodeReference" }, "position": { "$ref": "#/components/schemas/Position" } }, "additionalProperties": false }, "NodeResizeOperation": { "type": "object", "required": [ "type", "nodeId", "width", "height" ], "properties": { "type": { "const": "node.resize" }, "nodeId": { "$ref": "#/components/schemas/BatchNodeReference" }, "width": { "type": "number", "minimum": 40, "maximum": 10000 }, "height": { "type": "number", "minimum": 40, "maximum": 10000 } }, "additionalProperties": false }, "NodeDeleteOperation": { "type": "object", "required": [ "type", "nodeId" ], "properties": { "type": { "const": "node.delete" }, "nodeId": { "$ref": "#/components/schemas/BatchNodeReference" } }, "additionalProperties": false }, "ConnectionCreateOperation": { "type": "object", "required": [ "type" ], "properties": { "type": { "const": "connection.create" }, "clientId": { "type": "string", "pattern": "^(?:client:)?[A-Za-z0-9_-]{1,100}$" }, "connection": { "$ref": "#/components/schemas/CanvasConnectionInput" }, "from": { "$ref": "#/components/schemas/BatchNodeReference" }, "to": { "$ref": "#/components/schemas/BatchNodeReference" }, "mode": { "type": "string", "enum": [ "list", "reference", "first-frame", "last-frame" ] } }, "anyOf": [ { "required": [ "connection" ] }, { "required": [ "from", "to" ] } ], "additionalProperties": false }, "ConnectionDeleteOperation": { "type": "object", "required": [ "type", "connectionId" ], "properties": { "type": { "const": "connection.delete" }, "connectionId": { "type": "string", "pattern": "^(?:connection:)?[A-Za-z0-9_-]{1,180}$" } }, "additionalProperties": false }, "CanvasOperation": { "oneOf": [ { "$ref": "#/components/schemas/CanvasUpdateOperation" }, { "$ref": "#/components/schemas/NodeCreateOperation" }, { "$ref": "#/components/schemas/NodeUpdateOperation" }, { "$ref": "#/components/schemas/NodeMoveOperation" }, { "$ref": "#/components/schemas/NodeResizeOperation" }, { "$ref": "#/components/schemas/NodeDeleteOperation" }, { "$ref": "#/components/schemas/ConnectionCreateOperation" }, { "$ref": "#/components/schemas/ConnectionDeleteOperation" } ], "discriminator": { "propertyName": "type", "mapping": { "canvas.update": "#/components/schemas/CanvasUpdateOperation", "node.create": "#/components/schemas/NodeCreateOperation", "node.update": "#/components/schemas/NodeUpdateOperation", "node.move": "#/components/schemas/NodeMoveOperation", "node.resize": "#/components/schemas/NodeResizeOperation", "node.delete": "#/components/schemas/NodeDeleteOperation", "connection.create": "#/components/schemas/ConnectionCreateOperation", "connection.delete": "#/components/schemas/ConnectionDeleteOperation" } } }, "CanvasOperationsInput": { "type": "object", "required": [ "operations" ], "properties": { "baseRevision": { "type": "string", "minLength": 1, "maxLength": 200 }, "idempotencyKey": { "type": "string", "minLength": 8, "maxLength": 200, "description": "Required for mutation. Ignored and not consumed when validateOnly is true." }, "validateOnly": { "type": "boolean", "default": false, "description": "Run the canonical operation engine and graph validator without persisting any change." }, "operations": { "type": "array", "minItems": 1, "maxItems": 200, "items": { "$ref": "#/components/schemas/CanvasOperation" } } }, "allOf": [ { "if": { "properties": { "validateOnly": { "const": true } }, "required": [ "validateOnly" ] }, "else": { "required": [ "baseRevision", "idempotencyKey" ] } } ], "additionalProperties": false }, "CanvasValidationResponse": { "type": "object", "required": [ "canvas", "proposal", "destructiveImpact", "validation" ], "properties": { "canvas": { "$ref": "#/components/schemas/CanvasSummary" }, "proposal": { "type": "object", "required": [ "clientReferences", "changedNodeReferences", "deletedNodeReferences", "changedConnectionReferences", "deletedConnectionReferences" ], "additionalProperties": true }, "destructiveImpact": { "type": "object", "required": [ "deletedNodeHandles", "deletedConnectionHandles", "mediaNodeHandles", "generatedNodeHandles" ], "additionalProperties": true }, "validation": { "type": "object", "required": [ "guideVersion", "scope", "canvas", "summary", "findings" ], "additionalProperties": true } }, "additionalProperties": false }, "CanvasWorkflowInput": { "type": "object", "required": [ "key", "label", "type", "useAsDefault" ], "properties": { "key": { "type": "string", "pattern": "^[A-Za-z0-9_-]{1,80}$" }, "label": { "type": "string", "minLength": 1, "maxLength": 80 }, "description": { "type": "string", "maxLength": 200 }, "type": { "type": "string", "enum": [ "image", "text", "sticky" ] }, "sourceNodeId": { "type": "string", "pattern": "^(?:node:)?[A-Za-z0-9_-]{1,180}$" }, "value": { "type": "string", "maxLength": 8000 }, "useAsDefault": { "type": "boolean", "description": "When true, preserve this durable source or text value as the input used when a later run omits the port." } }, "additionalProperties": false }, "CanvasWorkflowOutput": { "type": "object", "required": [ "key", "label", "type", "prompt", "inputKeys" ], "properties": { "key": { "type": "string", "pattern": "^[A-Za-z0-9_-]{1,80}$" }, "label": { "type": "string", "minLength": 1, "maxLength": 80 }, "description": { "type": "string", "maxLength": 200 }, "type": { "type": "string", "enum": [ "image", "text" ] }, "prompt": { "type": "string", "minLength": 1, "maxLength": 8000 }, "inputKeys": { "type": "array", "minItems": 1, "maxItems": 16, "items": { "type": "string", "pattern": "^[A-Za-z0-9_-]{1,80}$" } }, "model": { "type": "string", "maxLength": 650 }, "size": { "type": "string", "maxLength": 80 }, "quality": { "type": "string", "maxLength": 80 } }, "additionalProperties": false }, "CanvasWorkflowCreateInput": { "type": "object", "required": [ "name", "idempotencyKey", "inputs", "outputs" ], "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 160 }, "description": { "type": "string", "maxLength": 1200 }, "category": { "type": "string", "enum": [ "Brand & Visual Design", "Product Visualization", "Marketing & Ads", "Content Package" ], "default": "Product Visualization" }, "tags": { "type": "array", "maxItems": 12, "items": { "type": "string", "minLength": 1, "maxLength": 80 } }, "inputs": { "type": "array", "minItems": 1, "maxItems": 16, "items": { "$ref": "#/components/schemas/CanvasWorkflowInput" } }, "outputs": { "type": "array", "minItems": 1, "maxItems": 8, "items": { "$ref": "#/components/schemas/CanvasWorkflowOutput" } }, "idempotencyKey": { "type": "string", "minLength": 8, "maxLength": 200 }, "x": { "type": "number", "minimum": -100000, "maximum": 100000 }, "y": { "type": "number", "minimum": -100000, "maximum": 100000 } }, "additionalProperties": false }, "CanvasWorkflowInputResponse": { "type": "object", "required": [ "key", "portNodeId", "nodeId", "label", "useAsDefault" ], "properties": { "key": { "type": "string", "pattern": "^[A-Za-z0-9_-]{1,80}$" }, "portNodeId": { "type": "string", "pattern": "^node:" }, "nodeId": { "type": "string", "pattern": "^node:" }, "label": { "type": "string" }, "useAsDefault": { "type": "boolean" } }, "additionalProperties": false }, "CanvasWorkflowOutputResponse": { "type": "object", "required": [ "key", "portNodeId", "templateNodeId", "label" ], "properties": { "key": { "type": "string", "pattern": "^[A-Za-z0-9_-]{1,80}$" }, "portNodeId": { "type": "string", "pattern": "^node:" }, "templateNodeId": { "type": "string", "pattern": "^node:" }, "label": { "type": "string" } }, "additionalProperties": false }, "CanvasWorkflowResponse": { "type": "object", "required": [ "id", "handle", "version", "name", "visibility", "recipeNodeId", "workflowNodeId", "inputs", "outputs", "createdWithoutRunning" ], "properties": { "id": { "$ref": "#/components/schemas/StableId" }, "handle": { "type": "string", "pattern": "^recipe:" }, "version": { "type": "string" }, "name": { "type": "string" }, "visibility": { "const": "private" }, "recipeNodeId": { "type": "string", "pattern": "^node:" }, "workflowNodeId": { "type": "string", "pattern": "^node:" }, "inputs": { "type": "array", "items": { "$ref": "#/components/schemas/CanvasWorkflowInputResponse" } }, "outputs": { "type": "array", "items": { "$ref": "#/components/schemas/CanvasWorkflowOutputResponse" } }, "createdWithoutRunning": { "const": true } }, "additionalProperties": false }, "CanvasWorkflowMutationResponse": { "allOf": [ { "$ref": "#/components/schemas/MutationResponse" }, { "type": "object", "required": [ "workflow" ], "properties": { "workflow": { "$ref": "#/components/schemas/CanvasWorkflowResponse" } } } ] }, "CanvasResponse": { "type": "object", "required": [ "canvas", "activity" ], "properties": { "canvas": { "$ref": "#/components/schemas/Canvas" }, "activity": { "type": "array", "items": { "type": "object", "additionalProperties": true } } }, "additionalProperties": true }, "CanvasSummary": { "type": "object", "required": [ "id", "handle", "ownerUid", "title", "createdAt", "updatedAt", "revision", "nodeCount", "connectionCount" ], "properties": { "id": { "$ref": "#/components/schemas/StableId" }, "canvasType": { "type": "string", "enum": [ "agent" ] }, "handle": { "type": "string", "pattern": "^canvas:" }, "ownerUid": { "$ref": "#/components/schemas/StableId" }, "title": { "type": "string" }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" }, "revision": { "type": "string" }, "accessRole": { "type": "string", "enum": [ "owner", "editor", "viewer" ] }, "nodeCount": { "type": "integer", "minimum": 0 }, "connectionCount": { "type": "integer", "minimum": 0 } }, "additionalProperties": false }, "Error": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "string", "enum": [ "input_validation_error", "invalid_json", "unauthorized", "payment_required", "forbidden", "not_found", "conflict", "gone", "payload_too_large", "unsupported_media_type", "unprocessable_entity", "rate_limited", "internal_error", "upstream_error", "service_unavailable", "upstream_timeout", "request_failed" ] }, "message": { "type": "string", "minLength": 1 }, "fields": { "type": "array", "items": { "$ref": "#/components/schemas/ErrorField" } }, "details": { "type": "object", "additionalProperties": true } }, "additionalProperties": false }, "ErrorField": { "type": "object", "required": [ "field", "message" ], "properties": { "field": { "type": "string", "minLength": 1 }, "message": { "type": "string", "minLength": 1 } }, "additionalProperties": false }, "ErrorResponse": { "type": "object", "required": [ "error" ], "properties": { "error": { "$ref": "#/components/schemas/Error" } }, "additionalProperties": false }, "ImageAction": { "type": "object", "required": [ "id", "slug", "version", "title", "summary", "deterministic", "chargedCost", "estimatedSeconds", "inputs", "output", "parameters" ], "properties": { "id": { "type": "string", "pattern": "^action:" }, "slug": { "type": "string", "enum": [ "resize", "crop", "change-aspect-ratio", "side-by-side-composite", "add-text-to-image", "overlay-image", "color-grade", "rotate" ] }, "version": { "type": "string", "const": "1.0.0" }, "title": { "type": "string", "minLength": 1 }, "summary": { "type": "string", "minLength": 1 }, "deterministic": { "const": true }, "chargedCost": { "const": 0, "description": "These transformations do not spend AI-generation credits." }, "estimatedSeconds": { "type": "integer", "minimum": 1 }, "inputs": { "type": "array", "minItems": 1, "maxItems": 2, "items": { "$ref": "#/components/schemas/ImageActionInput" } }, "output": { "$ref": "#/components/schemas/ImageActionOutput" }, "parameters": { "type": "array", "items": { "$ref": "#/components/schemas/ImageActionParameter" } } }, "additionalProperties": false }, "ImageActionInput": { "type": "object", "required": [ "id", "title", "description", "type", "required" ], "properties": { "id": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,79}$" }, "title": { "type": "string" }, "description": { "type": "string" }, "type": { "const": "image" }, "required": { "const": true } }, "additionalProperties": false }, "ImageActionOutput": { "type": "object", "required": [ "id", "title", "description", "type" ], "properties": { "id": { "const": "image" }, "title": { "type": "string" }, "description": { "type": "string" }, "type": { "const": "image" } }, "additionalProperties": false }, "ImageActionParameter": { "type": "object", "required": [ "id", "title", "type", "required" ], "properties": { "id": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,79}$" }, "title": { "type": "string" }, "description": { "type": "string" }, "type": { "type": "string", "enum": [ "number", "select", "text", "color" ] }, "required": { "type": "boolean" }, "default": {}, "integer": { "type": "boolean" }, "min": { "type": "number" }, "max": { "type": "number" }, "step": { "type": "number", "exclusiveMinimum": 0 }, "maxLength": { "type": "integer", "minimum": 1 }, "valueType": { "const": "number" }, "options": { "type": "array", "items": { "$ref": "#/components/schemas/ImageActionParameterOption" } } }, "additionalProperties": false }, "ImageActionParameterOption": { "type": "object", "required": [ "value", "label" ], "properties": { "value": { "oneOf": [ { "type": "string" }, { "type": "number" } ] }, "label": { "type": "string" } }, "additionalProperties": false }, "ImageActionRunInput": { "type": "object", "required": [ "canvasId", "baseRevision", "idempotencyKey", "targetNodeId", "inputs", "params" ], "properties": { "canvasId": { "type": "string", "description": "A plain id, canvas:, or canvas:: handle." }, "baseRevision": { "type": "string", "minLength": 1, "maxLength": 200 }, "idempotencyKey": { "type": "string", "minLength": 8, "maxLength": 200 }, "targetNodeId": { "type": "string", "description": "A new, empty image node reserved for this Action result. It must not also appear in inputs, and it must have no content, asset binding, or active Run.", "pattern": "^(?:node:)?[A-Za-z0-9_-]{1,180}$" }, "inputs": { "type": "array", "description": "One or two durable images in the exact order declared by the selected Action.", "minItems": 1, "maxItems": 2, "items": { "type": "string", "pattern": "^(?:node:[A-Za-z0-9_-]{1,180}|asset:(?:[A-Za-z0-9_-]{1,180}:)?[A-Za-z0-9_-]{1,180})$" } }, "params": { "$ref": "#/components/schemas/ImageActionParameters" }, "webhook": { "$ref": "#/components/schemas/ImageJobWebhookInput" } }, "additionalProperties": false, "x-craftboard-cross-field-rules": [ "targetNodeId must not identify any node supplied in inputs", "targetNodeId must identify an empty, unbound image node" ] }, "ImageActionParameters": { "description": "Use the parameter object declared by GET /actions/{actionKey}. Unknown fields are rejected.", "anyOf": [ { "$ref": "#/components/schemas/ResizeActionParameters" }, { "$ref": "#/components/schemas/CropActionParameters" }, { "$ref": "#/components/schemas/ChangeAspectRatioActionParameters" }, { "$ref": "#/components/schemas/SideBySideActionParameters" }, { "$ref": "#/components/schemas/AddTextActionParameters" }, { "$ref": "#/components/schemas/OverlayImageActionParameters" }, { "$ref": "#/components/schemas/ColorGradeActionParameters" }, { "$ref": "#/components/schemas/RotateActionParameters" } ] }, "ResizeActionParameters": { "type": "object", "required": [ "width", "height" ], "properties": { "width": { "type": "integer", "minimum": 1, "maximum": 8192 }, "height": { "type": "integer", "minimum": 1, "maximum": 8192 }, "fit": { "type": "string", "enum": [ "cover", "contain", "fill", "inside", "outside" ], "default": "cover" }, "background": { "$ref": "#/components/schemas/ImageActionColor" } }, "additionalProperties": false }, "CropActionParameters": { "type": "object", "required": [ "width", "height" ], "properties": { "x": { "type": "integer", "minimum": 0, "maximum": 8191, "default": 0 }, "y": { "type": "integer", "minimum": 0, "maximum": 8191, "default": 0 }, "width": { "type": "integer", "minimum": 1, "maximum": 8192 }, "height": { "type": "integer", "minimum": 1, "maximum": 8192 } }, "additionalProperties": false }, "ChangeAspectRatioActionParameters": { "type": "object", "properties": { "ratio": { "type": "string", "enum": [ "1:1", "4:5", "3:4", "16:9", "9:16" ], "default": "4:5" }, "mode": { "type": "string", "enum": [ "crop", "pad" ], "default": "crop" }, "background": { "$ref": "#/components/schemas/ImageActionColor" } }, "additionalProperties": false }, "SideBySideActionParameters": { "type": "object", "properties": { "direction": { "type": "string", "enum": [ "horizontal", "vertical" ], "default": "horizontal" }, "gap": { "type": "integer", "minimum": 0, "maximum": 512, "default": 0 }, "background": { "$ref": "#/components/schemas/ImageActionColor" } }, "additionalProperties": false }, "AddTextActionParameters": { "type": "object", "required": [ "text" ], "properties": { "text": { "type": "string", "minLength": 1, "maxLength": 500 }, "fontSize": { "type": "integer", "minimum": 8, "maximum": 512, "default": 64 }, "position": { "type": "string", "enum": [ "top", "center", "bottom" ], "default": "bottom" }, "color": { "$ref": "#/components/schemas/ImageActionColor" }, "background": { "allOf": [ { "$ref": "#/components/schemas/ImageActionColor" } ], "default": "#00000099" }, "padding": { "type": "integer", "minimum": 0, "maximum": 512, "default": 32 } }, "additionalProperties": false }, "OverlayImageActionParameters": { "type": "object", "properties": { "position": { "type": "string", "enum": [ "top-left", "top-right", "center", "bottom-left", "bottom-right" ], "default": "center" }, "scale": { "type": "number", "minimum": 0.05, "maximum": 1, "multipleOf": 0.05, "default": 0.25 }, "opacity": { "type": "number", "minimum": 0.05, "maximum": 1, "multipleOf": 0.05, "default": 1 }, "margin": { "type": "integer", "minimum": 0, "maximum": 1024, "default": 24 } }, "additionalProperties": false }, "ColorGradeActionParameters": { "type": "object", "properties": { "brightness": { "type": "number", "minimum": 0.1, "maximum": 3, "multipleOf": 0.05, "default": 1 }, "saturation": { "type": "number", "minimum": 0, "maximum": 3, "multipleOf": 0.05, "default": 1 }, "hue": { "type": "number", "minimum": -180, "maximum": 180, "multipleOf": 1, "default": 0 }, "contrast": { "type": "number", "minimum": 0.1, "maximum": 3, "multipleOf": 0.05, "default": 1 } }, "additionalProperties": false }, "RotateActionParameters": { "type": "object", "properties": { "angle": { "type": "number", "enum": [ 90, 180, 270 ], "default": 90 }, "background": { "$ref": "#/components/schemas/ImageActionColor" } }, "additionalProperties": false }, "ImageActionColor": { "type": "string", "pattern": "^(?:transparent|#[0-9A-Fa-f]{6}(?:[0-9A-Fa-f]{2})?)$", "default": "#ffffff" }, "ImageJob": { "type": "object", "required": [ "id", "run", "kind", "pollUrl", "status" ], "properties": { "id": { "type": "string", "pattern": "^job:" }, "run": { "type": "string", "pattern": "^run:" }, "kind": { "type": "string", "enum": [ "image", "action" ] }, "pollUrl": { "type": "string", "pattern": "^/api/canvas-agent/v1/runs/" }, "rawId": { "type": "string", "format": "uuid" }, "status": { "type": "string", "enum": [ "preparing", "queued", "running", "finalizing", "canceling", "succeeded", "failed", "canceled", "expired" ], "description": "Current temporary job state. Successful results retain the observation record for 24 hours before the first successful server finalization and 15 minutes after it; an authenticated Run GET or pre-callback worker finalization both count. Failed and canceled records keep the normal 24-hour window. Expired tombstones remain seven days." }, "estimatedSeconds": { "type": "integer", "minimum": 1, "description": "Typical provider runtime for the selected model. This is guidance, not a deadline." }, "durationMs": { "type": "integer", "minimum": 0, "description": "Total observed duration once the job is terminal." }, "timing": { "$ref": "#/components/schemas/ImageJobTiming" }, "failure": { "$ref": "#/components/schemas/ImageJobFailure" }, "webhook": { "$ref": "#/components/schemas/ImageJobWebhookDelivery" }, "replayed": { "type": "boolean" }, "operation": { "type": "string", "enum": [ "generate", "edit", "variations", "action" ] }, "actionId": { "type": "string", "pattern": "^action:" }, "actionVersion": { "type": "string" }, "canvasId": { "type": "string", "pattern": "^canvas:" }, "canvasRevision": { "type": "string" }, "canvasUrl": { "type": "string", "format": "uri" }, "canceledAt": { "type": "string", "format": "date-time" }, "cancelReason": { "type": "string", "enum": [ "stale_preparing", "user_requested", "setup_failed" ] }, "targets": { "type": "array", "items": { "type": "string", "pattern": "^node:" } }, "references": { "type": "array", "items": { "type": "string" } }, "images": { "type": "array", "items": { "$ref": "#/components/schemas/ImageJobResultImage" } } }, "additionalProperties": true }, "VideoJob": { "type": "object", "required": [ "id", "rawId", "kind", "operation", "pollUrl", "status", "model", "progress", "estimatedSeconds", "createdAt", "updatedAt" ], "properties": { "id": { "type": "string", "pattern": "^job:" }, "rawId": { "type": "string", "format": "uuid" }, "kind": { "const": "video" }, "operation": { "const": "generate" }, "pollUrl": { "type": "string", "pattern": "^/api/canvas-agent/v1/jobs/" }, "status": { "type": "string", "enum": [ "queued", "running", "succeeded", "failed", "canceled" ] }, "model": { "type": "object", "required": [ "id", "name" ], "properties": { "id": { "type": "string" }, "name": { "type": "string" } }, "additionalProperties": false }, "progress": { "type": "number", "minimum": 0, "maximum": 100 }, "estimatedSeconds": { "type": "integer", "minimum": 1 }, "providerRunId": { "type": "string" }, "failure": { "$ref": "#/components/schemas/VideoJobFailure" }, "video": { "type": "object", "required": [ "downloadUrl" ], "properties": { "downloadUrl": { "type": "string", "pattern": "^/api/canvas-agent/v1/jobs/.+/output$" } }, "additionalProperties": false }, "replayed": { "type": "boolean" }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } }, "additionalProperties": false }, "VideoJobFailure": { "type": "object", "required": [ "code", "message", "retryable" ], "properties": { "code": { "type": "string", "enum": [ "video_generation_failed", "canceled" ] }, "message": { "type": "string" }, "retryable": { "type": "boolean" } }, "additionalProperties": false }, "ImageJobFailure": { "type": "object", "required": [ "code", "message", "retryable" ], "properties": { "code": { "type": "string", "enum": [ "provider_authentication_failed", "provider_timeout", "provider_rate_limited", "provider_rejected", "provider_unavailable", "runtime_failed", "action_input_invalid", "result_expired" ] }, "message": { "type": "string" }, "retryable": { "type": "boolean" }, "providerStatus": { "type": "integer", "minimum": 400, "maximum": 599 } }, "additionalProperties": false }, "ImageJobTiming": { "type": "object", "properties": { "createdAt": { "type": "string", "format": "date-time" }, "queuedAt": { "type": "string", "format": "date-time" }, "startedAt": { "type": "string", "format": "date-time" }, "completedAt": { "type": "string", "format": "date-time" }, "queueDurationMs": { "type": "integer", "minimum": 0 }, "executionDurationMs": { "type": "integer", "minimum": 0 }, "totalDurationMs": { "type": "integer", "minimum": 0 } }, "additionalProperties": false }, "ImageJobWebhookDelivery": { "description": "Durable delivery state. Gavana makes four total attempts. Retryable network failures and 408, 425, 429, or 5xx responses back off for 10 seconds, 60 seconds, then 5 minutes; redirects and other 4xx responses stop delivery.", "type": "object", "required": [ "id", "status", "attempts" ], "properties": { "id": { "type": "string", "pattern": "^webhook:" }, "status": { "type": "string", "enum": [ "pending", "delivering", "delivered", "failed" ] }, "attempts": { "type": "integer", "minimum": 0 }, "nextAttemptAt": { "type": "string", "format": "date-time" }, "lastAttemptAt": { "type": "string", "format": "date-time" }, "deliveredAt": { "type": "string", "format": "date-time" }, "lastStatus": { "type": "integer", "minimum": 100, "maximum": 599 }, "errorCode": { "type": "string", "enum": [ "invalid_destination", "delivery_failed", "redirect_not_allowed", "endpoint_rejected", "secret_unavailable", "finalization_unavailable", "finalization_auth_unavailable", "finalization_auth_expired", "finalization_failed" ] } }, "additionalProperties": false }, "ImageJobResultImage": { "type": "object", "required": [ "assetId", "nodeId", "previewUrl" ], "properties": { "assetId": { "type": "string", "pattern": "^asset:" }, "nodeId": { "type": "string", "pattern": "^node:" }, "mediaType": { "type": "string", "pattern": "^image/" }, "width": { "type": "integer", "minimum": 1 }, "height": { "type": "integer", "minimum": 1 }, "bytes": { "type": "integer", "minimum": 1 }, "previewUrl": { "type": "string", "format": "uri" }, "markdown": { "type": "string" } }, "additionalProperties": false }, "ImageJobWebhookPayload": { "type": "object", "required": [ "id", "run", "status", "targets" ], "properties": { "id": { "type": "string", "pattern": "^(?:run|job):" }, "run": { "type": "string", "pattern": "^run:" }, "kind": { "type": "string", "enum": [ "image", "action" ] }, "pollUrl": { "type": "string", "pattern": "^/api/canvas-agent/v1/runs/" }, "status": { "type": "string", "enum": [ "succeeded", "failed", "canceled", "expired" ] }, "operation": { "type": "string", "enum": [ "generate", "edit", "variations", "action" ] }, "actionId": { "type": "string", "pattern": "^action:" }, "actionVersion": { "type": "string" }, "canvasId": { "type": "string", "pattern": "^canvas:" }, "canvasRevision": { "type": "string" }, "canvasUrl": { "type": "string", "format": "uri" }, "finalizedAt": { "type": "string", "format": "date-time" }, "targets": { "type": "array", "items": { "type": "string", "pattern": "^node:" } }, "model": { "type": "string" }, "estimatedSeconds": { "type": "integer", "minimum": 1 }, "durationMs": { "type": "integer", "minimum": 0 }, "timing": { "$ref": "#/components/schemas/ImageJobTiming" }, "images": { "type": "array", "items": { "$ref": "#/components/schemas/ImageJobResultImage" } }, "warnings": { "type": "array", "items": { "type": "string" } }, "references": { "type": "array", "items": { "type": "string" } }, "referenceNodes": { "type": "array", "items": { "type": "string", "pattern": "^node:" } }, "failure": { "type": "object", "required": [ "code", "retryable" ], "properties": { "code": { "type": "string" }, "retryable": { "type": "boolean" } }, "additionalProperties": false } }, "additionalProperties": false }, "ImageJobWebhookEvent": { "type": "object", "required": [ "id", "type", "apiVersion", "createdAt", "data" ], "properties": { "id": { "type": "string", "pattern": "^event:" }, "type": { "type": "string", "enum": [ "image_job.succeeded", "image_job.failed", "image_job.canceled", "image_job.expired", "image_job.finalization_failed" ] }, "apiVersion": { "type": "string", "const": "v1" }, "createdAt": { "type": "string", "format": "date-time" }, "data": { "type": "object", "required": [ "run", "job" ], "properties": { "run": { "allOf": [ { "$ref": "#/components/schemas/ImageJobWebhookPayload" }, { "properties": { "id": { "pattern": "^run:" } } } ] }, "job": { "allOf": [ { "$ref": "#/components/schemas/ImageJobWebhookPayload" }, { "properties": { "id": { "pattern": "^job:" } } } ] } }, "additionalProperties": false } }, "additionalProperties": false }, "ImageJobInputBase": { "type": "object", "required": [ "canvasId", "baseRevision", "idempotencyKey" ], "properties": { "canvasId": { "type": "string", "description": "A plain id, canvas:, or canvas:: handle." }, "baseRevision": { "type": "string", "minLength": 1, "maxLength": 200 }, "idempotencyKey": { "type": "string", "minLength": 8, "maxLength": 200 }, "targetNodeId": { "type": "string", "pattern": "^(?:node:)?[A-Za-z0-9_-]{1,180}$" }, "targetNodeIds": { "type": "array", "minItems": 1, "maxItems": 4, "uniqueItems": true, "items": { "type": "string", "pattern": "^(?:node:)?[A-Za-z0-9_-]{1,180}$" } }, "prompt": { "type": "string", "minLength": 1, "maxLength": 8000 }, "promptNodeId": { "type": "string", "pattern": "^(?:node:)?[A-Za-z0-9_-]{1,180}$" }, "references": { "type": "array", "description": "Stable image handles. Across references and source, at most 16 handles are allowed and every handle must be unique.", "minItems": 1, "maxItems": 16, "uniqueItems": true, "items": { "type": "string", "pattern": "^(?:node:[A-Za-z0-9_-]{1,180}|asset:(?:[A-Za-z0-9_-]{1,180}:)?[A-Za-z0-9_-]{1,180})$" } }, "source": { "type": "string", "description": "A convenience reference appended to references. It must be unique across both fields, and the combined maximum is 16.", "pattern": "^(?:node:[A-Za-z0-9_-]{1,180}|asset:(?:[A-Za-z0-9_-]{1,180}:)?[A-Za-z0-9_-]{1,180})$" }, "count": { "type": "integer", "description": "Number of outputs. When supplied, it must equal the selected target count; when omitted, Gavana uses the selected target count.", "minimum": 1, "maximum": 4 }, "connectionId": { "$ref": "#/components/schemas/StableId" }, "model": { "type": "string", "maxLength": 650, "description": "A provider model id or opaque model: handle from GET /models." }, "size": { "type": "string", "maxLength": 80 }, "quality": { "type": "string", "maxLength": 80 }, "webhook": { "$ref": "#/components/schemas/ImageJobWebhookInput" } }, "allOf": [ { "if": { "required": [ "references", "source" ] }, "then": { "properties": { "references": { "maxItems": 15 } } } }, { "anyOf": [ { "required": [ "targetNodeId" ], "not": { "required": [ "targetNodeIds" ] }, "anyOf": [ { "not": { "required": [ "count" ] } }, { "properties": { "count": { "const": 1 } } } ] }, { "required": [ "targetNodeIds" ], "properties": { "targetNodeIds": { "minItems": 1, "maxItems": 1 } }, "anyOf": [ { "not": { "required": [ "count" ] } }, { "properties": { "count": { "const": 1 } } } ] }, { "required": [ "targetNodeIds" ], "properties": { "targetNodeIds": { "minItems": 2, "maxItems": 2 } }, "anyOf": [ { "not": { "required": [ "count" ] } }, { "properties": { "count": { "const": 2 } } } ] }, { "required": [ "targetNodeIds" ], "properties": { "targetNodeIds": { "minItems": 3, "maxItems": 3 } }, "anyOf": [ { "not": { "required": [ "count" ] } }, { "properties": { "count": { "const": 3 } } } ] }, { "required": [ "targetNodeIds" ], "properties": { "targetNodeIds": { "minItems": 4, "maxItems": 4 } }, "anyOf": [ { "not": { "required": [ "count" ] } }, { "properties": { "count": { "const": 4 } } } ] } ] } ], "x-craftboard-cross-field-rules": [ "references and source contain at most 16 handles combined", "references and source are unique when combined", "count equals the selected target count" ], "additionalProperties": false }, "VideoGenerationInput": { "type": "object", "required": [ "model", "prompt", "idempotencyKey" ], "properties": { "model": { "type": "string", "minLength": 1, "maxLength": 650, "description": "A provider model id or opaque model: handle from GET /models?capability=video.generate." }, "connectionId": { "$ref": "#/components/schemas/StableId" }, "prompt": { "type": "string", "minLength": 1, "maxLength": 8000 }, "idempotencyKey": { "type": "string", "minLength": 8, "maxLength": 200, "description": "A stable retry key. Reusing it with the same request returns the original job; reusing it with different inputs returns 409." }, "canvasId": { "type": "string", "description": "Required when a frame or reference is a node: handle. Accepts a plain id, canvas:, or canvas::." }, "ownerUid": { "$ref": "#/components/schemas/StableId" }, "aspectRatio": { "type": "string", "maxLength": 80 }, "durationSeconds": { "type": "integer", "minimum": 1, "maximum": 120 }, "resolution": { "type": "string", "maxLength": 80 }, "generateAudio": { "type": "boolean" }, "firstFrame": { "$ref": "#/components/schemas/VideoFrameReference" }, "lastFrame": { "$ref": "#/components/schemas/VideoFrameReference" }, "references": { "type": "array", "maxItems": 9, "uniqueItems": true, "items": { "$ref": "#/components/schemas/VideoFrameReference" } } }, "allOf": [ { "if": { "required": [ "lastFrame" ] }, "then": { "required": [ "firstFrame" ] } } ], "x-craftboard-cross-field-rules": [ "lastFrame requires firstFrame", "node: frame references require canvasId", "connectionId must match the selected model handle when both are supplied" ], "additionalProperties": false }, "VideoFrameReference": { "type": "string", "maxLength": 2048, "pattern": "^(?:node:[A-Za-z0-9_-]{1,180}|asset:(?:[A-Za-z0-9_-]{1,180}:)?[A-Za-z0-9_-]{1,180}|https://.+)$", "description": "A stable image node or asset handle, or a public HTTPS image URL." }, "ImageJobWebhookInput": { "type": "object", "required": [ "url", "secret" ], "properties": { "url": { "type": "string", "format": "uri", "pattern": "^https://", "maxLength": 2048, "description": "A public HTTPS callback endpoint. Private, loopback, local-network, credential-bearing, and fragment-bearing URLs are rejected." }, "secret": { "type": "string", "minLength": 32, "maxLength": 512, "writeOnly": true, "description": "A caller-owned HMAC secret encrypted at rest and never returned by the API." } }, "additionalProperties": false }, "ImageModel": { "type": "object", "required": [ "id", "handle", "modelId", "name", "provider", "providerLabel", "connectionId", "connectionName", "type", "capabilities", "parameters", "estimatedSeconds", "beta" ], "properties": { "id": { "type": "string", "pattern": "^[A-Za-z0-9_-]{8,600}$" }, "handle": { "type": "string", "pattern": "^model:[A-Za-z0-9_-]{8,600}$" }, "modelId": { "type": "string", "minLength": 1, "maxLength": 240 }, "name": { "type": "string" }, "provider": { "type": "string", "enum": [ "craftboard", "openai", "google/nano-banana", "black-forest-labs", "recraft", "ideogram", "qwen", "openrouter" ] }, "providerLabel": { "type": "string" }, "connectionId": { "oneOf": [ { "$ref": "#/components/schemas/StableId" }, { "type": "null" } ] }, "connectionName": { "type": "string" }, "type": { "type": "string", "enum": [ "image", "video" ] }, "capabilities": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/components/schemas/ImageModelCapability" } }, "parameters": { "type": "array", "items": { "$ref": "#/components/schemas/ImageModelParameter" } }, "estimatedSeconds": { "type": "integer", "minimum": 1 }, "beta": { "type": "boolean" } }, "additionalProperties": false }, "ImageModelCapability": { "type": "string", "enum": [ "image.generate", "image.edit", "image.variations", "video.generate", "video.generate.fromImage", "video.generate.fromFrames", "video.generate.fromReferences" ] }, "ImageModelParameter": { "type": "object", "required": [ "name", "label", "description", "type", "required", "capabilities" ], "properties": { "name": { "type": "string" }, "label": { "type": "string" }, "description": { "type": "string" }, "type": { "type": "string", "enum": [ "string", "integer", "number", "boolean", "string[]", "image[]" ] }, "required": { "type": "boolean" }, "default": {}, "min": { "type": "number" }, "max": { "type": "number" }, "options": { "type": "array", "items": { "type": "object", "required": [ "label", "value" ], "properties": { "label": { "type": "string" }, "value": { "type": "string" }, "description": { "type": "string" } }, "additionalProperties": false } }, "capabilities": { "type": "array", "items": { "$ref": "#/components/schemas/ImageModelCapability" } } }, "additionalProperties": false }, "ImageGenerationInput": { "allOf": [ { "$ref": "#/components/schemas/ImageJobInputBase" }, { "anyOf": [ { "required": [ "prompt" ] }, { "required": [ "promptNodeId" ] } ] } ] }, "ImageImportInput": { "type": "object", "required": [ "canvasId", "imageUrl", "idempotencyKey" ], "properties": { "canvasId": { "type": "string", "minLength": 1, "maxLength": 600, "description": "A plain id, canvas:, or canvas:: handle." }, "imageUrl": { "type": "string", "format": "uri", "pattern": "^https://", "maxLength": 4096 }, "sourceId": { "type": "string", "minLength": 1, "maxLength": 1000, "description": "Optional stable source identity, such as ChatGPT file_id. When present, Gavana uses it instead of the expiring download URL to match idempotent retries." }, "title": { "type": "string", "minLength": 1, "maxLength": 160, "default": "Image from ChatGPT" }, "idempotencyKey": { "type": "string", "minLength": 8, "maxLength": 200 }, "x": { "type": "number", "minimum": -100000, "maximum": 100000 }, "y": { "type": "number", "minimum": -100000, "maximum": 100000 } }, "additionalProperties": false }, "ImageImportResponse": { "type": "object", "required": [ "status", "replayed", "canvasId", "canvasRevision", "canvasUrl", "image" ], "properties": { "status": { "const": "succeeded" }, "replayed": { "type": "boolean" }, "canvasId": { "type": "string", "pattern": "^canvas:" }, "canvasRevision": { "type": "string" }, "canvasUrl": { "type": "string", "format": "uri" }, "image": { "type": "object", "required": [ "assetId", "nodeId", "mediaType", "width", "height", "bytes", "previewUrl", "markdown" ], "properties": { "assetId": { "type": "string", "pattern": "^asset:" }, "nodeId": { "type": "string", "pattern": "^node:" }, "mediaType": { "type": "string", "enum": [ "image/png", "image/jpeg", "image/webp", "image/gif" ] }, "width": { "type": "integer", "minimum": 1 }, "height": { "type": "integer", "minimum": 1 }, "bytes": { "type": "integer", "minimum": 1, "maximum": 52428800 }, "previewUrl": { "type": "string", "format": "uri" }, "markdown": { "type": "string" } }, "additionalProperties": false } }, "additionalProperties": false }, "ImageEditInput": { "allOf": [ { "$ref": "#/components/schemas/ImageJobInputBase" }, { "allOf": [ { "anyOf": [ { "required": [ "prompt" ] }, { "required": [ "promptNodeId" ] } ] }, { "anyOf": [ { "required": [ "references" ] }, { "required": [ "source" ] } ] } ] } ] }, "ImageVariationsInput": { "allOf": [ { "$ref": "#/components/schemas/ImageJobInputBase" }, { "anyOf": [ { "required": [ "references" ] }, { "required": [ "source" ] } ] } ] }, "MutationResponse": { "type": "object", "required": [ "canvas" ], "properties": { "canvas": { "$ref": "#/components/schemas/Canvas" }, "replayed": { "type": "boolean" }, "resolvedIds": { "type": "object", "additionalProperties": { "type": "string" } }, "changedNodeIds": { "type": "array", "items": { "type": "string", "pattern": "^node:" } }, "deletedNodeIds": { "type": "array", "items": { "type": "string", "pattern": "^node:" } }, "changedConnectionIds": { "type": "array", "items": { "type": "string", "pattern": "^connection:" } }, "deletedConnectionIds": { "type": "array", "items": { "type": "string", "pattern": "^connection:" } } }, "additionalProperties": true }, "Position": { "type": "object", "required": [ "x", "y" ], "properties": { "x": { "type": "number", "minimum": -10000000, "maximum": 10000000 }, "y": { "type": "number", "minimum": -10000000, "maximum": 10000000 } }, "additionalProperties": false }, "ProviderConnection": { "type": "object", "required": [ "id", "provider", "name", "maskedKey", "models" ], "properties": { "id": { "$ref": "#/components/schemas/StableId" }, "provider": { "type": "string", "enum": [ "openai", "google/nano-banana", "black-forest-labs", "recraft", "ideogram", "qwen", "openrouter" ] }, "name": { "type": "string" }, "maskedKey": { "type": "string" }, "models": { "type": "array", "items": { "type": "string" } } }, "additionalProperties": true }, "Recipe": { "type": "object", "required": [ "id", "handle", "version", "name", "inputs", "outputs" ], "properties": { "id": { "$ref": "#/components/schemas/StableId" }, "handle": { "type": "string", "pattern": "^recipe:" }, "version": { "type": "string" }, "name": { "type": "string" }, "summary": { "type": "string" }, "description": { "type": "string" }, "tags": { "type": "array", "items": { "type": "string" } }, "inputs": { "type": "array", "items": { "$ref": "#/components/schemas/RecipePort" } }, "outputs": { "type": "array", "items": { "$ref": "#/components/schemas/RecipePort" } } }, "additionalProperties": true }, "RecipePort": { "description": "A named typed Recipe boundary port. Written reference ports may deliberately accept either written content or an image reference when the Recipe description declares that intent.", "type": "object", "required": [ "nodeId", "label", "description", "useAsPreset", "nodeType" ], "properties": { "nodeId": { "$ref": "#/components/schemas/StableId" }, "key": { "type": "string", "pattern": "^[A-Za-z0-9_-]{1,80}$", "description": "Optional stable caller-facing key for a high-level workflow input or output." }, "label": { "type": "string" }, "description": { "type": "string" }, "useAsPreset": { "type": "boolean" }, "nodeType": { "type": "string", "enum": [ "image", "text", "sticky" ] } }, "additionalProperties": true }, "RecipeForkInput": { "type": "object", "required": [ "canvasId", "baseRevision", "idempotencyKey" ], "properties": { "canvasId": { "type": "string", "description": "A plain canvas id." }, "ownerUid": { "$ref": "#/components/schemas/StableId" }, "version": { "type": "string", "maxLength": 80 }, "baseRevision": { "type": "string", "minLength": 1, "maxLength": 200 }, "idempotencyKey": { "type": "string", "minLength": 8, "maxLength": 200 }, "x": { "type": "number", "minimum": -100000, "maximum": 100000 }, "y": { "type": "number", "minimum": -100000, "maximum": 100000 } }, "additionalProperties": false }, "RecipeRunInput": { "type": "object", "required": [ "canvasId", "baseRevision", "idempotencyKey" ], "properties": { "canvasId": { "type": "string", "minLength": 1, "maxLength": 560, "description": "Stable canvas: or canvas:: destination." }, "baseRevision": { "type": "string", "minLength": 1, "maxLength": 200 }, "idempotencyKey": { "type": "string", "minLength": 8, "maxLength": 200 }, "version": { "type": "string", "maxLength": 80 }, "instanceNodeId": { "type": "string", "pattern": "^(?:node:)?[A-Za-z0-9_-]{1,180}$", "description": "Optional private Recipe instance already present and connected on the destination canvas." }, "inputs": { "type": "object", "maxProperties": 16, "description": "Typed values keyed by the declared input node id or normalized label. Values may be node:, asset:, or plain text.", "additionalProperties": { "type": "string", "minLength": 1, "maxLength": 8000 } }, "model": { "type": "string", "maxLength": 650, "description": "Optional model handle or provider model override for image outputs." }, "size": { "type": "string", "maxLength": 80, "description": "Optional size override for image outputs." }, "quality": { "type": "string", "maxLength": 80, "description": "Optional quality override for image outputs." }, "webhook": { "$ref": "#/components/schemas/ImageJobWebhookInput" } }, "additionalProperties": false }, "RecipeRunInputBinding": { "type": "object", "required": [ "key", "label", "type", "nodeId", "nodeHandle", "summary" ], "properties": { "key": { "type": "string" }, "label": { "type": "string" }, "type": { "type": "string", "enum": [ "image", "text", "sticky" ] }, "nodeId": { "$ref": "#/components/schemas/StableId" }, "nodeHandle": { "type": "string", "pattern": "^node:" }, "sourceHandle": { "type": "string", "pattern": "^(?:node|asset):" }, "summary": { "type": "string" } }, "additionalProperties": false }, "RecipeRunFailure": { "type": "object", "required": [ "code", "message", "retryable" ], "properties": { "code": { "type": "string", "enum": [ "recipe_input_invalid", "recipe_step_failed", "recipe_output_missing", "recipe_run_canceled", "delegation_revoked" ] }, "message": { "type": "string" }, "retryable": { "type": "boolean" }, "outputKey": { "type": "string" } }, "additionalProperties": false }, "RecipeRunOutput": { "type": "object", "required": [ "key", "label", "type", "status", "nodeId", "nodeHandle" ], "properties": { "key": { "type": "string" }, "label": { "type": "string" }, "type": { "type": "string", "enum": [ "image", "text", "sticky" ] }, "status": { "type": "string", "enum": [ "pending", "running", "succeeded", "failed", "canceled" ] }, "nodeId": { "$ref": "#/components/schemas/StableId" }, "nodeHandle": { "type": "string", "pattern": "^node:" }, "jobId": { "type": "string", "format": "uuid" }, "runHandle": { "type": "string", "pattern": "^run:" }, "assetId": { "type": "string", "pattern": "^asset:" }, "value": { "type": "string", "maxLength": 24000 }, "startedAt": { "type": "string", "format": "date-time" }, "completedAt": { "type": "string", "format": "date-time" }, "failure": { "$ref": "#/components/schemas/RecipeRunFailure" } }, "additionalProperties": false }, "RecipeRun": { "type": "object", "required": [ "schemaVersion", "id", "rawId", "handle", "run", "kind", "operation", "status", "recipeId", "recipeHandle", "recipeVersion", "recipeInstanceNodeId", "recipeInstanceNodeHandle", "canvasId", "canvasHandle", "inputs", "outputs", "targets", "currentStep", "estimatedSeconds", "timing", "pollUrl", "createdAt", "updatedAt" ], "properties": { "schemaVersion": { "const": 1 }, "id": { "type": "string", "pattern": "^recipe-" }, "rawId": { "type": "string", "pattern": "^recipe-" }, "handle": { "type": "string", "pattern": "^run:recipe-" }, "run": { "type": "string", "pattern": "^run:recipe-" }, "kind": { "const": "recipe" }, "operation": { "const": "recipe" }, "status": { "type": "string", "enum": [ "queued", "running", "succeeded", "failed", "canceled" ] }, "recipeId": { "$ref": "#/components/schemas/StableId" }, "recipeHandle": { "type": "string", "pattern": "^recipe:" }, "recipeVersion": { "type": "string" }, "recipeInstanceNodeId": { "$ref": "#/components/schemas/StableId" }, "recipeInstanceNodeHandle": { "type": "string", "pattern": "^node:" }, "canvasId": { "$ref": "#/components/schemas/StableId" }, "canvasHandle": { "type": "string", "pattern": "^canvas:" }, "canvasUrl": { "type": "string", "format": "uri" }, "inputs": { "type": "array", "items": { "$ref": "#/components/schemas/RecipeRunInputBinding" } }, "outputs": { "type": "array", "items": { "$ref": "#/components/schemas/RecipeRunOutput" } }, "targets": { "type": "array", "items": { "type": "string", "pattern": "^node:" } }, "currentStep": { "type": "string" }, "nextStep": { "type": "string" }, "estimatedSeconds": { "type": "integer", "minimum": 1 }, "durationMs": { "type": "integer", "minimum": 0 }, "timing": { "$ref": "#/components/schemas/ImageJobTiming" }, "failure": { "$ref": "#/components/schemas/RecipeRunFailure" }, "webhook": { "$ref": "#/components/schemas/ImageJobWebhookDelivery" }, "replayed": { "type": "boolean" }, "pollUrl": { "type": "string", "pattern": "^/api/canvas-agent/v1/runs/" }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" }, "startedAt": { "type": "string", "format": "date-time" }, "completedAt": { "type": "string", "format": "date-time" }, "canceledAt": { "type": "string", "format": "date-time" } }, "additionalProperties": false }, "Run": { "oneOf": [ { "$ref": "#/components/schemas/ImageJob" }, { "$ref": "#/components/schemas/RecipeRun" } ] }, "RecipeRunWebhookEvent": { "type": "object", "required": [ "id", "type", "apiVersion", "createdAt", "data" ], "properties": { "id": { "type": "string", "pattern": "^event:" }, "type": { "type": "string", "enum": [ "recipe_run.succeeded", "recipe_run.failed", "recipe_run.canceled" ] }, "apiVersion": { "const": "v1" }, "createdAt": { "type": "string", "format": "date-time" }, "data": { "type": "object", "required": [ "run" ], "properties": { "run": { "type": "object", "required": [ "id", "status", "operation", "recipeId", "recipeVersion", "canvasId", "outputs" ], "properties": { "id": { "type": "string", "pattern": "^run:" }, "status": { "type": "string", "enum": [ "succeeded", "failed", "canceled" ] }, "operation": { "const": "recipe" }, "recipeId": { "type": "string", "pattern": "^recipe:" }, "recipeVersion": { "type": "string" }, "canvasId": { "type": "string", "pattern": "^canvas:" }, "outputs": { "type": "array", "items": { "type": "object", "required": [ "key", "status", "nodeId" ], "properties": { "key": { "type": "string" }, "status": { "type": "string", "enum": [ "succeeded", "failed", "canceled" ] }, "nodeId": { "type": "string", "pattern": "^node:" }, "assetId": { "type": "string", "pattern": "^asset:" } }, "additionalProperties": false } }, "failure": { "type": "object", "required": [ "code", "retryable" ], "properties": { "code": { "type": "string" }, "retryable": { "type": "boolean" } }, "additionalProperties": false } }, "additionalProperties": false } }, "additionalProperties": false } }, "additionalProperties": false }, "StableId": { "type": "string", "pattern": "^[A-Za-z0-9_-]{1,180}$" }, "Viewport": { "type": "object", "required": [ "x", "y", "k" ], "properties": { "x": { "type": "number", "minimum": -10000000, "maximum": 10000000 }, "y": { "type": "number", "minimum": -10000000, "maximum": 10000000 }, "k": { "type": "number", "exclusiveMinimum": 0, "maximum": 10 } }, "additionalProperties": false } } } } ```