VertcieDocumentation
Developer / public http api

Public runtime HTTP API

Status: Normative.

The standalone image element has a separate implementation-preview Runtime storage flow: POST /api/runtime/publications/{publishedFileId}/images with lookup, prepare, and finalize actions. It is not the asynchronous /renders queue and does not use the /api/v1 envelope. See Standalone runtime images for its properties, deployment status and board authorization requirements.

Base examples use https://app.vertcie.com. All protected calls send x-vertcie-key.

Claude Web and tool generation

Use the canonical OpenAPI 3.1 document:

https://app.vertcie.com/api/v1/openapi.json

The unauthenticated discovery document is:

https://app.vertcie.com/api/v1

Configure x-vertcie-key as the API-key credential in Claude. Do not put the key in a URL. Every JSON response uses the v1 ok, data, and meta envelope or the stable ok: false error envelope. X-Request-ID correlates customer requests with Vertcie usage records.

Issue Claude a Server / Claude key. Server keys accept originless server-to-server calls and reject requests carrying a browser Origin. Browser keys require an allowed Origin and reject originless calls. This prevents a server credential from becoming a usable browser credential if exposed.

The remainder of this page includes compatibility-route details for existing integrations. New Claude tools should use only the /api/v1 operations from the OpenAPI document.

Browser custom elements

Browser consumers that do not need to call the HTTP API directly should use the supported wrapper elements. Load their shared module once:

<script
  type="module"
  src="https://cdn.vertcie.com/runtime/vertcie-client-elements.js"
></script>

Then embed either client using its permanent Published File ID:

<vertcie-client-expanders
  pid="PUBLISHED_FILE_ID"
  api-key="VERTCIE_PUBLIC_API_KEY"
></vertcie-client-expanders>

<vertcie-client-signature
  pid="PUBLISHED_FILE_ID"
  signature="PRODUCT_SIGNATURE"
  api-key="VERTCIE_PUBLIC_API_KEY"
></vertcie-client-signature>

Humanscale's isolated Client UX+ uses the same API contract and its own loader:

<script
  type="module"
  src="https://cdn.vertcie.com/runtime/vertcie-humanscale.js"
></script>

<vertcie-humanscale
  pid="PUBLISHED_FILE_ID"
  api-key="VERTCIE_PUBLIC_API_KEY"
></vertcie-humanscale>

Its UI is brand-specific, while all product behavior remains canonical manifest data. The element must not infer rules from a product name, option label, mesh name, or Published File ID.

Both wrappers use the same publication-manifest, shader, asset, and canonical selection-resolution APIs documented below. They default to the production API endpoint and active publication revision. Pin an immutable revision with the optional revision attribute.

An authenticated same-origin Vertcie workspace can omit api-key; Runtime sends the active session credentials. Customer-site embeds are cross-origin and must use an origin-restricted public runtime key.

Customer integration boundary

An external integration must use a dedicated Server / Claude key issued for its Organization. The key must be granted only the Boards the integration is allowed to read or change. It must never be embedded in browser JavaScript, a mobile application, a URL, or a query string. Calls from a customer-facing UI go through a customer-controlled server or serverless proxy, which adds x-vertcie-key after receiving the browser request.

The default limit is 600 requests per minute per API key, shared across all application instances and all routes used by that key. An authorized account owner can set a key-specific limit from 10 through 10,000 requests per minute. A 429 response includes Retry-After; wait that many seconds before retrying.

Cache publication packages and active manifests briefly and revalidate them when the user starts a new configuration session. Cache immutable revision data by its revision identifier. Cache swatch and image bytes using their HTTP cache headers rather than requesting them once per UI interaction. Signed asset URLs are temporary credentials: do not persist or redistribute them.

Operation to UI mapping

OpenAPI operationTypical UI responsibility
searchPublicationsProduct search or product-family picker
resolveModelBySignatureResolve an existing SKU/signature to its product
getPublicationInitial configurator package: option groups, choices, shader references, rules, and package-defined metadata
getRuntimeManifestRuntime option tree and selection metadata used to populate dropdowns such as Textile
suggestPublicationSelectionNatural-language configuration assistant
resolvePublicationSelectionApply current choices and calculate visible meshes, materials, and transforms
createSelectionRevisionSave an immutable configuration snapshot
listPublicationImagesProduct thumbnails, configured images, and swatches associated with the publication
createPublicationRenderRequest a new configured product image
resolvePublicationMeshPathsResolve model assets for the 3D viewer
getDerivedAsset / prepareDerivedAssetRead or prepare AR assets
recordRuntimeEventsSubmit bounded runtime activity from browser clients
listRuntimeEventsRead sanitized activity generated by the calling API key

See Runtime telemetry for scopes, filters, event fields, response envelopes, pagination, redaction, and request examples.

