Legacy Projects — What Differs
Legacy projects keep working. Here is exactly what differs.
Projects created before 8 October 2026, or created without the v2 engine, run on Totalum's first engine and are called legacy projects. Nothing changes for them: every endpoint they use keeps its path, body, response and errors, with no end date and no migration to do. A project's engine is in Get Project: engineVersion: "v2" means the current engine; no engineVersion means legacy. Never infer it from the creation date.
This page is the one list of differences. The rest of the API reference describes the current engine.
#What legacy projects do not have
These endpoints answer 400 ENGINE_NOT_SUPPORTED on a legacy project:
- Project state and control: Get Project State, Get Agent Progress, Pause / Resume, Rotate Preview URL.
- Agent settings: the project system prompt and custom MCP servers, Resume Multi-Prompt Batch.
- Database: backups, restore points, point-in-time restore and the move to Turso; Ask Database, Get Database Usage, Undo Agent Run Database Change.
- Operations: Get Project Logs, Get Project Usage, Get Site Analytics, Feature Limits, the per-visitor Rate Limit, Scheduled Jobs.
- Keys and files: project API keys and Get Project Env.
- Ship: Mobile Apps, Payments and the project webhook, Visual Edits, and attaching a domain bought on Totalum.
- Options: EU-only data (
dataResidency: "eu"answers400 DATA_RESIDENCY_UNAVAILABLE), the agent tiers (cheap,normal,expensive,auto).
#What behaves differently
| Endpoint | On a legacy project |
|---|---|
| Run AI Agent | No agent tiers: the legacy model parameter keeps the values it had before them. Leave it out (recommended) to run the default, most capable model; its one other value selects a faster, lower-cost model. An unknown value is ignored with a note in data.warnings and the default runs. effort (low, medium, high, xhigh) and fastMode are honoured. A prompt takes 5–40 minutes |
| List Projects | productionProjectUrl is always <projectId>.totalum-project.com: the custom domain shows only on Get Project |
| Get Project | No engineVersion and none of the v2 fields (preview, sandbox, lifecycle, currentRun, dataResidency, operations…). The preview can also be a cached snapshot: use the field named by developmentUrlFieldToUse (cachedDevelopmentUrl or temporalDevelopmentProjectUrl) |
| Deploy to Production / status | No confirmDestructive; the status carries versionId instead of deploymentId, step and liveUrl |
| Write File Content | Answers rebuildRequired: true: call Rebuild Project to see the change |
| Upload File | Up to 8 MB |
| Clear Agent Context | The next prompt still receives the recent conversation |
| Export / Import | An export code of a legacy project ends in .zip and imports only into a legacy project, never on a new account (409 ENGINE_LEGACY_UNAVAILABLE) (and a current-engine code only into a current-engine project: 409 ENGINE_MISMATCH) |
| Get Credit Costs | ?engine=legacy returns the legacy price list |
| Fixed prices | Legacy projects use the legacy price list and pay no monthly hosting fees |
Request-level refusals (ROUTE_NOT_FOUND, METHOD_NOT_ALLOWED, INVALID_JSON, PAYLOAD_TOO_LARGE) answer in the JSON envelope on the current engine only. On a legacy project, and on the older host api-accounts.totalum.app, 403 VCAAS_INSUFFICIENT_CREDITS answers { "error", "code" }, a secret that fails validation { "success": false, "message", "errors": [...] }, and INVALID_WEBHOOK_EVENT lists only agent.prompt.finished and project.credit_limit.reached (every event is still accepted on the current engine).
#The database endpoints
Only the database endpoints are a different set. Legacy projects keep the legacy database endpoints (a JSON query language over the legacy project database); current-engine projects use the SQL-shaped Database endpoints. Calling one set on the other engine's project answers 400 PROJECT_ENGINE_MISMATCH, and errorDetails.useEndpoint names the endpoint to call. Paths are relative to https://builder-api.totalum.app/api/v1/vcaas.
| Original engine (unchanged) | New engine |
|---|---|
GET /projects/:projectId/database/tables-structure | GET /projects/:projectId/database/schema |
POST /projects/:projectId/database/query | POST /projects/:projectId/database/rows |
POST /projects/:projectId/database/records | POST /projects/:projectId/database/records |
PATCH /projects/:projectId/database/records/:recordId | PATCH /projects/:projectId/database/records/:recordId |
DELETE /projects/:projectId/database/records/:recordId | DELETE /projects/:projectId/database/records/:recordId |
POST /projects/:projectId/database/records/:recordId/link | POST /projects/:projectId/database/relations |
DELETE /projects/:projectId/database/records/:recordId/link | POST /projects/:projectId/database/relations |
| (none — new-engine only) | POST /projects/:projectId/database/records/bulk |
| (none — new-engine only) | POST /projects/:projectId/database/sql |
The three records routes keep their path; on a current-engine project their body is { env, table, data }.
{
"errors": {
"errorCode": "PROJECT_ENGINE_MISMATCH",
"errorMessage": "This project uses the new engine. Use POST /projects/:projectId/database/rows instead of POST /projects/:projectId/database/query — see https://www.totalum.app/docs/api/migration-v2",
"errorDetails": { "engine": "v2", "useEndpoint": "POST /projects/:projectId/database/rows", "docsUrl": "https://www.totalum.app/docs/api/migration-v2" }
},
"data": null
}Side by side — paid orders of 100 or more, newest first:
- POST /projects/my-app/database/query
- {"tableName":"orders","queryOptions":{"_filter":{"status":"paid","total":{"gte":100}},"_sort":{"createdAt":-1},"_limit":20}}
+ POST /projects/my-app/database/rows
+ {"env":"live","table":"orders","filter":{"and":[{"column":"status","op":"eq","value":"paid"},{"column":"total","op":"gte","value":100}]},"sort":[{"column":"created_at","dir":"desc"}],"page":{"limit":20}}#Creating a project on an engine
New projects are created on the current engine. Send "engineVersion": "v2" on Create or Launch Project to require it (a refusal creates nothing). "engineVersion": "legacy" still creates a legacy project for an integration that depends on the legacy database endpoints.
#Choose The Engine For New Projects
/api/v1/vcaas/account/v2-opt-inapi-keyFreeWhile the current engine is offered as an opt-in, this switch makes the account's new projects use it (read it with GET /api/v1/vcaas/account/v2-opt-in: { v2OptIn, available }, where available says whether the switch decides anything right now). The account's own key only.
Body parameters
| Field | Type | Required | Description |
|---|---|---|---|
v2OptIn | boolean | Yes | true = new projects on the current engine |
Response fields
| Field | Type | Description |
|---|---|---|
data.v2OptIn | boolean | The switch now |
Example request
curl -X PUT \
-H "api-key: tlm_sk_your_key" \
-H "Content-Type: application/json" \
-d '{"v2OptIn":true}' \
https://builder-api.totalum.app/api/v1/vcaas/account/v2-opt-inconst res = await fetch("https://builder-api.totalum.app/api/v1/vcaas/account/v2-opt-in", {
method: "PUT",
headers: {
"api-key": process.env.TOTALUM_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
"v2OptIn": true
}),
});
const { errors, data } = await res.json();{ "errors": null, "data": { "v2OptIn": true } }Error codes
| Code | HTTP | Meaning |
|---|---|---|
INVALID_V2_OPT_IN | 400 | v2OptIn is not a boolean |
API_KEY_SCOPE_FORBIDDEN | 403 | This key cannot change account settings |
