Answered from these docs only, by a model that cannot see your account. Check the pages it cites.

Read API

Every endpoint Roiva's read API serves: what each one answers, the parameters it takes, and every field it returns.

View as Markdown View as JSON

Answered from these docs only, by a model that cannot see your account. Check the pages it cites.

Generated from what Roiva ships, on every deploy.

On every paid plan, Roiva serves a read API at https://roiva.ai/api/v1, for pulling an account's figures into a warehouse, a notebook or your own tooling.

The contract

The OpenAPI document is at /api/v1/openapi.json, and needs no token to read — point a client generator at it. It is produced from the routes and the serializers rather than written, so it cannot describe an endpoint that is not served. Every section below comes from that same document.

Connecting

Send a personal access token as an Authorization: Bearer header. An Owner or Admin issues one under Organization Settings → API Access, and it is the same token an MCP client uses. It acts as the user who issued it, so removing them from the account stops it working. The token can also be sent as the password in HTTP Basic authentication, with any user name, which is how Power BI keeps it. A reporting token, issued under Organization Settings → Reporting Tables, reads only the /reporting endpoints; see Reporting tables.

curl https://roiva.ai/api/v1/roi \
  -H "Authorization: Bearer YOUR_TOKEN"

Reading a list

Every list answers with the same envelope, so the tables below describe a row rather than repeating the wrapper:

{
  "data": [ { "id": 1 } ],
  "page": { "next_cursor": "MjAyNi0wOS0yOA", "has_more": true }
}

Pass next_cursor back as cursor until has_more is false. The cursor walks (updated_at, id) oldest-change-first, so a row changed mid-walk is seen again rather than missed — a repeat an upsert absorbs. With updated_since beside it, that is an incremental sync: ask for what changed, walk forward, remember where you stopped.

A row deleted in Roiva is not returned at all, so an incremental sync keeps a copy of it. To hold an exact copy of the figures, read the reporting tables instead: they are rebuilt whole every night, and checked against Roiva's reports before they can be read.

What it will not do

Every endpoint reads. Nothing here records a cost, approves value or moves an initiative, and that is a fact about the routes rather than a promise: only GETs are declared, and a guard spec holds every route under /api to it.

Amounts are integer cents with the currency beside them, never a formatted string. An entry keeps the currency its source gave it, and usd_amount_cents beside it is what /roi adds: the amount in US dollars at the European Central Bank's average rate over its period (an undated cost's booking day), with the rate. /roi is in dollars, and says in value_left_out and cost_left_out what had no rate to count. Version 1 does not break: fields and endpoints are added, and removing or renaming one would be version 2. How Roiva calculates value is what the figures mean.

GET /api/v1/roi

Approved cash value and freed capacity, kept apart, with total cost, net cash value and cash ROI, over a reporting window. Freed capacity is in neither the net value nor the ROI. The same computation the ROI dashboard and the Board Brief read. Sample initiatives are left out unless include_sample is true, as the Board Brief leaves them out.

Parameter Type What it means
window stringoptional The reporting window. Defaults to all. An unrecognized value is refused rather than answered for another period. One of: 1yr, 3yr, 5yr, all.
initiative_id integeroptional Narrow the figures to one initiative in this account. An id this account cannot see answers 404.
include_sample booleanoptional · default false Include provisioned demo initiatives, which are left out by default. A warehouse that ingests them reports figures nobody spent.

What it answers with.