SKU and pricing fields are package-defined metadata; v1 does not currently publish a separate price-calculation operation. A consumer must not infer a price from option labels or invent a SKU. If the selected publication does not contain the required SKU or price breakdown, treat that capability as unavailable and request a contract extension before building the UI.

Representative request and response

Identifiers and option entries are opaque examples. Always use values returned by the customer's granted publication; do not copy these sample identifiers into production requests.

Find an example publication:

GET /api/v1/publications?query=Freedom&limit=20 HTTP/1.1
Host: app.vertcie.com
x-vertcie-key: [CUSTOMER_SERVER_KEY]
x-request-id: example-product-search-0001
{
  "ok": true,
  "data": [
    {
      "publishedFileId": "pub_example_chair",
      "title": "Freedom",
      "signature": "freedom"
    }
  ],
  "meta": {
    "requestId": "example-product-search-0001"
  }
}

Resolve a populated selection after reading its actual option and shader entries from the publication or runtime manifest:

POST /api/v1/publications/pub_example_chair/selection-resolutions HTTP/1.1
Host: app.vertcie.com
Content-Type: application/json
x-vertcie-key: [CUSTOMER_SERVER_KEY]
x-request-id: example-config-0001

{
  "client": "expanders",
  "selections": {
    "option-group-id-from-manifest": "option-id-from-manifest",
    "shader-slot-id-from-manifest": "shader-id-from-manifest"
  }
}

For a Compositor, keep the client mode at request level and include stable scene targeting as context. Never target a product by array index. revision accepts a positive integer or "latest"; the response always identifies the resolved numeric revision.

{
  "client": "signature",
  "revision": "latest",
  "context": {
    "sceneId": "planning-study-1",
    "objectId": "ottoman-1"
  },
  "signature": "OTKR"
}

The equivalent Expander request uses the same envelope with "client": "expanders" and a selections object. Successful responses echo context and return canonical mesh visibility, hydrated materials, and transform-node operations.

{
  "ok": true,
  "data": {
    "format": "vertcie/runtime-selection-resolution/v1",
    "publishedFileId": "pub_example_chair",
    "revision": 4,
    "client": "expanders",
    "signature": null,
    "selections": {
      "option-group-id-from-manifest": "option-id-from-manifest",
      "shader-slot-id-from-manifest": "shader-id-from-manifest"
    },
    "activeGroupIds": ["option-group-id-from-manifest", "shader-slot-id-from-manifest"],
    "visibleMeshIds": ["mesh-id-from-publication"],
    "selectedShaderIds": ["shader-id-from-manifest"],
    "materials": [
      { "meshId": "mesh-id-from-publication", "shaderId": "shader-id-from-manifest" }
    ],
    "transforms": [],
    "meshPaths": {
      "mesh-id-from-publication": "https://temporary-authorized-asset-url"
    }
  },
  "meta": {
    "requestId": "example-config-0001"
  }
}

selections is the preferred request shape and maps manifest branch IDs to manifest option IDs. The compatibility selectedOptions and selectedShaders arrays remain accepted when their entries carry the same manifest IDs. Never reconstruct identifiers from display labels.

For Runtime publications, this endpoint loads the active manifest by default, or the immutable manifest named by revision, and executes the same canonical session used by Preview/Publish and the browser runtime. Conditional groups, duplicate migrated routes, transforms, material-family ownership, and Fabric/Leather exclusivity therefore resolve identically. visibleMeshIds contains manifest asset IDs (the same IDs used by manifest.assets), and meshPaths contains only the resolved visible assets.

To resolve a Signature client, send { "client": "signature", "signature": "..." }. The complete signature must resolve uniquely through every authored stage. Partial, unmatched, or ambiguous signatures fail closed. Legacy PublishedVersion IDs return their existing payload shape.

Example error:

{
  "ok": false,
  "error": {
    "code": "resource_not_found",
    "message": "The requested resource was not found.",
    "requestId": "example-config-0002"
  }
}

The same 404 is returned for missing, discontinued, cross-tenant, and ungranted resources so an API key cannot enumerate another customer's data. Do not retry it unchanged. The current API does not expose inventory status; an out-of-stock workflow requires a separate inventory source or a future contracted field.

Quick start

const baseUrl = "https://VERTCIE_HOST";
const key = process.env.VERTCIE_API_KEY!;

const response = await fetch(
  `${baseUrl}/api/get-published-file?publishedFileId=${encodeURIComponent("PUBLISHED_FILE_ID")}`,
  { headers: { "x-vertcie-key": key } },
);
if (!response.ok) throw new Error(`Vertcie request failed: ${response.status}`);
const published = await response.json();

Browser requests should include their natural Origin. A key with allowed origins rejects missing or unmatched origins. Server applications need a key issued for that use.

Runtime manifests

Follow the active revision for Expanders:

GET /api/runtime/publications/PUBLISHED_FILE_ID/manifests/expanders
x-vertcie-key: VERTCIE_PUBLIC_API_KEY

