Skip to main content

Types Reference

Every canonical type the SDK exports, with the full interface definition and a plain-English description of what it represents and when you’d see it. Money rule: every dollar amount is number, not string. Values come back at full precision. Round at render time, never before. Null rule: a null means “not applicable here,” not zero. Most commonly: marginPercent: null means “revenue was zero, so margin cannot be computed.” Render as a dash, not 0%.

RevenueMetrics

The canonical revenue shape. Returned by analytics.revenue, embedded inside the revenue block of customers.getWithRevenue and subscriptions.getWithRevenue.
interface RevenueMetrics {
  revenue: number;
  cost: number;
  margin: number;
  marginPercent: number | null;

  usageRevenue: number;
  recurringRevenue: number;
  seatRevenue: number;
  onetimeRevenue: number;

  eventCount: number;
  eventCountWithNullCost: number;

  bySubscription: SubscriptionRevenue[];
  byStrategy: StrategyRevenue[];
}
In plain English: the whole revenue picture for a scope (org, one customer, one subscription, whatever you filtered by). Revenue is the full number including fees and prorations. Cost is what you paid to providers. Margin is revenue minus cost. The four xRevenue fields add up to the revenue total and tell you WHERE it came from (usage events, recurring fees, seats, or one-time charges). eventCount is every event; eventCountWithNullCost is the subset whose cost couldn’t be calculated yet. When you’d see it: any canonical analytics call, plus the revenue blocks on customer and subscription detail pages.

SubscriptionRevenue

One row per active subscription inside RevenueMetrics.bySubscription.
interface SubscriptionRevenue {
  subscriptionId: string;
  customerId: string;
  agentId: string;
  planId: string;
  revenue: number;
  cost: number;
  margin: number;
  usageRevenue: number;
  recurringRevenue: number;
  seatRevenue: number;
  onetimeRevenue: number;
  eventCount: number;
}
In plain English: how one specific subscription contributed to the overall revenue. Useful for sorting “who are my biggest-revenue subscriptions” or drilling into a specific sub’s margin. When you’d see it: inside RevenueMetrics.bySubscription, returned by analytics.revenue and the two getWithRevenue overlays.

StrategyRevenue

One row per pricing strategy inside RevenueMetrics.byStrategy.
interface StrategyRevenue {
  strategyId: string;
  chargeType: ChargeType;
  pricingModel: PricingModel | null;
  signalId: string | null;
  revenue: number;
  quantity: number;
}
In plain English: how one specific pricing rule contributed to the overall revenue. chargeType tells you whether this was a usage rate, a recurring fee, a seat fee, or a one-time charge. pricingModel tells you the shape of usage rates (flat/graduated/volume/credit_pool). For usage strategies, quantity is the total quantity that ran through the rate in the window; for non-usage strategies it’s 0. When you’d see it: inside RevenueMetrics.byStrategy.

CostMetrics

The canonical cost shape. Returned by analytics.costBreakdown.
interface CostMetrics {
  cost: number;
  eventCount: number;
  eventCountWithNullCost: number;
  byAgent: CostByAgentRow[];
  byCustomer: CostByCustomerRow[];
  bySignal: CostBySignalRow[];
  byDay: CostByDayRow[];
  byPlan: CostByPlanRow[];
  byModel: CostByModelRow[];
  prior?: Omit<CostMetrics, "prior">;
}
In plain English: your total service cost in a window, sliced six different ways so you can find where the money is going. prior is a same-length window immediately before startDate, populated only when you asked for it with includePriorWindow: true. When you’d see it: analytics.costBreakdown.

CostByAgentRow

interface CostByAgentRow {
  agentId: string;
  cost: number;
  eventCount: number;
}
In plain English: cost attributed to one agent in the window.

CostByCustomerRow

interface CostByCustomerRow {
  customerId: string;
  cost: number;
  eventCount: number;
}
In plain English: cost attributed to one customer in the window.

CostBySignalRow

interface CostBySignalRow {
  signalId: string | null;
  cost: number;
  eventCount: number;
}
In plain English: cost attributed to one signal in the window. signalId: null covers orphan events that aren’t tied to a signal.

CostByDayRow

interface CostByDayRow {
  date: string;
  cost: number;
  eventCount: number;
}
In plain English: cost for one UTC calendar day. One row per day with activity. date is an ISO string (JSON doesn’t carry Date objects); convert on your side if you need a Date.

CostByPlanRow

interface CostByPlanRow {
  planId: string | null;
  cost: number;
  eventCount: number;
}
In plain English: cost attributed to one pricing plan in the window. planId: null covers events whose subscription isn’t on a plan.

CostByModelRow

interface CostByModelRow {
  model: string | null;
  cost: number;
  eventCount: number;
}
In plain English: cost attributed to one LLM model in the window. model: null covers non-LLM events and events whose model wasn’t recognized yet.

AgentEarned

The canonical shape returned by analytics.agentEarned.
interface AgentEarned {
  revenue: number;
  eventCount: number;
  bySubscription: AgentEarnedSubscriptionRow[];
  byStrategy: AgentEarnedStrategyRow[];
}
In plain English: activity-only revenue. Usage events × pricing strategy rates, summed up. No recurring fees, no seat fees, no one-time charges, no prorations. The earliest leading indicator that agents are doing billable work. When you’d see it: analytics.agentEarned.

AgentEarnedSubscriptionRow

interface AgentEarnedSubscriptionRow {
  subscriptionId: string;
  customerId: string;
  agentId: string;
  planId: string;
  revenue: number;
  eventCount: number;
}
In plain English: activity-revenue contribution from one subscription.

AgentEarnedStrategyRow

