Ledgers and metrics
Read any number in Continual from its ledger, list the records behind it, and define your own metrics through the API.
Every number in Continual is a sum of ledger entries. This page shows how to read a metric, read a
ledger directly, list the records behind a number, and define your own metrics. The examples use
CONTINUAL_URL and CONTINUAL_API_KEY, as REST API sets up.
Read a metric
List your organization's metrics, then read one over a period:
curl "$CONTINUAL_URL/api/v1/metrics" -H "Authorization: Bearer $CONTINUAL_API_KEY"
curl -G "$CONTINUAL_URL/api/v1/metrics/<metric ID>:values" \
-H "Authorization: Bearer $CONTINUAL_API_KEY" \
--data-urlencode 'fromDate=2026-10-01' \
--data-urlencode 'toDate=2026-10-31' \
--data-urlencode 'grain=week' \
--data-urlencode 'compareTo=previous'const query = new URLSearchParams({
fromDate: "2026-10-01",
toDate: "2026-10-31",
grain: "week",
compareTo: "previous",
})
const response = await fetch(
`${process.env.CONTINUAL_URL}/api/v1/metrics/${metricId}:values?${query}`,
{ headers: { Authorization: `Bearer ${process.env.CONTINUAL_API_KEY}` } }
)
const { value, compared, series, groups } = await response.json()The answer for Pipeline, the first week of its series shown:
{
"currency": "USD",
"value": "1203601.600000",
"compared": "762658.800000",
"sum": "1203601.600000",
"per": null,
"series": [
{
"startDate": "2026-09-28",
"value": "837062.400000",
"compared": "0",
"sum": "837062.400000",
"per": null
}
],
"groups": []
}| Field | What it holds |
|---|---|
currency | The currency money is in: your organization's, unless you name another; null otherwise |
value | The value for the period: a flow's total over it, or a balance at its end |
compared | The value of what you compared it with |
sum | What the value is made of: the sum, which a ratio divides |
per | What a ratio's sum is divided by; null for a plain sum |
series | One value per day, week, or month, each with its compared, sum, and per |
groups | One value per group, when you name groupBy |
A sum of nothing is "0"; a ratio over nothing is null. Numbers are decimal strings, so they keep
every digit.
What a read takes
metrics.values and a ledger's balances take the same inputs.
| Input | What it says |
|---|---|
fromDate | The period's first day |
toDate | The period's last day |
scenario | actual unless named |
asKnownAt | Only what was recorded by this moment, to read a number as it was reported then |
where | Which entries, in the filter language, as JSON |
groupBy | What to group by, as a JSON array |
A metric's values also take grain (day, week, or month), compareTo (previous,
lastYear, or a scenario such as budget), and currency.
where and groupBy name a ledger's dimensions, such as stage or owner, or a field of the
record a dimension names, such as customer.name or account.type. A record's field is read as the
record is now. groupBy also takes book, currency, unit, actor, record, day, week, and
month. A flow can be grouped by actor; a balance cannot.
Pipeline by customer name:
curl -G "$CONTINUAL_URL/api/v1/metrics/<metric ID>:values" \
-H "Authorization: Bearer $CONTINUAL_API_KEY" \
--data-urlencode 'fromDate=2026-10-01' \
--data-urlencode 'toDate=2026-10-31' \
--data-urlencode 'groupBy=["customer.name"]'List the records behind a number
Group by record to list the records a value is made of, each with its share. The deals won in
October, by Bookings:
curl -G "$CONTINUAL_URL/api/v1/metrics/<metric ID>:values" \
-H "Authorization: Bearer $CONTINUAL_API_KEY" \
--data-urlencode 'fromDate=2026-10-01' \
--data-urlencode 'toDate=2026-10-31' \
--data-urlencode 'groupBy=["record"]'Each group's record is a record ID. Read the records with records.batchGet
(POST /api/v1/records:batchGet).
Read a ledger
Each ledger has two Queries at its name: balances, which sums its entries for each group with
every measure, and entries, which lists the entries of one record.
| Ledger | What it keeps |
|---|---|
finance.generalLedger | What invoices, payments, and journal entries post |
sales.dealLifecycle | Deals moving between stages, with their amounts |
projects.taskLifecycle | Tasks moving between statuses |
<record type>Lifecycle | Every record type with a status, such as todoLifecycle |
Deals by stage at the end of October:
curl -G "$CONTINUAL_URL/api/v1/sales.dealLifecycle:balances" \
-H "Authorization: Bearer $CONTINUAL_API_KEY" \
--data-urlencode 'toDate=2026-10-31' \
--data-urlencode 'groupBy=["stage"]'{
"rows": [
{
"group": { "stage": "lost" },
"bookAmount": "0",
"amount": "45600.00",
"quantity": null,
"measures": {
"count": "3",
"arrivals": "3",
"entered": "5372890200.000"
},
"entries": 3
}
]
}A lifecycle ledger's measures:
| Measure | What it is |
|---|---|
count | How many records are in each state |
arrivals | How many entered a state |
departures | How many left a state |
duration | The seconds each spent in a state, posted as it leaves |
entered | The sum of the times, in seconds since 1970, that the records in a state entered it |
A metric reads age, how long the records in a state have been there, from count and entered.
The entries of one record, such as a deal:
curl -G "$CONTINUAL_URL/api/v1/sales.dealLifecycle:entries" \
-H "Authorization: Bearer $CONTINUAL_API_KEY" \
--data-urlencode 'record=<deal ID>'Each entry has its accountingDate, its effectiveAt and recordedAt times, its actor, its
dimensions, and its amounts and measures. Entries are only ever added: a correction posts an entry
that reverses another, named in its corrects.
Define your own metric
A metric is a record. Create one with metrics.create. This one counts the deals lost in a period:
curl -X POST "$CONTINUAL_URL/api/v1/metrics" \
-H "Authorization: Bearer $CONTINUAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Deals lost",
"unit": "count",
"direction": "lower",
"sum": {
"kind": "flow",
"ledger": "sales.dealLifecycle",
"measure": "arrivals",
"where": { "field": "stage", "operator": "eq", "value": "lost" }
},
"requestId": "create-deals-lost"
}'| Field | What it says |
|---|---|
sum | What it adds up: a ledger, a measure, and which entries |
per | What the sum is divided by, for a ratio; leave it out for a plain sum |
unit | count, money, percent (the ratio times 100), or duration (seconds) |
direction | higher or lower: which way is good |
A sum's kind is flow, for the entries dated in a period, or balance, for every entry through
its end. Its measure is amount, bookAmount, quantity, or one of the ledger's measures. Set
normal to credit to read credits as positive, as revenue and liabilities are. A new metric reads
its ledger's whole history at once.
Revenue, from every account whose type is revenue in the general ledger:
{
"kind": "flow",
"ledger": "finance.generalLedger",
"measure": "bookAmount",
"where": { "field": "account.type", "operator": "eq", "value": "revenue" },
"normal": "credit"
}The metrics your apps ship are records too, with a key such as sales.winRate. Installing a new
version of an app updates them.