Usage & Analytics
What your apps use, what they cost, and who visits them.
Everything is reported in credits. A project spends credits in two categories: development (prompts, publishes and other actions in the builder) and infrastructure (what the running app uses: hosting, database, files, AI, e-mail and the other built-in features).
#Get Project Usage
/api/v1/vcaas/projects/:projectId/usageapi-keyFreeWhat one project's app used, per feature, in a date range.
Path parameters
| Parameter | Type | Description |
|---|---|---|
projectId | string | The project id |
Query parameters
| Field | Type | Required | Description |
|---|---|---|---|
from | string | Yes | ISO 8601 start (2026-10-01T00:00:00Z) |
to | string | Yes | ISO 8601 end |
groupBy | string | No | "day" (default) or "month" |
env | string | No | "dev", "live" or "all" (default) |
Response fields
| Field | Type | Description |
|---|---|---|
data.range | object | { from, to } as asked |
data.groupBy | string | The bucket used |
data.env | string | dev, live or all |
data.dimensions | object[] | One row per feature: { dimension, units, unit, credits, period } (a feature with no use has units: 0) |
data.series | object[] | { ts, integration, units, unit, credits } per bucket and feature |
data.totals | object | { credits, byDimension } for the range |
data.period | object | { from, to } the figures cover |
data.refusals | object[] | Calls a feature limit refused: { feature, kind: "limit" | "disabled", cap, period, consumed, at, count } |
data.infrastructure | object | { d1: { rowsRead, rowsWritten, storageBytes }, worker: { requests, cpuMs }, storage: { bytes } } |
data.accrualPending | number | undefined | Credits used but not settled yet |
Example request
curl -H "api-key: tlm_sk_your_key" \
"https://builder-api.totalum.app/api/v1/vcaas/projects/barber-bookings/usage?from=2026-10-01T00:00:00Z&to=2026-10-08T00:00:00Z"const res = await fetch("https://builder-api.totalum.app/api/v1/vcaas/projects/barber-bookings/usage?from=2026-10-01T00:00:00Z&to=2026-10-08T00:00:00Z", {
headers: {
"api-key": process.env.TOTALUM_API_KEY,
},
});
const { errors, data } = await res.json();{
"errors": null,
"data": {
"range": { "from": "2026-10-01T00:00:00Z", "to": "2026-10-08T00:00:00Z" },
"groupBy": "day",
"env": "all",
"dimensions": [{ "dimension": "email", "units": 42, "unit": "recipients", "credits": 0.42, "period": { "from": "2026-10-01T00:00:00Z", "to": "2026-10-08T00:00:00Z" } }],
"series": [{ "ts": "2026-10-07T00:00:00Z", "integration": "email", "units": 12, "unit": "recipients", "credits": 0.12 }],
"totals": { "credits": 0.61, "byDimension": { "email": { "units": 42, "unit": "recipients", "credits": 0.42 } } },
"period": { "from": "2026-10-01T00:00:00Z", "to": "2026-10-08T00:00:00Z" },
"refusals": [],
"infrastructure": { "d1": { "rowsRead": 30211, "rowsWritten": 240, "storageBytes": 2457600 }, "worker": { "requests": 8120, "cpuMs": 40210 }, "storage": { "bytes": 1048576 } }
}
}#Get Account Usage
/api/v1/vcaas/usageapi-keyFreeThe same report for the whole account, with a per-project breakdown (100 projects a page).
Query parameters
| Field | Type | Required | Description |
|---|---|---|---|
from | string | Yes | ISO 8601 start |
to | string | Yes | ISO 8601 end |
groupBy | string | No | "day" (default) or "month" |
env | string | No | "dev", "live" or "all" (default) |
cursor | string | No | nextCursor of the previous page |
Response fields
| Field | Type | Description |
|---|---|---|
data.byProject | object[] | { projectId, label, engineVersion, totals, period } for the projects of this page |
data.account | object | { plan, balance, accountCaps: { hour, day }, consumedThisPeriod }: accountCaps are the account's spending caps in credits per hour and per 24 hours (0 when they are agreed per account) |
data.nextCursor | string | null | Next page of projects; null on the last |
data.dimensions, data.series, data.totals, data.period | As in Get Project Usage, for this page's projects |
Example request
curl -H "api-key: tlm_sk_your_key" \
"https://builder-api.totalum.app/api/v1/vcaas/usage?from=2026-10-01T00:00:00Z&to=2026-10-08T00:00:00Z"const res = await fetch("https://builder-api.totalum.app/api/v1/vcaas/usage?from=2026-10-01T00:00:00Z&to=2026-10-08T00:00:00Z", {
headers: {
"api-key": process.env.TOTALUM_API_KEY,
},
});
const { errors, data } = await res.json();{
"errors": null,
"data": {
"byProject": [{ "projectId": "barber-bookings", "label": "Barber bookings", "engineVersion": "v2", "totals": { "credits": 0.61 }, "period": { "from": "2026-10-01T00:00:00Z", "to": "2026-10-08T00:00:00Z" } }],
"account": { "plan": "starter", "balance": 412.5, "accountCaps": { "hour": 360, "day": 900 }, "consumedThisPeriod": 31.2 },
"nextCursor": null,
"dimensions": [],
"series": [],
"totals": { "credits": 0.61, "byDimension": {} },
"period": { "from": "2026-10-01T00:00:00Z", "to": "2026-10-08T00:00:00Z" }
}
}#Get Site Analytics
/api/v1/vcaas/projects/:projectId/analytics/siteapi-keyFreeVisits of the published site (or the preview): a time series, or the top values of one dimension. Counts are sampled at high traffic; unique visitors are approximate.
Path parameters
| Parameter | Type | Description |
|---|---|---|
projectId | string | The project id |
Query parameters
| Field | Type | Required | Description |
|---|---|---|---|
from | string | No | ISO 8601 start |
to | string | No | ISO 8601 end |
granularity | string | No | "minute", "hour" or "day" |
metric | string | No | Up to 4, comma-separated: page_views, hits, uniques, errors, bytes, ttfb_p50, ttfb_p95 |
dimension | string | No | Top values of: path, referrer, country, device, browser, os, status, hostname |
limit | number | No | 1–100 top values |
bots | string | No | "exclude" (default), "include" or "only" |
env | string | No | "live" (published and custom hosts) or "dev" (preview); both when omitted |
Response fields
| Field | Type | Description |
|---|---|---|
data.series | object[] | undefined | Time series: { t, <metric>: number, … } |
data.top | object[] | undefined | With dimension: { key, share, <metric>: number, … } |
data.window | object | { from, to, granularity } |
data.source | string | "wae" |
data.approximate | object | { uniques: boolean } |
data.cachedAt | string | When the figures were computed |
Example request
curl -H "api-key: tlm_sk_your_key" \
"https://builder-api.totalum.app/api/v1/vcaas/projects/barber-bookings/analytics/site?dimension=path&metric=page_views&env=live"const res = await fetch("https://builder-api.totalum.app/api/v1/vcaas/projects/barber-bookings/analytics/site?dimension=path&metric=page_views&env=live", {
headers: {
"api-key": process.env.TOTALUM_API_KEY,
},
});
const { errors, data } = await res.json();{
"errors": null,
"data": {
"top": [{ "key": "/", "share": 0.62, "page_views": 310 }, { "key": "/book", "share": 0.21, "page_views": 105 }],
"window": { "from": "2026-10-01T00:00:00.000Z", "to": "2026-10-08T00:00:00.000Z", "granularity": "day" },
"source": "wae",
"approximate": { "uniques": true },
"cachedAt": "2026-10-08T12:00:00.000Z"
}
}#Spending Analytics
/api/v1/credits/spending-analyticsapi-keyFreeCredits spent per day, by category and usage type, for charts and reports (90 days at most). Note the path: it is not under /vcaas.
Query parameters
| Field | Type | Required | Description |
|---|---|---|---|
from | string | Yes | Start date YYYY-MM-DD |
to | string | Yes | End date YYYY-MM-DD, at most 90 days after from |
projectId | string | No | Only one project |
Response fields
| Field | Type | Description |
|---|---|---|
data.daily | object[] | { date, development, infrastructure, byType, recurrent, oneTime } per day |
data.totals | object | { development, infrastructure, total, byType, recurrent, oneTime, unsplit, uncategorized } |
data.projects | string[] | Projects with spending in the range |
data.byProject | object[] | { projectId, total, development, infrastructure, recurrent, oneTime } |
byType keys are the usage types of the charges, for example prompt, deploy, create_project, start_server, project_monthly_fee and the built-in features the app used.
Example request
curl -H "api-key: tlm_sk_your_key" \
"https://builder-api.totalum.app/api/v1/credits/spending-analytics?from=2026-10-01&to=2026-10-07"const res = await fetch("https://builder-api.totalum.app/api/v1/credits/spending-analytics?from=2026-10-01&to=2026-10-07", {
headers: {
"api-key": process.env.TOTALUM_API_KEY,
},
});
const { errors, data } = await res.json();{
"errors": null,
"data": {
"daily": [{ "date": "2026-10-07", "development": 7.9, "infrastructure": 0.3, "byType": { "prompt": 7.4, "deploy": 0.5, "email": 0.1 }, "recurrent": 8.2, "oneTime": 0 }],
"totals": { "development": 7.9, "infrastructure": 0.3, "total": 8.2, "byType": { "prompt": 7.4, "deploy": 0.5, "email": 0.1 }, "recurrent": 8.2, "oneTime": 0, "unsplit": 0, "uncategorized": 0 },
"projects": ["barber-bookings"],
"byProject": [{ "projectId": "barber-bookings", "total": 8.2, "development": 7.9, "infrastructure": 0.3, "recurrent": 8.2, "oneTime": 0 }]
}
}A missing or invalid range answers 400 VALIDATION_ERROR in the usual envelope (an account with legacy projects, and the older host api-accounts.totalum.app: { "success": false, "error": "…" }).
