A read-only JSON view of the PRISM CAFE base: the chart of accounts, the dimensions, the rules, and any single record with its texts.
Every path under /api/v1/ needs a shared key, sent as a header.
Ask Rasmus for it.
curl -H "X-API-Key: YOUR_KEY" https://data.prismcafe.dk/api/v1/overview
Without a valid key the answer is 401. This page and
/health are the only paths that need no key, and neither of them
reads the base.
/api/v1/ lists them and is the one to build against: it is
generated from the same list the server routes on, so it cannot fall behind.
| Path | What it answers |
|---|---|
/api/v1/overview |
How much the base holds, per database and per category, plus the current version stamp of each database and the languages in use. |
/api/v1/accounts |
The chart of accounts. Accounts, their subaccounts (datatype, whether they can be posted to, which levels they sit on) and every value with its properties. Texts included throughout. |
/api/v1/dimensions |
The axes and their levels (position, type, predecessor), the relations between levels (kind, inheritance, what a conditional one depends on), and the properties. |
/api/v1/rules |
The rules the base holds itself to: severity, reach, what each one checks, and the worked example it carries. |
/api/v1/records/<id> |
A single record: the row it lives in, and every text it has. |
Field names are the base's own. Nothing is renamed and
nothing is translated. subaccount_id is
subaccount_id, can_post is can_post. If
you have seen the schema, you have seen these names.
Two kinds of missing are kept apart. A text carries a
state. "filled" means there is one;
"n/a" means somebody has decided there will not be one. A language
that simply has not been written yet is absent altogether. The three are
different facts, and the API does not flatten them into one.
"texts": {
"name": {
"en": { "state": "filled", "value": "Volume" },
"da": { "state": "n/a", "value": null }
}
}
The API never reads the base where it lies, because that file is written
while this serves. It reads a copy, and it takes a new copy at intervals. Every
answer carries a source block saying when the copy was taken, how
old it is, and its checksum. A copy that fails its check is discarded and the
previous one keeps serving, so an answer can be stale but never half-written.
"source": {
"copy_taken_at": "2026-08-05T14:31:02Z",
"copy_age_seconds": 12.4,
"copy_md5": "...",
"refresh_interval_seconds": 30,
"last_refusal": null
}
This API only reads. There is no path that writes, and the connection to the
base is opened read-only, so a write cannot be made even by mistake. A
POST, PUT, PATCH or DELETE
is answered 405.