> ## 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.

# Cohort object

> The six values Beacon publishes on a cohort, the three levels they sit at, and which doors each one is available through.

The cohort object carries six values, and two timestamps that accompany every one of them on every door: `as_of` and `computed_at`.

<Note>
  The names, types and availability below are fixed. No read interface or MCP tool serves them yet — this page publishes the shape ahead of the doors.
</Note>

A cohort is a set of customer accounts that went through the same event at the same time and are then followed as a set rather than one at a time. Its membership is frozen the moment it opens: an account that qualifies later belongs to a later cohort, never to the one already open. That freezing is what makes two cohorts comparable years apart. [Cohort type](/definitions/cohort-type) covers what opens one and [cohort dimension](/definitions/cohort-dimension) covers how its members are grouped; this page covers what is published about a cohort once it exists.

**The six values do not all sit at the same level, and reading them as though they do is the main way this object is misread.** Two describe the cohort itself and never move. Two are a curve — one point for every month the cohort has lived. Two are struck twice in a cohort's life and not at all before the first of them.

## Example payload

```json theme={null}
{
  "object": "cohort",
  "id": "coh_7b41e0d2",
  "as_of": "2026-08-17T06:00:00Z",
  "computed_at": "2026-08-17T06:04:12Z",
  "cohort_type": "became_customer",
  "cohort_dimension": ["acquisition_period", "segment"],
  "retention_curve": [
    { "month": 1, "cohort_net_revenue_retention": 1.00, "cohort_gross_revenue_retention": 1.00 },
    { "month": 2, "cohort_net_revenue_retention": 0.98, "cohort_gross_revenue_retention": 0.96 },
    { "month": 3, "cohort_net_revenue_retention": 1.02, "cohort_gross_revenue_retention": 0.95 }
  ],
  "economics": {
    "struck_at_month": 18,
    "cohort_acquisition_cost": 1850,
    "cohort_lifetime_value": 12400
  }
}
```

## Attributes

| Value | Type | Method | What it holds |
| - | - | - | - |
| `as_of` | Timestamp, UTC | System | The moment the value describes — a property of the data, not of Beacon's activity. For a value composed from several sources it is the oldest of them, unless the value names an anchor source and says so. Present on every response and every property. |
| `computed_at` | Timestamp, UTC | System | When Beacon last worked the value out. Present on every response and every property. |
| `cohort_type` | String, one of thirteen types | Measured | The event that opened the cohort — `first_touch`, `account_created`, `entered_pipeline`, `became_customer`, `revenue_started`, `reached_first_value`, `campaign`, `channel`, `expanded`, `contracted`, `churned`, `reactivated`, `entered_lifecycle`. A `campaign`, `channel` or `entered_lifecycle` cohort also carries the name of your campaign, channel or lifecycle; how that name is published is not fixed yet. The set is fixed and is the same for every company. [Definition](/definitions/cohort-type) |
| `cohort_dimension` | String or list, from a set of seven | Measured | Which dimension or dimensions the cohort is cut on — `acquisition_period`, `activation_date`, `product_family`, `fit_tier`, `fit_score`, `usage_cluster`, `segment`. This gives you the axis and not the point on it. [Definition](/definitions/cohort-dimension) |
| `cohort_net_revenue_retention` | Number, ratio | Measured | How much recurring revenue the cohort still holds against what it opened with, after expansion, contraction and churn. A ratio — 1.08, never 108 — which can rise above 1.0. One value per month of the cohort's life, not one value for the cohort. [Definition](/definitions/cohort-net-revenue-retention) |
| `cohort_gross_revenue_retention` | Number, ratio | Measured | The same curve without the expansion term. It cannot rise above 1.0, and the gap between the two curves is what expansion contributed. [Definition](/definitions/cohort-gross-revenue-retention) |
| `cohort_acquisition_cost` | Number, reporting currency | Measured | What it cost to acquire one customer in the cohort, stated per customer acquired rather than as the cohort's total. [Definition](/definitions/cohort-acquisition-cost) |
| `cohort_lifetime_value` | Number, reporting currency | Measured | What one customer in the cohort is worth over the window the figure is struck at, stated on the same per-customer basis so the two can be set beside each other. [Definition](/definitions/cohort-lifetime-value) |

**Neither retention value is one number for a cohort.** Each is a curve — one point for each month the cohort has lived — and the shape those points make is what the figure exists to show. A single number taken off a curve is a month's reading, not the cohort's result.

**`cohort_dimension` publishes the axis, not the point on it.** It tells you a cohort is cut on acquisition period. It does not tell you which period. The value naming the point is not published today; a reader who needs the specific month reads the cohort's own identifier instead.

**Beacon does not publish a lifetime-value-to-acquisition-cost ratio for a cohort.** Both figures are per customer, so dividing one by the other looks valid. That ratio is struck for a segment as a whole, where the population is large enough to carry it, and a second one is not struck for a cohort inside a segment — two figures bearing the same name over two different populations leaves a reader unable to tell which one they are holding.

## Availability

✓ available by default · ⊕ available after an opt-in that states who becomes able to see the value · — not available.

