Usage and units
Mandatum meters what your integration does, in four units. The same unit names appear on every MCP result, in the REST citation response, and in the usage endpoint and page, so you can reconcile what a gateway or a direct caller reports.
The four units #
| Unit | Counts | Written by |
|---|---|---|
call |
One authenticated tool call or metered REST request, whatever its outcome. | Every MCP tool call and every metered REST route. A request refused with 401 before authentication is not counted. |
verified_citation |
One citation that resolved (verdict: resolved). Unresolved citations are free. |
verifyCitation, over MCP and POST /api/v1/citations/verify. |
gap_report |
One new gap report issuance. A reused issuance writes none. | POST /api/v1/gaps/{analysisId}/issue and the issueGapReport tool. Written by the database in the same transaction as the issuance. |
tokens |
Model input and output tokens for a model call the app made on your behalf, with an estimated cost. | The app's own agent runs. Not written by a direct tool call. |
The units on a response describe what the call bills. A failed call returns no _meta.datafed.units. A citation call that resolves nothing returns verified_citation with count: 0, so the entry is always present on the REST response. The usage rows above are the metering record, and they include failed authenticated calls.
Units on MCP and REST responses #
Every successful MCP tool result carries _meta.datafed.units:
{
"_meta": {
"datafed": {
"units": [{ "unit": "call", "count": 1 }]
}
}
}For verifyCitation the unit is verified_citation, with one count per resolved citation: [{ "unit": "verified_citation", "count": 3 }].
POST /api/v1/citations/verify returns the same array in its body as units. The count there is the number of results whose verdict is resolved, so you can read your bill from the response itself.
Prices for the platform are on the pricing page. The price table behind est_cost_usd is the one described below.
The usage endpoint #
GET /api/v1/usage returns metered totals for the key's workspace over a window.
- Scope:
usage:read. A key without it gets403with"code": "tool_not_enabled_for_key". - Who: the key's owner must be a workspace owner or admin. Other members get
403, whatever the key's scopes. - Scope of data: only the key's own workspace.
| Query parameter | Default | Meaning |
|---|---|---|
from |
The first instant of the current UTC month | ISO-8601 date or timestamp, inclusive. |
to |
Now | ISO-8601 date or timestamp, exclusive. |
group |
none |
none for surface and unit totals only, day for UTC dates, key for each credential (with its name), or tool. |
from must be earlier than to. An unparseable value, or a group other than the four above, returns 400.
curl "$MANDATUM_BASE/api/v1/usage?from=2026-10-01&to=2026-10-22&group=key" \
-H "Authorization: Bearer $MANDATUM_API_KEY"{
"window": { "from": "2026-10-01T00:00:00.000Z", "to": "2026-10-22T00:00:00.000Z" },
"group": "key",
"totals": {
"by_unit": {
"call": { "count": 1204, "est_cost_usd": 0 },
"verified_citation": { "count": 87, "est_cost_usd": 0 },
"gap_report": { "count": 0, "est_cost_usd": 0 },
"tokens": { "count": 88210, "est_cost_usd": 0.4132 }
},
"est_cost_usd": 0.4132
},
"rows": [
{
"key": "3f1c…",
"key_name": "quickstart",
"surface": "rest",
"unit": "call",
"count": 1204,
"est_cost_usd": null,
"input_tokens": null,
"output_tokens": null
}
]
}by_unit always lists all four units, zero-filled. totals.est_cost_usd is null when no row in the window has a cost.
Where usage is recorded #
Each row records the surface it came from:
| Surface | What writes a row |
|---|---|
mcp |
Every MCP request, including tools/list. |
rest |
GET and POST /api/v1/statutes/search, GET /api/v1/statutes/{cap}, POST /api/v1/citations/verify, and POST /api/v1/gaps/{analysisId}/issue. |
app |
Model calls made by the app's own agent runs. |
POST /api/v1/gaps/{analysisId}/issue writes two rows, by design: one call row from the route, and one gap_report row from the database function that issues the report, in the same transaction. A reused issuance writes the call row only. Because the database writes the gap_report row, a retry cannot bill twice.
Other REST routes (gaps analysis, benchmark, skills, matters, documents, runs and webhooks) are not metered yet. A call to them writes no row. Read the totals with that in mind: they are the metered calls, not a record of everything a key did.
GET /api/v1/runs/{id} reports usage for a workflow run. It sums that run's tokens rows, and it is null when none were recorded. null means "not measured", not zero.
Costs are estimates #
est_cost_usd is computed from the model price table. It is an estimate for planning and for spotting outliers. It is not an invoice. The price table is provisional and will be confirmed before any figure is billed, so do not reconcile billing from these numbers yet.
The usage page #
Workspace owners and admins can see the same totals in the app at /w/<workspace>/settings/usage, with a CSV export. The page is not linked from the sidebar yet, so open it from the address bar.