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

# Revenue API

> Read revenue, refunds, disputes, and MRR in your reporting currency, list the revenue ledger, and send revenue from your server.

<Note>
  Revenue is part of product analytics, which is coming soon. Projects without product analytics get
  `403` with the code `coming_soon` or `plan_upgrade_required`. Call `analytics.status` to see the
  state of a project.
</Note>

The revenue API reads the revenue ledger of a project and sends revenue from your server. See
[Revenue](/features/revenue) for how Squasher counts revenue and MRR, and [Stripe](/integrations/stripe)
to connect Stripe.

## Operations

| Operation | Method and path | Access | Purpose |
| - | - | - | - |
| `revenue.status` | `GET /v1/projects/{project_id}/revenue/status` | `revenue:read` | Setup check: Stripe, webhook, backfill, rows, links to people, rates. |
| `revenue.overview` | `GET /v1/projects/{project_id}/revenue/overview` | `revenue:read` | Gross, refunds, disputes, net, customers, series, by currency and by plan. |
| `revenue.mrr` | `GET /v1/projects/{project_id}/revenue/mrr` | `revenue:read` | MRR at the start and end of the range, the movements, and a series. |
| `revenue.impact` | `GET /v1/projects/{project_id}/revenue/impact` | `revenue:read` | Estimated revenue at risk for an issue, incident, release, or page (a range). |
| `revenue.attribution` | `GET /v1/projects/{project_id}/revenue/attribution` | `revenue:read` | Net revenue by the source, medium, or campaign of a touch. |
| `revenue.listEvents` | `GET /v1/projects/{project_id}/revenue/events` | `revenue:read` | Ledger rows, newest first, with a cursor. |
| `revenue.sendEvents` | `POST /v1/projects/{project_id}/revenue/events` | `revenue:write` | Record up to 100 money movements from your server. |
| `revenue.sendSubscriptions` | `POST /v1/projects/{project_id}/revenue/subscriptions` | `revenue:write` | Record up to 100 subscription states (MRR from a time on). |
| `revenue.getSettings` | `GET /v1/projects/{project_id}/revenue/settings` | `revenue:read` | The reporting currency. |
| `revenue.updateSettings` | `PUT /v1/projects/{project_id}/revenue/settings` | `revenue:write` | Set the reporting currency. |
| `integrations.connectStripe` | `POST /v1/projects/{project_id}/provider-connections/stripe` | `providers:write` | Connect Stripe with a restricted read-only key. |
| `integrations.setStripeWebhookSecret` | `PUT /v1/projects/{project_id}/provider-connections/stripe/webhook` | `providers:write` | Save the signing secret of the Stripe webhook endpoint. |

The `read` and `write` key shortcuts do not include the revenue scopes: give a key `revenue:read`
or `revenue:write` explicitly. In the dashboard, only owners and admins can see revenue.

The read operations take `from` and `to` (ISO 8601). The default range is the last 30 days; a range
can be at most 400 days. The overview also returns the previous period of the same length.

## Revenue impact

`revenue.impact` takes `target` (`issue`, `incident`, `release`, or `page`) and `id` (the issue,
incident, or release id, or a page path such as `/checkout`). It returns an estimate as a range
(`low` to `high`) in the reporting currency, the method, and a `status`:

| `status` | Meaning |
| - | - |
| `estimated` | The range is set. |
| `no_sessions` | No browser session had the problem in the last 30 days. |
| `no_identity` | No affected session belongs to an identified person, so revenue cannot match. |
| `no_revenue` | The project has no positive net revenue in the compared time; the range is 0. |