Field Type What it is
scope objectalways present What these figures cover.
scope.type string Whether these figures cover the whole portfolio or one initiative. One of: portfolio, initiative.
scope.id integer The initiative's id, when the scope is an initiative.
scope.title string The initiative's title, when the scope is an initiative.
period objectalways present The stretch of time they cover.
period.window string The reporting window these figures cover.
period.label string How the app names that window to a reader.
period.from string First day covered. Absent for all time, which has no first day.
period.through string Last day covered: today, in UTC, for a trailing window. A trailing window's dates move every day, so store them with the figures.
currency stringalways present ISO 4217 code every amount below is in.
cash_value_cents integeralways present Approved value that shows in the books, in cents: the margin on revenue earned, costs that fell, losses and spend that didn't happen, and freed capacity a person showed became cash. Unapproved entries do not count.
freed_capacity_cents integeralways present Approved hours and output freed, priced at what they cost, in cents. Not cash, and in no other figure here: report it beside cash_value_cents and never add the two.
realized_capacity_cents integeralways present The part of the freed capacity a person showed became cash, in cents. It is already in cash_value_cents and already out of freed_capacity_cents.
total_cost_cents integeralways present Everything the initiatives in scope have cost, in cents.
net_value_cents integeralways present Cash value minus total cost, in cents. Freed capacity is not in it.
roi numbermay be null Cash ROI: net_value_cents divided by total cost. Null when there is no cost to divide by, which is not the same as zero.
value_left_out array of object Approved value in scope in another currency with no dollar figure, so in no figure here: one row a currency, in that currency's cents. Most is waiting for the ECB to publish through its period and converts then; value in a currency the ECB doesn't publish, with no period, or approved in a month locked before its rates were in doesn't.
cost_left_out array of object Cost in scope with no dollar figure, so in no figure here: one row a currency, in that currency's cents. A cost in a currency the ECB doesn't publish, or locked in its month before it was converted.
provisional_cost_cents integer The part of total_cost_cents in another currency counted at the ECB's latest rate, because its period's rates weren't all published yet. It moves to the period's average once they are.
cost objectalways present total_cost_cents split into its one-time and running halves.
cost.capex_cents integer The one-time part of total cost, in cents.
cost.opex_cents integer The running part of total cost, in cents.

GET /api/v1/initiatives

Ordered oldest change first, so a caller can walk forward from where they stopped. Sample initiatives are left out unless asked for.

Parameter Type What it means
limit integeroptional · default 100 Rows per page, up to 500.
cursor stringoptional The next_cursor from the previous page. Opaque: its shape is not part of the contract.
updated_since stringoptional Only rows changed at or after this moment, which is what makes a repeat pull cheap. At or after, not after, so a caller passing back the last updated_at they saw cannot miss a row saved in the same millisecond.
include_sample booleanoptional · default false Include provisioned demo initiatives, which are left out by default. A warehouse that ingests them reports figures nobody spent.

What a row carries.

Field Type What it is
id integeralways present —
title stringalways present —
description stringmay be null —
hypothesis stringmay be null —
stage stringalways present Where it is in its lifecycle. One of: identified, reviewing, implementing, live, paused, completed, rejected, dismissed.
is_sample booleanalways present Provisioned demo data. Left out of lists unless include_sample=true, because a warehouse that ingests it reports figures nobody spent.
category stringmay be null —
priority integermay be null Lower is higher priority.
source stringmay be null How the initiative came to exist.
business_unit stringmay be null —
department stringmay be null —
gl_dimension_value stringmay be null —
owner objectmay be null Who, inside this account. Names, never email addresses.
owner.id integer —
owner.name stringmay be null Empty when they have given no name. Never an email address.
confidence_score numbermay be null —
roi_time_horizon_years integermay be null —
currency stringmay be null —
expected_capex_cents integermay be null Amount in cents, in the currency beside it.
expected_opex_cents integermay be null Amount in cents, in the currency beside it.
expected_cost_savings_cents integermay be null Planned cash a falling cost saves per value period.
expected_capacity_cents integermay be null Planned freed capacity per value period: hours priced at what they cost. Not cash, and in no planned ROI.
expected_revenue_uplift_cents integermay be null Planned revenue per value period, top line, as the business case states it. Planned value counts it at the account's contribution margin.
started_at stringmay be null —
went_live_at stringmay be null —
approved_at stringmay be null —
closed_at stringmay be null —
submitted_for_review_at stringmay be null —
created_at stringalways present When the row was first written.
updated_at stringalways present When it last changed. This is what the list is ordered by, what a cursor points into, and what updated_since compares against.

GET /api/v1/cost_entries

What the account has spent, one row per entry, whoever or whatever recorded it. Ordered oldest change first.

