Quickstart: Build and Deploy Your First App
One script, start to finish: a prompt in, a published app out.
These docs are for using the AI app builder via the API. If you'd rather build visually, click and prompt in your browser, use the app builder directly — no code required:
This is the shortest complete path through the Totalum App Builder API: one script that takes a prompt and returns a published app — a Next.js app with its own database, sign-in and hosting. Copy it, run it, and you have a live URL.
Using an AI agent? If you work with Claude Code, Codex, Cursor or any other coding agent, give it the docs and it can drive the whole API for you — copy them to your clipboard or hand it the file:
#The flow
| # | Step | Endpoint | Time |
|---|---|---|---|
| 1 | Create the project and run the first prompt | POST /projects/launch | returns at once |
| 2 | Follow the run until it is done | GET /projects/:id/agent/status (+ /agent/progress) | usually a few minutes |
| 3 | Open the development preview | GET /projects/:id → temporalDevelopmentProjectUrl | instant |
| 4 | Publish | POST /projects/:id/deployments/deploy | returns at once |
| 5 | Follow the publish | GET /projects/:id/deployments/status | 2 to 5 minutes |
| 6 | Read the live URL | GET /projects/:id → productionProjectUrl | instant |
Prompts change the development version (preview + development database); a publish puts that version live (live site + live database). The development cycle explains it in one minute.
#The complete script
Save as quickstart.ts, then run it:
export TOTALUM_API_KEY=tlm_sk_your_key
npx tsx quickstart.tsThis is the whole program:
/**
* Totalum App Builder API — end-to-end quickstart.
* Launch a project, follow the agent live, publish it.
* Run: TOTALUM_API_KEY=tlm_sk_your_key npx tsx quickstart.ts
*/
const API = "https://builder-api.totalum.app/api/v1/vcaas";
const API_KEY = process.env.TOTALUM_API_KEY;
const PROMPT =
"Build a task tracker: a landing page explaining the product, and a dashboard " +
"where a signed-in user can create, complete and delete tasks.";
if (!API_KEY) throw new Error("Missing TOTALUM_API_KEY. Get one at https://platform.totalum.app/api");
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
/** Every call goes through here: unwraps `{ errors, data }` and throws on failure. */
async function api(method: string, path: string, body?: unknown) {
const res = await fetch(`${API}${path}`, {
method,
headers: { "api-key": API_KEY!, "Content-Type": "application/json" }, // server-side only
body: body ? JSON.stringify(body) : undefined,
});
const r = await res.json();
if (!res.ok || r.errors) {
throw Object.assign(new Error(r.errors?.errorMessage ?? r.error ?? res.statusText), {
code: r.errors?.errorCode ?? r.code ?? res.status,
});
}
return r.data;
}
async function main() {
// 1. Create the project AND run the first prompt. A taken id gets a suffix: use the returned one.
const launched = await api("POST", "/projects/launch", { projectId: "task-tracker", prompt: PROMPT });
const id: string = launched.projectId;
console.log(`Project "${id}" — ${launched.agent.message}`);
for (const w of launched.warnings) console.warn(`[${w.step}] ${w.errorMessage}`);
if (!launched.agent.started) await api("POST", `/projects/${id}/agent/start`, { prompt: PROMPT });
// 2. Follow the run: the stage and the files it touches, then its final message.
for (let stage = ""; ; ) {
await sleep(10_000);
const progress = await api("GET", `/projects/${id}/agent/progress`);
if (progress && progress.stage !== stage) console.log(` … ${(stage = progress.stage)} (${progress.files.length} files)`);
const status = await api("GET", `/projects/${id}/agent/status`);
if (status.status === "done") {
for (const m of status.realtimeConversation) if (m.messageType === "finished") console.log(`\n${m.message}`);
console.log(`Credits: ${status.creditsSpent}`);
break;
}
}
// 3. The development preview (read it again after every prompt).
const project = await api("GET", `/projects/${id}`);
console.log(`Preview: ${project.temporalDevelopmentProjectUrl}`);
// 4–5. Publish, then wait for it to go live.
await api("POST", `/projects/${id}/deployments/deploy`);
for (;;) {
await sleep(10_000);
const d = await api("GET", `/projects/${id}/deployments/status`);
if (d.status === "success") break;
if (d.status === "error") throw new Error(d.errorDetails?.fixSummary ?? "Publish failed");
console.log(` publishing… ${d.step ?? ""}`);
}
// 6. The live address (your custom domain once you add one).
const live = await api("GET", `/projects/${id}`);
console.log(`Live: https://${live.productionProjectUrl}`);
}
main().catch((e) => {
console.error(e.code ? `API error [${e.code}]: ${e.message}` : e);
process.exit(1);
});#What you should see
Project "task-tracker" — Process started. Estimated time: about 8 minutes…
… starting (0 files)
… working (6 files)
… build (11 files)
… deploy (11 files)
Done: a landing page and a dashboard where signed-in users manage their tasks. I signed up a test user and created, completed and deleted a task: all 200.
Credits: 14.2
Preview: https://task-tracker-dev-temporal-link-preview-k3y9x2ab.totalum-project.com
publishing… build
publishing… migration
Live: https://task-tracker.totalum-project.comThat is a real Next.js app with its own database and sign-in. Keep changing it: every change is another POST /projects/:id/agent/start, checked on the preview, then published.
#The five things that trip people up
tlm_sk_ keys carry full account access: user → your frontend → your backend → Totalum API. Never put the key in browser or mobile code. A leaked key is deleted from the API section of your account.
- Prompts and publishes are asynchronous. They answer at once; poll every 10–15 seconds. Status reads are free.
- Prompts never change the live site. Only a publish does. Show users the preview while they iterate.
- Re-read the preview URL after every prompt: it can change (it also rotates monthly).
- One heavy operation at a time per project: publishing during a prompt answers
409 AGENT_RUNNING. - Budget on the price of a prompt (3 to 50 credits), not on the 1-credit minimum balance.
#Try it in Postman
Import the OpenAPI 3.1 spec and every endpoint appears as a ready-to-send request: Import → Link → https://www.totalum.app/openapi.json, then set the apiKey variable.
#Where to go next
- AI Agent — tiers, attachments, multi-prompt batches, stopping a run.
- Database — read and write the app's data.
- Custom Domains — put the app on your own domain.
- Webhooks — get called when a run or a publish ends, instead of polling.
- Totalum MCP — hand all of this to Claude Code, Cursor or any MCP agent.
- Create Your Own AI App Builder — an open-source builder on these calls, ready to clone.
