Docs
BlogHomeStart building

AI Agent

Drive the AI agent that builds and edits your project, in single- or multi-prompt mode.


The AI agent builds and modifies your project from natural-language prompts. Agent runs are asynchronous — you start a run, then poll for status. All endpoints require the api-key header.

#Run AI Agent

POST/api/v1/vcaas/projects/:projectId/agent/startUses credits

Start the AI agent with a prompt to build or modify your project. Supports two modes:

  • Single-prompt (default, recommended): omit multiPrompt. One prompt, 10 to 30 minutes, 10 to 40 credits.
  • Multi-prompt (rare, opt-in): include multiPrompt. A sequential batch that runs unsupervised. Each prompt still takes 10 to 30 minutes and 10 to 40 credits, so a 10-prompt batch can run for several hours and burn hundreds of credits.
When to use multi-prompt

Only use multi-prompt when a single job genuinely requires several sequential AI runs AND the user has explicitly accepted the cost and time. For everything else, send one prompt at a time — it is faster, cheaper, and lets the user steer between steps. Multi-prompt is unsupervised: no human approval step, no pause between prompts. If unsure, do NOT pass multiPrompt.

Asynchronous

Returns immediately with status "init". Poll GET /agent/status every 10–15s and show realtimeConversation messages live. Single-prompt: complete when status is "done". Multi-prompt: poll multiPrompt.status until "done"/"cancelled" — the per-prompt status flips between "init" and "done" repeatedly. After every prompt completes you MUST refresh the preview URL via GET /projects/:projectIddevelopmentUrlFieldToUse (default temporalDevelopmentProjectUrl if null/undefined).

Path parameters

ParameterTypeDescription
projectIdstringThe project to run the agent on

Body parameters

FieldTypeRequiredDescription
promptstringYes¹Single-prompt: the user instruction. Multi-prompt + letTotalumDecide: the high-level goal Totalum breaks down. Multi-prompt + prompts[]: ignored.
inputFilesarrayNoReference images/files for the agent
inputFiles[].namestringYesFile name
inputFiles[].imageDescriptionstringYesDescription of the image content
inputFiles[].urlstringYesPublic URL or uploaded file URL
multiPromptobjectNoOpt into the unsupervised multi-prompt batch mode. Omit for normal use.
multiPrompt.promptsstring[]No²Up to 50 prompts to run sequentially. Each item must be a non-empty string.
multiPrompt.letTotalumDecidebooleanNo²When true, Totalum plans the prompt list from the top-level prompt.

¹ prompt is required unless multiPrompt.prompts is provided (then it is ignored). ² When multiPrompt is present, exactly one of prompts (non-empty array, ≤ 50 items) or letTotalumDecide=true must be set.

Response fields

FieldTypeDescription
data.projectIdstringThe project ID
data.statusstringAlways "init" on success — for both single and multi-prompt mode
data.messagestringInstructions on how to poll for status (multi-prompt includes the cost/time warning)
data.multiPromptobject | undefinedPresent only when the request had multiPrompt. Detailed batch status is on GET /agent/status under multiPrompt.
data.multiPrompt.totalPromptsnumber | undefinedKnown when the caller provided prompts; absent while Totalum is still planning a letTotalumDecide batch.

Example request

bash
# Single-prompt (recommended)
curl -X POST -H "api-key: tlm_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"Create a landing page with a contact form","inputFiles":[]}' \
  https://api-accounts.totalum.app/api/v1/vcaas/projects/my-app/agent/start

# Multi-prompt with explicit list
curl -X POST -H "api-key: tlm_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"multiPrompt":{"prompts":["Set up auth","Add a Stripe checkout","Wire up the dashboard"]}}' \
  https://api-accounts.totalum.app/api/v1/vcaas/projects/my-app/agent/start

