Assets
Read durable assets and upload raster references.
Base URL: https://app.gavana.ai/api/canvas-agent/v1 · Authentication: HTTP bearer, token format cba_<token-id>.<secret>
Operations
| Operation | Purpose | Scopes |
|---|---|---|
GET /assets | List accessible assets | asset:read |
POST /assets | Upload a durable raster reference | asset:read, image:generate?, video:generate? |
GET /assets/{assetId} | Get an accessible asset | asset:read |
GET /assets/preview | Read a short-lived scoped image preview | none |
POST /product-references/import | Import a product-page gallery as a Product References pack | canvas:read, canvas:write, asset:read |
GET /assets
List accessible assets
Assets are ordered by updatedAt descending, then handle descending.
- Operation id:
listAssets - Scopes: Requires
asset:read. - CLI equivalent:
gavana asset list
Parameters
| Parameter | In | Type | Required | Notes |
|---|---|---|---|---|
canvasId | query | string | No | Optional plain canvas id used to filter or scope the request. Pattern ^[A-Za-z0-9_-]{1,180}$. |
ownerUid | query | string | No | Identifies the owner of a shared canvas or asset. Owner-qualified handles let the CLI supply it automatically. Pattern ^[A-Za-z0-9_-]{1,180}$. |
limit | query | integer | No | Maximum number of items in this page. min 1, max 200. |
cursor | query | string | No | Opaque continuation cursor from page.nextCursor. Reuse it with the same list filters. max length 8192. |
Responses
| Status | Payload | Meaning |
|---|---|---|
200 | object | Accessible durable assets. |
default | ErrorResponse | A stable machine-readable error. The response always includes X-Request-ID. |
200 response body
| Field | Type | Required | Notes |
|---|---|---|---|
assets | array of Asset | Yes | — |
assets[].id | string | Yes | Pattern ^[A-Za-z0-9_-]{1,180}$. |
assets[].handle | string | Yes | Shared assets include their owner: asset:<ownerUid>:<id>. Pattern ^asset:(?:[A-Za-z0-9_-]{1,180}:)?[A-Za-z0-9_-]{1,180}$. |
assets[].ownerUid | string | No | Pattern ^[A-Za-z0-9_-]{1,180}$. |
assets[].kind | string | No | One of image, prompt. |
assets[].name | string | Yes | — |
assets[].mimeType | string | No | — |
assets[].width | integer | No | min 0. |
assets[].height | integer | No | min 0. |
assets[].bytes | integer | No | min 0. |
assets[].previewUrl | string (uri) | No | — |
assets[].previewExpiresInSeconds | integer | No | min 1. |
assets[].node | string | No | Pattern ^node:. |
page | CursorPage | Yes | — |
page.limit | integer | Yes | min 1, max 200. |
page.hasMore | boolean | Yes | — |
page.nextCursor | string | null | Yes | max length 8192. |
Example
curl "https://app.gavana.ai/api/canvas-agent/v1/assets" \
-H "Authorization: Bearer $GAVANA_AGENT_TOKEN"POST /assets
Upload a durable raster reference
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.
- Operation id:
uploadAsset - Scopes: Requires
asset:read. Requires at least one ofimage:generateorvideo:generate. When canvasId query parameter is present, also requirescanvas:read+canvas:write. - CLI equivalent:
gavana asset upload
Parameters
| Parameter | In | Type | Required | Notes |
|---|---|---|---|---|
canvasId | query | string | No | Optional plain canvas id used to filter or scope the request. Pattern ^[A-Za-z0-9_-]{1,180}$. |
ownerUid | query | string | No | Identifies the owner of a shared canvas or asset. Owner-qualified handles let the CLI supply it automatically. Pattern ^[A-Za-z0-9_-]{1,180}$. |
X-Gavana-File-Name | header | string | No | max length 255. |
X-Craftboard-File-Name | header | string | No | Deprecated. Legacy alias for X-Gavana-File-Name. max length 255. |
Request body (application/octet-stream, image/png, image/jpeg, image/webp, image/gif, required)
Responses
| Status | Payload | Meaning |
|---|---|---|
201 | object | A durable asset. |
default | ErrorResponse | A stable machine-readable error. The response always includes X-Request-ID. |
201 response body
| Field | Type | Required | Notes |
|---|---|---|---|
asset | Asset | Yes | — |
asset.id | string | Yes | Pattern ^[A-Za-z0-9_-]{1,180}$. |
asset.handle | string | Yes | Shared assets include their owner: asset:<ownerUid>:<id>. Pattern ^asset:(?:[A-Za-z0-9_-]{1,180}:)?[A-Za-z0-9_-]{1,180}$. |
asset.ownerUid | string | No | Pattern ^[A-Za-z0-9_-]{1,180}$. |
asset.kind | string | No | One of image, prompt. |
asset.name | string | Yes | — |
asset.mimeType | string | No | — |
asset.width | integer | No | min 0. |
asset.height | integer | No | min 0. |
asset.bytes | integer | No | min 0. |
asset.previewUrl | string (uri) | No | — |
asset.previewExpiresInSeconds | integer | No | min 1. |
asset.node | string | No | Pattern ^node:. |
Example
curl -X POST "https://app.gavana.ai/api/canvas-agent/v1/assets" \
-H "Authorization: Bearer $GAVANA_AGENT_TOKEN"GET /assets/{assetId}
Get an accessible asset
For a shared asset, pass the ownerUid encoded in its owner-qualified handle. The CLI does this automatically.
- Operation id:
getAsset - Scopes: Requires
asset:read. - CLI equivalent:
gavana asset get
Parameters
| Parameter | In | Type | Required | Notes |
|---|---|---|---|---|
assetId | path | string | Yes | Pattern ^(?:asset:)?[A-Za-z0-9_-]{1,180}$. |
ownerUid | query | string | No | Identifies the owner of a shared canvas or asset. Owner-qualified handles let the CLI supply it automatically. Pattern ^[A-Za-z0-9_-]{1,180}$. |
Responses
| Status | Payload | Meaning |
|---|---|---|
200 | object | A durable asset. |
default | ErrorResponse | A stable machine-readable error. The response always includes X-Request-ID. |
200 response body
| Field | Type | Required | Notes |
|---|---|---|---|
asset | Asset | Yes | — |
asset.id | string | Yes | Pattern ^[A-Za-z0-9_-]{1,180}$. |
asset.handle | string | Yes | Shared assets include their owner: asset:<ownerUid>:<id>. Pattern ^asset:(?:[A-Za-z0-9_-]{1,180}:)?[A-Za-z0-9_-]{1,180}$. |
asset.ownerUid | string | No | Pattern ^[A-Za-z0-9_-]{1,180}$. |
asset.kind | string | No | One of image, prompt. |
asset.name | string | Yes | — |
asset.mimeType | string | No | — |
asset.width | integer | No | min 0. |
asset.height | integer | No | min 0. |
asset.bytes | integer | No | min 0. |
asset.previewUrl | string (uri) | No | — |
asset.previewExpiresInSeconds | integer | No | min 1. |
asset.node | string | No | Pattern ^node:. |
Example
curl "https://app.gavana.ai/api/canvas-agent/v1/assets/asset:9d3e7c21" \
-H "Authorization: Bearer $GAVANA_AGENT_TOKEN"GET /assets/preview
Read a short-lived scoped image preview
The encrypted preview token is the authorization grant for this endpoint. Agent bearer tokens are not accepted or required.
- Operation id:
previewAsset - Scopes: Requires a valid Agent Access token; no additional product scope.
Parameters
| Parameter | In | Type | Required | Notes |
|---|---|---|---|---|
token | query | string | Yes | min length 1. |
Responses
| Status | Payload | Meaning |
|---|---|---|
200 | image/png | A proxied PNG, JPEG, WebP, or GIF image. |
default | ErrorResponse | A stable machine-readable error. The response always includes X-Request-ID. |
Example
curl "https://app.gavana.ai/api/canvas-agent/v1/assets/preview?token=<token>" \
-H "Authorization: Bearer $GAVANA_AGENT_TOKEN"POST /product-references/import
Import a product-page gallery as a Product References pack
Safely fetches one public HTTPS product page, discovers up to 12 distinct raster gallery images, stores them as private canvas assets and nodes, and creates one semantic Product References Section. An exact variant selector such as colorDisplayCode=08 is never inferred: if page evidence cannot tie the requested selector to gallery images, the response is review_required and creates no pack. Without a selector, pages that expose multiple variant values also return review_required rather than mix them. This operation never invokes an image or video provider.
- Operation id:
importProductReferencePack - Scopes: Requires
canvas:read+canvas:write+asset:read.
Request body (application/json, required)
| Field | Type | Required | Notes |
|---|---|---|---|
canvasId | string | Yes | A plain id, canvas:<id>, or canvas:<ownerUid>:<id> handle. min length 1, max length 600. |
productPageUrl | string (uri) | Yes | max length 4096. Pattern ^https://. |
variantSelector | string | No | Optional exact key=value selector, for example colorDisplayCode=08. Gavana returns review_required instead of inferring a variant. min length 3, max length 300. |
title | string | No | Default "Product References". min length 1, max length 160. |
idempotencyKey | string | Yes | min length 8, max length 200. |
Responses
| Status | Payload | Meaning |
|---|---|---|
200 | ProductReferencePackImportResponse | A durable product-reference pack or an explicit review-required result when an exact requested variant cannot be evidenced. |
default | ErrorResponse | A stable machine-readable error. The response always includes X-Request-ID. |
200 response body
| Field | Type | Required | Notes |
|---|---|---|---|
(variant 1).status | “succeeded” | Yes | — |
(variant 1).replayed | boolean | Yes | — |
(variant 1).canvasId | string | Yes | Pattern ^canvas:. |
(variant 1).canvasRevision | string | Yes | — |
(variant 1).canvasUrl | string (uri) | Yes | — |
(variant 1).page | ProductReferencePage | Yes | — |
(variant 1).page.url | string (uri) | Yes | — |
(variant 1).page.resolvedUrl | string (uri) | Yes | — |
(variant 1).variant | ProductReferenceVariant | Yes | — |
(variant 1).variant.selector | string | No | — |
(variant 1).variant.evidence | string | Yes | One of exact, not_requested, selection_required, unavailable. |
(variant 1).pack | ProductReferencePack | Yes | — |
(variant 1).pack.sectionId | string | Yes | Pattern ^node:. |
(variant 1).pack.title | string | Yes | — |
(variant 1).pack.imageCount | integer | Yes | min 1, max 12. |
(variant 1).images | array of ProductReferencePackImage | Yes | min items 1, max items 12. |
(variant 1).images[].assetId | string | Yes | Pattern ^asset:. |
(variant 1).images[].nodeId | string | Yes | Pattern ^node:. |
(variant 1).images[].mediaType | string | Yes | One of image/png, image/jpeg, image/webp, image/gif. |
(variant 1).images[].width | integer | Yes | min 1. |
(variant 1).images[].height | integer | Yes | min 1. |
(variant 1).images[].bytes | integer | Yes | min 1, max 52428800. |
(variant 1).images[].sourceImageUrl | string (uri) | Yes | — |
(variant 1).images[].previewUrl | string (uri) | Yes | — |
(variant 1).images[].markdown | string | Yes | — |
(variant 1).discovery | ProductReferenceDiscovery | No | — |
(variant 1).discovery.discoveredCandidateCount | integer | Yes | min 0. |
(variant 1).discovery.skippedImageCount | integer | Yes | min 0. |
(variant 1).discovery.limited | boolean | No | Present on an initial successful import when discovery found more than the 12-image pack limit. |
(variant 2).status | “review_required” | Yes | — |
(variant 2).reviewRequired | true | Yes | — |
(variant 2).reason | string | Yes | One of variant_evidence_unavailable, variant_selection_required, no_gallery_images_discovered, no_supported_raster_images. |
(variant 2).canvasId | string | Yes | Pattern ^canvas:. |
(variant 2).page | ProductReferencePage | Yes | — |
(variant 2).page.url | string (uri) | Yes | — |
(variant 2).page.resolvedUrl | string (uri) | Yes | — |
(variant 2).variant | ProductReferenceVariant | Yes | — |
(variant 2).variant.selector | string | No | — |
(variant 2).variant.evidence | string | Yes | One of exact, not_requested, selection_required, unavailable. |
(variant 2).discovery | ProductReferenceDiscovery | Yes | — |
(variant 2).discovery.discoveredCandidateCount | integer | Yes | min 0. |
(variant 2).discovery.skippedImageCount | integer | Yes | min 0. |
(variant 2).discovery.limited | boolean | No | Present on an initial successful import when discovery found more than the 12-image pack limit. |
Example
curl -X POST "https://app.gavana.ai/api/canvas-agent/v1/product-references/import" \
-H "Authorization: Bearer $GAVANA_AGENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"canvasId": "canvas:8f2c1d40-9a77-4c2e-9c11-2b0a5f6d7e31",
"productPageUrl": "https://example.com/gavana-webhook",
"idempotencyKey": "2026-08-04-first-attempt"
}'Errors
Every failure uses the shared error envelope described in Errors and X-Request-ID. The response always carries X-Request-ID; share that value with support instead of the request payload.