Parameter Type What it means
limit integeroptional · default 100 Rows per page, up to 500.
cursor stringoptional The next_cursor from the previous page. Opaque: its shape is not part of the contract.
updated_since stringoptional Only rows changed at or after this moment, which is what makes a repeat pull cheap. At or after, not after, so a caller passing back the last updated_at they saw cannot miss a row saved in the same millisecond.
initiative_id integeroptional Only rows belonging to one initiative in this account.
period_from stringoptional The start of the window. Entries are matched on where their period begins, which is how Roiva's own reports slice a period: an entry belongs to the period it starts in, so a twelve-month entry beginning in January is in Q1 and in no other quarter. Asking for a quarter therefore returns the rows the dashboard counted for it. Either bound may be given on its own.
period_to stringoptional The end of the window, matched the same way — see period_from.
include_sample booleanoptional · default false Include provisioned demo initiatives, which are left out by default. A warehouse that ingests them reports figures nobody spent.

What a row carries.

Field Type What it is
id integeralways present —
initiative_id integeralways present —
amount_cents integermay be null Amount in cents, in the currency beside it.
currency stringmay be null —
usd_amount_cents integermay be null The amount in US dollars, in cents: amount_cents itself when currency is USD, converted at usd_rate otherwise, or at the rate for the day it was booked when it has no period. Null, and in no total /roi gives, for a currency the ECB doesn't publish or a cost locked in its month before it was converted.
usd_rate numbermay be null US dollars per unit of currency: the average of the European Central Bank's daily euro reference rates from usd_rate_from to usd_rate_through, crossed through the euro. Null for a dollar entry.
usd_rate_from stringmay be null The first ECB day usd_rate averages.
usd_rate_through stringmay be null The last ECB day usd_rate averages.
usd_rate_provisional boolean Whether usd_rate is the ECB's latest rate rather than its period's average, because the period's rates weren't all published yet. It moves to the average once they are, unless its month was locked before then, and updated_at changes when it does.
cost_type stringmay be null Software, tokens, implementation, infrastructure and so on. "adjustment" prices a linked vendor's usage by the books, and can be negative.
cost_category stringalways present Whether it is one-time or running. Follows from the type unless somebody changed it. One of: capex, opex.
period_start stringmay be null —
period_end stringmay be null —
vendor_id integermay be null The vendor this is spend with, and the field to group spend by — it is what Roiva's own Vendors page groups on. Resolved from vendor_name when the entry is written, so the two usually agree; they come apart when two vendors are merged, because that repoints vendor_id on the existing entries and leaves their names alone. One vendor's rows can then carry several names, and grouping on the name splits its spend. Null where no name was given, which Roiva reports apart rather than against a vendor.
vendor_name stringmay be null The name as it was recorded, which is free text: an abbreviation, a product name, or a spelling the vendor has since been merged out of.
description stringmay be null —
notes stringmay be null —
is_estimated boolean —
locked boolean In a locked accounting period, so nothing changes or deletes it, synced or typed, until the month is reopened.
source object Where the record came from: typed in, recorded through the Roiva Assistant, imported, calculated, or brought in by a connection.
source.type stringmay be null manual (typed in), assistant (recorded through the Roiva Assistant), csv (imported from a file), calculated (by a formula), integration (brought in by a connection) or system (written by Roiva). Not every kind of record takes every one.
source.ref stringmay be null The id the originating system knows it by.
source.connection_id integermay be null —
created_at stringalways present When the row was first written.
updated_at stringalways present When it last changed. This is what the list is ordered by, what a cursor points into, and what updated_since compares against.

GET /api/v1/value_entries

What the account's initiatives have returned. Only entries whose status is "approved" are reported value; of those, cash counts toward ROI and freed capacity is reported beside it, never added. See counts_toward_roi on each row.