# Multi-prompt with Totalum planning
curl -X POST -H "api-key: tlm_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"Build a full SaaS billing system with auth, Stripe, and a customer portal","multiPrompt":{"letTotalumDecide":true}}' \
  https://api-accounts.totalum.app/api/v1/vcaas/projects/my-app/agent/start
Success · 200 OK
json
{
  "errors": null,
  "data": {
    "projectId": "my-app",
    "status": "init",
    "message": "Process started, can take from 10 to 30 minutes (10 to 40 credits). Fetch GET .../agent/status every 10-15 seconds to track progress."
  }
}

Multi-prompt response also includes multiPrompt:

json
{
  "errors": null,
  "data": {
    "projectId": "my-app",
    "status": "init",
    "message": "Multi-prompt run started with 3 prompts. ⚠️ Multi-prompt mode is expensive and slow — only use it when a job genuinely requires multiple sequential AI runs. Each prompt typically takes 10 to 30 minutes and costs 10 to 40 credits...",
    "multiPrompt": { "totalPrompts": 3 }
  }
}
Error · 409
json
{
  "errors": { "errorCode": "AGENT_RUNNING", "errorMessage": "An agent is already running on this project" },
  "data": null
}

Error codes

CodeHTTPMeaning
MISSING_PROJECT_ID400projectId is required
PROJECT_NOT_FOUND404Project does not exist or you don't own it
MISSING_PROMPT400prompt is required (single-prompt mode, or letTotalumDecide=true — it is the planner goal)
INVALID_MULTI_PROMPT400multiPrompt was set but neither (or both) of prompts[] and letTotalumDecide=true were provided
TOO_MANY_PROMPTS400multiPrompt.prompts exceeds the 50-item limit
INVALID_PROMPT_ITEM400A multiPrompt.prompts entry is not a non-empty string
AGENT_RUNNING409An agent is already running on this project
AUTO_EXECUTION_ALREADY_ACTIVE409A previous multi-prompt batch is still active (executing/paused/awaiting approval). Cancel it first.
DEPLOYMENT_RUNNING409Cannot start agent while a deployment is in progress
RECOVERY_RUNNING409Cannot start agent while a version recovery is in progress — poll versionRecovery until null, then retry
INSUFFICIENT_CREDITS402Minimum 50 credits required to start agent (multi-prompt typically needs many more)
PROMPT_SECURITY_VIOLATION400Prompt failed security validation

#Get Agent Status

GET/api/v1/vcaas/projects/:projectId/agent/statusFree

Poll to track agent progress and get real-time messages. Poll every 10–15 seconds.

Refresh preview URL when done

When status becomes "done", you MUST refresh the preview URL by calling GET /projects/:projectId and reading developmentUrlFieldToUse ("temporalDevelopmentProjectUrl" for the live server or "cachedDevelopmentUrl" for a cached snapshot). If developmentUrlFieldToUse is null or undefined, default to temporalDevelopmentProjectUrl. The URL can change after each agent run.

Path parameters

ParameterTypeDescription
projectIdstringThe project to poll

Response fields

