Source Code & Uploads
Take your code anywhere; give the agent your files.
The source code is yours: a standard Next.js project you can run locally or host yourself (For developers). Uploaded files are stored in the project's file storage.
#Download Source Code
/api/v1/vcaas/projects/:projectId/source-codeapi-key2 creditsA short-lived link to the project's current code as an archive. With the project's .env (Get Project Env) it runs locally with npm ci && npm run dev. Downloading source code is included on paid plans.
Path parameters
| Parameter | Type | Description |
|---|---|---|
projectId | string | The project id |
Query parameters
| Field | Type | Required | Description |
|---|---|---|---|
intent | string | No | view when you only show the code (for example in a code viewer), which works on every plan |
Response fields
| Field | Type | Description |
|---|---|---|
data.filesCount | number | Files in the archive |
data.lastCommitSha | string | undefined | Commit of the current version |
data.downloadUrl | string | null | Signed download URL (valid a few minutes) |
Example request
curl -H "api-key: tlm_sk_your_key" \
https://builder-api.totalum.app/api/v1/vcaas/projects/barber-bookings/source-codeconst res = await fetch("https://builder-api.totalum.app/api/v1/vcaas/projects/barber-bookings/source-code", {
headers: {
"api-key": process.env.TOTALUM_API_KEY,
},
});
const { errors, data } = await res.json();{ "errors": null, "data": { "filesCount": 96, "lastCommitSha": "9f2c1ab4d3e5f60718293a4b5c6d7e8f90a1b2c3", "downloadUrl": "https://files.totalum.app/source/barber-bookings.tar.gz?sig=…" } }Error codes
| Code | HTTP | Meaning |
|---|---|---|
PLATFORM_CAPABILITY_QUOTA_REACHED | 403 | Source download is not included on your plan (upgradePlan says which is needed) |
INSUFFICIENT_CREDITS | 402 | Not enough credits |
#Upload File
/api/v1/vcaas/projects/:projectId/files/uploadapi-keyFreeUpload one file (up to 20 MB) as multipart/form-data with the field file. Use the returned url in inputFiles of Run AI Agent. For a bigger file, pass its own public URL in inputFiles instead; no upload is needed.
Path parameters
| Parameter | Type | Description |
|---|---|---|
projectId | string | The project id |
Body parameters(multipart/form-data)
| Field | Type | Required | Description |
|---|---|---|---|
file | file | Yes | The file, up to 20 MB |
private | string | No | "true" = stored privately (served only through signed links) |
Response fields
| Field | Type | Description |
|---|---|---|
data.fileNameId | string | The stored file's key: the key that List Files shows and Delete Files takes |
data.url | string | Its URL (for inputFiles); "" for a private file |
data.private | boolean | undefined | true for a private file |
data.createdAt | string | When it was stored (ISO 8601) |
Example request
curl -X POST \
-H "api-key: tlm_sk_your_key" \
-F "file=@./logo.png" \
https://builder-api.totalum.app/api/v1/vcaas/projects/barber-bookings/files/uploadimport { readFile } from "node:fs/promises";
const form = new FormData();
form.append("file", new Blob([await readFile("./logo.png")]), "logo.png");
const res = await fetch("https://builder-api.totalum.app/api/v1/vcaas/projects/barber-bookings/files/upload", {
method: "POST",
headers: {
"api-key": process.env.TOTALUM_API_KEY,
},
body: form,
});
const { errors, data } = await res.json();{
"errors": null,
"data": {
"fileNameId": "p/barber-bookings/01JC8Z3K4M5N6P7Q8R9S0T1V2W.png",
"url": "https://files.totalum-project.com/p/barber-bookings/01JC8Z3K4M5N6P7Q8R9S0T1V2W.png",
"createdAt": "2026-11-01T10:15:00.000Z"
}
}Error codes
| Code | HTTP | Meaning |
|---|---|---|
MISSING_FILE | 400 | No multipart field file |
FILE_TOO_LARGE | 413 | Over 20 MB — pass the file's own URL in inputFiles instead |
RATE_LIMITED | 429 | More than 300 uploads a minute |
#List Files
/api/v1/vcaas/projects/:projectId/filesapi-keyFreeThe files stored in the project, newest first: the ones uploaded through Upload File and the ones the app itself stored. Projects on the new engine only; a legacy project answers 400 ENGINE_NOT_SUPPORTED.
Path parameters
| Parameter | Type | Description |
|---|---|---|
projectId | string | The project id |
Query parameters
| Field | Type | Required | Description |
|---|---|---|---|
folder | string | No | Only the files stored in this folder or its subfolders |
type | string | No | Content type, e.g. application/pdf, or its first part, e.g. image |
name | string | No | Part of the file name (not case-sensitive) |
createdFrom | string | No | Stored at or after this time (ISO 8601) |
createdTo | string | No | Stored at or before this time (ISO 8601) |
cursor | string | No | nextCursor of the previous page |
limit | number | No | Page size. Default 100, max 100 |
Response fields
| Field | Type | Description |
|---|---|---|
data.items[].key | string | The file's key (the fileNameId of its upload) |
data.items[].fileName | string | File name |
data.items[].fileSize | number | Size in bytes |
data.items[].contentType | string | e.g. image/png |
data.items[].visibility | string | "public-by-link" or "private" |
data.items[].createdAt | string | When it was stored (ISO 8601) |
data.nextCursor | string | null | Pass it as cursor for the next page; null on the last page |
Example request
curl -H "api-key: tlm_sk_your_key" \
"https://builder-api.totalum.app/api/v1/vcaas/projects/barber-bookings/files?type=image&limit=20"const res = await fetch("https://builder-api.totalum.app/api/v1/vcaas/projects/barber-bookings/files?type=image&limit=20", {
headers: {
"api-key": process.env.TOTALUM_API_KEY,
},
});
const { errors, data } = await res.json();{
"errors": null,
"data": {
"items": [
{
"key": "p/barber-bookings/01JC8Z3K4M5N6P7Q8R9S0T1V2W.png",
"fileName": "logo.png",
"fileSize": 48213,
"contentType": "image/png",
"visibility": "public-by-link",
"createdAt": "2026-11-01T10:15:00.000Z"
}
],
"nextCursor": null
}
}Error codes
| Code | HTTP | Meaning |
|---|---|---|
VALIDATION_ERROR | 400 | A filter is invalid, e.g. limit over 100 or a date that is not ISO 8601 |
ENGINE_NOT_SUPPORTED | 400 | A legacy project |
PROJECT_NOT_FOUND | 404 | Project does not exist or you don't own it |
#Delete Files
/api/v1/vcaas/projects/:projectId/filesapi-keyFreeDelete stored files by key, for example when a user asks you to erase their documents. Up to 100 keys per call. Free at any balance, and safe to repeat: a key that is already deleted (or never existed) comes back in notFound, not as an error. Projects on the new engine only; a legacy project answers 400 ENGINE_NOT_SUPPORTED.
What happens to a deleted file
- Its public URL stops being served everywhere within 1 hour: a location of Cloudflare's network that cached the file can keep serving its copy for up to 1 hour after the delete, then the URL answers
410 Gone(404once the recovery copy is gone). A browser that already downloaded the file can keep its own copy for up to 1 hour after that download. - Signed URLs to it stop working at once, including the ones created before the delete.
- It disappears from List Files and stops counting toward the project's storage.
- A recovery copy is kept for 30 days, then removed for good (the nightly backup copy too).
- Deleting the project deletes all of its files.
Path parameters
| Parameter | Type | Description |
|---|---|---|
projectId | string | The project id |
Body parameters
| Field | Type | Required | Description |
|---|---|---|---|
keys | string[] | Yes | 1 to 100 file keys: the fileNameId of Upload File, the key of List Files |
Response fields
| Field | Type | Description |
|---|---|---|
data.deleted | string[] | The keys deleted by this call |
data.notFound | string[] | The keys with no file to delete (already deleted, or never stored) |
Example request
curl -X DELETE \
-H "api-key: tlm_sk_your_key" \
-H "Content-Type: application/json" \
-d '{"keys": ["p/barber-bookings/01JC8Z3K4M5N6P7Q8R9S0T1V2W.png"]}' \
https://builder-api.totalum.app/api/v1/vcaas/projects/barber-bookings/filesconst res = await fetch("https://builder-api.totalum.app/api/v1/vcaas/projects/barber-bookings/files", {
method: "DELETE",
headers: {
"api-key": process.env.TOTALUM_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
"keys": [
"p/barber-bookings/01JC8Z3K4M5N6P7Q8R9S0T1V2W.png"
]
}),
});
const { errors, data } = await res.json();{
"errors": null,
"data": {
"deleted": ["p/barber-bookings/01JC8Z3K4M5N6P7Q8R9S0T1V2W.png"],
"notFound": []
}
}{
"errors": {
"errorCode": "FILE_KEY_FORBIDDEN",
"errorMessage": "Not files of project barber-bookings: p/other-project/01JC8Z3K4M5N6P7Q8R9S0T1V2X.pdf",
"errorDetails": { "keys": ["p/other-project/01JC8Z3K4M5N6P7Q8R9S0T1V2X.pdf"] }
},
"data": null
}Error codes
| Code | HTTP | Meaning |
|---|---|---|
VALIDATION_ERROR | 400 | keys is missing, empty, over 100, or not all strings |
ENGINE_NOT_SUPPORTED | 400 | A legacy project |
FILE_KEY_FORBIDDEN | 403 | A key is not one of this project's files (another project's, or malformed). Nothing is deleted |
PROJECT_NOT_FOUND | 404 | Project does not exist or you don't own it |
