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.jsonThe unauthenticated discovery document is:
https://app.vertcie.com/api/v1Configure 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 operation | Typical UI responsibility |
|---|---|
searchPublications | Product search or product-family picker |
resolveModelBySignature | Resolve an existing SKU/signature to its product |
getPublication | Initial configurator package: option groups, choices, shader references, rules, and package-defined metadata |
getRuntimeManifest | Runtime option tree and selection metadata used to populate dropdowns such as Textile |
suggestPublicationSelection | Natural-language configuration assistant |
resolvePublicationSelection | Apply current choices and calculate visible meshes, materials, and transforms |
createSelectionRevision | Save an immutable configuration snapshot |
listPublicationImages | Product thumbnails, configured images, and swatches associated with the publication |
createPublicationRender | Request a new configured product image |
resolvePublicationMeshPaths | Resolve model assets for the 3D viewer |
getDerivedAsset / prepareDerivedAsset | Read or prepare AR assets |
recordRuntimeEvents | Submit bounded runtime activity from browser clients |
listRuntimeEvents | Read 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_KEYPin immutable revision 4:
GET /api/runtime/publications/PUBLISHED_FILE_ID/revisions/4/manifests/expanders
x-vertcie-key: VERTCIE_PUBLIC_API_KEYReplace 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
| Query | Required | Values/default | Purpose |
|---|---|---|---|
publishedFileId | yes | non-empty string | Published artifact identifier |
loadMode or load-mode | no | default; signature | Signature mode returns a package-oriented response |
includeMeshPaths | no | 1 enables | Include mesh path information |
includeHierarchy | no | 1 enables in default mode | Include hierarchy data |
includeDiagnostics | no | 1 enables | Include diagnostic metadata |
includeExpanderFragmentUrls | no | enabled unless 0 in default mode | Include expander fragments |
includeSignatureBranchUrls | no | 1 enables | Include signature branch URLs |
packageOnly | no | 1 enables; forced in signature mode | Limit to package data |
packageMetadataOnly | no | 1 enables; forced in signature mode | Limit package representation |
treeMode | no | full; expander | Select 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-imageaccepts at least one oftitle,signature, orpublishedFileId.GET /api/get-image-by-signaturerequiressignature.
Optional query fields:
| Field | Constraint |
|---|---|
width, height | number from 1 through 4096 |
format | jpeg, jpg, png, webp, or avif |
newestOnly | true enables |
rotation, dolly, boom, fov, targetHeight | bounded numeric camera values |
environmentRotation, environmentIntensity | bounded 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
| Status | Typical body/error | Meaning |
|---|---|---|
400 | validation message | Missing or invalid bounded input |
401 | missing_key, invalid_key | Public key absent or unusable |
403 | origin_denied | Origin is outside key policy |
404 | resource-specific message | No matching published artifact |
413 | request_too_large | JSON body exceeded route limit |
415 | signed uploads only | Unsupported upload method/content type |
502 | operation-specific failure | Backing provider failed |
503 | runtime_unavailable or auth_unavailable | Runtime 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.