FieldTypeDescription
data.projectIdstringThe project ID
data.statusstring"init" (a prompt is currently running) | "done" (last prompt finished) | "idle" (never run). For multi-prompt runs this flips between "init" and "done" repeatedly as the batch advances — poll multiPrompt.status to track the whole batch.
data.startedAtstring | nullISO 8601 start time of the current prompt (not the whole batch)
data.realtimeConversationarraySingle-prompt: messages from the current run. Multi-prompt: messages from the whole batch (scoped to multiPrompt.startedAt).
data.realtimeConversation[].authorstring"user" | "agent"
data.realtimeConversation[].messagestringThe message text
data.realtimeConversation[].messageTypestring"regular" | "starting" | "building" | "finished" | "error" | "limit-reached"
data.realtimeConversation[].createdAtstringISO 8601 message date
data.realtimeConversation[].versionIdstring | undefinedVersion created at this step
data.realtimeConversation[].secretKeysNeededobject | undefinedSecrets the agent needs (key: { isProvided, description })
data.realtimeConversation[].gitDiffUrlstring | undefinedDiff URL for this step
data.creditsSpentnumber | undefinedCredits spent on the current prompt (present when status is "done")
data.multiPromptobject | nullPresent only when a multi-prompt batch exists. The canonical signal for "is a multi-prompt run in flight" — poll its status until "done"/"cancelled".
data.multiPrompt.statusstring"planning" | "executing" | "paused" | "done" | "cancelled"
data.multiPrompt.totalPromptsnumberNumber of prompts in the batch (0 during planning)
data.multiPrompt.currentPromptIndexnumberIndex of the in-flight prompt; -1 before the first one starts
data.multiPrompt.promptsarrayOrdered list of prompts in the batch
data.multiPrompt.prompts[].ordernumberPosition in the batch
data.multiPrompt.prompts[].promptstringThe prompt text
data.multiPrompt.prompts[].statusstring"pending" | "executing" | "done" | "failed"
data.multiPrompt.startedAtstringISO 8601 start time of the whole batch
data.multiPrompt.updatedAtstringISO 8601 last change to the batch state

Example request

bash
curl -H "api-key: tlm_sk_your_key" \
  https://api-accounts.totalum.app/api/v1/vcaas/projects/my-app/agent/status
Success · 200 OK
json
{
  "errors": null,
  "data": {
    "projectId": "my-app",
    "status": "init",
    "startedAt": "2026-03-11T10:35:00.000Z",
    "realtimeConversation": [
      {
        "author": "agent",
        "message": "Creating the project structure...",
        "messageType": "building",
        "createdAt": "2026-03-11T10:36:00.000Z"
      },
      {
        "author": "agent",
        "message": "Project built successfully!",
        "messageType": "finished",
        "versionId": "v_abc123",
        "gitDiffUrl": "https://...",
        "secretKeysNeeded": {
          "STRIPE_SECRET_KEY": { "isProvided": false, "description": "Required for processing payments" }
        },
        "createdAt": "2026-03-11T10:50:00.000Z"
      }
    ],
    "creditsSpent": 3.2,
    "multiPrompt": null
  }
}

Multi-prompt example (running prompt 2 of 3):

json
{
  "errors": null,
  "data": {
    "projectId": "my-app",
    "status": "init",
    "startedAt": "2026-03-11T11:05:00.000Z",
    "realtimeConversation": [ /* messages from the whole batch */ ],
    "multiPrompt": {
      "status": "executing",
      "totalPrompts": 3,
      "currentPromptIndex": 1,
      "prompts": [
        { "order": 0, "prompt": "Set up auth",        "status": "done" },
        { "order": 1, "prompt": "Add Stripe checkout", "status": "executing" },
        { "order": 2, "prompt": "Wire up dashboard",   "status": "pending" }
      ],
      "startedAt": "2026-03-11T10:35:00.000Z",
      "updatedAt": "2026-03-11T11:05:00.000Z"
    }
  }
}
Error · 404
json
{
  "errors": { "errorCode": "PROJECT_NOT_FOUND", "errorMessage": "Project does not exist or you don't own it" },
  "data": null
}

Error codes

CodeHTTPMeaning
MISSING_PROJECT_ID400projectId is required
PROJECT_NOT_FOUND404Project does not exist or you don't own it

#Get Full Conversation

GET/api/v1/vcaas/projects/:projectId/agent/full-conversationFree

Retrieve the complete conversation history across all agent runs (not just the current one).

Path parameters

ParameterTypeDescription
projectIdstringThe project whose conversation to fetch

Response fields

FieldTypeDescription
data.projectIdstringThe project ID
data.conversationarrayAll messages from all agent runs
data.conversation[].authorstring"user" | "agent"
data.conversation[].messagestringThe message text
data.conversation[].messageTypestring"regular" | "starting" | "building" | "finished" | "error" | "limit-reached"
data.conversation[].createdAtstringISO 8601 message date
data.conversation[].versionIdstring | undefinedVersion created at this step
data.conversation[].secretKeysNeededobject | undefinedAPI keys the agent needs (key: { isProvided, description }). Add missing keys as project secrets.
data.conversation[].gitDiffUrlstring | undefinedDiff URL for this step