interface AgentEarnedStrategyRow {
  strategyId: string;
  pricingModel: PricingModel | null;
  signalId: string | null;
  revenue: number;
  quantity: number;
}
In plain English: activity-revenue contribution from one pricing strategy. quantity is the total quantity that ran through the rate.

InvoiceTotals

The canonical invoice-totals shape. Returned by analytics.invoiceTotals.
interface InvoiceTotals {
  billed: number;
  collected: number;
  draft: number;
  outstanding: number;
  overdueAmount: number;
  overdueCount: number;
  invoicesSentCount: number;
}
In plain English: finance-team numbers. billed is what you invoiced in the window (status issued or overdue). collected is what got paid in the window. draft is inventory of invoices not yet sent. outstanding is billed minus collected (age-independent). overdueAmount and overdueCount are current-state right now (not filtered by the date window). invoicesSentCount is how many non-draft invoices were dated in the window. When you’d see it: analytics.invoiceTotals.

Mrr

Returned by analytics.mrr.
interface Mrr {
  mrr: number;
  arr: number;
}
In plain English: last complete calendar month’s billed total, plus its annualized version (mrr × 12). Stable across the current month (doesn’t move until the next month rolls over). When you’d see it: analytics.mrr.

RunRateMrrResult

Returned by analytics.runRateMrr.
interface RunRateMrrResult {
  mrr: number;
  breakdown: RunRateMrrBreakdownRow[];
}
In plain English: what MRR would be if the last 30 days of activity kept going at this pace. Recurring + seat + actual usage, monthly-normalized. One breakdown row per active subscription. When you’d see it: analytics.runRateMrr.

RunRateMrrBreakdownRow

interface RunRateMrrBreakdownRow {
  subscriptionId: string;
  customerId: string;
  agentId: string;
  planId: string;
  recurring: number;
  seatBased: number;
  usage: number;
  total: number;
}
In plain English: per-subscription slice of run-rate MRR. recurring is the monthly-normalized recurring fees. seatBased is seat fees based on max(booked, minimum) seats. usage is actual last-30-days events run through the pricing rate. The three add up to total, and all the totals add up to the top-level mrr.

CommittedMrrResult

Returned by analytics.committedMrr.
interface CommittedMrrResult {
  mrr: number;
  breakdown: CommittedMrrBreakdownRow[];
}
In plain English: contractual floor. The monthly revenue your contracts guarantee, regardless of whether customers actually use the product. By definition, this is always less than or equal to RunRateMrrResult.mrr. When you’d see it: analytics.committedMrr.

CommittedMrrBreakdownRow

interface CommittedMrrBreakdownRow {
  subscriptionId: string;
  customerId: string;
  agentId: string;
  planId: string;
  recurring: number;
  seatBased: number;
  usage: number;
  total: number;
}
In plain English: per-subscription slice of committed MRR. Same shape as the run-rate breakdown, but the usage column is minimum_commitment × rate (or 0 when the pricing strategy has no minimum set), not actual usage.

SubscriptionDetailWithRevenue

Returned by subscriptions.getWithRevenue.
interface SubscriptionDetailWithRevenue {
  subscription: SubscriptionDetail;
  revenue: RevenueMetrics;
}
In plain English: a wrapper that pairs the normal subscription record with a canonical revenue block scoped to that subscription for a date window. Lets you build a subscription detail page in one round trip. When you’d see it: subscriptions.getWithRevenue.

CustomerDetailWithRevenue

Returned by customers.getWithRevenue.
interface CustomerDetailWithRevenue {
  customer: Customer;
  revenue: RevenueMetrics;
}
In plain English: a wrapper that pairs the normal customer record with a canonical revenue block scoped to that customer for a date window. Lets you build a customer detail page in one round trip. When you’d see it: customers.getWithRevenue.

Parameter types (for completeness)

All canonical analytics methods accept typed parameter objects. These are exported so you can use them in your own function signatures.

RevenueMetricsParams

interface RevenueMetricsParams {
  startDate: string;
  endDate: string;
  customerId?: string;
  agentId?: string;
  signalId?: string;
  subscriptionId?: string;
}

CostMetricsParams

interface CostMetricsParams {
  startDate: string;
  endDate: string;
  customerId?: string;
  agentId?: string;
  signalId?: string;
  subscriptionId?: string;
  includePriorWindow?: boolean;
}

InvoiceTotalsParams

interface InvoiceTotalsParams {
  startDate: string;
  endDate: string;
  customerId?: string;
}
Invoice totals accept a narrower filter surface than revenue (only customerId). That’s intentional: invoice math runs at the customer scope, not per-subscription or per-signal.

MrrParams

interface MrrParams {
  customerId?: string;
  subscriptionId?: string;
}
MRR methods do not take a date window. analytics.mrr uses a fixed “last complete calendar month” window. analytics.runRateMrr uses a fixed “last 30 days” window. analytics.committedMrr is not window-dependent at all.

AgentEarnedParams

interface AgentEarnedParams {
  startDate: string;
  endDate: string;
  customerId?: string;
  agentId?: string;
  signalId?: string;
  subscriptionId?: string;
}

Rounding and precision

Every money field in every type above is a raw number. No pre-rounding, no string wrapping. Round exactly once, at the UI boundary:
const metrics = await mf.analytics.revenue({ ... });

// Right
display(metrics.revenue.toFixed(2));

// Wrong: compounds rounding errors across downstream math
const rounded = Number(metrics.revenue.toFixed(2));
const later = rounded * someMultiplier;

Next steps

  • Analytics: the seven methods that return these shapes
  • Subscriptions: where SubscriptionDetailWithRevenue comes from
  • Customers: where CustomerDetailWithRevenue comes from