Pin immutable revision 4:

GET /api/runtime/publications/PUBLISHED_FILE_ID/revisions/4/manifests/expanders
x-vertcie-key: VERTCIE_PUBLIC_API_KEY

Replace expanders with signature for the Signature client. The active route may resolve to a newer revision after publication activation. The exact-revision route validates a positive revision and returns only a manifest matching the requested Published File ID, revision, and client. Exact-revision responses are immutable and may be cached accordingly.

Browser integrations should normally use the Runtime component configuration rather than constructing these paths:

{ publishedFileId: "PUBLISHED_FILE_ID", useLatest: true }
{ publishedFileId: "PUBLISHED_FILE_ID", revision: 4 }

Published file

GET /api/get-published-file

QueryRequiredValues/defaultPurpose
publishedFileIdyesnon-empty stringPublished artifact identifier
loadMode or load-modenodefault; signatureSignature mode returns a package-oriented response
includeMeshPathsno1 enablesInclude mesh path information
includeHierarchyno1 enables in default modeInclude hierarchy data
includeDiagnosticsno1 enablesInclude diagnostic metadata
includeExpanderFragmentUrlsnoenabled unless 0 in default modeInclude expander fragments
includeSignatureBranchUrlsno1 enablesInclude signature branch URLs
packageOnlyno1 enables; forced in signature modeLimit to package data
packageMetadataOnlyno1 enables; forced in signature modeLimit package representation
treeModenofull; expanderSelect hierarchy representation

The payload is a versioned published package. Store publishedFileId, the chosen latest/pinned policy, and stable selection identifiers—not signed URLs embedded in the response.

Model lookup

GET /api/get-model?signature=SIGNATURE&publishedFileId=PUBLISHED_FILE_ID

signature is required. publishedFileId is optional but recommended when the catalog context is known. GET /api/get-model?health=true is an unauthenticated route-health check; it does not prove catalog, storage, or authorization health.

Image lookup and generation

  • GET /api/get-image accepts at least one of title, signature, or publishedFileId.
  • GET /api/get-image-by-signature requires signature.

Optional query fields:

FieldConstraint
width, heightnumber from 1 through 4096
formatjpeg, jpg, png, webp, or avif
newestOnlytrue enables
rotation, dolly, boom, fov, targetHeightbounded numeric camera values
environmentRotation, environmentIntensitybounded numeric environment values

The normal success response is an array, including when lookup uses a single identifier. If no image exists and all five camera fields plus publishedFileId are supplied, the route may return a queued/generated-image descriptor. Treat its state as asynchronous; do not assume the image bytes exist merely because the request returned 200.

Resolve a selection

POST /api/resolve-selection

{
  "publishedFileId": "PUBLISHED_FILE_ID",
  "selectedOptions": [],
  "selectedShaders": []
}

Both selection fields default to empty arrays and each is limited to 2,000 entries. The result has this stable envelope:

type ResolvedSelection = {
  visibleMeshIds: string[] | null;
  materials: unknown[];
  transforms: unknown[];
};

Selection entry shapes are package-defined. Obtain them from the published hierarchy/runtime SDK rather than inventing values.

Create a published-selection revision

POST /api/update-published-selection

Send publishedFileId and at least one of selectedOptions, selectedShaders, or selectedMeshes. Each supplied field must be an array of at most 2,000 entries. The operation is append-only and returns:

type RevisionResult = {
  publishedFileId: string;
  revisionId: string;
  updated: string[];
};

This endpoint does not mutate the original published snapshot.

Mesh paths and AR

POST /api/get-mesh-paths resolves a bounded list of mesh identifiers. Use this route rather than constructing object paths.

GET /api/get-ar-asset?publishedFileId=...&assetKey=... returns an AR descriptor. assetKey, when supplied, is a lowercase hexadecimal content key of 20–64 characters.

POST /api/get-ar-asset supports the controlled prepareUpload and finalizeUpload integration flow. It accepts publishedFileId, assetKey, action, optional ext (glb or gltf), and optional includeIosAsset. Upload bytes only to the returned signed URL, with the exact specified content type, then finalize.

USDZ delivery supports HEAD, GET, and a single HTTP byte range. Do not persist the delivery URL.

Errors

StatusTypical body/errorMeaning
400validation messageMissing or invalid bounded input
401missing_key, invalid_keyPublic key absent or unusable
403origin_deniedOrigin is outside key policy
404resource-specific messageNo matching published artifact
413request_too_largeJSON body exceeded route limit
415signed uploads onlyUnsupported upload method/content type
502operation-specific failureBacking provider failed
503runtime_unavailable or auth_unavailableRuntime provider is not usable

Use bounded exponential backoff with jitter only for transient failures. Do not retry validation, authentication, authorization, or missing-resource responses unchanged.