Example request

bash
curl -H "api-key: tlm_sk_your_key" \
  https://api-accounts.totalum.app/api/v1/vcaas/projects/my-app/agent/full-conversation
Success · 200 OK
json
{
  "errors": null,
  "data": {
    "projectId": "my-app",
    "conversation": [
      { "author": "user", "message": "Create a landing page", "messageType": "regular", "createdAt": "..." },
      { "author": "agent", "message": "Building project structure...", "messageType": "building", "createdAt": "..." },
      {
        "author": "agent",
        "message": "Project built successfully!",
        "messageType": "finished",
        "versionId": "v_abc123",
        "gitDiffUrl": "https://...",
        "secretKeysNeeded": {
          "STRIPE_SECRET_KEY": { "isProvided": false, "description": "Required for processing payments" }
        },
        "createdAt": "..."
      }
    ]
  }
}
Error · 404
json
{
  "errors": { "errorCode": "PROJECT_NOT_FOUND", "errorMessage": "Project does not exist or you don't own it" },
  "data": null
}

Error codes

CodeHTTPMeaning
MISSING_PROJECT_ID400projectId is required
PROJECT_NOT_FOUND404Project does not exist or you don't own it

#Stop Agent

POST/api/v1/vcaas/projects/:projectId/agent/stopFree

Send a stop signal to a running agent.

Path parameters

ParameterTypeDescription
projectIdstringThe project whose agent to stop

Response fields

FieldTypeDescription
data.messagestringConfirmation message

Example request

bash
curl -X POST -H "api-key: tlm_sk_your_key" \
  https://api-accounts.totalum.app/api/v1/vcaas/projects/my-app/agent/stop
Success · 200 OK
json
{ "errors": null, "data": { "message": "Agent stop signal sent" } }
Error · 400
json
{
  "errors": { "errorCode": "NO_PROCESS_RUNNING", "errorMessage": "No agent process is currently running" },
  "data": null
}

Error codes

CodeHTTPMeaning
MISSING_PROJECT_ID400projectId is required
PROJECT_NOT_FOUND404Project does not exist or you don't own it
NO_PROCESS_RUNNING400No agent process is currently running

#Concurrency rules

  • Only one heavy operation at a time per project: agent, deployment, version recovery, or server start.
  • If deploy or recover is called and the server is not active, it auto-starts (charges START_SERVER credits) and returns SERVER_NOT_READY. Poll GET /projects/:projectId until agentServerStatus is "Active", then retry.
  • Agent start IS allowed during server operations (the backend waits internally).

#Complete integration flow

  1. Ensure project existsPOST /projects, body { "projectId": "my-app" }. Create one if the user doesn't already have a project.
  2. Send prompt to AI agentPOST /projects/my-app/agent/start, body { "prompt": "Build a SaaS landing page" }. Async, takes 6–15 min.
  3. Poll agent status (every 10–15s)GET /projects/my-app/agent/status. "init" = working (show realtimeConversation), "done" = finished (creditsSpent = total). On "done", immediately call GET /projects/:projectId and refresh the preview URL.
    • 3.1 Refresh preview URL (on page load, page refresh, and after every prompt finishes) — GET /projects/my-app, read developmentUrlFieldToUse: use cachedDevelopmentUrl (static snapshot while the server is archived) or temporalDevelopmentProjectUrl (live dev server); default temporalDevelopmentProjectUrl if null/undefined. Reload the iframe when the URL changes.
  4. PublishPOST /projects/my-app/deployments/deploy. Builds, deploys, and assigns a public URL. Takes 1–3 min.
  5. Poll deployment status (every 10–15s)GET /projects/my-app/deployments/status; on "success", get productionProjectUrl from GET /projects/my-app.
  6. (Optional) Custom domainPUT /projects/my-app/domain, body { "hostname": "app.yourdomain.com" }; configure the returned DNS records; poll customDomain.status until "active".