| Value | Read interface | MCP tools | Events | CRM property | CRM name | Audience ceiling |
| - | - | - | - | - | - | - |
| `as_of` | ✓ | ✓ | in every event | ✓ | `beacon_as_of` | `operational` |
| `computed_at` | ✓ | ✓ | in every event | ✓ | `beacon_computed_at` | `operational` |
| `cohort_type` | ✓ | ✓ | ✓ | ✓ | `beacon_cohort_type` | `operational` |
| `cohort_dimension` | ✓ | ✓ | ✓ | ✓ | `beacon_cohort_dimension` | `operational` |
| `cohort_net_revenue_retention` | ✓ | ✓ | ⊕ | ⊕ | `beacon_cohort_net_revenue_retention` | `operational` |
| `cohort_gross_revenue_retention` | ✓ | ✓ | ⊕ | ⊕ | `beacon_cohort_gross_revenue_retention` | `operational` |
| `cohort_acquisition_cost` | ✓ | ✓ | ⊕ | ⊕ | `beacon_cohort_acquisition_cost` | `operational` |
| `cohort_lifetime_value` | ✓ | ✓ | ⊕ | ⊕ | `beacon_cohort_lifetime_value` | `operational` |

**The events door is listed and not yet served.** A value marked on it has a named event — `cohort.cohort_net_revenue_retention.changed` fires once for each new monthly point, `cohort.cohort_lifetime_value.changed` at each of the two strikes — sent once per recalculation, carrying the new value, the previous value and both timestamps. Nothing sends an event today and there is nothing to subscribe to yet. `as_of` and `computed_at` have no event of their own; they travel inside every event. `cohort_type` and `cohort_dimension` never change once a cohort exists, so their events are rare by construction; whether the creation of a new cohort is itself announced is not yet decided. The two money figures are available on this door behind the opt-in, under a grant that covers their ceiling — an event carries what a money figure needs alongside it the way a read-interface response does. A CRM property cannot, which is why the note below on your CRM records says the rendering there is still being worked out.

**Every value on this object is `operational`, the two money figures included.** `cohort_acquisition_cost` and `cohort_lifetime_value` are read by your finance team as a matter of course, and their ceiling says so. What still sets them apart is how a money figure travels, not who may look at it — the paragraph below on your CRM records covers that.

**What the opt-in on the two retention curves is for.** Writing either curve onto your CRM records is off by default; turning it on takes an opt-in that states who becomes able to see it. Again a rule about where the value may travel, not about who may look at it.

**The two money figures on your CRM records, and the part that is not yet settled.** Writing either onto your CRM records is off by default; turning it on takes an opt-in that states who becomes able to see it — the same rule about where a value may travel that governs the retention curves above.

**What accompanies a money figure there is not settled.** Each of these is an aggregate, assembled from many parts each converted where it was recorded, so it travels with your reporting currency and the kinds of anchor its parts were pinned under — and it carries no single anchor date and no single billing currency, because it does not have one. Through the read interface and through MCP all of that travels with the figure automatically, in the same response. A CRM property holds one value. **The marks above say the door is open behind an opt-in; they do not say the rendering is finished.** That is being worked out and will be stated here when it is.

**Nothing on this object is reduced to a band on the way into your CRM.** The two retention curves land as ratios. Neither is a modelled value, so neither is banded for the reason a modelled value is.

Both money figures are stated in your single reporting currency. The revenue and spend behind them are converted where they are recorded, under the rules set out in [currency](/currency); no second conversion happens when a cohort figure is struck. Neither retention curve carries a currency of its own — each is a ratio of two revenue figures.

**No rounding rule is set for the two retention curves.** Beacon applies none of its own and fixes no number of decimal places. A screen or an export may round for display, so where you compare two points, compare them at the precision you received them rather than the precision a screen showed you.

Enumerated values are lowercase with underscores — `became_customer`, `acquisition_period`, `usage_cluster` — on every door.

## Freshness

| Value | Recomputed |
| - | - |
| `cohort_type` · `cohort_dimension` | Never. Both are fixed when the cohort is created. Cutting the same population differently produces a new cohort, not an updated one |
| `cohort_net_revenue_retention` · `cohort_gross_revenue_retention` | One new point per month of the cohort's life. A point already struck is not restruck — month 6 stands as month 6's reading even after month 24 has arrived |
| `cohort_acquisition_cost` | Once the acquisition spend for the period is recorded and attributed. It moves after that only if the spend itself is restated |
| `cohort_lifetime_value` | At two points only — 18 months and 24 months after the cohort opened. Before the first there is no figure at all, not a provisional one and not an estimate |

**A cohort passes through three states, and how much of this object is populated depends on which one it is in.** It is **open** while it is still accumulating and its outcome window is incomplete. It is **closing** at 18 months, where enough of its life has happened for provisional results. It is **closed** at 24 months, where the window is complete and the figures are that cohort's record. A cohort is not closed early because an answer is wanted sooner, and it is not held open to allow late additions. Once closed, nothing on this object moves again.

**Membership never changes, so nothing on this object moves for the reason segment figures move.** A segment figure can shift because an account crossed a boundary, with no customer doing anything differently. That cannot happen here. Everything on a cohort moves because the customers already in it did something, or because a figure behind them was restated.

Small cohorts carry weaker figures than large ones. Below 20 accounts in a segment tier, results for that tier are pooled with comparable segments and labelled as an estimate across segments, with the account count shown.

Both timestamps travel with every value. Compare against `as_of` rather than the time of the request, and read `computed_at` when you want to know how recently Beacon looked. [How current a number is](/how-current-a-number-is) covers both.

## Versioning

The published object is versioned separately from Beacon's internal model. A value is never removed from a published version — it is deprecated, and the removal lands in the next version. A published name is permanent; a rename ships as a redirect.


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