> ## Documentation Index
> Fetch the complete documentation index at: https://docs.beaconrevenue.io/llms.txt
> Use this file to discover all available pages before exploring further.

# API reference

> The Beacon Data API — what your own systems can read out of Beacon, what travels with every value, the five refusals it returns, and what it will never do.

The Beacon Data API is how your own systems read Beacon's figures — your warehouse, your BI tool, your scripts. It publishes a small, stable set of values about your accounts, your deals, your segments, your cohorts, your company as a whole, your chart of accounts and your posted ledger, and nothing else.

<Warning>
  **Nothing serves this API yet.** There is no address to call, no key to hold, and no Beacon deployment that answers it. This page publishes the contract ahead of the build, so the names and shapes are fixed before anything is written against them.

  Read it to plan an integration. You cannot build one against it today.
</Warning>

**Version `PUB-2026.09.16-v0.7`.** This contract has its own version, separate from Beacon's internal one. Beacon can change how it works inside without changing what you read here.

## What you can read

Seven collections.

| Read | Returns |
| - | - |
| `GET /accounts` | Your accounts, one row each |
| `GET /deals` | Your deals, one row each |
| `GET /segments` | Your segments, one row each |
| `GET /cohorts` | Your cohorts, one row each |
| `GET /periods` | Your company, one row per period |
| `GET /chart-of-accounts` | Your chart-of-accounts categories, one row each |
| `GET /ledger-entries` | Your posted general-ledger entries, one row each |

All seven accept `entity_scope`, which narrows the read to one entity inside your grant and can only ever narrow it, and `page`, which is an opaque cursor from the previous response rather than an offset.

Three collections are not about a customer: `GET /periods`, `GET /chart-of-accounts` and `GET /ledger-entries`. A key covers exactly one company, so the company half of the period object's name is not in the address — a period is a period of yours, and a period is a month, a quarter, a year or the trailing twelve months.

### The values on each

The values, their types and what each one holds are the [account object](/data-model/account), the [deal object](/data-model/deal), the [segment object](/data-model/segment), the [cohort object](/data-model/cohort), the [company and period object](/data-model/company-period), the [chart of accounts object](/data-model/chart-of-accounts) and the [ledger entry object](/data-model/ledger-entry). This page does not restate them.

**Sixteen account values, seven deal values, six segment values, six cohort values, thirteen company-and-period values, fourteen chart-of-accounts values and eight ledger-entry values are published through this API**, plus `as_of` and `computed_at`, which travel with every one of them.

**The chart of accounts and the posted ledger joined in `v0.6`**, at the addresses their object pages have named since 2026-09-01. Neither is a customer record, so neither reaches your CRM. Nothing on either is produced yet.

**One authored segment value is not among them.** Beacon holds seven at that level; one describes how the segment was cut, and it is held back on every read door while a question about how it is derived is still open. It is absent here rather than listed as unavailable.

**`pipeline_velocity` — how healthily a segment's open pipeline is moving — joined in `v0.4`**, and is the sixth segment value above. It was published on the [segment object](/data-model/segment) on 2026-08-29 and reached this API on 2026-09-14, as an addition; nothing already published changed.

It is one figure read at more than one level, and **the level is the object you read it on** — the same measure is published for your company as a whole. The company-wide score is catalogued on the [company and period object](/data-model/company-period) and is not yet in this contract: `GET /periods` reads thirteen values at this version, and the fourteenth arrives as an addition. A third level, by team, is deliberately not published anywhere: Beacon has no definition of a team to attach it to, so rather than return an empty one it declines the row outright.

**A value's audience level says which reader may receive it under your grant.** It is not a statement that the value can never leave Beacon. Each object page carries the level for every value it publishes; read it there rather than assuming a level from the grain.

<Note>
  **Those counts are the values this API publishes, which is not the same as the values Beacon holds.** Beacon authors seventeen values on an account and eight on a deal. One value at each level is written into the model but held back from publication until the work behind it is finished, so it is not readable here at any version.

  On the account that value is `cost_to_serve_amount`. On the deal it is a price-realization band, which the deal object does not list.

  A count of published values and a count of authored values are both correct and they are not the same number. Where you see a count, check which one it is.
</Note>

## What travels with every value

A value never arrives as a bare number.

| Field | Holds |
| - | - |
| `as_of` | The moment the value describes. A property of your data, not a record of Beacon's activity |
| `computed_at` | When Beacon last worked the value out |
| `as_of_anchor` | Present only when `as_of` came from a single named source rather than from the oldest of several. When it is absent, the oldest rule was used |

`as_of` and `computed_at` are both always present. They answer different questions and neither substitutes for the other: one tells you when something was true, the other tells you when Beacon last looked.

