{
  "openapi": "3.1.0",
  "info": {"title":"Images API","version":"1.8.0","description":"Images API with separate human/explicit legacy routes and assertion-only machine aliases. Common assertions are rejected on human API routes. No bearer, cookie or raw service credential fallback on machine routes. Shared delegates preserve scope, server-derived system:<client> ownership, quotas, generation pause, idempotency and durable recovery. Catalog reads execute no job/provider/storage operation and never qualify spending. Machine ingress and header stripping require separate provider qualification; this contract does not attest live activation. See docs/service-route-separation.md and docs/scene-layer-set-contract.md."},
  "servers": [{ "url": "/" }],
  "security": [{"bearerAuth":[]},{"bearerAuth":[],"systemWorkloadMode":[]}],
  "paths": {
    "/api/v1/jobs/{jobId}/original": {"get":{"summary":"Read the retained provider original, including after background-processing failure","parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Owned original raster bytes; requires artifacts:read"},"401":{"description":"Identity required"},"403":{"description":"Read scope denied"},"404":{"description":"Not retained, deleted or not owned"}}}},
    "/api/v1/service/jobs/{jobId}/original": {"get":{"summary":"Service-family retained original","security":[{"commonServiceAssertion":[],"systemWorkloadMode":[]},{"bearerAuth":[],"systemWorkloadMode":[]}],"parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Owned original raster bytes; requires artifacts:read and caller resource authorization"},"401":{"description":"Technical identity required"},"403":{"description":"Read or caller policy denied"},"404":{"description":"Not retained, deleted or not owned"}}}},
    "/api/v1/jobs/generate/managed": {"post":{"summary":"Generate from art-only input; Images owns financial admission","parameters":[{"$ref":"#/components/parameters/OwnedIdempotencyKey"}],"requestBody":{"$ref":"#/components/requestBodies/ManagedImageRequest"},"responses":{"202":{"$ref":"#/components/responses/Job"},"400":{"$ref":"#/components/responses/ManagedImageRefusal"},"401":{"description":"Identity absent or invalid"},"403":{"description":"images:generate denied"},"409":{"description":"Changed intent or Images internal policy unavailable; no new provider call"},"415":{"$ref":"#/components/responses/ManagedJsonMediaRefusal"},"429":{"description":"Receiver quota denied"},"503":{"description":"Generation, storage or queue unavailable; preserve uncertain outcome"}}}},
    "/api/v1/jobs/edit/managed": {"post":{"summary":"Edit from art-only input; Images owns financial admission","parameters":[{"$ref":"#/components/parameters/OwnedIdempotencyKey"}],"requestBody":{"$ref":"#/components/requestBodies/ManagedImageRequest"},"responses":{"202":{"$ref":"#/components/responses/Job"},"400":{"$ref":"#/components/responses/ManagedImageRefusal"},"401":{"description":"Identity absent or invalid"},"403":{"description":"images:edit denied"},"409":{"description":"Changed intent or Images internal policy unavailable; no new provider call"},"415":{"$ref":"#/components/responses/ManagedJsonMediaRefusal"},"429":{"description":"Receiver quota denied"},"503":{"description":"Generation, storage or queue unavailable; preserve uncertain outcome"}}}},
    "/api/v1/service/jobs/generate/managed": {"post":{"summary":"Service-family receiver-managed generation","security":[{"commonServiceAssertion":[],"systemWorkloadMode":[]},{"bearerAuth":[],"systemWorkloadMode":[]}],"parameters":[{"$ref":"#/components/parameters/OwnedIdempotencyKey"}],"requestBody":{"$ref":"#/components/requestBodies/ManagedImageRequest"},"responses":{"202":{"$ref":"#/components/responses/Job"},"400":{"$ref":"#/components/responses/ManagedImageRefusal"},"401":{"description":"Technical identity absent or invalid; no human fallback"},"403":{"description":"images:generate denied"},"409":{"description":"Idempotency conflict or Images internal policy unavailable"},"415":{"$ref":"#/components/responses/ManagedJsonMediaRefusal"},"429":{"description":"Receiver quota denied"},"503":{"description":"Dependency unavailable; never automatically retry paid POST"}}}},
    "/api/v1/service/jobs/edit/managed": {"post":{"summary":"Service-family receiver-managed editing","security":[{"commonServiceAssertion":[],"systemWorkloadMode":[]},{"bearerAuth":[],"systemWorkloadMode":[]}],"parameters":[{"$ref":"#/components/parameters/OwnedIdempotencyKey"}],"requestBody":{"$ref":"#/components/requestBodies/ManagedImageRequest"},"responses":{"202":{"$ref":"#/components/responses/Job"},"400":{"$ref":"#/components/responses/ManagedImageRefusal"},"401":{"description":"Technical identity absent or invalid; no human fallback"},"403":{"description":"images:edit denied"},"409":{"description":"Idempotency conflict or Images internal policy unavailable"},"415":{"$ref":"#/components/responses/ManagedJsonMediaRefusal"},"429":{"description":"Receiver quota denied"},"503":{"description":"Dependency unavailable; never automatically retry paid POST"}}}},
    "/api/v1/scene-layer-sets/jobs/managed": {"post":{"summary":"Create coherent layers from art-only intent; Images owns financial admission","parameters":[{"$ref":"#/components/parameters/OwnedIdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SceneLayerSetIntent"}}}},"responses":{"202":{"description":"Existing durable SceneLayerSetJob"},"400":{"description":"Invalid intent, financial/unknown fields or key"},"401":{"description":"Identity absent or invalid"},"403":{"description":"images:edit, jobs:read or artifacts:read denied"},"409":{"description":"Changed intent, unavailable owned input or Images internal policy unavailable"},"429":{"description":"Receiver quota denied"},"503":{"description":"Generation, storage or queue unavailable; preserve uncertain outcome"}}}},
    "/api/v1/service/scene-layer-sets/jobs/managed": {"post":{"summary":"Service-family receiver-managed coherent layers","security":[{"commonServiceAssertion":[],"systemWorkloadMode":[]},{"bearerAuth":[],"systemWorkloadMode":[]}],"parameters":[{"$ref":"#/components/parameters/OwnedIdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SceneLayerSetIntent"}}}},"responses":{"202":{"description":"Existing durable SceneLayerSetJob"},"400":{"description":"Invalid intent, financial/unknown fields or key"},"401":{"description":"Technical identity absent or invalid; no human fallback"},"403":{"description":"images:edit, jobs:read or artifacts:read denied"},"409":{"description":"Changed intent, unavailable owned input or Images internal policy unavailable"},"429":{"description":"Receiver quota denied"},"503":{"description":"Dependency unavailable; never automatically retry paid POST"}}}},
    "/api/v1/jobs/reconciliation": {"get":{"summary":"Observe the original ordinary job by exact owned idempotency key without replay","description":"Dedicated technical workload and jobs:read only; no human/shared credential fallback. One in-memory owner/key lookup; no provider, recovery or job submission. No query or body. Missing/deleted/foreign matches are unavailable, never proof of no charge or permission to resubmit.","security":[{"bearerAuth":[],"systemWorkloadMode":[]}],"parameters":[{"$ref":"#/components/parameters/OwnedIdempotencyKey"}],"responses":{"200":{"description":"Minimal read-only observation; no request, key, prompt, nonce, artifact bytes or charge proof","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageJobReconciliation"}}}},"400":{"description":"Missing, invalid or ambiguous key, query or body"},"401":{"description":"Missing or invalid technical identity"},"403":{"description":"Technical workload/jobs:read required"},"404":{"description":"No available exact owned ordinary job; do not replay"},"503":{"description":"Store/index unavailable or release sealed"}}}},
    "/api/v1/service/jobs/reconciliation": {"get":{"summary":"Same exact owned metadata observation through the existing service identity boundary","description":"Existing Common or qualified Railway service transport, jobs:read and unchanged producer operation restrictions. Same minimal receiver delegate and no-effects semantics as the direct workload route. No credential fallback, bulk query, paid submission or retry permission.","security":[{"commonServiceAssertion":[],"systemWorkloadMode":[]},{"bearerAuth":[],"systemWorkloadMode":[]}],"parameters":[{"$ref":"#/components/parameters/OwnedIdempotencyKey"}],"responses":{"200":{"description":"Minimal read-only observation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageJobReconciliation"}}}},"400":{"description":"Missing, invalid or ambiguous key, query or body"},"401":{"description":"Technical authentication rejected"},"403":{"description":"Scope or existing producer operation denied"},"404":{"description":"No available exact owned ordinary job; do not replay"},"503":{"description":"Identity/store unavailable or release sealed"}}}},
    "/api/v1/scene-layer-sets/cost-admission": {"post":{"summary":"Validate and price one coherent scene layer set without provider execution","description":"Requires images:edit, jobs:read and artifacts:read. The approved master is resolved by owner and SHA-256. Returns an intent-bound ten-minute estimate with operationExecuted:false.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SceneLayerCostAdmissionRequest"}}}},"responses":{"200":{"description":"Bounded cost admission"},"400":{"description":"Invalid layout, approval, layers or masks"},"403":{"description":"Operation scopes denied"},"409":{"description":"Owned approved master unavailable"}}}},
    "/api/v1/scene-layer-sets/jobs": {"post":{"summary":"Queue one persistent idempotent scene layer set operation","description":"Requires a matching cost admission, accepted ceilings and stable Idempotency-Key. Images owns all layer calls and performs no automatic paid retry.","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SceneLayerSetRequest"}}}},"responses":{"202":{"description":"Aggregate scene layer job"},"400":{"description":"Invalid request or key"},"403":{"description":"Operation scopes denied"},"409":{"description":"Cost admission, ownership or idempotency conflict"},"503":{"description":"Provider, queue or persistence unavailable"}}}},
    "/api/v1/scene-layer-sets/jobs/{jobId}": {"get":{"summary":"Read owner-scoped aggregate layer progress","parameters":[{"$ref":"#/components/parameters/JobId"}],"responses":{"200":{"description":"Aggregate job with completed/total counts"},"404":{"description":"Not found for this owner"}}}},
    "/api/v1/scene-layer-sets/jobs/{jobId}/manifest": {"get":{"summary":"Read the verified aligned layer manifest","parameters":[{"$ref":"#/components/parameters/JobId"}],"responses":{"200":{"description":"images.scene-layer-manifest/v1 with per-layer hashes, coverage and provenance"},"404":{"description":"Not completed or not owned"}}}},
    "/api/v1/scene-layer-sets/jobs/{jobId}/bundle": {"get":{"summary":"Download manifest and successful transparent PNG layers","parameters":[{"$ref":"#/components/parameters/JobId"}],"responses":{"200":{"description":"application/vnd.wingoria.scene-layer-set+zip"},"404":{"description":"Not completed or not owned"}}}},
    "/api/v1/scene-layer-sets/jobs/{jobId}/cancel": {"post":{"summary":"Cancel the owner-scoped aggregate operation","description":"Requires jobs:cancel for authenticated workloads. Completed provider calls are retained and are never retried automatically.","parameters":[{"$ref":"#/components/parameters/JobId"}],"responses":{"200":{"description":"Cancelled aggregate job"},"403":{"description":"Cancel permission denied"},"404":{"description":"Not found for this owner"}}}},
    "/api/v1/scene-layer-sets/jobs/{jobId}/layers/{layer}": {"get":{"summary":"Download one verified transparent PNG layer","parameters":[{"$ref":"#/components/parameters/JobId"},{"name":"layer","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z][a-z0-9-]{0,31}$"}}],"responses":{"200":{"description":"Aligned image/png with manifest SHA-256"},"400":{"description":"Invalid layer name"},"404":{"description":"Layer, job or owner not found"}}}},
    "/api/v1/service/scene-layer-sets/cost-admission": {"post":{"summary":"Common v2 machine alias for scene layer cost admission","security":[{"commonServiceAssertion":[]}],"responses":{"200":{"description":"Bounded non-executing admission"},"401":{"description":"Invalid service identity"},"403":{"description":"Operation not granted"}}}},
    "/api/v1/service/scene-layer-sets/jobs": {"post":{"summary":"Common v2 machine alias for one aggregate layer operation","security":[{"commonServiceAssertion":[]}],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"responses":{"202":{"description":"Persistent aggregate job"},"403":{"description":"Operation not granted"},"409":{"description":"Admission or idempotency conflict"}}}},
    "/api/v1/styles": {"get":{"summary":"Read the shared Images style catalog","description":"Requires the explicit styles:read scope. Legacy-opaque workloads use their existing bearer plus X-Images-Workload: system-assets-v1. Returns built-ins plus server-persisted custom styles. No job or provider operation. Cache-Control: no-store.","security":[{"bearerAuth":[],"systemWorkloadMode":[]}],"responses":{"200":{"description":"Versioned shared style catalog","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageStyleCatalog"}}}},"401":{"description":"Missing or invalid technical identity"},"403":{"description":"styles:read is not granted"},"503":{"description":"Shared style storage unavailable"}}}},
    "/api/v1/service/styles": {"get":{"summary":"Read the shared Images style catalog through Common v2","description":"Requires a registered Common v2 service identity with styles:read. Returns built-ins plus server-persisted custom styles. No bearer/cookie fallback and no job/provider operation. Cache-Control: no-store.","security":[{"commonServiceAssertion":[]}],"responses":{"200":{"description":"Versioned shared style catalog","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageStyleCatalog"}}}},"401":{"description":"Missing, invalid or mixed service identity"},"403":{"description":"Producer or styles:read scope not authorized"},"503":{"description":"Signing keys or shared style storage unavailable"}}}},
    "/api/v1/guides": {"get":{"summary":"Read the shared Images production-guide catalog","description":"Requires styles:read. Returns built-in and server-persisted guides; performs no job or provider operation.","security":[{"bearerAuth":[],"systemWorkloadMode":[]}],"responses":{"200":{"description":"Versioned guide catalog","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageGuideCatalog"}}}},"401":{"description":"Missing or invalid technical identity"},"403":{"description":"styles:read is not granted"},"503":{"description":"Shared guide storage unavailable"}}}},
    "/api/v1/service/guides": {"get":{"summary":"Read the shared Images production-guide catalog through Common v2","description":"Requires a registered Common v2 service identity with styles:read. Performs no job or provider operation.","security":[{"commonServiceAssertion":[]}],"responses":{"200":{"description":"Versioned guide catalog","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageGuideCatalog"}}}},"401":{"description":"Missing, invalid or mixed service identity"},"403":{"description":"Producer or styles:read scope not authorized"},"503":{"description":"Shared guide storage unavailable"}}}},
    "/api/v1/style-library": {"get":{"summary":"Read the shared editable style library","description":"Personal Wingoria session with jobs:read. Returns server-persisted custom styles, folders and assignments with X-Style-Library-Version for conditional saves.","responses":{"200":{"description":"Shared editable library","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SharedStyleLibrary"}}}},"401":{"description":"Sign in required"},"403":{"description":"Personal read permission required"},"503":{"description":"Shared style storage unavailable"}}},"put":{"summary":"Save the shared editable style library","description":"Personal Wingoria session with images:edit and exact If-Match revision. Writes one bounded document to durable Images storage; ambiguous failures are never retried automatically.","parameters":[{"name":"If-Match","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SharedStyleLibrary"}}}},"responses":{"200":{"description":"Saved with the next X-Style-Library-Version"},"400":{"description":"Invalid library"},"401":{"description":"Sign in required"},"403":{"description":"Personal edit permission required"},"409":{"description":"Concurrent edit; reload before saving"},"428":{"description":"If-Match required"},"503":{"description":"Shared style storage unavailable or write outcome uncertain"}}}},
    "/api/v1/ui-themes/session": {"get":{"summary":"Identify the authenticated browser theme-batch recovery namespace","description":"Read-only. Namespace is derived from the verified owner and optional operator actor. Requires jobs read permission; does not authorize a generation or expose other owners. Cache-Control: no-store.","responses":{"200":{"description":"Stable owner-scoped browser cache namespace","content":{"application/json":{"schema":{"type":"object","properties":{"cacheNamespace":{"type":"string","pattern":"^[a-f0-9]{64}$"},"operationExecuted":{"const":false}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Scope denied"}}}},
    "/api/v1/art-bible/{style}/reference-preview": {"parameters":[{"name":"style","in":"path","required":true,"schema":{"type":"string"}}],"post":{"summary":"Preview a public reference image before saving it","description":"Images operator edit permission required. JSON url accepts a public HTTPS PNG/JPEG/WebP link or Met collection page. Credential-free, public-address-pinned downloads, checked redirects, 20 MiB maximum, 25 second deadline. Returns dataUrl and source metadata without saving. The client reviews the preview, samples colors, and saves through the existing versioned curation PUT.","responses":{"200":{"description":"Image preview and source metadata"},"400":{"description":"Unsupported or unavailable public image"},"403":{"description":"Operator permission required"},"429":{"description":"Image download capacity reached"}}}},
    "/api/v1/3d/workflow/plans/{id}/break-apart": {"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"summary":"Analyze the approved front pose and automatically generate separate component images","description":"Requires images:edit and existing read/artifact permissions, Idempotency-Key, revision, provider and confirmImagesCost:true. One visual analysis plus up to 12 image edits. Replays never resubmit paid work.","responses":{"200":{"description":"Updated preparation"},"409":{"description":"Reference or revision conflict"}}}},
    "/api/v1/3d/workflow/plans/{id}/approve-parts": {"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"summary":"Approve all completed component front references","description":"Requires images:edit, Idempotency-Key and revision. All parts must have completed GPT image edits. No provider call.","responses":{"200":{"description":"Updated preparation"},"409":{"description":"Reference or revision conflict"}}}},
    "/api/v1/3d/workflow/plans/{id}/reference-pack": {"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"summary":"Download approved component PNGs and their manifest in one private ZIP","description":"Requires artifact/read permissions. All parts must be approved. Exact immutable PNGs, bounded to 128 MiB of image content. Each PNG is a separate Tripo input.","responses":{"200":{"description":"Private ZIP with PNGs and manifest"},"409":{"description":"Reference or revision conflict"}}}},
    "/api/v1/3d/workflow/capabilities": {"get":{"summary":"3D workflow gates, GPT providers and API v3 model limits","responses":{"200":{"description":"Private configuration state, never credentials; not a live account qualification"}}}},
    "/api/v1/3d/workflow/plans": {"get":{"summary":"List this owner's preparation plans","responses":{"200":{"description":"Owner-scoped plan array"}}},"post":{"summary":"Create a plan from an authorized Gallery image","description":"Requires images:edit, jobs:read, artifacts:read and Idempotency-Key. JSON sourceImageJobId,subject. Whole-subject reference first, followed by visual Break apart analysis. See docs/3d-parts-workflow.md.","responses":{"200":{"description":"Plan or replay"},"404":{"description":"Source unavailable"}}}},
    "/api/v1/3d/workflow/plans/{id}": {"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"summary":"Read an owned plan","responses":{"200":{"description":"Plan with revision and references"},"404":{"description":"Plan unavailable"}}},"put":{"summary":"Edit a component manifest","description":"Idempotency-Key and current revision required; JSON revision,subject,parts[{id,name,instructions,faceLimit}]. Changed subject/components invalidate references.","responses":{"200":{"description":"Updated plan"},"409":{"description":"Revision or idempotency conflict"}}}},
    "/api/v1/3d/workflow/plans/{id}/images": {"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"summary":"Queue a separately confirmed Images Edit reference","description":"JSON revision,partId,view(front/left/back/right),provider,confirmImagesCost:true,pose(t/a; default t). Requires edit/read/artifact scopes and Idempotency-Key. Parts require an approved whole front; side views require an approved part front. This operation can incur Images provider charges.","responses":{"200":{"description":"Plan containing the Images edit job ID"},"409":{"description":"Reference prerequisite, revision or idempotency conflict"}}}},
    "/api/v1/3d/workflow/plans/{id}/approve": {"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"summary":"Approve a completed Images Edit reference as immutable PNG input","description":"JSON revision,partId,view,approve. Requires Idempotency-Key and edit/read/artifact scopes. No Tripo call.","responses":{"200":{"description":"Plan with immutable preparation ID and SHA-256"},"409":{"description":"Reference not ready or revision conflict"}}}},
    "/api/v1/3d/workflow/plans/{id}/generate": {"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"summary":"Admit a durable batch from approved references","description":"Requires generate/read/artifact scopes, Idempotency-Key, current revision and confirmPaid:true. JSON workflow(lowPoly/editableParts/creatureAssembly),parameters(model,faceLimit,texture,pbr,exportUv,seed,imageAutofix,orientation,generateParts,quad,smartLowPoly,textureQuality,textureVersion,delight,textureAlignment,textureSeed,geometryQuality,autoSize,compress),multiview. P1 faces 50–20000; P2 triangles 48–50000/quads 48–25000; H smart low-poly triangles 500–20000/quads 500–10000. H standard up to 1500000 triangles (Ultra 2000000), quads 150000. Editable parts requires H and no textures/PBR/quad/smart low-poly. Quad FBX artifacts are downloaded for Blender; GLB retains the browser viewer. Assembly creates one image-to-model job per component. See docs/3d-parts-workflow.md.","responses":{"202":{"description":"Durably queued batch"},"200":{"description":"Same-key replay"},"400":{"description":"Invalid or incompatible parameters"},"409":{"description":"Unapproved reference or revision conflict"},"429":{"description":"Queue or storage capacity"},"503":{"description":"Provider disabled or unconfigured"}}}},
    "/api/v1/3d/workflow/batches": {"get":{"summary":"List owned generation batches","parameters":[{"name":"planId","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Batch array with separate child jobs"}}}},
    "/api/v1/3d/workflow/batches/{id}": {"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"summary":"Read an owned generation batch","responses":{"200":{"description":"Per-part jobs and statuses"},"404":{"description":"Batch unavailable"}}}},
    "/api/v1/3d/workflow/batches/{id}/assembly": {"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"summary":"Export part lineage and verified artifacts for assembly","responses":{"200":{"description":"images.3d-assembly/v1; alignment and rigging still required"},"404":{"description":"Batch unavailable"}}}},
    "/api/v1/3d/workflow/jobs/{id}/segment": {"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"summary":"Queue separate paid mesh segmentation for an owned completed task","description":"Idempotency-Key and confirmPaid:true required. Server uses the durable original Tripo task ID with API v3 mesh/segment and model v1.0-20250506.","responses":{"202":{"description":"Queued segmentation job"},"200":{"description":"Same-key replay"},"404":{"description":"Owned completed task unavailable"}}}},
    "/api/v1/3d/library/tripo/prepare": {"post":{"summary":"Prepare an owned completed Tripo GLB as a texture-free static prop","description":"Fresh administrator plus edit/read/artifact permissions. JSON jobId and confirmTextureRemoval:true. No provider calls or persistent writes. Up to 32 MiB original; prepared GLB up to 8 MiB. Returns jobId,sourceSha256,glbBase64,artifact,rig,bounds. Unsupported geometry is rejected.","responses":{"200":{"description":"Transient locally prepared GLB and integrity metadata"},"400":{"description":"Missing confirmation or unsupported geometry"},"403":{"description":"Fresh administrator required"},"404":{"description":"Completed source not found for this owner"},"413":{"description":"Request or source too large"},"429":{"description":"Another preparation is running"}}}},
    "/api/v1/3d/library/tripo/import": {"post":{"summary":"Import a reviewed Tripo static prop with account-specific rights evidence","description":"Fresh administrator plus edit/read/artifact permissions. JSON jobId,preparedSha256,externalId,title,description,category,clusters,tags,author,licenseUrl,licenseEvidence,confirmPreparedModel:true,confirmRights:true. Reprepares the owned original and compares its hash. Forces prop kind and LicenseRef-Tripo-API-Terms, records source job and both hashes. No provider calls. See docs/library-3d.md.","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9._:-]{8,128}$"}}],"responses":{"200":{"description":"Imported or identical existing asset"},"400":{"description":"Missing review, rights evidence or invalid metadata"},"403":{"description":"Fresh administrator required"},"404":{"description":"Completed source not found for this owner"},"409":{"description":"Prepared hash, immutable asset or idempotency conflict"},"429":{"description":"Preparation busy or library full"}}}},
    "/api/v1/3d/library/capabilities": { "get": { "summary": "Private Library 3D availability and fresh administrator import permission", "responses": { "200": { "description": "enabled, canImport, maximumAssetBytes (8 MiB), maximumAnimations (128)" }, "401": { "description": "Images authentication required" }, "403": { "description": "Read permissions required" } } } },
    "/api/v1/3d/library": { "get": { "summary": "Search this Images owner's private model catalog", "description": "q matches all words in names, tags, clusters, author and license. category, cluster and kind combine with q. offset defaults to 0 and limit to 24 (maximum 100). Returns items,total,offset,limit and owner-only facets with string arrays categories,clusters,kinds. See docs/library-3d.md.", "responses": { "200": { "description": "Private catalog page with source/license evidence, derived rig, animations and bounds, and local GLB integrity receipt" }, "400": { "description": "Invalid search bounds" }, "401": { "description": "Authentication required" }, "403": { "description": "Insufficient permissions" } } } },
    "/api/v1/3d/library/{id}": { "get": { "summary": "Read an owner-scoped Library 3D asset", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^asset_[a-f0-9]{32}$"}}], "responses": { "200": { "description": "Asset metadata; no provider credentials or internal owner identity" }, "404": { "description": "Not found for this owner" } } } },
    "/api/v1/3d/library/{id}/artifact": { "get": { "summary": "Download a verified private library GLB", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^asset_[a-f0-9]{32}$"}}], "responses": { "200": { "description": "model/gltf-binary with X-Artifact-Sha256, no-store" }, "404": { "description": "Not found for this owner" }, "503": { "description": "Integrity or storage failure" } } } },
    "/api/v1/3d/library/import": { "post": { "summary": "Idempotent administrator import of one licensed, untextured GLB", "description": "Requires a fresh server-resolved Images administrator grant plus images:edit, jobs:read and artifacts:read. Workload identities and legacy keys cannot import. JSON schemaVersion images.3d-library.import/v1, externalId,title,description,kind (prop/character/animal/environment),category,clusters,tags,source (url,author,licenseId,licenseUrl,licenseEvidence,optional licenseEvidenceUrl),glbBase64. GLB maximum 8 MiB. Character/animal require their own rig and compatible embedded clips. Metadata is derived and stored atomically on the existing private volume. No provider calls.", "parameters": [{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9._:-]{8,128}$"}}], "responses": { "200": { "description": "Imported asset or identical existing asset" }, "400": { "description": "Invalid manifest, provenance or GLB" }, "401": { "description": "Authentication required" }, "403": { "description": "Fresh administrator permission required" }, "409": { "description": "Idempotency or immutable external-ID conflict" }, "413": { "description": "Body exceeds 12 MiB" }, "429": { "description": "Catalog capacity reached" }, "503": { "description": "Storage unavailable" } } } },
    "/api/v1/3d/capabilities": { "get": { "summary": "3D preparation and paid-generation gates; server-managed Tripo configuration state only", "responses": { "200": { "description": "images.3d.v1, pinned model, preparationEnabled, generationEnabled, credentialConfigured and non-secret locator. No live balance/key validation is performed." }, "401": { "description": "Authentication required" }, "403": { "description": "Image job/artifact read scopes required" } } } },
    "/api/v1/3d/preparations": { "post": { "summary": "Free deterministic subject isolation from an authorized Gallery/Reference Library image", "description": "Requires images:edit, jobs:read, artifacts:read. JSON sourceImageJobId and outline array of normalized {x,y} points (3–256). PNG/JPEG up to 20 MiB, 4096 pixels per side; crop extents at least 256 pixels. Returns a private prepared 1024-square PNG. No provider call.", "parameters": [{ "name": "Idempotency-Key", "in": "header", "required": true, "schema": { "type": "string", "pattern": "^[A-Za-z0-9._:-]{8,128}$" } }], "responses": { "201": { "description": "Prepared Images 3D job" }, "200": { "description": "Same-key replay" }, "400": { "description": "Invalid source or outline" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "Source not found for this owner" }, "409": { "description": "Idempotency conflict" }, "429": { "description": "Quota or capacity exceeded" }, "503": { "description": "Preparation/storage unavailable" } } } },
    "/api/v1/3d/jobs": { "get": { "summary": "List owner-authorized 3D jobs and preparations", "responses": { "200": { "description": "Job array: id, mode, status, progress, timestamps, errorCode, local artifact contentType/byteLength/sha256, optional consumed credits. Optional providerTaskId for owner reconciliation; no provider URLs or keys." } } }, "post": { "summary": "Submit one explicitly authorized paid Tripo generation", "description": "Requires images:generate, jobs:read, artifacts:read. JSON mode=textTo3D with prompt (1–1024 chars) OR mode=imageTo3D with preparationId; confirmPaid must be true. Both server feature gates, private key and persistent local volume are required. Same-key replays never create another paid task. Statuses: queued, submitting, running, succeeded, failed, cancelled, outcomeUnknown; preparation status is prepared. outcomeUnknown requires provider reconciliation.", "parameters": [{ "name": "Idempotency-Key", "in": "header", "required": true, "schema": { "type": "string", "pattern": "^[A-Za-z0-9._:-]{8,128}$" } }], "responses": { "202": { "description": "Queued Images 3D job" }, "200": { "description": "Same-key replay" }, "400": { "description": "Invalid request or missing paid confirmation" }, "403": { "description": "Insufficient permissions" }, "409": { "description": "Idempotency conflict" }, "429": { "description": "Quota or queue full" }, "503": { "description": "Disabled, unconfigured or storage unavailable" } } } },
    "/api/v1/3d/jobs/{id}": { "get": { "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string", "pattern": "^model_[a-f0-9]{32}$" } }], "responses": { "200": { "description": "Owner-authorized Images 3D job" }, "404": { "description": "Not found for this owner" } } } },
    "/api/v1/3d/jobs/{id}/artifact": { "get": { "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string", "pattern": "^model_[a-f0-9]{32}$" } }], "responses": { "200": { "description": "Private prepared PNG or verified GLB; requires artifacts:read, includes X-Artifact-Sha256", "content": { "image/png": { "schema": { "type": "string", "format": "binary" } }, "model/gltf-binary": { "schema": { "type": "string", "format": "binary" } } } }, "404": { "description": "Not found for this owner or artifact not ready" } } } },
    "/api/v1/service/jobs/generate": {"post":{"summary":"Queue image generation","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Mandatory for system-assets-v1 creation and retry; optional only for compatibility identities. Stable per intended attempt, including uncertain transport replay. Same producer/key with different normalized request, operation or retry source returns 409.","schema":{"type":"string","minLength":8,"maxLength":128}}],"requestBody":{"$ref":"#/components/requestBodies/ImageRequest"},"responses":{"202":{"description":"Image job","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageJob"}}},"headers":{"Location":{"description":"Relative machine-family job URL, also on idempotent replay and retry","schema":{"type":"string","pattern":"^/api/v1/service/jobs/job_[0-9a-f]{32}$"}}}},"400":{"description":"Invalid request or missing required workload key"},"401":{"description":"Missing, invalid or mixed service identity; no human fallback"},"403":{"description":"Common caller or operation scope denied"},"409":{"description":"Idempotency conflict"},"422":{"description":"Provider or option unavailable"},"429":{"description":"HTTP or retained-record admission limit"},"503":{"description":"Signing keys unavailable, generation paused or storage unavailable"}},"security":[{"commonServiceAssertion":[]}]}},
    "/api/v1/service/jobs/edit": {"post":{"summary":"Queue reference-based editing","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Mandatory for system-assets-v1 creation and retry; optional only for compatibility identities. Stable per intended attempt, including uncertain transport replay. Same producer/key with different normalized request, operation or retry source returns 409.","schema":{"type":"string","minLength":8,"maxLength":128}}],"requestBody":{"$ref":"#/components/requestBodies/ImageEditRequest"},"responses":{"202":{"description":"Image job","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageJob"}}},"headers":{"Location":{"description":"Relative machine-family job URL, also on idempotent replay and retry","schema":{"type":"string","pattern":"^/api/v1/service/jobs/job_[0-9a-f]{32}$"}}}},"400":{"description":"Invalid request or missing required workload key"},"401":{"description":"Missing, invalid or mixed service identity; no human fallback"},"403":{"description":"Common caller or operation scope denied"},"409":{"description":"Idempotency conflict"},"422":{"description":"Provider or option unavailable"},"429":{"description":"HTTP or retained-record admission limit"},"503":{"description":"Signing keys unavailable, generation paused or storage unavailable"}},"security":[{"commonServiceAssertion":[]}]}},
    "/api/v1/service/jobs": {"get":{"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}},{"name":"status","in":"query","schema":{"enum":["queued","running","succeeded","failed","cancelled"]}},{"name":"provider","in":"query","schema":{"type":"string","maxLength":100}},{"name":"operation","in":"query","schema":{"enum":["generate","edit"]}},{"name":"search","in":"query","schema":{"type":"string","maxLength":200},"description":"Matches ID, provider or model, not prompt text"},{"name":"from","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"until","in":"query","schema":{"type":"string","format":"date-time"},"description":"Exclusive upper date bound"},{"name":"workspace","in":"query","schema":{"enum":["images","spine","ui","spritesheets","patina"]},"description":"Optional gallery category, filtered before counts and pagination. Does not grant access to another owner. Omit to retain all authorized jobs."}],"responses":{"200":{"description":"Client-isolated jobs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ImageJob"}}}},"headers":{"X-Total-Count":{"description":"Authorized filtered total before pagination","schema":{"type":"integer","minimum":0}}}},"400":{"description":"Invalid filters or pagination"},"401":{"description":"Missing, invalid or mixed service identity; no human fallback"},"403":{"description":"Common caller or operation scope denied"},"503":{"description":"Signing keys unavailable, generation paused or storage unavailable"}},"summary":"Browse authorized retained jobs with filters and pagination","security":[{"commonServiceAssertion":[]}]},"post":{"summary":"Queue image generation","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Mandatory for system-assets-v1 creation and retry; optional only for compatibility identities. Stable per intended attempt, including uncertain transport replay. Same producer/key with different normalized request, operation or retry source returns 409.","schema":{"type":"string","minLength":8,"maxLength":128}}],"requestBody":{"$ref":"#/components/requestBodies/ImageRequest"},"responses":{"202":{"description":"Image job","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageJob"}}},"headers":{"Location":{"description":"Relative machine-family job URL, also on idempotent replay and retry","schema":{"type":"string","pattern":"^/api/v1/service/jobs/job_[0-9a-f]{32}$"}}}},"400":{"description":"Invalid request or missing required workload key"},"401":{"description":"Missing, invalid or mixed service identity; no human fallback"},"403":{"description":"Common caller or operation scope denied"},"409":{"description":"Idempotency conflict"},"422":{"description":"Provider or option unavailable"},"429":{"description":"HTTP or retained-record admission limit"},"503":{"description":"Signing keys unavailable, generation paused or storage unavailable"}},"security":[{"commonServiceAssertion":[]}]}},
    "/api/v1/service/jobs/{jobId}": {"get":{"parameters":[{"$ref":"#/components/parameters/JobId"}],"responses":{"200":{"$ref":"#/components/responses/Job"},"401":{"description":"Missing, invalid or mixed service identity; no human fallback"},"403":{"description":"Common caller or operation scope denied"},"404":{"description":"Not found"},"503":{"description":"Signing keys unavailable, generation paused or storage unavailable"}},"security":[{"commonServiceAssertion":[]}]}},
    "/api/v1/service/jobs/{jobId}/artifact": {"get":{"parameters":[{"$ref":"#/components/parameters/JobId"}],"responses":{"200":{"description":"Generated image"},"401":{"description":"Missing, invalid or mixed service identity; no human fallback"},"403":{"description":"Common caller or operation scope denied"},"404":{"description":"Not found"},"503":{"description":"Signing keys unavailable, generation paused or storage unavailable"}},"security":[{"commonServiceAssertion":[]}]}},
    "/api/v1/service/jobs/{jobId}/cancel": {"post":{"parameters":[{"$ref":"#/components/parameters/JobId"}],"responses":{"200":{"$ref":"#/components/responses/Job"},"401":{"description":"Missing, invalid or mixed service identity; no human fallback"},"403":{"description":"Common caller or operation scope denied"},"404":{"description":"Not found"},"503":{"description":"Signing keys unavailable, generation paused or storage unavailable"}},"security":[{"commonServiceAssertion":[]}]}},
    "/api/v1/service/jobs/{jobId}/retry": {"post":{"summary":"Create a new job from a terminal job's retained request","parameters":[{"$ref":"#/components/parameters/JobId"},{"name":"Idempotency-Key","in":"header","required":true,"description":"Mandatory for system-assets-v1 creation and retry; optional only for compatibility identities. Stable per intended attempt, including uncertain transport replay. Same producer/key with different normalized request, operation or retry source returns 409.","schema":{"type":"string","minLength":8,"maxLength":128}}],"responses":{"202":{"description":"Image job","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageJob"}}},"headers":{"Location":{"description":"Relative machine-family job URL, also on idempotent replay and retry","schema":{"type":"string","pattern":"^/api/v1/service/jobs/job_[0-9a-f]{32}$"}}}},"400":{"description":"Invalid or missing required workload key"},"401":{"description":"Missing, invalid or mixed service identity; no human fallback"},"403":{"description":"Common caller or operation scope denied"},"404":{"description":"Not found"},"409":{"description":"Idempotency/source conflict, nonterminal source or unavailable request"},"429":{"description":"HTTP or retained-record admission limit"},"503":{"description":"Signing keys unavailable, generation paused or storage unavailable"}},"security":[{"commonServiceAssertion":[]}]}},
    "/api/v1/admission": {"get":{"summary":"Check the existing private Railway Spines bridge","description":"Authenticates the existing legacy Spines bearer and jobs:read permission without storage, quota, provider I/O or generation. Requires one UUID X-Correlation-ID and echoes it unchanged. This route is separate from Cloudflare Common v2.","parameters":[{"name":"X-Correlation-ID","in":"header","required":true,"schema":{"type":"string","format":"uuid"}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Private Railway bridge admitted; no operation executed"},"400":{"description":"Missing, duplicate or invalid correlation identifier"},"401":{"description":"Missing or invalid bearer"},"403":{"description":"Caller is not Spines or lacks jobs:read"}}}},
    "/api/v1/service/workloads/admission": {"get":{"summary":"Check registered workload admission without job or artifact I/O","description":"Assertion-only common-v2 admission; requires jobs:read. No bearer, cookie or raw service credentials. The qualified edge must strip client credentials and replace untrusted assertion headers. Optional workload selector is system-assets-v1. No quota, storage or provider operation; generationBudgetQualified=false. Not proof of a successful job.","security":[{"commonServiceAssertion":[]}],"responses":{"200":{"description":"Protected owner, scopes, effective request/job limits and generation switch; no credential values","content":{"application/json":{"schema":{"type":"object","required":["contract","admitted","authentication","owner","scopes","limits","generationEnabled","generationBudgetQualified","operationExecuted"],"properties":{"contract":{"const":"system-assets-v1"},"admitted":{"const":true},"authentication":{"enum":["cloudflare-common-v2"]},"owner":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"limits":{"type":"object"},"generationEnabled":{"type":"boolean"},"generationBudgetQualified":{"const":false},"operationExecuted":{"const":false}}}}}},"401":{"description":"Missing, invalid or mixed technical credentials"},"403":{"description":"Producer or scope not authorized"},"503":{"description":"Signing keys unavailable"}}}},
    "/api/v1/workloads/admission": {"get":{"summary":"Check registered workload admission without job or artifact I/O","description":"Compatibility admission only for an explicitly configured legacy-opaque producer. Requires its bearer and system-assets-v1 selector. Common assertions are rejected; use /api/v1/service/workloads/admission for common-v2. No quota/storage/provider operation or spending authorization.","security":[{"bearerAuth":[],"systemWorkloadMode":[]}],"responses":{"200":{"description":"Protected owner, scopes, effective request/job limits and generation switch; no credential values","content":{"application/json":{"schema":{"type":"object","required":["contract","admitted","authentication","owner","scopes","limits","generationEnabled","generationBudgetQualified","operationExecuted"],"properties":{"contract":{"const":"system-assets-v1"},"admitted":{"const":true},"authentication":{"enum":["legacy-opaque"]},"owner":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"limits":{"type":"object"},"generationEnabled":{"type":"boolean"},"generationBudgetQualified":{"const":false},"operationExecuted":{"const":false}}}}}},"401":{"description":"Missing, invalid or mixed technical credentials"},"403":{"description":"Producer or scope not authorized"},"503":{"description":"Signing keys unavailable"}}}},
    "/api/v1/art-bible/{style}": {
      "parameters": [{"name":"style","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z0-9-]{1,60}$"},"description":"ID registered in art-bible/styles.json"}],
      "get": {"summary":"Read private shared Art Bible curation","description":"Requires a fresh personal Images operator grant and jobs:read. Returns version, items, folders, clusters, references and palette. Reference data URLs remain private. Public artwork remains available separately.","responses":{"200":{"description":"Curation JSON; send X-Art-Bible-Version unchanged in If-Match for the next write","headers":{"ETag":{"schema":{"type":"string"}},"X-Art-Bible-Version":{"description":"Exact storage revision; do not use a proxy-weakened HTTP ETag as the write token","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Sign in required"},"403":{"description":"Personal operator grant required"},"404":{"description":"Unknown style"},"503":{"description":"Private R2 storage unavailable"}}},
      "put": {"summary":"Save shared Art Bible curation atomically","description":"Requires a personal Images operator grant and images:edit. Conditional R2 write; no automatic retries after ambiguous errors. Body fields: version=1, items keyed by card ID (status studi/approved/discarded/deleted, previous, folder, cluster, author), folders, clusters, references, palette; optional referenceLinks (maximum 50) with id=link:UUID, sourceStyle and sourceId. Links must resolve to an original reference in another registered style; no chains, arbitrary URLs or copied bytes. Author metadata is at most 120 characters. Reference fields: id, title, collection=Uploaded references, category=riferimenti, status=studi, dataUrl. PNG/JPEG/WebP only; 2 MiB each, 8 MiB total, 50 references; serialized document at most 12 MiB. Delete is recoverable metadata, not original-file deletion.","parameters":[{"name":"If-Match","in":"header","required":true,"description":"Exact X-Art-Bible-Version from the last successful GET or PUT; weak ETags are not accepted","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Saved; next storage revision returned in X-Art-Bible-Version","headers":{"ETag":{"schema":{"type":"string"}},"X-Art-Bible-Version":{"description":"Exact storage revision; do not use a proxy-weakened HTTP ETag as the write token","schema":{"type":"string"}}}},"400":{"description":"Invalid document or reference"},"401":{"description":"Sign in required"},"403":{"description":"Operator edit permission required"},"404":{"description":"Unknown style"},"409":{"description":"Concurrent edit; reload before saving"},"413":{"description":"Document too large"},"428":{"description":"If-Match required"},"503":{"description":"Storage unavailable or ambiguous write; read back before retrying"}}}
    },
    "/api/v1/textures/capabilities": { "get": { "summary": "PATINA activation and session operation permissions", "responses": { "200": { "description": "generationEnabled, canGenerate, canEdit, modes and reason" }, "401": { "description": "Authentication required" }, "403": { "description": "Personal session is not admitted to system assets" } } } },
    "/api/v1/textures/jobs": { "post": { "summary": "Queue one PATINA system material; requires job/artifact read and generate or edit scope", "parameters": [{ "name": "Idempotency-Key", "in": "header", "required": true, "schema": { "type": "string", "pattern": "^[A-Za-z0-9._:-]{8,128}$" } }], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TextureRequest" } } } }, "responses": { "202": { "$ref": "#/components/responses/Job" }, "400": { "description": "Invalid mode/input or idempotency key" }, "401": { "description": "Authentication required" }, "403": { "description": "Insufficient system permissions" }, "409": { "description": "Idempotency key already used for different inputs" }, "429": { "description": "Quota or pending job capacity exceeded" }, "503": { "description": "PATINA or system generation disabled" } } } },
    "/api/v1/textures/jobs/{jobId}": { "get": { "parameters": [{ "$ref": "#/components/parameters/JobId" }], "responses": { "200": { "$ref": "#/components/responses/Job" }, "404": { "description": "Not found for this owner" } } } },
    "/api/v1/textures/jobs/{jobId}/cancel": { "post": { "parameters": [{ "$ref": "#/components/parameters/JobId" }], "responses": { "200": { "$ref": "#/components/responses/Job" }, "403": { "description": "Missing job read/cancel permission" }, "404": { "description": "Not found" } } } },
    "/api/v1/textures/jobs/{jobId}/retry": { "post": { "parameters": [{ "$ref": "#/components/parameters/JobId" }, { "name": "Idempotency-Key", "in": "header", "required": true, "schema": { "type": "string", "pattern": "^[A-Za-z0-9._:-]{8,128}$" } }], "responses": { "202": { "$ref": "#/components/responses/Job" }, "403": { "description": "Missing original operation or retry permission" }, "404": { "description": "Not found" }, "409": { "description": "Job not terminal or attempt key conflict" }, "429": { "description": "Quota or pending capacity exceeded" }, "503": { "description": "Generation disabled" } } } },
    "/api/v1/textures/jobs/{jobId}/bundle": { "get": { "parameters": [{ "$ref": "#/components/parameters/JobId" }], "responses": { "200": { "description": "Complete images.texture-bundle.v1 ZIP", "content": { "application/zip": { "schema": { "type": "string", "format": "binary" } } } }, "404": { "description": "Not found" } } } },
    "/api/v1/textures/jobs/{jobId}/manifest": { "get": { "parameters": [{ "$ref": "#/components/parameters/JobId" }], "responses": { "200": { "description": "Versioned manifest with mode and hash/length/dimensions for each map; requires artifact read permission" }, "404": { "description": "Not found" } } } },
    "/api/v1/textures/jobs/{jobId}/maps/{role}": { "get": { "parameters": [{ "$ref": "#/components/parameters/JobId" }, { "name": "role", "in": "path", "required": true, "schema": { "type": "string", "enum": ["texture", "basecolor", "normal", "roughness", "metalness", "height"] } }], "responses": { "200": { "description": "Owner-authorized PNG map", "content": { "image/png": { "schema": { "type": "string", "format": "binary" } } } }, "404": { "description": "Not found" } } } },
    "/auth/config": { "get": { "security": [], "summary": "Public session bootstrap (publishable key only)", "responses": { "200": { "description": "Mode, accepted Supabase origin and pinned Authentication/Accounts contract references. Never contains service-role, Google or operator secrets." } } } },
    "/api/v1/session": { "get": { "summary": "Verified login and independent rights availability", "responses": { "200": { "description": "authenticated=true; rights=available, denied or not-available. This is not a global-role assertion." }, "401": { "description": "Missing or invalid identity" }, "503": { "description": "Identity provider temporarily unavailable; preserve host session" } } } },
    "/api/v1/storage/activate": { "post": { "summary": "Activate an R2 process using a finite owner-qualified allowance", "description": "Requires the explicit system-assets surface and fresh Supabase admin permission. Reserves one prepaid process lease and verifies the external recovery anchor before loading jobs. No caller budget, R2 keys or recovery paths accepted. Does not create a cycle, refund a reservation or generate an image. Login remains valid on storage failure. See docs/r2-runtime-lease.md.", "responses": { "200": { "description": "Storage ready within the current finite process allowance" }, "401": { "description": "Missing or invalid personal login" }, "403": { "description": "System administration not permitted" }, "404": { "description": "R2 is not the selected backend" }, "503": { "description": "Storage lease or recovery unavailable; preserve session, no automatic retry" } } } },
    "/health": { "get": { "security": [], "responses": { "200": { "description": "Healthy" } } } },
    "/ready": { "get": { "security": [], "responses": { "200": { "description": "Ready" }, "503": { "description": "Not ready" } } } },
    "/api/v1/providers": { "get": { "security": [], "responses": { "200": { "description": "Supported provider adapters, configuration status and non-secret locators", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ProviderDescriptor" } } } } } } } },
    "/api/v1/providers/credits": {"get":{"summary":"Read BFL credits (Images operator only)","description":"60-second cached balance; unknown is null, never zero. No upstream credential or error body is returned.","responses":{"200":{"description":"Balance and observation time","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderCreditBalance"}}}},"401":{"description":"Authentication required"},"403":{"description":"Fresh Images operator authorization required"}}}},
    "/api/v1/images/generate": { "post": { "summary": "Generate an image synchronously", "requestBody": { "$ref": "#/components/requestBodies/ImageRequest" }, "responses": { "200": { "$ref": "#/components/responses/ImageResult" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "422": { "description": "Provider or option unavailable" } } } },
    "/api/v1/images/edit": { "post": { "summary": "Edit reference images synchronously", "requestBody": { "$ref": "#/components/requestBodies/ImageRequest" }, "responses": { "200": { "$ref": "#/components/responses/ImageResult" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "422": { "description": "Provider or option unavailable" } } } },
    "/api/v1/jobs/generate": { "post": { "summary": "Queue image generation", "parameters": [{ "$ref": "#/components/parameters/IdempotencyKey" }], "requestBody": { "$ref": "#/components/requestBodies/ImageRequest" }, "responses": { "202": { "$ref": "#/components/responses/Job" }, "400": { "description": "Invalid request or missing required workload key" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "description": "Scope denied" }, "409": { "description": "Idempotency conflict" }, "422": { "description": "Provider or option unavailable" }, "429": { "description": "HTTP or retained-record admission limit" }, "503": { "description": "Generation disabled, persistence fault or queue full" } } } },
    "/api/v1/jobs/edit": { "post": { "summary": "Queue reference-based editing", "parameters": [{ "$ref": "#/components/parameters/IdempotencyKey" }], "requestBody": { "$ref": "#/components/requestBodies/ImageEditRequest" }, "responses": { "202": { "$ref": "#/components/responses/Job" }, "400": { "description": "Invalid request or missing required workload key" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "description": "Scope denied" }, "409": { "description": "Idempotency conflict" }, "422": { "description": "Provider or option unavailable" }, "429": { "description": "HTTP or retained-record admission limit" }, "503": { "description": "Generation disabled, persistence fault or queue full" } } } },
    "/api/v1/jobs": {"get":{"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}},{"name":"status","in":"query","schema":{"enum":["queued","running","succeeded","failed","cancelled"]}},{"name":"provider","in":"query","schema":{"type":"string","maxLength":100}},{"name":"operation","in":"query","schema":{"enum":["generate","edit"]}},{"name":"search","in":"query","schema":{"type":"string","maxLength":200},"description":"Matches ID, provider or model, not prompt text"},{"name":"from","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"until","in":"query","schema":{"type":"string","format":"date-time"},"description":"Exclusive upper date bound"},{"name":"workspace","in":"query","schema":{"enum":["images","spine","ui","spritesheets","patina"]},"description":"Optional gallery category, filtered before counts and pagination. Does not grant access to another owner. Omit to retain all authorized jobs."},{"name":"project","in":"query","schema":{"type":"string","maxLength":80},"description":"Named project, or __unassigned for images without a project."},{"name":"view","in":"query","schema":{"enum":["active","bin","all"],"default":"active"},"description":"Current assets, Bin tombstones, or both. Authorization is applied first."}],"responses":{"200":{"description":"Client-isolated jobs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ImageJob"}}}},"headers":{"X-Total-Count":{"description":"Authorized filtered total before pagination","schema":{"type":"integer","minimum":0}}}},"400":{"description":"Invalid filters or pagination"},"401":{"$ref":"#/components/responses/Unauthorized"}},"summary":"Browse authorized retained jobs with filters and pagination"},"post":{"summary":"Queue image generation","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"$ref":"#/components/requestBodies/ImageRequest"},"responses":{"202":{"$ref":"#/components/responses/Job"},"400":{"description":"Invalid request or missing required workload key"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Scope denied"},"409":{"description":"Idempotency conflict"},"422":{"description":"Provider or option unavailable"},"429":{"description":"HTTP or retained-record admission limit"},"503":{"description":"Generation disabled, persistence fault or queue full"}}}},
    "/api/v1/jobs/{jobId}": { "get": { "parameters": [{ "$ref": "#/components/parameters/JobId" }], "responses": { "200": { "$ref": "#/components/responses/Job" }, "404": { "description": "Not found" } } }, "delete": { "summary": "Move an owned terminal asset to the Bin", "parameters": [{ "$ref": "#/components/parameters/JobId" }], "responses": { "204": { "description": "Moved to Bin" }, "403": { "description": "Scope denied" }, "409": { "description": "Asset is not an owned terminal job" } } } },
    "/api/v1/jobs/{jobId}/artifact": { "get": { "parameters": [{ "$ref": "#/components/parameters/JobId" }], "responses": { "200": { "description": "Generated image" }, "404": { "description": "Not found" } } } },
    "/api/v1/jobs/{jobId}/cancel": { "post": { "parameters": [{ "$ref": "#/components/parameters/JobId" }], "responses": { "200": { "$ref": "#/components/responses/Job" }, "404": { "description": "Not found" } } } },
    "/api/v1/jobs/{jobId}/retry": { "post": { "summary": "Create a new job from a terminal job's retained request", "parameters": [{ "$ref": "#/components/parameters/JobId" }, { "$ref": "#/components/parameters/IdempotencyKey" }], "responses": { "202": { "$ref": "#/components/responses/Job" }, "400": { "description": "Invalid or missing required workload key" }, "403": { "description": "Scope denied" }, "404": { "description": "Not found" }, "409": { "description": "Idempotency/source conflict, nonterminal source or unavailable request" }, "429": { "description": "HTTP or retained-record admission limit" }, "503": { "description": "Generation disabled, persistence fault or queue full" } } } },
    "/api/v1/jobs/{jobId}/restore": { "post": { "summary": "Restore an owned asset from the Bin", "parameters": [{ "$ref": "#/components/parameters/JobId" }], "responses": { "200": { "description": "Restored" }, "403": { "description": "Scope denied" }, "404": { "description": "Asset is not in this owner's Bin" } } } },
    "/api/v1/jobs/bin": { "delete": { "summary": "Permanently empty the authenticated owner's Bin", "description": "Deletes active catalog metadata, primary artifacts and retained object history. Disaster-recovery archives follow their separate retention policy.", "responses": { "200": { "description": "Number of assets permanently removed" }, "403": { "description": "Scope denied" }, "503": { "description": "Storage deletion could not be verified" } } } }
  },
  "components": {
    "securitySchemes": {"bearerAuth":{"type":"http","scheme":"bearer"},"commonServiceAssertion":{"type":"apiKey","in":"header","name":"Cf-Access-Jwt-Assertion","description":"Signed common ServiceIdentity 2.0 assertion, accepted only on /api/v1/service routes. No bearer/cookie/raw credential fallback. Qualified ingress must strip raw credentials and replace untrusted assertion headers. Caller credentials remain in its protected helper. No live machine hostname is assumed."},"systemWorkloadMode":{"type":"apiKey","in":"header","name":"X-Images-Workload","description":"Protocol selector, not a secret: literal system-assets-v1. Legacy-opaque producers require their bearer; common producers use the signed assertion instead. No mixed credentials or fallback. Workloads may read the catalog and use durable job routes; inline generation routes return 403."}},
    "parameters": {
      "OwnedIdempotencyKey": {"name":"Idempotency-Key","in":"header","required":true,"description":"The single original stable key, never a new attempt key or owner selector; not echoed or placed in URLs","schema":{"type":"string","minLength":8,"maxLength":128,"pattern":"^[A-Za-z0-9._:-]{8,128}$"}},
      "JobId": { "name": "jobId", "in": "path", "required": true, "schema": { "type": "string", "pattern": "^job_[0-9a-f]{32}$" } },
      "IdempotencyKey": { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Mandatory for system-assets-v1 creation and retry; optional only for compatibility identities. Stable per intended attempt, including uncertain transport replay. Same producer/key with different normalized request, operation or retry source returns 409.", "schema": { "type": "string", "minLength": 8, "maxLength": 128 } }
    },
    "requestBodies": { "ImageRequest": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImageGenerationRequest" } } } } , "ImageEditRequest": {"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageEditRequest"}}}}, "ManagedImageRequest": {"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedImageRequest"}}}} },
    "responses": {
      "ManagedImageRefusal": {"description":"Nonconforming body or key; no job/provider call. Body parsing reports a precise reason and safe field path. Artistic/key validation retains its existing code and message.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ManagedRequestError"},{"type":"object","additionalProperties":false,"required":["code"],"properties":{"code":{"type":"string"},"message":{"type":"string"}}}]}}}},
      "ManagedJsonMediaRefusal": {"description":"JSON Content-Type required; no job/provider call.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedRequestError"}}}},
      "Unauthorized": { "description": "Missing or invalid client token" },
      "Job": { "description": "Image job", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImageJob" } } } },
      "ImageResult": { "description": "Generated image and verified metadata", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImageResult" } } } }
    },
    "schemas": {
      "ImageEditRequest": {"allOf":[{"$ref":"#/components/schemas/ImageGenerationRequest"},{"type":"object","properties":{"editPipeline":{"type":["string","null"],"enum":["spines.visual-edit/v1",null],"description":"Explicit registered Spine GPT Responses edit; requires source-first subject, matching mask and preserveSourceCanvas. One dispatch, no automatic retry."}}}],"description":"Queued reference editing. The optional registered Spine pipeline is not part of managed artistic input; its source, mask, workspace and model constraints are validated before dispatch."},
      "ManagedImageRequest": {"allOf":[{"$ref":"#/components/schemas/ImageGenerationRequest"},{"type":"object","properties":{"generationProfile":{"type":["string","null"],"description":"Optional explicit bounded compatibility mode. Omit for ordinary generation/editing with any configured provider and its supported options."},"fineTuneId":{"type":["string","null"]},"fineTuneStrength":{"type":["number","null"]},"references":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ManagedImageReference"}},"mask":{"anyOf":[{"$ref":"#/components/schemas/ManagedImageMask"},{"type":"null"}]}}}],"unevaluatedProperties":false,"description":"Artistic input only; no caller quote or spending acceptance. Images privately selects credentials and uses the configured provider's normal transport. No generation profile is required. Explicit bounded profiles retain their original restrictions. Property names are case-sensitive and duplicate properties are rejected."},
      "ManagedImageReference": {"allOf":[{"$ref":"#/components/schemas/ImageReference"},{"type":"object","properties":{"role":{"enum":["subject","character","composition","style","palette","texture","layout"]}}}],"unevaluatedProperties":false,"description":"Managed reference: only base64, mimeType, role and fileName. Unknown and duplicate fields are rejected before job creation."},
      "ManagedImageMask": {"allOf":[{"$ref":"#/components/schemas/ImageReference"},{"type":"object","properties":{"mimeType":{"const":"image/png"}}}],"unevaluatedProperties":false,"description":"Managed mask: same four allowed fields; PNG with alpha channel, matching the first reference dimensions. Unknown or duplicate fields are rejected."},
      "ManagedRequestError": {"type":"object","additionalProperties":false,"required":["code","reason","field","message"],"properties":{"code":{"const":"invalid_managed_request"},"reason":{"enum":["invalid_json","unknown_field","duplicate_field","required_field","invalid_field_type","invalid_field_value","unsupported_media_type"]},"field":{"type":"string","description":"Safe JSON path. For unknown fields, identifies the containing object without echoing an untrusted field name."},"message":{"type":"string","description":"Specific corrective explanation; never echoes submitted values or raw exception text."}}},
      "ImageJobReconciliation": {"type":"object","additionalProperties":false,"required":["contractVersion","operationExecuted","jobId","owner","operation","status","provider","createdAt","updatedAt","observedAt"],"properties":{"contractVersion":{"const":"images.owned-job-reconciliation/v1"},"operationExecuted":{"const":false},"jobId":{"type":"string","pattern":"^job_[a-f0-9]{32}$"},"owner":{"type":"string","pattern":"^system:[a-z][a-z0-9-]{1,39}$"},"operation":{"enum":["generate","edit"]},"status":{"enum":["queued","running","succeeded","failed","cancelled"]},"provider":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,63}$"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"observedAt":{"type":"string","format":"date-time"}},"description":"Exact retained job observation only. No receipt of provider dispatch/charge and no permission to retry. Get the qualified actual job ID through existing authorized readers for error/usage/artifact details."},
      "SceneLayerCostAdmissionRequest": {"type":"object","required":["intent"],"properties":{"intent":{"$ref":"#/components/schemas/SceneLayerSetIntent"}}},
      "SceneLayerSetRequest": {"type":"object","required":["intent","costAdmissionId","maximumProviderCalls","maximumCredits"],"properties":{"intent":{"$ref":"#/components/schemas/SceneLayerSetIntent"},"costAdmissionId":{"type":"string"},"maximumProviderCalls":{"type":"integer","minimum":1,"maximum":24},"maximumCredits":{"type":"number","minimum":1,"maximum":24},"maximumProviderSubtotalUsd":{"type":["number","null"],"exclusiveMinimum":0},"acceptedPriceRevision":{"type":["string","null"]}},"description":"Native default seven roles require 13 single-attempt calls; BG2 requires two. Explicit qualified monetary ceilings are required for paid native execution. Credits count calls, not invoiced money."},
      "SceneLayerSetIntent": {"type":"object","required":["approvedMasterJobId","approval","layout"],"properties":{"approvedMasterJobId":{"type":"string","pattern":"^job_[a-f0-9]{32}$"},"approval":{"type":"object","required":["approvalId","approvedBy","approvedAt","masterSha256"]},"layout":{"type":"object","required":["schemaVersion","referenceId","revision","contentSha256","canvasWidth","canvasHeight","groundBoundaryY","camera"]},"layers":{"type":["array","null"],"minItems":1,"maxItems":12,"items":{"type":"string","pattern":"^[a-z][a-z0-9-]{0,31}$"},"description":"Defaults to sky,bg4,bg3,bg2,bg1,ground,foreground in exact back-to-front order."},"regionMasks":{"type":["array","null"],"maxItems":12},"overscanPixels":{"type":"integer","minimum":0,"maximum":1024,"default":128},"reconstructHiddenContent":{"type":"boolean","default":true},"provider":{"type":["string","null"]},"quality":{"enum":["low","medium","high"]},"stylePreset":{"type":["string","null"],"maxLength":4000},"guidePreset":{"type":["string","null"],"maxLength":4000},"parentSet":{"$ref":"#/components/schemas/SceneLayerParentReference"},"layersToRegenerate":{"type":["array","null"],"minItems":1,"maxItems":12,"uniqueItems":true,"items":{"type":"string","pattern":"^[a-z][a-z0-9-]{0,31}$"}},"compositionReference":{"$ref":"#/components/schemas/SceneLayerOwnedReference"},"layerPurposes":{"type":["object","null"],"maxProperties":12,"additionalProperties":{"type":"string","minLength":1,"maxLength":1000}},"viewport":{"type":["object","null"],"required":["left","top","width","height"],"description":"Native pixel viewport; full-frame 2752x1536 reserves zero overscan."},"overscanBounds":{"type":["object","null"],"required":["left","top","right","bottom"]},"registration":{"type":["object","null"],"required":["schemaVersion","mapping","targetWidth","targetHeight","nativeSeamNormalized","targetSeamNormalized"],"description":"Approved core.scene-registration/v1 metadata; Images records but never applies pixel transformations."},"carryForward":{"type":["array","null"],"minItems":1,"maxItems":11,"items":{"$ref":"#/components/schemas/SceneLayerCarryForwardReference"}}},"description":"Production plans require owned composition, purposes, viewport/overscan and Core registration. Style plus guide total is bounded to 4000 characters. Carry-forward and parent regeneration are mutually exclusive; at least one new layer is required. Failed/cancelled sources may retain only successful owned hash-valid roles. Artwork excludes baked runtime atmosphere."},
      "SceneLayerParentReference": {"type":["object","null"],"required":["jobId","manifestSha256"],"properties":{"jobId":{"type":"string","pattern":"^job_[a-f0-9]{32}$"},"manifestSha256":{"type":"string","pattern":"^[a-f0-9]{64}$"}}},
      "SceneLayerOwnedReference": {"type":["object","null"],"required":["jobId","sha256"],"properties":{"jobId":{"type":"string","pattern":"^job_[a-f0-9]{32}$"},"sha256":{"type":"string","pattern":"^[a-f0-9]{64}$"},"requestReferenceIndex":{"type":["integer","null"],"minimum":0}}},
      "SceneLayerCarryForwardReference": {"type":"object","required":["layer","sourceSet","artifactSha256"],"properties":{"layer":{"type":"string","pattern":"^[a-z][a-z0-9-]{0,31}$"},"sourceSet":{"allOf":[{"$ref":"#/components/schemas/SceneLayerParentReference"},{"type":"object"}]},"artifactSha256":{"type":"string","pattern":"^[a-f0-9]{64}$"},"maskSha256":{"type":["string","null"],"pattern":"^[a-f0-9]{64}$"}},"description":"Pins an unchanged successful owned terminal-set layer and optional original Core mask; never repeats its paid calls or overwrites the source."},
      "ImageStyleCatalog": {"type":"object","required":["schemaVersion","revision","styles"],"properties":{"schemaVersion":{"const":"images.styles.catalog/v1"},"revision":{"type":"string","pattern":"^sha256:[a-f0-9]{64}$"},"styles":{"type":"array","items":{"$ref":"#/components/schemas/ImageStyle"}}}},
      "ImageStyle": {"type":"object","required":["id","name","category","revision","positiveDirection","negativeDirection","referencePolicy","tags"],"properties":{"id":{"type":"string","pattern":"^[a-z0-9-]+$"},"name":{"type":"string"},"category":{"enum":["Rendering","Wingoria","Saved"]},"revision":{"type":"string","pattern":"^sha256:[a-f0-9]{64}$"},"positiveDirection":{"type":"string"},"negativeDirection":{"type":"string"},"referencePolicy":{"$ref":"#/components/schemas/ImageStyleReferencePolicy"},"tags":{"type":"array","items":{"type":"string"}}}},
      "ImageStyleReferencePolicy": {"type":"object","required":["role","minimumImages","recommendedImages","maximumImages","providerCapabilityRequired"],"properties":{"role":{"const":"style"},"minimumImages":{"const":0},"recommendedImages":{"const":3},"maximumImages":{"const":5},"providerCapabilityRequired":{"const":true}}},
      "ImageGuideCatalog": {"type":"object","required":["schemaVersion","revision","guides"],"properties":{"schemaVersion":{"const":"images.guides.catalog/v1"},"revision":{"type":"string","pattern":"^sha256:[a-f0-9]{64}$"},"guides":{"type":"array","items":{"$ref":"#/components/schemas/ImageGuide"}}}},
      "ImageGuide": {"type":"object","required":["id","name","category","revision","direction","negativeDirection","tags"],"properties":{"id":{"type":"string","pattern":"^[a-z0-9-]+$"},"name":{"type":"string"},"category":{"type":"string"},"revision":{"type":"string","pattern":"^sha256:[a-f0-9]{64}$"},"direction":{"type":"string"},"negativeDirection":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}}}},
      "SharedStyleLibrary": {"type":"object","required":["version","styles","folders","assignments"],"properties":{"version":{"const":1},"styles":{"type":"array","maxItems":200,"items":{"type":"object","required":["id","title","text","negative"],"properties":{"id":{"type":"string","pattern":"^saved-[a-z0-9-]+$"},"title":{"type":"string","minLength":1,"maxLength":80},"text":{"type":"string","minLength":1,"maxLength":8000},"negative":{"type":"string","maxLength":8000},"kind":{"enum":["style","guide"],"default":"style"},"tags":{"type":"array","maxItems":12,"items":{"type":"string","pattern":"^[a-z0-9-]{1,40}$"}}}}},"folders":{"type":"array","maxItems":30,"items":{"type":"object","required":["id","title"],"properties":{"id":{"type":"string","pattern":"^folder-[a-z0-9-]+$"},"title":{"type":"string","minLength":1,"maxLength":80}}}},"assignments":{"type":"object","additionalProperties":{"type":"string","pattern":"^folder-[a-z0-9-]+$"}}}},
      "ProviderCreditBalance": {"type":"object","properties":{"provider":{"type":"string"},"status":{"enum":["available","unavailable","not-configured"]},"remaining":{"type":["number","null"]},"unit":{"const":"credits"},"observedAt":{"type":["string","null"],"format":"date-time"}}},
      "TextureInput": { "type": "object", "required": ["mimeType", "base64"], "properties": { "mimeType": { "type": "string", "enum": ["image/png", "image/jpeg", "image/webp"] }, "base64": { "type": "string", "description": "Inline image bytes, at most 10 MiB decoded; mask must be PNG with matching dimensions" } } },
      "TextureRequest": { "type": "object", "required": ["mode"], "properties": { "mode": { "type": "string", "enum": ["textToMaterial", "imageToMaterial", "inpaintMaterial", "imageToMaps", "extractMaterial"] }, "prompt": { "type": "string", "maxLength": 4000, "description": "Required except imageToMaps, where it must be omitted" }, "image": { "$ref": "#/components/schemas/TextureInput" }, "mask": { "$ref": "#/components/schemas/TextureInput" }, "seed": { "type": "integer", "format": "int32" } } },
      "ProviderDescriptor": {"type":"object","required":["id","model","configured","supportsEditing","maximumReferences","supportsSeed","aspectRatios","resolutions","supportsTransparentBackground"],"properties":{"id":{"type":"string","examples":["nano-banana-pro"]},"displayName":{"type":["string","null"],"examples":["Nano Banana Pro"]},"model":{"type":"string","examples":["gemini-3-pro-image"]},"configured":{"type":"boolean"},"supportsEditing":{"type":"boolean"},"maximumReferences":{"type":"integer","minimum":0},"supportsSeed":{"type":"boolean"},"configurationLocator":{"type":["string","null"],"description":"Environment locator name only; never a credential value"},"aspectRatios":{"type":"array","items":{"type":"string"}},"resolutions":{"type":"array","items":{"enum":["1K","2K","4K"]}},"maximumPromptCharacters":{"type":"integer","default":8000,"description":"Service character budget, not model token context"},"maximumStyleCharacters":{"type":"integer","default":8000,"description":"Service character budget, not model token context"},"maximumCombinedTextCharacters":{"type":"integer","default":8000,"description":"Service character budget, not model token context"},"supportsTransparentBackground":{"type":"boolean","default":false,"description":"Whether the provider can return a native alpha channel"}}},
      "ImageReference": { "type": "object", "required": ["base64", "mimeType"], "properties": { "base64": { "type": "string", "contentEncoding": "base64" }, "mimeType": { "enum": ["image/png", "image/jpeg", "image/webp"] }, "role": { "enum": ["subject", "character", "composition", "style", "palette", "texture", "layout", "mask"] }, "fileName": { "type": ["string", "null"] } } },
      "ImageGenerationRequest": {"type":"object","required":["prompt"],"properties":{"noTransparency":{"type":"boolean","default":false,"description":"Skip automatic PNG background removal. Explicit legacy background opaque is also an opt-out. Exact-canvas, masked, bounded and dedicated scene/spritesheet contracts are unchanged."},"prompt":{"type":"string","maxLength":8000},"provider":{"type":["string","null"]},"size":{"type":"string","description":"Legacy: 1024x1024, 1536x1024 or 1024x1536. With preserveSourceCanvas=true: exact first-reference WIDTHxHEIGHT, each axis 1–4096."},"preserveSourceCanvas":{"type":"boolean","default":false,"description":"Edit+PNG only: first reference must be a valid static PNG matching size exactly. Return a real PNG on the same canvas or fail without an artifact. No resize/crop, alpha reconstruction or visual fidelity guarantee. See docs/edit-png-canvas-contract.md."},"aspectRatio":{"type":["string","null"],"enum":["1:1","2:3","3:2","3:4","4:3","4:5","5:4","9:16","16:9","21:9",null]},"resolution":{"type":["string","null"],"enum":["1K","2K","4K",null]},"quality":{"enum":["low","medium","high"]},"assetKind":{"enum":["image","texture","ui"]},"outputFormat":{"enum":["png","jpeg","webp"]},"background":{"enum":["auto","transparent","opaque"]},"stylePreset":{"type":["string","null"],"maxLength":8000},"guidePreset":{"type":["string","null"],"maxLength":8000},"seed":{"type":["integer","null"],"minimum":0},"references":{"type":["array","null"],"maxItems":10,"items":{"$ref":"#/components/schemas/ImageReference"}},"patina":{"enum":["none","light","medium","heavy"]},"tileable":{"type":"boolean"},"camera":{"type":["string","null"],"maxLength":200},"purpose":{"type":["string","null"],"maxLength":200},"slot":{"type":["string","null"],"maxLength":200},"mask":{"anyOf":[{"$ref":"#/components/schemas/ImageReference"},{"type":"null"}]},"workspace":{"type":["string","null"],"enum":["images","ui","spine","spritesheets",null],"description":"Gallery category only, not an authorization selector. UI asset kinds and Spine system owners retain their category."}},"description":"Prompt, stylePreset and guidePreset combined must not exceed 8000 characters. Camera, purpose and slot are prompt guidance, not geometric constraints."},
      "ImageJob": {"type":"object","required":["id","owner","operation","status","provider","createdAt","updatedAt"],"properties":{"id":{"type":"string"},"owner":{"type":"string"},"operation":{"enum":["generate","edit"]},"status":{"enum":["queued","running","succeeded","failed","cancelled"]},"provider":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"originalArtifact":{"$ref":"#/components/schemas/ImageArtifact"},"artifact":{"$ref":"#/components/schemas/ImageArtifact"},"workspace":{"type":"string","enum":["images","spine","ui","spritesheets","patina"],"description":"Category derived from the retained request and owner, including legacy jobs."},"project":{"type":"string","maxLength":80,"description":"Optional owner-scoped Gallery project."},"prompt":{"type":"string","description":"Original prompt, returned only within the authorized job view."}}},
      "ImageArtifact": {"type":["object","null"],"required":["mimeType","width","height","sha256","downloadUrl"],"properties":{"editProvenance":{"type":["object","null"],"properties":{"pipeline":{"type":"string"},"responseId":{"type":"string"},"interpreterModel":{"type":"string"},"imageModel":{"type":"string"},"sourceSha256":{"type":"string"},"revisedPrompt":{"type":"string","maxLength":32000,"description":"Effective provider prompt when returned; empty means unavailable, not approval."}}},"mimeType":{"type":"string"},"width":{"type":"integer"},"height":{"type":"integer"},"sha256":{"type":"string","pattern":"^[0-9a-fA-F]{64}$"},"downloadUrl":{"type":"string","format":"uri-reference","description":"Response-family URL: /api/v1/service/jobs/{id}/artifact for machine job DTOs, /api/v1/jobs/{id}/artifact for human/legacy job DTOs. Response-only projection; stored metadata is unchanged. Official machine clients fetch by job ID and do not follow this value or redirects."},"model":{"type":["string","null"]}}},
      "ImageResult": { "type": "object", "required": ["id", "provider", "model", "mimeType", "width", "height", "sha256", "base64"], "properties": { "id": { "type": "string" }, "provider": { "type": "string" }, "model": { "type": "string" }, "mimeType": { "type": "string" }, "width": { "type": "integer" }, "height": { "type": "integer" }, "sha256": { "type": "string" }, "base64": { "type": "string", "contentEncoding": "base64" } } }
    }
  }
}