Parameter Type What it means
limit integeroptional · default 100 Rows per page, up to 500.
cursor stringoptional The next_cursor from the previous page. Opaque: its shape is not part of the contract.
updated_since stringoptional Only rows changed at or after this moment, which is what makes a repeat pull cheap. At or after, not after, so a caller passing back the last updated_at they saw cannot miss a row saved in the same millisecond.
initiative_id integeroptional Only rows belonging to one initiative in this account.
status stringoptional Only entries with this status. Only "approved" is reported value. One of: draft, calculated, reviewed, approved, disputed, archived.
period_from stringoptional The start of the window. Entries are matched on where their period begins, which is how Roiva's own reports slice a period: an entry belongs to the period it starts in, so a twelve-month entry beginning in January is in Q1 and in no other quarter. Asking for a quarter therefore returns the rows the dashboard counted for it. Either bound may be given on its own.
period_to stringoptional The end of the window, matched the same way — see period_from.
include_sample booleanoptional · default false Include provisioned demo initiatives, which are left out by default. A warehouse that ingests them reports figures nobody spent.

What a row carries.

Field Type What it is
id integeralways present —
initiative_id integeralways present —
amount_cents integermay be null Amount in cents, in the currency beside it.
currency stringmay be null —
usd_amount_cents integermay be null The amount in US dollars, in cents: amount_cents itself when currency is USD, converted at usd_rate otherwise. Null while it has no rate, and then it is in no total /roi gives.
usd_rate numbermay be null US dollars per unit of currency: the average of the European Central Bank's daily euro reference rates from usd_rate_from to usd_rate_through, crossed through the euro. Null for a dollar entry.
usd_rate_from stringmay be null The first ECB day usd_rate averages.
usd_rate_through stringmay be null The last ECB day usd_rate averages.
status stringalways present Only "approved" is reported value. The others are on their way there or were sent back, and summing every row gives a figure that disagrees with /roi. One of: draft, calculated, reviewed, approved, disputed, archived.
counts_toward_roi booleanalways present Whether this entry is in the cash ROI /roi reports. True exactly when status is "approved" and entry_type is cash (revenue_gain, cost_savings, cost_avoidance, capacity_realized). Approved freed capacity (capacity) is reported beside ROI, never in it, so it is false. So is an entry in another currency with no dollar figure yet: /roi adds dollars, and leaves it out until it has one.
entry_type stringmay be null The kind of value: revenue_gain (cash: the margin on revenue earned), cost_savings (cash: a bill that fell), cost_avoidance (cash: a cost that didn't happen), capacity_realized (cash: freed capacity shown to have become cash), capacity (freed capacity: hours and output freed up, priced at what they cost, not cash). Cash and freed capacity are two figures, never added together.
period_start stringmay be null —
period_end stringmay be null —
is_estimated boolean —
locked boolean Approved, in a locked accounting period: Roiva refuses to edit, send back or delete it until the month is reopened. False for an entry in that month not yet approved: it can still be recalculated, and can't be approved until the reopening.
basis string What it was compared with: a baseline measured before go-live (measured), one measured after go-live on work done without the AI (reconstructed), a benchmark, a judgment or a figure marked an estimate (estimated), or no baseline (none). One of: measured, reconstructed, estimated, none.
confidence_score numbermay be null —
quality_score numbermay be null —
notes stringmay be null What a person wrote about this figure in their own words — for a saving, typically what changed: their team's doing, or a vendor's pricing.
provenance stringmay be null Where the number came from, in one phrase: synced from a connection, calculated from a formula, recorded through the Roiva Assistant, or entered by hand.
formula_id integermay be null The formula that calculated it, for a calculated entry.
formula_key stringmay be null That formula's key, stable across its versions.
formula_version integermay be null The version of the formula the figure was computed with, recorded when it was evaluated. A formula can be revised afterwards; this stays the version that produced this figure.
source object Where the record came from: typed in, recorded through the Roiva Assistant, imported, calculated, or brought in by a connection.
source.type stringmay be null manual (typed in), assistant (recorded through the Roiva Assistant), csv (imported from a file), calculated (by a formula), integration (brought in by a connection) or system (written by Roiva). Not every kind of record takes every one.
source.ref stringmay be null The id the originating system knows it by.
source.connection_id integermay be null —
approved_at stringmay be null —
created_at stringalways present When the row was first written.
updated_at stringalways present When it last changed. This is what the list is ordered by, what a cursor points into, and what updated_since compares against.

GET /api/v1/metrics

The metric definitions behind the figures: what each one measures, its type and its unit.

Parameter Type What it means
limit integeroptional · default 100 Rows per page, up to 500.
cursor stringoptional The next_cursor from the previous page. Opaque: its shape is not part of the contract.
updated_since stringoptional Only rows changed at or after this moment, which is what makes a repeat pull cheap. At or after, not after, so a caller passing back the last updated_at they saw cannot miss a row saved in the same millisecond.

What a row carries.

Field Type What it is
id integeralways present —
metric_key stringalways present The canonical key, as the metric registry spells it.
name stringalways present —
description stringmay be null —
metric_type stringmay be null count, duration, percentage, currency and so on.
unit stringmay be null —
currency_metric boolean Whether its readings are money.
active boolean —
created_at stringalways present When the row was first written.
updated_at stringalways present When it last changed. This is what the list is ordered by, what a cursor points into, and what updated_since compares against.

GET /api/v1/observations

The readings and baselines the value formulas run on. Ordered oldest change first.

Parameter Type What it means
limit integeroptional · default 100 Rows per page, up to 500.
cursor stringoptional The next_cursor from the previous page. Opaque: its shape is not part of the contract.
updated_since stringoptional Only rows changed at or after this moment, which is what makes a repeat pull cheap. At or after, not after, so a caller passing back the last updated_at they saw cannot miss a row saved in the same millisecond.
initiative_id integeroptional Only rows belonging to one initiative in this account.
metric_key stringoptional Only readings of one metric, by its canonical key.

What a row carries.

Field Type What it is
id integeralways present —
metric_id integermay be null —
metric_key stringmay be null —
initiative_id integermay be null —
value numbermay be null The reading itself, in the metric's unit; money in currency.
currency stringmay be null ISO 4217 code a money reading's value is in: a CRM's deals all in euros are in EUR. Empty for a reading that isn't money.
role stringmay be null Whether it is a baseline or a reading.
baseline_method stringmay be null How a baseline was measured, when it is one. history and time_study are measured; without_ai_sample is reconstructed after go-live; benchmark and estimate are estimates. One of: history, time_study, without_ai_sample, benchmark, estimate.
observed_at stringmay be null —
period_start stringmay be null —
period_end stringmay be null —
is_estimated boolean —
sample_size integermay be null —
quality_score numbermay be null —
source object Where the record came from: typed in, recorded through the Roiva Assistant, imported, calculated, or brought in by a connection.
source.type stringmay be null manual (typed in), assistant (recorded through the Roiva Assistant), csv (imported from a file), calculated (by a formula), integration (brought in by a connection) or system (written by Roiva). Not every kind of record takes every one.
source.ref stringmay be null The id the originating system knows it by.
source.connection_id integermay be null —
created_at stringalways present When the row was first written.
updated_at stringalways present When it last changed. This is what the list is ordered by, what a cursor points into, and what updated_since compares against.

GET /api/v1/budgets

The signed-off budget, not the business case the initiatives list carries. One row per initiative, including initiatives with no budget — see `budgeted`, which says which rows belong in a variance total. Ordered oldest change first, by the initiative.

Parameter Type What it means
limit integeroptional · default 100 Rows per page, up to 500.
cursor stringoptional The next_cursor from the previous page. Opaque: its shape is not part of the contract.
include_sample booleanoptional · default false Include provisioned demo initiatives, which are left out by default. A warehouse that ingests them reports figures nobody spent.
initiative_id integeroptional Only rows belonging to one initiative in this account.
budgeted booleanoptional · default false Only initiatives that have an approved budget. Applied after the comparison runs, since it is not a column, so a page can come back shorter than limit while there are still more pages.

What a row carries.

Field Type What it is
initiative_id integeralways present —
budgeted booleanalways present Whether an approved budget exists at all. False means the figures below compare spend against nothing, so these rows belong out of any variance total — which is what Roiva's own totals do.
status stringalways present "over" when either half is over, because an unspent CapEx envelope early in a build must not hide an OpEx run rate that is already over. "scheduled" means a budget exists but has not started. One of: no_budget, scheduled, within, over.
over_parts array of stringalways present Which half is over, when status is "over". One of: capex, opex.
currency stringmay be null —
as_of stringalways present The day the comparison was made — today.
capex_budget_cents integer The current version's envelope.
capex_actual_cents integer CapEx spent since the budget began. Zero when budgeted is false: there is no budget window to measure over, so this is not the initiative's total spend. Read /api/v1/cost_entries for that.
capex_remaining_cents integer Negative when the envelope is exceeded.
opex_budget_to_date_cents integer Each month's rate summed from the month the budget began through this one, at whichever version covered each month. A revision changes the months after it and never restates the ones before.
opex_actual_cents integer OpEx spent since the budget began. Zero when budgeted is false: there is no budget window to measure over, so this is not the initiative's total spend. Read /api/v1/cost_entries for that.
budget_monthly_run_rate_cents integer The current version's rate, as a monthly figure.
actual_monthly_run_rate_cents integermay be null The average over the last 3 complete months the budget covered. Null until one complete month has passed.
budget_to_date_cents integeralways present CapEx envelope plus OpEx to date.
actual_to_date_cents integeralways present Zero when budgeted is false: there is no budget window to measure over, so this is not the initiative's total spend. Read /api/v1/cost_entries for that.
variance_cents integeralways present budget_to_date_cents minus actual_to_date_cents. Positive is under budget.
used_ratio numbermay be null Actual over budget to date. Null when there is no budget to date to divide by.
spent_before_budget_cents integer Spend dated before the month the budget began. Reported apart rather than charged against an envelope that did not exist yet, so it is in neither figure above.
opex_budget_fiscal_year_cents integer The whole fiscal year's OpEx budget.
opex_budget_fiscal_ytd_cents integer The part of it through as_of.
opex_actual_fiscal_ytd_cents integer —
budget_started_on stringmay be null The month the first approved version took effect.
revised boolean Whether the budget has been changed since it was first approved.
version_count integer —
revision_pending boolean A revision is waiting for the account Owner, because it would put the budget above the account's approval threshold. The figures here are still the approved ones.
current_version objectmay be null The approved version in effect, or null when there is no budget yet or every version starts in a later month.
current_version.id integer —
current_version.effective_from string The figures apply from the whole month containing this date, not from the day — so a version effective on the 28th covers that month in full, and budget_started_on is the first of it. There is no day proration.
current_version.ends_on stringmay be null The last month covered, again whole-month.
current_version.capex_cents integer A one-off total, not accrued.
current_version.opex_cents integer A rate, per opex_cadence.
current_version.opex_cadence string One of: monthly, quarterly, annually.
current_version.source string Whether it came from the initiative's approval, a later revision, or was set by hand. One of: approval, revision, manual.
current_version.reason stringmay be null Why it was set, in the words of whoever set it.
current_version.set_by objectmay be null Who, inside this account. Names, never email addresses.

GET /api/v1/decisions

Continue, scale, fix, pause or retire, with the rationale and the figures as they stood when it was decided. Immutable once written, so a row read today says what was known then. Ordered oldest change first.

Parameter Type What it means
limit integeroptional · default 100 Rows per page, up to 500.
cursor stringoptional The next_cursor from the previous page. Opaque: its shape is not part of the contract.
updated_since stringoptional Only rows changed at or after this moment, which is what makes a repeat pull cheap. At or after, not after, so a caller passing back the last updated_at they saw cannot miss a row saved in the same millisecond.
initiative_id integeroptional Only rows belonging to one initiative in this account.
outcome stringoptional Only decisions with this outcome. One of: continue, scale, fix, pause, retire.

What a row carries.

Field Type What it is
id integeralways present —
initiative_id integermay be null Null when the initiative it was about no longer exists. subject_title still says what it was.
subject_title stringalways present The initiative's title as it stood when the decision was made, so the row still reads after the initiative is renamed or gone.
outcome stringalways present What was decided. One of: continue, scale, fix, pause, retire.
outcome_label stringalways present How Roiva words the outcome on a page.
rationale stringalways present Why, in the words of whoever decided. Always present.
stage_before stringalways present One of: identified, reviewing, implementing, live, paused, completed, rejected, dismissed.
stage_after stringalways present One of: identified, reviewing, implementing, live, paused, completed, rejected, dismissed.
stage_changed booleanalways present Some outcomes leave the initiative where it was.
decided_at stringmay be null When it was decided, which is the date to report it under.
decided_by objectmay be null Who, inside this account. Names, never email addresses.
decided_by.id integer —
decided_by.name stringmay be null Empty when they have given no name. Never an email address.
next_review_on stringmay be null When this is meant to be looked at again. Roiva suggests a date from the outcome; whoever decided can change it.
currency stringmay be null —
cash_value_cents integermay be null Approved cash value at the moment of the decision. Approved only, as everywhere: this is the figure that was on the screen, not a recomputation.
freed_capacity_cents integermay be null Approved freed capacity at the moment of the decision: hours freed, priced at what they cost. Not cash, and in neither net_cents nor roi.
cost_to_date_cents integermay be null Amount in cents, in the currency beside it.
net_cents integermay be null cash_value_cents minus cost_to_date_cents, as of the decision.
planned_value_cents integermay be null The cash the business case had promised in total: planned savings, plus planned revenue at the account's contribution margin.
planned_value_to_date_cents integermay be null The part of that plan due by the decision date.
roi numbermay be null The cash ROI as of the decision. Null where there was no cost to divide by.
created_at stringalways present When the row was first written.
updated_at stringalways present When it last changed. This is what the list is ordered by, what a cursor points into, and what updated_since compares against.

GET /api/v1/integrations

What each connection is, whether it is working, and when data last arrived. Credentials, stored settings and error prose are never served — see the field descriptions for what stands in for them. Ordered oldest change first.

Parameter Type What it means
limit integeroptional · default 100 Rows per page, up to 500.
cursor stringoptional The next_cursor from the previous page. Opaque: its shape is not part of the contract.
updated_since stringoptional Only rows changed at or after this moment, which is what makes a repeat pull cheap. At or after, not after, so a caller passing back the last updated_at they saw cannot miss a row saved in the same millisecond.
platform stringoptional Only connections to one platform.
status stringoptional Only connections in this state. One of: active, paused, error, disconnected.

What a row carries.

Field Type What it is
id integeralways present —
platform stringalways present Which system this connects to.
name stringmay be null —
description stringmay be null —
status stringalways present Whether it is working. "error" means syncs are failing; "paused" and "disconnected" mean somebody stopped it. One of: active, paused, error, disconnected.
auth_type stringmay be null How it authenticates. The credentials themselves are never served. One of: oauth, api_key, basic, webhook, github_app, service_account, file_upload.
last_sync_status stringmay be null How the most recent sync ended.
last_synced_at stringmay be null When data last arrived. The field to watch: a connection can read "active" and still not have synced for a week.
reauth_required_at stringmay be null Set when the platform refused the grant Roiva holds. Non-null means no amount of retrying will fix it and a person has to reconnect.
external_account_id stringmay be null What the platform calls the account on its side, for joining to its own data.
external_account_name stringmay be null —
primary_source_categories array of stringalways present The categories this connection is the canonical source for. Where two connections could serve the same category, only the primary one's readings are used.
metric_categories array of stringalways present What this platform's connections can serve at all, whether or not this one is primary.
simulated booleanalways present A connection whose syncs are answered by Roiva's simulator rather than by the platform. Only an internal Roiva account can hold one.
connected_by objectmay be null Who, inside this account. Names, never email addresses.
connected_by.id integer —
connected_by.name stringmay be null Empty when they have given no name. Never an email address.
created_at stringalways present When the row was first written.
updated_at stringalways present When it last changed. This is what the list is ordered by, what a cursor points into, and what updated_since compares against.

GET /api/v1/reporting/schema.json

Every table, column, type and description, as JSON. Public, like this document: it names columns, never an account's figures.

Parameter Type What it means
None — This endpoint takes no parameters.

What it answers with.

Field Type What it is
version stringalways present The schema version the files follow, such as v1.
tables array of objectalways present Each table's name, grain, description and columns, with each column's name, type, nullability and description.

GET /api/v1/reporting/latest

Which tables the newest snapshot holds, with each file's rows, size, SHA-256 and URL. 404 until an Owner or Admin turns on reporting tables and the first build completes.

Parameter Type What it means
None — This endpoint takes no parameters.

What it answers with.

Field Type What it is
snapshot_id stringalways present The snapshot every table's rows carry in snapshot_id.
schema_version stringalways present The version of the reporting schema the files follow.
generated_at stringalways present The moment every table describes.
tables array of objectalways present —

GET /api/v1/reporting/latest/{table}.parquet

The whole table as one Parquet file. Point Power BI's Parquet.Document, a warehouse loader or pandas at it.

Parameter Type What it means
table stringrequired The table's name, from the manifest or the schema. One of: snapshot, initiatives, reported_value, value_inputs, value_supporting_documents, metric_readings, costs, approval_decisions, budgets, budget_vs_actual, portfolio_decisions, accounting_periods, ai_spend, reported_totals.

What it answers with.

Field Type What it is
file Parquet One reporting table as a Parquet file.

GET /api/v1/reporting/snapshots/{snapshot_id}

As the newest snapshot's, for an earlier one still kept.

Parameter Type What it means
snapshot_id stringrequired A snapshot's id, such as 20260915T070000Z. Snapshots are kept 14 days; the newest is kept until a newer one replaces it.

What it answers with.

Field Type What it is
snapshot_id stringalways present The snapshot every table's rows carry in snapshot_id.
schema_version stringalways present The version of the reporting schema the files follow.
generated_at stringalways present The moment every table describes.
tables array of objectalways present —

GET /api/v1/reporting/snapshots/{snapshot_id}/{table}.parquet

As the newest snapshot's table, for an earlier snapshot still kept.

Parameter Type What it means
snapshot_id stringrequired A snapshot's id, such as 20260915T070000Z. Snapshots are kept 14 days; the newest is kept until a newer one replaces it.
table stringrequired The table's name, from the manifest or the schema. One of: snapshot, initiatives, reported_value, value_inputs, value_supporting_documents, metric_readings, costs, approval_decisions, budgets, budget_vs_actual, portfolio_decisions, accounting_periods, ai_spend, reported_totals.

What it answers with.

Field Type What it is
file Parquet One reporting table as a Parquet file.

GET /api/v1/initiatives/{id}

The same fields the list serves, for an initiative a caller already has the id of. An id belonging to another account answers 404 rather than 403, because a 403 would confirm it exists.

Parameter Type What it means
id integerrequired The initiative's Roiva id.

What it answers with.

Field Type What it is
id integeralways present —
title stringalways present —
description stringmay be null —
hypothesis stringmay be null —
stage stringalways present Where it is in its lifecycle. One of: identified, reviewing, implementing, live, paused, completed, rejected, dismissed.
is_sample booleanalways present Provisioned demo data. Left out of lists unless include_sample=true, because a warehouse that ingests it reports figures nobody spent.
category stringmay be null —
priority integermay be null Lower is higher priority.
source stringmay be null How the initiative came to exist.
business_unit stringmay be null —
department stringmay be null —
gl_dimension_value stringmay be null —
owner objectmay be null Who, inside this account. Names, never email addresses.
owner.id integer —
owner.name stringmay be null Empty when they have given no name. Never an email address.
confidence_score numbermay be null —
roi_time_horizon_years integermay be null —
currency stringmay be null —
expected_capex_cents integermay be null Amount in cents, in the currency beside it.
expected_opex_cents integermay be null Amount in cents, in the currency beside it.
expected_cost_savings_cents integermay be null Planned cash a falling cost saves per value period.
expected_capacity_cents integermay be null Planned freed capacity per value period: hours priced at what they cost. Not cash, and in no planned ROI.
expected_revenue_uplift_cents integermay be null Planned revenue per value period, top line, as the business case states it. Planned value counts it at the account's contribution margin.
started_at stringmay be null —
went_live_at stringmay be null —
approved_at stringmay be null —
closed_at stringmay be null —
submitted_for_review_at stringmay be null —
created_at stringalways present When the row was first written.
updated_at stringalways present When it last changed. This is what the list is ordered by, what a cursor points into, and what updated_since compares against.