Docs
BlogHomeStart building

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:

Download the docs fileThe short guide for agents, one .md file

#The flow

#StepEndpointTime
1Create the project and run the first promptPOST /projects/launchreturns at once
2Follow the run until it is doneGET /projects/:id/agent/status (+ /agent/progress)usually a few minutes
3Open the development previewGET /projects/:id → temporalDevelopmentProjectUrlinstant
4PublishPOST /projects/:id/deployments/deployreturns at once
5Follow the publishGET /projects/:id/deployments/status2 to 5 minutes
6Read the live URLGET /projects/:id → productionProjectUrlinstant

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:

bash
export TOTALUM_API_KEY=tlm_sk_your_key
npx tsx quickstart.ts

This is the whole program:

typescript
/**
 * 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

text
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.com

That 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

Keep the API key on your server

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.

  1. Prompts and publishes are asynchronous. They answer at once; poll every 10–15 seconds. Status reads are free.
  2. Prompts never change the live site. Only a publish does. Show users the preview while they iterate.
  3. Re-read the preview URL after every prompt: it can change (it also rotates monthly).
  4. One heavy operation at a time per project: publishing during a prompt answers 409 AGENT_RUNNING.
  5. 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.