For a figure built from several sources, **the oldest source governs** — a combined figure is only as current as its oldest ingredient, so Beacon never overstates how fresh something is. A value whose `as_of` cannot be established is not returned at all; you get a refusal instead of a number with a made-up timestamp.

`as_of_anchor` carries `basis`, which says how the timestamp on a page of results was arrived at: `stalest_row` when the page returned rows and `as_of` is the oldest among them, or `empty_collection` when the page returned nothing, in which case `as_of` equals `computed_at`. That is stated rather than hidden, because a page **with** rows where the two are equal would be a defect, and you can only tell the two cases apart because the response says which one you have.

## Refusals

When Beacon cannot serve a value it returns a named refusal and, where saying so would not disclose something beyond your access, what would make the value available. **A refusal is a successful response carrying a reason — never a null, never a zero, and never a missing field.**

**A `null` means something else: the value does not apply to that row.** A top-level category has no parent; a category that is not a cost of service has no service layer. Only a value its object page marks "or null" can be `null`, and the page says when. A value that applies but is not available yet is always a refusal.

| Reason | Means |
| - | - |
| `not_computed` | Beacon has not produced that figure. It will not invent one |
| `not_activated` | A connected system this value needs is not switched on. The response names which, and names the reduced mode if there is one |
| `outside_grant` | The request falls outside your role, your entity scope, or the kinds of data your grant reaches. The response names which of the three, without disclosing what lies beyond it |
| `stale_beyond_floor` | The value exists and is older than the freshness limit set for it |
| `no_grain` | The thing you asked about is not in Beacon at all |

Every refusal carries `schema_version` — the version of this contract it was issued under. **It never carries Beacon's internal version**, which is what keeps the two independent.

The five reasons are fixed. No sixth will be added without a published change.

<Note>
  The refusal model is published here as proposed. It is settled enough to build against and is not yet final.
</Note>

## What connects, and what it reads

A connecting system presents a key Beacon issued, over a bearer token. **Beacon never holds your passwords to anything** — the credentials you use with your own source tools stay in those tools and never pass through this API.

That key resolves to one grant, which names a role and an entity scope. Everything served under it sits inside that access — never wider. What a grant states, and how to issue or revoke one, is on [Access and grants](/access-and-grants).

**No such key can be issued today.** The part of Beacon that issues them does not exist yet, and neither does the register of approved destinations that a key would be allowed to send data to.

## What this API will not do

**It does not write.** This surface reads. Beacon writes back to your CRM through a separate path where every write is a draft a person approves, and nothing here can be turned into one.

**No open query.** Every request names something Beacon already publishes, at a version. There is no query language and no expression field.

**Nothing worked out on request.** Beacon serves what it has already computed. Ask twice, get the same answer twice.

**No raw billing lines.** Individual invoice lines are never published by any Beacon interface. They are read when Beacon prepares your recurring-revenue figures and then discarded; there is no path to them here or anywhere else.

**No exact account or deal figure where Beacon publishes a band.** On an account, recurring revenue arrives as `mrr_band`; on a deal, size arrives as `deal_amount_band`. Neither object publishes the exact amount today. Where Beacon does not already hold a band it refuses rather than working one out at the point of reading, and the boundaries of the bands it does hold are set from your own configuration rather than chosen by Beacon.

The company total is different and is published exactly, on `GET /periods`. That is the one grain where an exact recurring-revenue figure is published today.

**Beacon's own internal read surface is not published here, at any version.** It is written in the column names of Beacon's storage, so publishing it would turn every internal change into a change you would have to absorb. This contract exists to be the stable thing instead.

## What this API does not cover

Beacon defines values beyond the seven above — target and plan figures, and further finance objects such as cash, runway and budget. **Those are not on this API and are not declared here**, and they are not yet published in any form.

When a level becomes readable here, it will arrive as an addition rather than as a change to what is already published. **Version `v0.2` was the first instance of that** — segments and cohorts joined on 2026-08-29 — **`v0.3` the second**, company-level periods on 2026-09-14, **`v0.4` the third**, `pipeline_velocity` joining the segment collection the same day, and **`v0.6` the fourth**, the chart of accounts and the posted ledger on 2026-09-16. Nothing already published changed on any of the four.

## Versioning

This contract's version moves when this contract's shape changes. It does not move when Beacon changes something inside, and Beacon's internal version does not move when this one does.

A new optional value, or a value becoming readable that was only declared, raises the version. **A value never changes type, changes meaning, becomes required, or disappears inside a version.** A published name is permanent; a rename ships as a redirect.

Read the availability marker on each value before planning around it. Most values on all seven objects are declared and not yet produced — on `GET /periods`, `GET /chart-of-accounts` and `GET /ledger-entries` that is true of every value without exception — and reading one today would return `not_computed` rather than a number, if there were anything to read it from.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.