An estimate is kept for up to 5 minutes; new revenue or another change in the project starts a
fresh one. See [Revenue impact](/features/revenue#revenue-impact) for the two methods.

## Revenue attribution

`revenue.attribution` takes `from` and `to`, `model` (`last_touch`, the default, or `first_touch`),
and `dimension` (`source`, the default, `medium`, or `campaign`). It returns `rows` with the value,
`kind`, `net` in the reporting currency, `share` (percent of the net revenue in the range),
`payments`, and `people`:

| `kind` | Meaning |
| - | - |
| `touch` | Revenue credited to a source, medium, or campaign. |
| `direct` | The payer is a known person but had no touch before the payment. |
| `unlinked` | The payment has no analytics id (`distinct_id` or `anonymous_id`). |

Touch values come first, by net revenue, at most 100 (`truncated` is `true` when more exist).
`lookback_days` is how far before `from` touches are read. A result is kept for up to 5 minutes.
A range with too many events for one request returns `422` with `RANGE_TOO_LARGE`; narrow `from`
and `to`. The API never returns a partial total.
See [Revenue attribution](/features/revenue#revenue-attribution).

## Amounts

* `amount_minor` and the `*_minor` fields are integers in the smallest unit of their own currency.
  Divide by `10 ^ currency_exponent` for the decimal amount.
* Other amounts are decimals in the reporting currency (`currency` in the response).
* Refunds and disputes are negative; dispute reversals are positive.
* `fx.missing_currencies` lists currencies without a reference rate. Their amounts are in
  `by_currency` but not in converted totals.

## Send money movements

`POST /revenue/events` takes `{ "events": [...] }` with up to 100 items:

| Field | Required | Meaning |
| - | - | - |
| `id` | yes | Your id of the movement. Sending it again replaces the earlier send. |
| `type` | yes | `payment`, `refund`, `dispute`, or `dispute_reversal`. |
| `amount` | yes | Positive integer in the smallest currency unit. `type` sets the sign. |
| `currency` | yes | ISO 4217 code, for example `USD`. |
| `occurred_at` | yes | When the money moved (ISO 8601). At most one day in the future. |
| `customer_id` | no | Your customer id. |
| `distinct_id` | no | The user id you pass to `identify()`, to link the revenue to the person. |
| `anonymous_id` | no | The visitor id of a visitor who has not signed in. |
| `parent_id` | no | For a refund or dispute: the `id` of its payment. |
| `subscription_id` | no | The subscription of a recurring payment. |
| `plan` | no | Plan name, for the breakdown by plan. |
| `recurring` | no | `true` for a renewal payment. |
| `status` | no | `posted` (default) or `voided`. A voided movement does not count. |

The response is `202` with `accepted` (items in the request) and `written` (rows that changed).

## Send subscription states

`POST /revenue/subscriptions` takes `{ "subscriptions": [...] }` with up to 100 items: `id`,
`status`, `mrr` (monthly amount in the smallest currency unit, `0` when it does not pay), `currency`,
`effective_at`, and optional `customer_id` and `plan`. Send a new state each time a subscription
changes; Squasher keeps every state, so MRR movements work for any range.

## CLI

```bash theme={null}
squasher revenue status --project "$SQUASHER_PROJECT_ID"
squasher revenue overview --project "$SQUASHER_PROJECT_ID" --from 2026-09-01T00:00:00Z
squasher revenue mrr --project "$SQUASHER_PROJECT_ID"
squasher revenue impact --project "$SQUASHER_PROJECT_ID" --target issue SQ-142
squasher revenue attribution --project "$SQUASHER_PROJECT_ID" --model first_touch --dimension campaign
squasher revenue events --project "$SQUASHER_PROJECT_ID" --kind refund
squasher revenue send-events --project "$SQUASHER_PROJECT_ID" --file events.json
squasher revenue set-currency --project "$SQUASHER_PROJECT_ID" EUR
```

`send-events` and `send-subscriptions` read a JSON array (or the request body) from a file; use
`--file -` for stdin. Add `--json` to any command to print the API response.

## MCP

Agents connected to the [Squasher MCP server](/integrations/mcp) can read revenue, MRR, revenue impact, and attribution, and send
revenue events. Connecting Stripe and saving its signing secret need the API, the CLI, or the
dashboard.


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