# Totalum App Builder API — Usage & Analytics

This file is the complete reference for this area. The short guide for agents is https://www.totalum.app/totalum-api.md.

- Base URL: `https://builder-api.totalum.app/api/v1/vcaas`
- Authentication: header `api-key: tlm_sk_…` on every request, from a server only.
- Response envelope: `{ "errors": null | { "errorCode", "errorMessage", "errorDetails?" }, "data": … }`.


---

# 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

```endpoint
method: GET
path: /api/v1/vcaas/projects/:projectId/usage
cost: Free
```

What 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**

```bash
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"
```

:::success Success · 200 OK
```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

```endpoint
method: GET
path: /api/v1/vcaas/usage
cost: Free
```

The 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](https://www.totalum.app/docs/limits#account-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](#get-project-usage), for this page's projects |

**Example request**

```bash
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"
```

:::success Success · 200 OK
```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

```endpoint
method: GET
path: /api/v1/vcaas/projects/:projectId/analytics/site
cost: Free
```

Visits 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**

```bash
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"
```

:::success Success · 200 OK
```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

```endpoint
method: GET
path: /api/v1/credits/spending-analytics
cost: Free
```

Credits 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**

```bash
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"
```

:::success Success · 200 OK
```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": "…" }`).