Key integration principles
  • Agent and deployment are ASYNCHRONOUS — always poll for status.
  • Show real-time agent conversation messages during generation.
  • NEVER call the Totalum API from frontend code — always go through your backend server.
  • ALWAYS refresh the dev preview URL (GET /projects/:projectId) on page load, page refresh, and after each prompt; use developmentUrlFieldToUse; default temporalDevelopmentProjectUrl if null/undefined.
  • On the dev preview, don't show the production URL; display an open-in-blank link so the user always sees the realtime dev preview (production may be outdated until published).
  • Keep the API key secret — it must never leave your backend server.

#Global error codes

All errors are shaped as { "errors": { "errorCode": "CODE", "errorMessage": "..." }, "data": null }.

CodeHTTPMeaning
INSUFFICIENT_CREDITS402Not enough credits for this operation
PROJECT_CREDIT_LIMIT_REACHED403Project monthly credit limit reached for that category
PROJECT_NOT_ALLOWED403API key doesn't have access to this project
PROJECT_NOT_FOUND404Project doesn't exist or you don't own it
AGENT_RUNNING409Agent already running on this project
DEPLOYMENT_RUNNING409A deployment is in progress
RECOVERY_RUNNING409A version recovery is in progress
SERVER_NOT_READY409Server auto-starting, poll until Active
NO_DEPLOYMENT404No deployment found. Deploy first and wait until status is "success"
MISSING_PROMPT400prompt field is required
MISSING_PROJECT_ID400projectId field is required
INVALID_PROJECT_NAME400Invalid projectId format
INVALID_PROJECT_NAME_LENGTH400Project name must be 4-35 characters
PROJECT_ALREADY_EXISTS409A project with this ID already exists
PLAN_NOT_API400Only API plan projects can be deleted
PROMPT_SECURITY_VIOLATION400Prompt failed security validation
NO_PROCESS_RUNNING400No agent process is currently running
MISSING_FILE400file field is required (multipart)
UPLOAD_FAILED500File upload failed
MISSING_VERSION_ID400versionId is required
MISSING_SECRET_FIELDS400secretName and secretValue are required
INVALID_SECRET_KEY_NAME400Invalid secret key name format
MISSING_SECRET_ID400secretId is required
MISSING_HOSTNAME400hostname is required
MISSING_TABLE_NAME400tableName is required
GET_ACCOUNT_ERROR400Internal error fetching account info
LIST_PROJECTS_ERROR400Internal error listing projects
RATE_LIMIT_EXCEEDED429Too many requests (max 10 project creations per 60s)
MISSING_WEBHOOK_FIELDS400url and event are required
INVALID_WEBHOOK_URL400Webhook URL must use HTTPS
INVALID_WEBHOOK_EVENT400Event not in allowed list
WEBHOOK_EVENT_ALREADY_EXISTS409A webhook for this event already exists
WEBHOOK_NOT_FOUND404Webhook not found
MISSING_GITHUB_FIELDS400token and repositoryFullName are required
GITHUB_VALIDATION_FAILED400Token invalid, missing permissions, or repo not found
GITHUB_SECRET_STORE_ERROR400Failed to store GitHub credentials
GITHUB_SYNC_FAILED400Initial sync with GitHub failed
GITHUB_NOT_CONNECTED400GitHub is not connected to this project
GITHUB_PULL_ERROR400Failed to pull changes from GitHub
MISSING_LIMIT_FIELDS400At least one credit limit field is required
INVALID_LIMIT400Credit limit must be a positive number
INVALID_SYNC_DIRECTION400syncDirection must be "totalum_to_github" or "github_to_totalum"