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

# Schema Reference

> Every v2.6 Lakehouse table and column, with the keys to join on.

> [!WARNING]
>
> **Available on request.** The Autumn Lakehouse is provisioned per customer. Contact us at [hey@useautumn.com](mailto:hey@useautumn.com) to get access. Any customer may use our [SQL endpoint](https://docs.useautumn.com/documentation/query-with-sql.md) instead.

Every table is named `v2_6_<object>` and grouped below by lane. The event log is the exception: it is `events`, shared with v2.3. Column types are listed in [Querying → Types](https://docs.useautumn.com/documentation/lakehouse/v2-6/querying.md#types).

## Keys

* Every table has `org_id` (your Autumn organization) and `env` (`live` or `sandbox`, never `production`). Match both in every join and filter `env` in every query.
* Join on `internal_*` ids, `customer_plan_id` and `balance_id`. Your own ids (`customer_id`, `plan_id`, `feature_id`, `entity_id`) can be renamed, can be null, are shared by every version of a plan, or are unique only within one customer.
* The **Key** line on each table is its primary key.

## Catalog

These four tables describe your pricing, not your customers: the features you meter, the plans you sell and what each plan includes. They change only when you edit your catalog.

```mermaid theme={null}
flowchart LR
  F["v2_6_features<br/>messages, seats, sso"]
  P["v2_6_plans<br/>Pro v2, Team v1"]
  PI["v2_6_plan_items<br/>Pro: 1,000 messages a month"]
  PL["v2_6_plan_licenses<br/>Team: 5 Member seats"]
  P -->|internal_plan_id| PI
  F -->|internal_feature_id| PI
  P -->|parent_internal_plan_id| PL
  P -->|license_internal_plan_id| PL
```

A plan with three features has one row in `v2_6_plans` and three rows in `v2_6_plan_items`. Every version of a plan is its own row, so join on `internal_plan_id` to get the exact version a customer is on, and group by `plan_id` when you want all versions together.

> [accordion] v2\_6\_features — feature catalog
>
> Every feature you have defined in Autumn: the things you meter or gate, such as `messages`, `seats` or `sso`. One row is one feature, the same object `POST /v1/features.get` returns.
>
> **One row per:** feature. **Key:** `org_id`, `env`, `internal_feature_id`. **API object:** Feature.
>
> | Column | Type | Description | Example |
> | - | - | - | - |
> | `org_id` | string | Your Autumn organization id. | `org_123` |
> | `env` | string | `live` or `sandbox`. | `live` |
> | `internal_feature_id` | string | Autumn's internal id for the feature. Every other table joins to features on this. | `fe_01` |
> | `feature_id` | string | The feature id you chose, as used in `check` and `track` (for example `messages`). | `messages` |
> | `name` | string | Display name. | `Messages` |
> | `type` | string | `boolean`, `metered`, `credit_system` or `ai_credit_system`. | `metered` |
> | `consumable` | boolean | For metered features: `true` if usage is used up and resets (messages, credits), `false` if it is held (seats, storage). | `true` |
> | `combine` | string | How grants of this feature from several plans combine: `sum`, `max` or `min`. | `sum` |
> | `event_names` | string (JSON) | JSON array of the event names that draw down this feature, for example `["message_sent"]`. | `["message_sent"]` |
> | `credit_schema` | string (JSON) | For credit systems: the credit cost of each metered feature. | |
> | `model_markups` | string (JSON) | For AI credit systems: per-model markup overrides. | |
> | `default_markup` | decimal | For AI credit systems: the default percentage markup. | |
> | `provider_markups` | string (JSON) | For AI credit systems: per-provider markup percentages. | |
> | `display` | string (JSON) | JSON `{singular, plural}` used in UI text. | `{"singular":"message","plural":"messages"}` |
> | `archived` | boolean | `true` if the feature is archived. | `false` |
> | `processors` | string (JSON) | Stripe product and meter ids linked to the feature, if any. | |

> [accordion] v2\_6\_plans — plan versions, with base price and trial
>
> Every plan in your catalog, one row per version. If you changed Pro after customers subscribed, Pro v1 and Pro v2 are two rows with the same `plan_id` and different `internal_plan_id`s. The plan's base price and free trial are columns on the row.
>
> **One row per:** plan version. **Key:** `org_id`, `env`, `internal_plan_id`. **API object:** Plan.
>
> | Column | Type | Description | Example |
> | - | - | - | - |
> | `org_id` | string | Your Autumn organization id. | `org_123` |
> | `env` | string | `live` or `sandbox`. | `live` |
> | `internal_plan_id` | string | Autumn's internal id for this plan version. Subscriptions, purchases, plan items and balances join here. | `prod_02` |
> | `plan_id` | string | The plan id you chose (for example `pro`). Shared by every version of the plan. | `pro` |
> | `name` | string | Display name. | `Pro` |
> | `description` | string | Optional description. | |
> | `group` | string | Plan group. Plans in the same group replace each other. | |
> | `version` | long | Version number, starting at 1. | `2` |
> | `version_slug` | string | Version label, `v{n}` unless you set one. | `v2` |
> | `active` | boolean | `true` for the current version of the plan. At most one version is active. | `true` |
> | `add_on` | boolean | `true` if the plan is an add-on, attached beside a main plan. | `false` |
> | `auto_enable` | boolean | `true` if the plan is attached automatically to new customers (typical for free plans). | |
> | `price_amount` | decimal | Base price, in major currency units (dollars, not cents). Null for a plan with no base price. | `20` |
> | `price_interval` | string | Billing interval of the base price, such as `month`, `year` or `one_off`. | `month` |
> | `price_interval_count` | decimal | Intervals per billing cycle (for example `3` with `month` for quarterly). | `1` |
> | `price_id` | string | Autumn's id for the base price. Null for a plan with no base price. | |
> | `price_additional_currencies` | string (JSON) | The base price in your other currencies, as JSON array text `[{currency, amount}]` in major units. Null when the base price has only one currency. | |
> | `price_display` | string (JSON) | Price text for pricing pages. | |
> | `price_processors` | string (JSON) | Stripe ids linked to the base price. | |
> | `trial_duration_length` | decimal | Free trial length, in `trial_duration_type` units. Null if the plan has no trial. | `14` |
> | `trial_duration_type` | string | `day` or `month`. | `day` |
> | `trial_card_required` | boolean | `true` if a card is needed to start the trial. | `true` |
> | `trial_on_end` | string | What happens when the trial ends. | |
> | `processors` | string (JSON) | Stripe ids linked to the plan. | |
> | `created_at` | long (epoch ms) | When the plan version was created. | |
> | `archived` | boolean | `true` if the plan is archived and can't be attached to new customers. | |
> | `config` | string (JSON) | JSON plan settings, such as `ignore_past_due` and `anchor_to_month_start`. | |
> | `billing_controls` | string (JSON) | Default spend limits, usage limits, alerts and auto top-ups this plan gives its customers. | |
> | `metadata` | string (JSON) | JSON metadata you set on the plan. | |
> | `base_variant_id` | string | Deprecated in the API in favour of `variant_details`. Kept because the API still returns it. | |
> | `variant_details` | string (JSON) | For a plan variant, which base plan it came from and how it differs. | |
> | `base_internal_plan_id` | string | For a plan variant, the base plan's `internal_plan_id`. Null otherwise. Joins `v2_6_plans.internal_plan_id`. | `null` |

> [accordion] v2\_6\_plan\_items — what each plan version includes
>
> What a plan grants, one row per feature on the plan. "Pro includes 1,000 messages a month, then \$0.02 per message" is one row. The item's price, reset and rollover settings are columns on the row.
>
> **One row per:** item on a plan version. **Key:** `org_id`, `env`, `internal_plan_item_id`. **API object:** Plan item (`plan.items[]`).
>
> | Column | Type | Description | Example |
> | - | - | - | - |
> | `org_id` | string | Your Autumn organization id. | `org_123` |
> | `env` | string | `live` or `sandbox`. | `live` |
> | `internal_plan_item_id` | string | Autumn's internal id for the item. | `pi_01` |
> | `internal_plan_id` | string | The plan version this item belongs to. Joins `v2_6_plans.internal_plan_id`. | `prod_02` |
> | `plan_id` | string | The plan's id. | `pro` |
> | `internal_feature_id` | string | The feature this item grants. Joins `v2_6_features.internal_feature_id`. | |
> | `feature_id` | string | The feature's id. | `messages` |
> | `price_id` | string | Id of the item's price, if it has one. Custom plans reference it from `v2_6_customer_plan_items`. | |
> | `position` | long | The item's place in the plan's `items` list as the API returns it, 1 first: priced items first, then by feature name. Order by it to match the API. | |
> | `included` | decimal | Units included for free. For consumable features the balance resets to this each interval. | `1000` |
> | `unlimited` | boolean | `true` if the feature is unlimited on this plan. | `false` |
> | `pooled` | boolean | `true` if this item's grants on a customer's entities add up into one shared customer balance. | |
> | `reset_interval` | string | How often the balance resets: `day`, `week`, `month`, `year` and so on. Null if it never resets. | `month` |
> | `reset_interval_count` | decimal | Intervals between resets. | |
> | `price_amount` | decimal | Price per `price_billing_units` once included usage is used, in major currency units. Null for tiered or free items. | `0.02` |
> | `price_tiers` | string (JSON) | JSON array of tiers, `[{to, amount, flat_amount, additional_currencies}]`. `to` is a number or `"inf"`. `additional_currencies` is the tier's price in your other currencies, `[{currency, amount}]`. | |
> | `price_additional_currencies` | string (JSON) | For a single-tier price, the price in your other currencies as JSON array text `[{currency, amount}]` in major units. Null otherwise; tiered prices carry them per tier in `price_tiers`. | |
> | `price_tier_behavior` | string | `graduated` or `volume`. | |
> | `price_interval` | string | Billing interval of the price. | |
> | `price_interval_count` | decimal | Intervals per billing cycle. | |
> | `price_billing_units` | decimal | Units per price step (100 means usage is billed in blocks of 100). | `1` |
> | `price_billing_method` | string | `prepaid` (bought upfront, like seats) or `usage_based` (pay as you go). | `usage_based` |
> | `price_max_purchase` | decimal | Most units a customer can buy beyond `included`. Null for no limit. | |
> | `price_processors` | string (JSON) | Stripe ids linked to the price. | |
> | `display` | string (JSON) | Item text for pricing pages. | |
> | `rollover_max` | decimal | Most unused units that carry into the next cycle. | `500` |
> | `rollover_max_percentage` | decimal | Rollover cap as a percentage of the grant, instead of `rollover_max`. | |
> | `rollover_expiry_duration_type` | string | Unit for how long rolled-over units last. | `month` |
> | `rollover_expiry_duration_length` | decimal | How many of those units they last. | `1` |
> | `expiry_duration` | string | For one-off prepaid items: unit for how long purchased units last. | |
> | `expiry_length` | decimal | For one-off prepaid items: how many of those units they last. | |
> | `feature_override` | string (JSON) | Feature settings this plan overrides, such as a credit system's costs. | |
> | `threshold_billing` | string (JSON) | Threshold billing settings for the item. | |
> | `is_custom` | boolean | `true` if the item belongs to one customer's custom plan rather than your catalog. See `v2_6_customer_plan_items`. | `false` |

> [!NOTE]
>
> A row with `is_custom = true` belongs to one customer's custom plan, not to your catalog. Filter `is_custom = false` when you want your published pricing only. See [Custom plans](https://docs.useautumn.com/documentation/lakehouse/v2-6/schema.md#custom-plans).

> [accordion] v2\_6\_plan\_licenses — seats a plan provides
>
> Which plans come with licenses (seats) of another plan. "Team includes 5 Member licenses" is one row: Team is the parent plan, Member is the license plan. Customers then assign those seats to their entities. Only your catalog's links are here, not per-customer changes.
>
> **One row per:** license link in your catalog. **Key:** `org_id`, `env`, `plan_license_id`. **API object:** Plan license (`plan.licenses[]`).
>
> | Column | Type | Description | Example |
> | - | - | - | - |
> | `org_id` | string | Your Autumn organization id. | `org_123` |
> | `env` | string | `live` or `sandbox`. | `live` |
> | `plan_license_id` | string | Autumn's internal id for the link. | `pl_01` |
> | `parent_internal_plan_id` | string | The plan that offers the licenses. Joins `v2_6_plans.internal_plan_id`. | |
> | `parent_plan_id` | string | Its plan id. | `team` |
> | `license_internal_plan_id` | string | The plan that is assigned as a license. Joins `v2_6_plans.internal_plan_id`. | |
> | `license_plan_id` | string | Its plan id. | `member` |
> | `version` | long | The license plan version this link pins. | `1` |
> | `version_slug` | string | That version's label. | |
> | `included` | long | Licenses included with the parent plan for free. | `5` |
> | `metadata` | string (JSON) | JSON metadata you set on the link. | |

## Customers and plans

These tables describe who your customers are and which plans they hold. A customer can have entities (users, workspaces, projects inside the customer), and a plan can be attached to the customer or to one entity.

```mermaid theme={null}
flowchart TB
  C["v2_6_customers"]
  E["v2_6_entities"]
  S["v2_6_subscriptions<br/>recurring plans"]
  PU["v2_6_purchases<br/>one-off plans"]
  CPI["v2_6_customer_plan_items<br/>custom plans only"]
  L["v2_6_licenses<br/>seat pools"]
  P["v2_6_plans"]
  C -->|internal_customer_id| E
  C -->|internal_customer_id| S
  C -->|internal_customer_id| PU
  E -.->|internal_entity_id| S
  P -->|internal_plan_id| S
  P -->|internal_plan_id| PU
  S -->|customer_plan_id| CPI
  S -->|parent_customer_plan_id| L
  L -.->|customer_license_id| S
```

`customer_plan_id` is the id of one customer's copy of a plan. `internal_plan_id` is the plan version in your catalog. Ten customers on Pro v2 have ten different `customer_plan_id` values and share one `internal_plan_id`. Balances, flags and invoices point at `customer_plan_id` when they need the customer's own subscription (its status, its period), and at `internal_plan_id` when they need the plan.

> [accordion] v2\_6\_customers — customer record
>
> Your customers, one row each, with the fields `POST /v1/customers.get` returns at the top level. Their plans, balances and invoices are in their own tables.
>
> **One row per:** customer. **Key:** `org_id`, `env`, `internal_customer_id`. **API object:** Customer.
>
> | Column | Type | Description | Example |
> | - | - | - | - |
> | `org_id` | string | Your Autumn organization id. | `org_123` |
> | `env` | string | `live` or `sandbox`. | `live` |
> | `internal_customer_id` | string | Autumn's internal id for the customer. Every customer-level table joins here. | `cus_int_01` |
> | `customer_id` | string | Your id for the customer. It can be null and you can change it, so don't join on it. | `cus_123` |
> | `name` | string | Name. | `Example Co` |
> | `email` | string | Email. | `billing@example.com` |
> | `created_at` | long (epoch ms) | When the customer was created. | |
> | `fingerprint` | string | Your de-duplication fingerprint (for example a device id), if you set one. | |
> | `stripe_id` | string | Stripe customer id. | `cus_Sx1` |
> | `metadata` | string (JSON) | JSON metadata you set on the customer. | `{"region":"eu"}` |
> | `send_email_receipts` | boolean | `true` if Autumn emails receipts to the customer. | |
> | `billing_controls` | string (JSON) | Balance allocations to entities, auto top-ups, spend limits, usage limits, usage alerts and overage settings, including those inherited from the customer's plans. | |
> | `config` | string (JSON) | JSON customer settings, such as `disable_pooled_balance`. | `{"disable_pooled_balance":false}` |
> | `processors` | string (JSON) | The customer's ids at Stripe, Vercel and RevenueCat. | |

> [accordion] v2\_6\_entities — users, workspaces and other sub-customers
>
> Entities are things inside a customer that get their own plans or balances: a user, a workspace, a project. Each one is counted against a feature (often `seats`). Deleted entities are left out.
>
> **One row per:** entity. **Key:** `org_id`, `env`, `internal_entity_id`. **API object:** Entity.
>
> | Column | Type | Description | Example |
> | - | - | - | - |
> | `org_id` | string | Your Autumn organization id. | `org_123` |
> | `env` | string | `live` or `sandbox`. | `live` |
> | `internal_entity_id` | string | Autumn's internal id for the entity. | `ent_int_01` |
> | `entity_id` | string | Your id for the entity. Unique within one customer only. | `user_1` |
> | `internal_customer_id` | string | The customer the entity belongs to. Joins `v2_6_customers.internal_customer_id`. | `cus_int_01` |
> | `customer_id` | string | That customer's id. | `cus_123` |
> | `internal_feature_id` | string | The feature the entity is counted against (for example `seats`). Joins `v2_6_features.internal_feature_id`. | |
> | `feature_id` | string | That feature's id. | `seats` |
> | `name` | string | Name. | `Ada` |
> | `created_at` | long (epoch ms) | When the entity was created. | |
> | `billing_controls` | string (JSON) | The entity's spend limits, usage limits, alerts and overage settings. | |

> [accordion] v2\_6\_subscriptions — recurring plans a customer holds
>
> Every recurring plan a customer has or had: one row each time a plan was attached to a customer or to one of their entities. This is `customer.subscriptions[]`, but with every status, including ended ones, so you can analyse history.
>
> **One row per:** recurring plan attached to a customer, any status. **Key:** `org_id`, `env`, `customer_plan_id`. **API object:** Subscription (`customer.subscriptions[]`).
>
> | Column | Type | Description | Example |
> | - | - | - | - |
> | `org_id` | string | Your Autumn organization id. | `org_123` |
> | `env` | string | `live` or `sandbox`. | `live` |
> | `customer_plan_id` | string | Autumn's internal id for this customer's copy of the plan. Breakdowns, flags, licenses and `v2_6_customer_plan_items` join here. | `cp_01` |
> | `id` | string | The subscription id the API returns: the id you passed when attaching, otherwise `customer_plan_id`. | `cp_01` |
> | `internal_customer_id` | string | The customer. Joins `v2_6_customers.internal_customer_id`. | `cus_int_01` |
> | `customer_id` | string | The customer's id. | `cus_123` |
> | `internal_entity_id` | string | The entity the plan is attached to. Null for a customer-level plan. Joins `v2_6_entities.internal_entity_id`. | |
> | `entity_id` | string | That entity's id. | |
> | `internal_plan_id` | string | The plan version that was attached. Joins `v2_6_plans.internal_plan_id`. | `prod_02` |
> | `plan_id` | string | The plan's id. | `pro` |
> | `status` | string | Lifecycle status: `active`, `past_due`, `scheduled`, `trialing`, `pending`, `paused`, `expired` or `unknown`. The API itself only shows `active` and `scheduled`; see [the API's status](#the-apis-status-of-a-subscription). | `active` |
> | `past_due` | boolean | `true` if a payment is overdue. | `false` |
> | `auto_enable` | boolean | `true` if the plan was attached automatically. | |
> | `add_on` | boolean | `true` if it is an add-on. | |
> | `canceled_at` | long (epoch ms) | When it was canceled. Null if not canceled. | |
> | `expires_at` | long (epoch ms) | When it ends or ended. Null if no end is set. | |
> | `trial_ends_at` | long (epoch ms) | When the trial ends or ended. Null if there was no trial. | |
> | `started_at` | long (epoch ms) | When it started. | `1785542400000   -- 2026-08-01 00:00 UTC` |
> | `current_period_start` | long (epoch ms) | Start of the current billing period. | `1793491200000   -- 2026-11-01 00:00 UTC` |
> | `current_period_end` | long (epoch ms) | End of the current billing period. | `1796083200000   -- 2026-12-01 00:00 UTC` |
> | `quantity` | decimal | Quantity (for per-seat plans). | `1` |
> | `position` | long | The subscription's place in the customer's `subscriptions` list as the API returns it, 1 first: active, past-due and scheduled plans first, then paid plans, main plans before add-ons, newest first. Order by it to match the API. | |
> | `scope` | string | `customer` or `entity`: the level the plan is attached at. | `customer` |
> | `trial_duration_length` | decimal | The free trial the plan had when it was attached. The same as the catalog plan's unless the plan is custom. | |
> | `trial_duration_type` | string | `day` or `month`. | |
> | `trial_card_required` | boolean | `true` if the trial needed a card. | |
> | `trial_on_end` | string | What happens when the trial ends. | |
> | `customer_license_id` | string | For a seat (a license plan assigned to an entity): the license pool in `v2_6_licenses` it came from. Null otherwise. | |
> | `is_custom` | boolean | `true` if this customer has their own custom version of the plan. Its items are found through `v2_6_customer_plan_items`. | `false` |

### The API's status of a subscription

`v2_6_subscriptions.status` is the full lifecycle status, so you can see trials, expired plans and paused plans. The API's `subscriptions[]` array is narrower: it returns only live plans, and shows `past_due` as `active` with `past_due = true`. To get the list the API returns:

```sql theme={null}
SELECT
  id,
  plan_id,
  CASE status WHEN 'past_due' THEN 'active' ELSE status END AS api_status,
  past_due
FROM <namespace>.v2_6_subscriptions
WHERE env = 'live'
  AND internal_customer_id = '<internal_customer_id>'
  AND internal_entity_id IS NULL      -- customer-level plans; entity plans show on the entity
  AND customer_license_id IS NULL     -- seats show on the entity they're assigned to
  AND status IN ('active', 'past_due', 'scheduled');
```

> [accordion] v2\_6\_purchases — one-off plans a customer holds
>
> Every one-off plan a customer bought, such as a credit pack. This is `customer.purchases[]`, with every status.
>
> **One row per:** one-off plan attached to a customer, any status. **Key:** `org_id`, `env`, `customer_plan_id`. **API object:** Purchase (`customer.purchases[]`).
>
> | Column | Type | Description | Example |
> | - | - | - | - |
> | `org_id` | string | Your Autumn organization id. | `org_123` |
> | `env` | string | `live` or `sandbox`. | `live` |
> | `customer_plan_id` | string | Autumn's internal id for this purchase. Breakdowns and `v2_6_customer_plan_items` join here. | `cp_02` |
> | `internal_customer_id` | string | The customer. Joins `v2_6_customers.internal_customer_id`. | `cus_int_01` |
> | `customer_id` | string | The customer's id. | `cus_123` |
> | `internal_entity_id` | string | The entity it was bought for. Null for a customer-level purchase. Joins `v2_6_entities.internal_entity_id`. | |
> | `entity_id` | string | That entity's id. | |
> | `internal_plan_id` | string | The plan version bought. Joins `v2_6_plans.internal_plan_id`. | `prod_03` |
> | `plan_id` | string | The plan's id. | `credit_pack` |
> | `status` | string | Lifecycle status, as on `v2_6_subscriptions`. | `active` |
> | `expires_at` | long (epoch ms) | When access ends. Null for lifetime access. | |
> | `started_at` | long (epoch ms) | When it was bought. | `1792022400000   -- 2026-10-15 00:00 UTC` |
> | `quantity` | decimal | Units bought. | `1` |
> | `position` | long | The purchase's place in the customer's `purchases` list as the API returns it, 1 first, in the same order as `v2_6_subscriptions.position`. | |
> | `scope` | string | `customer` or `entity`. | `customer` |
> | `is_custom` | boolean | `true` if the customer has a custom version of the plan. | `false` |

### Custom plans

When you change a plan for one customer (more credits, a different price, an extra feature), Autumn gives that customer their own custom version of the plan. The subscription row has `is_custom = true`, but `internal_plan_id` still points at the catalog plan it was based on, whose items are not what this customer gets. The customer's own items are in `v2_6_plan_items` with `is_custom = true`, and `v2_6_customer_plan_items` says which of them belong to which subscription.

```mermaid theme={null}
flowchart LR
  S["v2_6_subscriptions<br/>is_custom = true"]
  CPI["v2_6_customer_plan_items"]
  PI["v2_6_plan_items<br/>is_custom = true"]
  S -->|customer_plan_id| CPI
  CPI -->|internal_plan_item_id| PI
```

To list what a customer's plan actually includes, custom or not:

```sql theme={null}
-- Catalog plans: the plan version's items
SELECT s.customer_plan_id, pi.feature_id, pi.included, pi.price_amount
FROM <namespace>.v2_6_subscriptions s
JOIN <namespace>.v2_6_plan_items pi
  ON pi.org_id = s.org_id AND pi.env = s.env
 AND pi.internal_plan_id = s.internal_plan_id AND pi.is_custom = false
WHERE s.is_custom = false

UNION ALL

-- Custom plans: the customer's own items
SELECT s.customer_plan_id, pi.feature_id, pi.included, pi.price_amount
FROM <namespace>.v2_6_subscriptions s
JOIN <namespace>.v2_6_customer_plan_items cpi
  ON cpi.org_id = s.org_id AND cpi.env = s.env
 AND cpi.customer_plan_id = s.customer_plan_id AND cpi.row_type = 'item'
JOIN <namespace>.v2_6_plan_items pi
  ON pi.org_id = cpi.org_id AND pi.env = cpi.env
 AND pi.internal_plan_item_id = cpi.internal_plan_item_id
WHERE s.is_custom = true;
```

The same works for `v2_6_purchases`. A row with `row_type = 'price'` and no `internal_plan_item_id` is the custom plan's base price.

> [accordion] v2\_6\_customer\_plan\_items — items and prices on custom plans
>
> Only used by custom plans. When you give one customer their own version of a plan (more credits, a different price), that customer's items and prices are not in your catalog plan. This table says which items and prices make up each custom subscription or purchase. If you don't use custom plans, it is empty and you can skip it.
>
> **One row per:** item or price on a custom plan. **Key:** `org_id`, `env`, `customer_plan_item_id`. **API object:** None of its own. It is how you rebuild `subscription.plan` for a custom plan.
>
> | Column | Type | Description | Example |
> | - | - | - | - |
> | `org_id` | string | Your Autumn organization id. | `org_123` |
> | `env` | string | `live` or `sandbox`. | `live` |
> | `customer_plan_item_id` | string | Autumn's internal id for the row. | `cpi_01` |
> | `row_type` | string | `item` (a feature on the custom plan) or `price` (a price on it). | `item` |
> | `customer_plan_id` | string | The custom subscription or purchase (`v2_6_subscriptions` or `v2_6_purchases`). | `cp_09` |
> | `internal_customer_id` | string | The customer. Joins `v2_6_customers.internal_customer_id`. | `cus_int_02` |
> | `internal_plan_item_id` | string | The custom item in `v2_6_plan_items` (that row has `is_custom = true`). Null on the base-price row. | `pi_77` |
> | `price_id` | string | The price, matching `v2_6_plan_items.price_id`. Null on a free item. When `internal_plan_item_id` is null, this is the plan's base price. | `null` |
> | `options` | string (JSON) | The prepaid quantity the customer chose for this price, if any. | `null` |

> [accordion] v2\_6\_licenses — seat pools
>
> A customer's license pools: "this customer has 7 Member seats from their Team plan, 4 assigned and 3 free". Only pools on live plans (active or past due) are included, as in `customer.licenses[]`.
>
> **One row per:** license pool. **Key:** `org_id`, `env`, `customer_license_id`. **API object:** Customer license (`customer.licenses[]`).
>
> | Column | Type | Description | Example |
> | - | - | - | - |
> | `org_id` | string | Your Autumn organization id. | `org_123` |
> | `env` | string | `live` or `sandbox`. | `live` |
> | `customer_license_id` | string | Autumn's internal id for the pool. Seat subscriptions point here. | `cl_01` |
> | `internal_customer_id` | string | The customer. Joins `v2_6_customers.internal_customer_id`. | |
> | `customer_id` | string | The customer's id. | `cus_123` |
> | `parent_customer_plan_id` | string | The customer's subscription that provides the seats. Joins `v2_6_subscriptions.customer_plan_id`. | |
> | `parent_internal_plan_id` | string | That plan's version. Joins `v2_6_plans.internal_plan_id`. | |
> | `parent_plan_id` | string | That plan's id. | `team` |
> | `license_internal_plan_id` | string | The plan given out as a seat. Joins `v2_6_plans.internal_plan_id`. | |
> | `license_plan_id` | string | Its id. | `member` |
> | `plan_license_id` | string | The catalog link in `v2_6_plan_licenses`. Null for a link made for this customer only. | |
> | `license_plan_name` | string | The seat plan's name. | `Member` |
> | `granted` | decimal | Seats in the pool: included plus paid. | `7` |
> | `usage` | decimal | Seats assigned to entities. | `4` |
> | `remaining` | decimal | Seats free to assign. | `3` |
> | `paid_quantity` | decimal | Seats bought on top of the included amount. | `2` |

> [!NOTE]
>
> A seat is a subscription too: the license plan attached to the entity that holds the seat. Its row in `v2_6_subscriptions` has `customer_license_id` set, and its `status`, `canceled_at` and billing period are copied from the plan that provides the seat.

## Balances

These tables hold what `POST /v1/customers.get` and `POST /v1/entities.get` return under `balances` and `flags`, already computed. Read [Working with balances](https://docs.useautumn.com/documentation/lakehouse/v2-6/balances.md) first: it explains the per-view rows and the order grants are used up in, with a worked example.

```mermaid theme={null}
flowchart LR
  B["v2_6_balances<br/>one per customer, feature, view"]
  BD["v2_6_breakdowns<br/>the grants, in order"]
  R["v2_6_rollovers<br/>carried-over balance"]
  PBC["v2_6_pooled_balance_contributions<br/>what feeds a pool"]
  FL["v2_6_flags<br/>on/off features"]
  B -->|balance_id| BD
  B -->|balance_id| R
  BD -->|pooled_balance_id| PBC
```

> [accordion] v2\_6\_balances — balance per customer, feature and view
>
> The balance a customer or entity sees for one feature: the `balances` object of `POST /v1/customers.get` or `POST /v1/entities.get`. There is one row for the customer's view, and one more for each entity's view, because an entity also sees its own grants. Filter on `scope`.
>
> **One row per:** (customer, feature, view). **Key:** `org_id`, `env`, `balance_id`. **API object:** Balance (`customer.balances{}`, `entity.balances{}`).
>
> | Column | Type | Description | Example |
> | - | - | - | - |
> | `org_id` | string | Your Autumn organization id. | `org_123` |
> | `env` | string | `live` or `sandbox`. | `live` |
> | `balance_id` | string | Key: `internal_customer_id:internal_feature_id:internal_entity_id`, with the last part empty for the customer's view. Breakdowns and rollovers join on it. | `cus_int_01:fe_01:` |
> | `internal_customer_id` | string | The customer. Joins `v2_6_customers.internal_customer_id`. | |
> | `customer_id` | string | The customer's id. | `cus_123` |
> | `internal_feature_id` | string | The feature. Joins `v2_6_features.internal_feature_id`. | |
> | `feature_id` | string | The feature's id. | `messages` |
> | `internal_entity_id` | string | The entity whose view this is. Null for the customer's view. Joins `v2_6_entities.internal_entity_id`. | `null` |
> | `entity_id` | string | That entity's id. | |
> | `scope` | string | `customer` for the customer's view, `entity` for an entity's view. | `customer` |
> | `granted` | decimal | Total granted: included plus prepaid, plus rollovers. | `1700` |
> | `remaining` | decimal | Total left to use, including rollovers. | `1350` |
> | `usage` | decimal | Total used this period, including what was used from rollovers. | `350` |
> | `unlimited` | boolean | `true` if any grant makes the feature unlimited. | `false` |
> | `overage_allowed` | boolean | `true` if usage can go past the balance and be billed as overage. | `true` |
> | `max_purchase` | decimal | Most that can be bought as a top-up. Null for no limit. | |
> | `next_reset_at` | long (epoch ms) | When the balance next resets. Null if it doesn't. | `1796083200000   -- 2026-12-01 00:00 UTC` |
> | `allocated` | decimal | Shared credits reserved for entities by balance allocations. Null when the customer doesn't allocate this feature. | |
> | `unallocated` | decimal | Shared credits no allocation holds. Any entity can use them. | |
> | `as_of` | long (epoch ms) | When Autumn computed this row. Expiry and reset dates were judged at this moment. | `1793872800000   -- 2026-11-05 10:00 UTC` |

> [accordion] v2\_6\_breakdowns — the grants behind a balance
>
> Where a balance comes from: one row per grant that makes up a balance, such as "1,000 from Pro this month" and "500 from a credit pack". This is the balance's `breakdown[]` array, in the same order, and `position` is the order Autumn uses the grants up.
>
> **One row per:** grant in a balance, per view. **Key:** `org_id`, `env`, `balance_id`, `breakdown_id`. **API object:** Balance breakdown (`balance.breakdown[]`).
>
> | Column | Type | Description | Example |
> | - | - | - | - |
> | `org_id` | string | Your Autumn organization id. | `org_123` |
> | `env` | string | `live` or `sandbox`. | `live` |
> | `balance_id` | string | The balance this row belongs to, in `v2_6_balances`. | `cus_int_01:fe_01:` |
> | `breakdown_id` | string | Autumn's internal id for the grant. One grant appears once in every view that sees it, so the key is `(balance_id, breakdown_id)`. | `ce_01` |
> | `id` | string | The id the API returns for this grant. Event deductions name it. | |
> | `position` | long | Place in the `breakdown[]` array, starting at 1. Autumn deducts from position 1 first. | `1` |
> | `internal_customer_id` | string | The customer. Joins `v2_6_customers.internal_customer_id`. | |
> | `internal_feature_id` | string | The feature. Joins `v2_6_features.internal_feature_id`. | |
> | `internal_entity_id` | string | The entity whose view this is. Null for the customer's view. Joins `v2_6_entities.internal_entity_id`. | |
> | `customer_plan_id` | string | The subscription or purchase that grants it. Null for a grant not tied to a plan, and for a pool. Joins `v2_6_subscriptions.customer_plan_id`. | `cp_01` |
> | `internal_plan_id` | string | The plan version. Joins `v2_6_plans.internal_plan_id`. | |
> | `plan_id` | string | The plan's id. Null for a grant not tied to a plan, and for a pool. | `pro` |
> | `internal_plan_item_id` | string | The plan item that defines the grant. Joins `v2_6_plan_items.internal_plan_item_id`. | |
> | `pooled_balance_id` | string | Set when this row is a shared pool. What feeds it is in `v2_6_pooled_balance_contributions`. | |
> | `included_grant` | decimal | Amount granted from the plan's included usage. | `1000` |
> | `prepaid_grant` | decimal | Amount granted from prepaid purchases. | `0` |
> | `remaining` | decimal | Amount left. | `850` |
> | `usage` | decimal | Amount used this period. | `150` |
> | `overage` | decimal | Usage beyond what was granted, which is billed as overage. 0 while usage stays within the grant. On a customer-level row of an entity-scoped grant it is summed across the entities. | |
> | `unlimited` | boolean | `true` if this grant is unlimited. An unlimited balance has a single breakdown row: `usage` is what was used, as a positive number, and `included_grant`, `prepaid_grant`, `remaining` and `overage` are 0. | |
> | `reset_interval` | string | How often this grant resets. Null if it doesn't. | `month` |
> | `reset_interval_count` | decimal | Intervals between resets. | |
> | `reset_resets_at` | long (epoch ms) | When this grant next resets. | `1796083200000   -- 2026-12-01 00:00 UTC` |
> | `price_amount` | decimal | Overage or prepaid price per `price_billing_units`, in major currency units. | |
> | `price_tiers` | string (JSON) | JSON array of price tiers. | |
> | `price_tier_behavior` | string | `graduated` or `volume`. | |
> | `price_billing_units` | decimal | Units per price step. | |
> | `price_billing_method` | string | `prepaid` or `usage_based`. | |
> | `price_max_purchase` | decimal | Most units that can be bought. Null for no limit. | |
> | `expires_at` | long (epoch ms) | When this grant expires. Null if it doesn't. | |
> | `source` | string | `customer` if the grant is shared at customer level, `entity` if the entity owns it. | `customer` |
> | `allocation_amount` | decimal | On an entity's view of a shared grant the customer allocates: the amount allocated to that entity. | |

> [accordion] v2\_6\_rollovers — carried-over balance
>
> Unused balance carried over from earlier periods that has not expired: the balance's `rollovers[]` array. Autumn uses rollovers up before any grant in `v2_6_breakdowns`.
>
> **One row per:** unexpired rollover, per view. **Key:** `org_id`, `env`, `balance_id`, `rollover_id`. **API object:** Balance rollover (`balance.rollovers[]`).
>
> | Column | Type | Description | Example |
> | - | - | - | - |
> | `org_id` | string | Your Autumn organization id. | `org_123` |
> | `env` | string | `live` or `sandbox`. | `live` |
> | `balance_id` | string | The balance this rollover belongs to. Joins `v2_6_balances.balance_id`. | `cus_int_01:fe_01:` |
> | `rollover_id` | string | Autumn's internal id for the rollover. Event deductions name it. | `ro_01` |
> | `breakdown_id` | string | The grant it rolled over from, in `v2_6_breakdowns` (same `balance_id`). | `ce_01` |
> | `internal_customer_id` | string | The customer. Joins `v2_6_customers.internal_customer_id`. | |
> | `internal_feature_id` | string | The feature. Joins `v2_6_features.internal_feature_id`. | |
> | `internal_entity_id` | string | The entity whose view this is. Null for the customer's view. Joins `v2_6_entities.internal_entity_id`. | |
> | `granted` | decimal | Amount carried over. | `200` |
> | `balance` | decimal | Amount of it still left. | `0` |
> | `expires_at` | long (epoch ms) | When it expires. Null if it doesn't. | `1796083200000   -- 2026-12-01 00:00 UTC` |

> [accordion] v2\_6\_flags — boolean features
>
> On/off features a customer or entity has, such as `sso`: the `flags` object of the customer or entity. If several plans grant the same flag, the row is the one the API shows.
>
> **One row per:** (customer, boolean feature, view). **Key:** `org_id`, `env`, `flag_id`. **API object:** Flag (`customer.flags{}`).
>
> | Column | Type | Description | Example |
> | - | - | - | - |
> | `org_id` | string | Your Autumn organization id. | `org_123` |
> | `env` | string | `live` or `sandbox`. | `live` |
> | `flag_id` | string | Key: `internal_customer_id:internal_feature_id:internal_entity_id`, built like `balance_id`. | `cus_int_01:fe_02:` |
> | `internal_customer_id` | string | The customer. Joins `v2_6_customers.internal_customer_id`. | |
> | `customer_id` | string | The customer's id. | `cus_123` |
> | `internal_feature_id` | string | The feature. Joins `v2_6_features.internal_feature_id`. | |
> | `feature_id` | string | The feature's id. | `sso` |
> | `internal_entity_id` | string | The entity whose view this is. Null for the customer's view. Joins `v2_6_entities.internal_entity_id`. | |
> | `entity_id` | string | That entity's id. | |
> | `scope` | string | `customer` or `entity`. | `customer` |
> | `breakdown_id` | string | Autumn's internal id for the grant behind the flag. Flags never appear in `v2_6_breakdowns`, so nothing there joins to it. | |
> | `id` | string | The id the API returns for the flag. | |
> | `customer_plan_id` | string | The subscription or purchase that grants it. Null for a flag not tied to a plan. Joins `v2_6_subscriptions.customer_plan_id`. | `cp_01` |
> | `internal_plan_id` | string | The plan version. Joins `v2_6_plans.internal_plan_id`. | |
> | `plan_id` | string | The plan's id. | `pro` |
> | `expires_at` | long (epoch ms) | When the flag expires. Null if it doesn't. | `null` |

> [accordion] v2\_6\_pooled\_balance\_contributions — what feeds a pooled balance
>
> What feeds a shared pool. With pooling, plans on several entities (say each seat's 100 credits) add up into one customer-level balance. The pool is one row in `v2_6_breakdowns`; this table lists the plans that feed it and how much each adds.
>
> **One row per:** contributor to a pool. **Key:** `org_id`, `env`, `contribution_id`. **API object:** Pooled balance contribution (`breakdown[].contributions.list[]`).
>
> | Column | Type | Description | Example |
> | - | - | - | - |
> | `org_id` | string | Your Autumn organization id. | `org_123` |
> | `env` | string | `live` or `sandbox`. | `live` |
> | `contribution_id` | string | Autumn's internal id for the contribution. | `pbc_01` |
> | `id` | string | The id the API returns. | |
> | `pooled_balance_id` | string | The pool, matching `v2_6_breakdowns.pooled_balance_id`. | `pb_01` |
> | `internal_customer_id` | string | The customer. Joins `v2_6_customers.internal_customer_id`. | |
> | `source_customer_plan_id` | string | The subscription that contributes. Joins `v2_6_subscriptions.customer_plan_id`. | |
> | `internal_entity_id` | string | The entity holding that subscription. Null for a customer-level plan. Joins `v2_6_entities.internal_entity_id`. | |
> | `entity_id` | string | That entity's id. | `user_1` |
> | `entity_name` | string | That entity's name. | `Ada` |
> | `internal_plan_id` | string | The contributing plan version. Joins `v2_6_plans.internal_plan_id`. | |
> | `plan_id` | string | Its id. | `seat` |
> | `plan_name` | string | Its name. | `Seat` |
> | `current_contribution` | decimal | Amount it adds to the pool this cycle. | `100` |
> | `next_cycle_contribution` | decimal | Amount it will add next cycle. | `100` |
> | `competes` | boolean | `true` when the feature combines by `max` or `min`, so only the winning share counts instead of adding up. | `false` |
> | `unlimited` | boolean | `true` if this contributor makes the pool unlimited. | |
> | `created_at` | long (epoch ms) | When the contribution started. | |

## Invoices

> [accordion] v2\_6\_invoices — invoice record
>
> Invoices for your customers, from Stripe or RevenueCat.
>
> **One row per:** invoice. **Key:** `org_id`, `env`, `invoice_id`. **API object:** Invoice (`POST /v1/invoices.list`).
>
> | Column | Type | Description | Example |
> | - | - | - | - |
> | `org_id` | string | Your Autumn organization id. | `org_123` |
> | `env` | string | `live` or `sandbox`. | `live` |
> | `invoice_id` | string | Autumn's internal id for the invoice. | `inv_01` |
> | `internal_customer_id` | string | The customer. Joins `v2_6_customers.internal_customer_id`. | |
> | `customer_id` | string | The customer's id. | `cus_123` |
> | `internal_entity_id` | string | The entity it was for, if any. Joins `v2_6_entities.internal_entity_id`. | |
> | `entity_id` | string | That entity's id. | |
> | `plan_ids` | string (JSON) | JSON array of the plan ids on the invoice. A deleted plan keeps the id it had. | `["pro"]` |
> | `processor_id` | string | The invoice's id at Stripe or RevenueCat. The API calls this field `stripe_id`. | `in_1Sx1` |
> | `processor_type` | string | `stripe` or `revenuecat`. | `stripe` |
> | `status` | string | For example `paid`, `open`, `void` or `draft`. | `paid` |
> | `total` | decimal | Invoice total before refunds, in major currency units. | `25` |
> | `amount_paid` | decimal | Amount paid. | `25` |
> | `refunded_amount` | decimal | Amount refunded. | `0` |
> | `currency` | string | ISO currency code, lower case. | `usd` |
> | `created_at` | long (epoch ms) | When the invoice was created. | `1793491200000   -- 2026-11-01 00:00 UTC` |
> | `hosted_invoice_url` | string | Link to the hosted invoice page. | |

> [accordion] v2\_6\_invoice\_line\_items — invoice lines
>
> The lines on each invoice: the base price, usage charges, seats.
>
> **One row per:** invoice line. **Key:** `org_id`, `env`, `line_item_id`. **API object:** Invoice item (`invoice.items[]`).
>
> | Column | Type | Description | Example |
> | - | - | - | - |
> | `org_id` | string | Your Autumn organization id. | `org_123` |
> | `env` | string | `live` or `sandbox`. | `live` |
> | `line_item_id` | string | Autumn's internal id for the line. | `li_02` |
> | `invoice_id` | string | The invoice, in `v2_6_invoices`. | `inv_01` |
> | `internal_customer_id` | string | The customer. Joins `v2_6_customers.internal_customer_id`. | |
> | `internal_plan_id` | string | The plan version the line is for. Joins `v2_6_plans.internal_plan_id`. | |
> | `plan_id` | string | Its id. | `pro` |
> | `internal_feature_id` | string | The feature the line charges for. Null for a base price. Joins `v2_6_features.internal_feature_id`. | |
> | `feature_id` | string | Its id. | `messages` |
> | `feature_name` | string | Its name. | `Messages` |
> | `period_start` | long (epoch ms) | Start of the period charged. | `1790812800000   -- 2026-10-01 00:00 UTC` |
> | `period_end` | long (epoch ms) | End of the period charged. | `1793491200000   -- 2026-11-01 00:00 UTC` |
> | `description` | string | The line's description, as shown on the invoice. | |
> | `quantity` | decimal | Units charged. | `250` |
> | `amount` | decimal | Line amount before discounts and tax, in major currency units. | `5` |
> | `entities` | string (JSON) | JSON array splitting the line by entity, `[{entity_id, quantity, amount}]`. | |

See [Working with invoices](https://docs.useautumn.com/documentation/lakehouse/v2-6/working-with-invoices.md) for revenue queries.

## Rewards and referrals

A reward is either a coupon (a discount) or a feature grant (free balance). A referral program says which reward a referral earns, and each use of a customer's referral code is a row in `v2_6_referrals`.

> [accordion] v2\_6\_coupons — discount rewards
>
> Your discount coupons: percentage off, a fixed amount off, or invoice credits, with their promo codes.
>
> **One row per:** coupon. **Key:** `org_id`, `env`, `internal_reward_id`. **API object:** Coupon.
>
> | Column | Type | Description | Example |
> | - | - | - | - |
> | `org_id` | string | Your Autumn organization id. | `org_123` |
> | `env` | string | `live` or `sandbox`. | `live` |
> | `internal_reward_id` | string | Autumn's internal id for the coupon. Referral programs join here. | `rew_01` |
> | `coupon_id` | string | The coupon id you chose. | `launch20` |
> | `name` | string | Display name. | `Launch 20%` |
> | `type` | string | `percentage_discount`, `fixed_discount` or `invoice_credits`. | `percentage_discount` |
> | `value` | decimal | Percentage, or amount in major currency units, depending on `type`. | `20` |
> | `duration_type` | string | How long the discount lasts, for example `one_off`, `months` or `forever`. | `months` |
> | `duration_length` | decimal | Number of `duration_type` units. | `3` |
> | `plan_ids` | string (JSON) | JSON array of the plan ids the coupon applies to. | `["pro"]` |
> | `promo_codes` | string (JSON) | JSON array of the promo codes that redeem it. | `[{"code":"LAUNCH20"}]` |
> | `created_at` | long (epoch ms) | When the coupon was created. | |

> [accordion] v2\_6\_feature\_grants — free-balance rewards
>
> Rewards that give free balance instead of a discount, for example "500 bonus messages".
>
> **One row per:** feature grant. **Key:** `org_id`, `env`, `internal_reward_id`. **API object:** Feature grant.
>
> | Column | Type | Description | Example |
> | - | - | - | - |
> | `org_id` | string | Your Autumn organization id. | `org_123` |
> | `env` | string | `live` or `sandbox`. | `live` |
> | `internal_reward_id` | string | Autumn's internal id for the grant. Referral programs join here. | `rew_02` |
> | `feature_grant_id` | string | The id you chose. | `bonus_messages` |
> | `name` | string | Display name. | `Bonus messages` |
> | `grants` | string (JSON) | JSON array of what is granted, `[{feature_id, included, expiry}]`. | `[{"feature_id":"messages","included":500}]` |
> | `promo_codes` | string (JSON) | JSON array of the promo codes that redeem it. | |
> | `created_at` | long (epoch ms) | When it was created. | |

> [accordion] v2\_6\_referral\_programs — referral configuration
>
> Your referral programs: which reward a referral earns, who receives it, and when.
>
> **One row per:** referral program. **Key:** `org_id`, `env`, `internal_referral_program_id`. **API object:** Referral program.
>
> | Column | Type | Description | Example |
> | - | - | - | - |
> | `org_id` | string | Your Autumn organization id. | `org_123` |
> | `env` | string | `live` or `sandbox`. | `live` |
> | `internal_referral_program_id` | string | Autumn's internal id for the program. | `rp_01` |
> | `referral_program_id` | string | The id you chose. | `invite_friends` |
> | `internal_reward_id` | string | The reward it gives: a row in `v2_6_coupons` or `v2_6_feature_grants`. | |
> | `reward_id` | string | That reward's id. | `bonus_messages` |
> | `redeem_on` | string | When the reward is given, for example at customer creation or at checkout. | `checkout` |
> | `received_by` | string | Who gets the reward: the referrer, or everyone. | `all` |
> | `max_redemptions` | decimal | Most times the program pays out for one referrer. | |
> | `plan_ids` | string (JSON) | JSON array of the plan ids that qualify. | `["pro"]` |
> | `exclude_trial` | boolean | `true` if starting a trial does not count. | |
> | `created_at` | long (epoch ms) | When the program was created. | |

> [accordion] v2\_6\_referrals — uses of a referral code
>
> Each time someone used a customer's referral code: who referred whom, under which program, and whether the reward was given.
>
> **One row per:** use of a referral code. **Key:** `org_id`, `env`, `redemption_id`. **API object:** Customer referral (`customer.referrals[]`).
>
> | Column | Type | Description | Example |
> | - | - | - | - |
> | `org_id` | string | Your Autumn organization id. | `org_123` |
> | `env` | string | `live` or `sandbox`. | `live` |
> | `redemption_id` | string | Autumn's internal id for the redemption. | `red_01` |
> | `internal_customer_id` | string | The referrer: the customer whose code was used. Joins `v2_6_customers.internal_customer_id`. | `cus_int_01` |
> | `referred_internal_customer_id` | string | The customer who used the code. Joins `v2_6_customers.internal_customer_id`. | `cus_int_02` |
> | `internal_referral_program_id` | string | The referral program. Joins `v2_6_referral_programs.internal_referral_program_id`. | |
> | `program_id` | string | Its id. | `invite_friends` |
> | `referred_customer_id` | string | The referred customer's id. | `cus_456` |
> | `referred_customer_name` | string | Their name. | |
> | `referred_customer_email` | string | Their email. | |
> | `reward_applied` | boolean | `true` once the reward has been given. | `true` |
> | `created_at` | long (epoch ms) | When the code was used. | |

## Events

> [accordion] events — usage event log
>
> Every usage event you sent with `track`. It is not versioned: v2.3 and v2.6 read the same table, and it only grows.
>
> **One row per:** event. **Key:** `org_id`, `env`, `id`. **API object:** Event.
>
> | Column | Type | Description | Example |
> | - | - | - | - |
> | `org_id` | string | Your Autumn organization id. | `org_123` |
> | `env` | string | `live` or `sandbox`. | `live` |
> | `id` | string | The event's id. | `evt_01` |
> | `internal_customer_id` | string | The customer. Joins `v2_6_customers.internal_customer_id`. | |
> | `customer_id` | string | The customer's id. | `cus_123` |
> | `internal_entity_id` | string | The entity, if the event was tracked for one. Joins `v2_6_entities.internal_entity_id`. | |
> | `entity_id` | string | That entity's id. | |
> | `internal_product_id` | string | The plan version the event was attributed to. Join it to `v2_6_plans.internal_plan_id`. It keeps the old name because events are not versioned. | |
> | `event_name` | string | The event name you tracked. | `message_sent` |
> | `value` | decimal | The value you tracked. | `1` |
> | `timestamp` | timestamp | When the event happened. A real timestamp, not epoch milliseconds. | `2026-11-04 09:12:00` |
> | `properties` | string (JSON) | JSON properties you sent with the event. | |
> | `deductions` | string (JSON) | JSON array of what the event drew down, `[{balance_id, feature_id, plan_id, value}]`. `balance_id` is a `v2_6_breakdowns.id` or a `v2_6_rollovers.rollover_id`. | `[{"balance_id":"ce_01","feature_id":"messages","plan_id":"pro","value":1}]` |
> | `org_slug` | string | Your organization's slug. | |
> | `created_at` | long (epoch ms) | When Autumn recorded the event (epoch ms), which can be later than `timestamp`. | |
> | `idempotency_key` | string | The idempotency key you sent, if any. | |

> [!WARNING]
>
> The table is `events`, not `v2_6_events`. v2.3 and v2.6 share it.


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