Analytics
The analytics resource on the SDK is how you read finished numbers back out of MarginFront. Revenue, cost, margin, billed, collected, MRR. Same math the dashboard runs, same shapes. All seven methods return plain TypeScript objects with typed fields. Money fields arenumber (not strings). If a margin can’t be calculated (because revenue is zero), marginPercent is null, never 0 or NaN.
This page covers:
analytics.revenue: revenue, cost, margin, and the breakdown of where revenue came fromanalytics.costBreakdown: cost sliced by agent, customer, signal, day, plan, and modelanalytics.agentEarned: activity-only revenue, before any fees are added onanalytics.invoiceTotals: billed, collected, outstanding, overdueanalytics.mrr: last complete calendar month’s billed totalanalytics.runRateMrr: trajectory if the last 30 days keep goinganalytics.committedMrr: contractual floor, regardless of usage
Setup
mf.analytics. No separate import, no special setup.
1. analytics.revenue
What it does in plain English: gives you the whole revenue picture for a time window. How much you earned, how much it cost you, your margin, and where the revenue came from (per subscription, per pricing strategy).
This is the number you’d show on an executive dashboard. It includes usage-based revenue plus recurring fees, seat fees, and one-time fees (prorated if the subscription only partly overlapped the window).
Signature
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
startDate | string | yes | ISO date, inclusive (e.g., "2026-04-01"). |
endDate | string | yes | ISO date, inclusive. |
customerId | string | no | Filter to one customer. UUID, not your external ID. |
agentId | string | no | Filter to one agent. UUID. |
signalId | string | no | Filter to one signal. UUID. |
subscriptionId | string | no | Filter to one subscription. UUID. |
Response shape
Example
What this returns, in plain English
revenuetotal dollars earned in the window. Usage plus recurring plus seat plus one-time fees.costtotal service cost (the bill from OpenAI, Anthropic, Twilio, etc.) for the events in the window.marginrevenue minus cost.marginPercentthe margin as a percentage. Comes back asnull(shown as a dash in dashboards) when revenue is zero, so you never see a0%orNaN%that would be misleading.usageRevenue/recurringRevenue/seatRevenue/onetimeRevenuethe four ways revenue can show up, split out. They add up torevenue.eventCountevery event counted in the window.eventCountWithNullCostevents that are in the count but whose cost couldn’t be calculated yet (unknown model, no pricing map). A “needs attention” number. See Tracking Events: NEEDS_COST_BACKFILL.bySubscriptionone row per active subscription in the window, each with its own revenue/cost/margin breakdown.byStrategyone row per pricing strategy that contributed revenue, with the strategy’s charge type, pricing model, and signal id.
2. analytics.costBreakdown
What it does in plain English: shows you where your money is going. Total cost in the window, sliced six different ways: by agent, by customer, by signal, by day, by pricing plan, and by LLM model. Optional period-over-period comparison.
This is the number behind a “cost explorer” dashboard. Find the expensive customer. Find the expensive model. Find the day your bill spiked.
Signature
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
startDate | string | yes | ISO date. |
endDate | string | yes | ISO date. |
customerId | string | no | Filter to one customer. |
agentId | string | no | Filter to one agent. |
signalId | string | no | Filter to one signal. |
subscriptionId | string | no | Filter to one subscription. |
includePriorWindow | boolean | no | When true, adds a prior field with same-length-previous-window totals. |
Response shape
{ <idField>: string | null, cost: number, eventCount: number }. See Types Reference for the exact row types.
Example
What this returns, in plain English
costtotal service cost in the window.eventCountevery event in the window.eventCountWithNullCostevents whose cost couldn’t be calculated. Counted, not dropped. Shows up as a “needs attention” indicator.byAgent/byCustomer/bySignal/byPlan/byModelcost broken out along each dimension. The id fields can benullwhen an event isn’t yet attached to that dimension (e.g., an orphan event with no pricing plan).byDaycost per UTC calendar day, one row per day with activity.prioronly present when you passedincludePriorWindow: true. Same shape as the outer object, but for the same-length window immediately beforestartDate. Lets you show trend arrows without a second call.
3. analytics.agentEarned
What it does in plain English: tells you how much revenue your agents produced from actual activity, before any fixed fees are added on top. Usage events multiplied by their pricing strategy rates, summed up.
This is the earliest signal that something is working. It moves the moment an event fires, without waiting for an invoice to finalize. If you want to answer “are my agents doing billable work this week,” this is the number.
Signature
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
startDate | string | yes | ISO date. |
endDate | string | yes | ISO date. |
customerId | string | no | Filter to one customer. |
agentId | string | no | Filter to one agent. |
signalId | string | no | Filter to one signal. |
subscriptionId | string | no | Filter to one subscription. |
Response shape
Example
What this returns, in plain English
revenueactivity-only revenue in the window. Usage events × their pricing strategy rate. No recurring fees, no seat fees, no one-time fees.eventCountevents that produced revenue (events tied to a usage pricing strategy).bySubscriptionper-subscription breakdown: how much revenue each sub produced and how many events did it.byStrategyper-pricing-strategy breakdown: which specific rate earned what, and the total quantity that ran through it.
When to use this vs analytics.revenue
Use agentEarned when you care about activity in near-real-time. Use revenue when you want the full picture including fixed fees and prorations. They’ll give you different numbers for the same window, on purpose.
4. analytics.invoiceTotals
What it does in plain English: tells you what you actually invoiced and what your customers actually paid. Billed, collected, draft inventory, outstanding A/R, and a live overdue count.
This is the finance-team view. It reads realized amounts off of invoices, not a formula. Non-draft invoices reconcile to the revenue formula, so you can trust these numbers directly.
Signature
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
startDate | string | yes | ISO date. |
endDate | string | yes | ISO date. |
customerId | string | no | Filter to one customer’s invoices. |
Response shape
Example
What this returns, in plain English
billedtotal on invoices you issued in the window (statusissuedoroverdue). Waiting on payment.collectedtotal on invoices you got paid for in the window (statuspaid).drafttotal on invoices you generated but haven’t sent yet. Inventory, not revenue.outstandingbilled minus collected. Money you’ve asked for but haven’t received.overdueAmounttotal on invoices currently past due. Age-based, not window-based. Current state right now.overdueCounthow many invoices are currently past due.invoicesSentCounthow many non-draft invoices were dated in the window.
5. analytics.mrr
What it does in plain English: tells you how much you actually billed last complete calendar month. Monthly recurring revenue, based on invoices that went out.
This is the “book MRR” number. Stable across the month (doesn’t change until the month rolls over), based on realized billing. If you want forward-looking MRR, use runRateMrr or committedMrr below.
Signature
Parameters
All optional.| Name | Type | Required | Description |
|---|---|---|---|
customerId | string | no | Filter to one customer. |
subscriptionId | string | no | Filter to one subscription. |
Response shape
Example
What this returns, in plain English
mrrtotal billed across all invoices dated in the previous calendar month.arrannualized:mrr × 12. A convenience so you don’t multiply in the UI.
6. analytics.runRateMrr
What it does in plain English: tells you what your MRR would be if the last 30 days of activity kept going at the same pace. Recurring fees, seat fees, and actual usage rolled forward.
This is the “current run rate” number. Useful when usage moves fast and last month’s MRR is already stale.
Signature
Parameters
Same asanalytics.mrr: optional customerId and subscriptionId. No date window.
Response shape
Example
What this returns, in plain English
mrrprojected monthly revenue if the last 30 days keep up this pace.breakdownone row per active subscription with its contribution split into recurring, seat, and usage parts. The three add up tototal, and all thetotals add up tomrr.
7. analytics.committedMrr
What it does in plain English: the floor. Tells you the monthly revenue your contracts guarantee, regardless of whether customers actually use the product. Recurring fees, seat fees, and usage minimums only.
Use this to answer “what’s the least we’ll bill next month?” By definition, committed MRR is always less than or equal to run-rate MRR (because run-rate counts actual usage, committed only counts minimums).
Signature
Parameters
Same asanalytics.mrr and analytics.runRateMrr: optional customerId and subscriptionId.
Response shape
Example
What this returns, in plain English
mrrthe monthly revenue your contracts guarantee. Recurring fees always apply. Seat fees use the booked seat count. Usage uses the minimum commitment on each pricing strategy (zero when there’s no minimum set).breakdownsame shape asrunRateMrr’s breakdown, but theusagecolumn uses the minimum-commitment floor instead of actual events.
Field types at a glance
All dollar amounts arenumber, not string. Values come back at full precision. Round at render time, not in storage:
marginPercent is number | null. A null means “no revenue yet, so margin can’t be computed.” Render it as a dash, not as 0%.
See Types Reference for the full interface definitions.
When to call which method
| Question | Method |
|---|---|
| What did we earn this month? | analytics.revenue |
| Where is our money going? | analytics.costBreakdown |
| How much activity in the last 24 hours? | analytics.agentEarned |
| What’s in A/R? | analytics.invoiceTotals |
| What was last month’s MRR (stable reporting number)? | analytics.mrr |
| What’s our current run rate? | analytics.runRateMrr |
| What’s our contractual floor? | analytics.committedMrr |
Next steps
- Types Reference: every interface in one place
- Subscriptions with Revenue: attach canonical revenue to a single subscription fetch
- Customers with Revenue: same, but for customers
- Tracking Events: the write side. Send events in so these methods have something to read

