Skip to content

Quickstart

Create a scene, then open it in the Smore studio. A source image is optional. Run the API requests from your server.

Start with the Smore agent prompt. It works with any coding agent and links to the docs and API contract it needs.

You need:

  • A Smore sk_test_… secret key
  • An exact localhost origin approved for your test organization
const apiKey = process.env.SMORE_SECRET_KEY;
if (!apiKey) throw new Error("SMORE_SECRET_KEY is required");
const smoreFetch = (path: string, init: RequestInit): Promise<Response> =>
fetch(`https://api.smore.video${path}`, {
...init,
headers: {
Authorization: `Bearer ${apiKey}`,
...init.headers,
},
});

Generate and durably store one canonical lowercase UUID v4 before sending the request. Reuse the same key and exact body after a transport failure.

const idempotencyKey = crypto.randomUUID();
const createResponse = await smoreFetch("/v1/scenes", {
body: JSON.stringify({
externalRef: "your-scene-draft-id",
prompt: "Create a simple navigable clay scene with a clear subject and shot camera",
}),
headers: {
"Content-Type": "application/json",
"Idempotency-Key": idempotencyKey,
},
method: "POST",
signal: AbortSignal.timeout(15_000),
});
if (createResponse.status !== 202) throw await createResponse.json();
const accepted = await createResponse.json();

Persist accepted.operationId. Poll it through separate short requests using the returned Retry-After value:

const operationResponse = await smoreFetch(
`/v1/operations/${accepted.operationId}`,
{ method: "GET", signal: AbortSignal.timeout(15_000) },
);
if (!operationResponse.ok) throw await operationResponse.json();
const operation = await operationResponse.json();

Continue polling only while operation.status === "processing". On success, store operation.result.scene.id and .version in your authorized server-side record.

const sessionResponse = await smoreFetch("/v1/embed-sessions", {
body: JSON.stringify({
expiresInSeconds: 3_600,
mode: "edit_and_perform",
origin: "http://localhost:3000",
sceneId: operation.result.scene.id,
theme: {
accentColor: "#7657ff",
colorScheme: "dark",
helpText: null,
partnerName: "Your product",
},
}),
headers: { "Content-Type": "application/json" },
method: "POST",
signal: AbortSignal.timeout(20_000),
});
if (sessionResponse.status !== 201) throw await sessionResponse.json();
const session = await sessionResponse.json();

Return session.url through an authenticated, same-origin endpoint with Cache-Control: private, no-store. Treat the complete URL as a bearer secret.

Register the message listener before assigning src.

<div style="min-width: 960px; height: 600px">
<iframe
id="smore-studio"
title="Scene camera studio"
allow="gamepad; hid; fullscreen"
referrerpolicy="no-referrer"
sandbox="allow-scripts allow-same-origin allow-pointer-lock allow-forms"
style="display:block;width:100%;height:100%;border:0"
></iframe>
</div>
const studio = document.querySelector<HTMLIFrameElement>("#smore-studio");
if (!studio) throw new Error("Studio iframe is required");
window.addEventListener("message", (event) => {
if (event.origin !== "https://embed.smore.video") return;
if (event.source !== studio.contentWindow) return;
if (event.data?.v !== 1) return;
if (event.data.type === "smore:ready") {
console.info("Smore studio is ready");
}
});
studio.src = session.url;

Never put the Smore secret key in this page. The browser needs only the short-lived embed URL returned by your backend.

The user can attach a reference image inside the studio. Smore applies it to the scene and enables recording after that edit finishes.