Skip to main content

Cost analytics

GET /v1/analytics/cost is the single place to read cost out of MarginFront with a full breakdown attached. Use it when you need to answer:
  • Which agents cost the most to run?
  • Which customers are driving the cost?
  • What is our cost trend day over day?
  • How did this window compare to the window before it?
Cost is tracked independently of pricing and subscriptions. An event contributes cost as long as it has a recorded usageCost, whether or not the customer has a paid plan. Useful for Cost-Tracking-mode organizations that are not billing yet. This is a read-only endpoint.

The endpoint

Method and URL:
GET /v1/analytics/cost
Auth: API key in the x-api-key header.

Query parameters

ParamTypeRequiredDescription
startDateISO dateyesStart of the window (inclusive). Example: 2026-04-01.
endDateISO dateyesEnd of the window (inclusive).
customerIdUUIDnoNarrow to one customer.
subscriptionIdUUIDnoNarrow to one subscription.
agentIdUUIDnoNarrow to one agent.
signalIdUUIDnoNarrow to one signal.
includePriorWindowbooleannoWhen true, the response also includes a prior field with the same shape for the prior span.

How the prior window works

If you pass includePriorWindow=true, the API computes a second window of the same length immediately before your primary window, and runs the same aggregation on it. You get both shapes back in one call. That is how you build period-over-period trend widgets without a second round-trip. One extra database query is used when this flag is set. Omit it when you do not need the trend.

Example curl calls

Org-wide cost for April 2026:
curl "https://api.marginfront.com/v1/analytics/cost?startDate=2026-04-01&endDate=2026-04-30" \
  -H "x-api-key: mf_sk_test_..."
One customer’s cost with trend:
curl "https://api.marginfront.com/v1/analytics/cost?customerId=bc8eceda-50e4-4138-b2a2-47e92d344540&startDate=2026-04-01&endDate=2026-04-30&includePriorWindow=true" \
  -H "x-api-key: mf_sk_test_..."
One agent’s cost broken down by day (the response always includes byDay):
curl "https://api.marginfront.com/v1/analytics/cost?agentId=3a1948ea-a701-4752-8c3d-df6c2f5833cf&startDate=2026-04-01&endDate=2026-04-30" \
  -H "x-api-key: mf_sk_test_..."

What you get back (200 OK)

{
  "cost": 3122.18,
  "eventCount": 41233,
  "eventCountWithNullCost": 12,

  "byAgent": [
    {
      "agentId": "b47e12fa-...",
      "cost": 1982.4,
      "eventCount": 24102
    }
  ],

  "byCustomer": [
    {
      "customerId": "5e7f8a3d-...",
      "cost": 742.8,
      "eventCount": 9801
    }
  ],

  "bySignal": [
    {
      "signalId": "69145379-...",
      "cost": 2104.5,
      "eventCount": 28940
    }
  ],

  "byDay": [
    {
      "date": "2026-04-01T00:00:00.000Z",
      "cost": 94.82,
      "eventCount": 1243
    },
    {
      "date": "2026-04-02T00:00:00.000Z",
      "cost": 102.15,
      "eventCount": 1378
    }
  ],

  "byPlan": [
    {
      "planId": "a1b2c3d4-...",
      "cost": 2843.1,
      "eventCount": 37120
    },
    {
      "planId": null,
      "cost": 279.08,
      "eventCount": 4113
    }
  ],

  "byModel": [
    {
      "model": "gpt-4o-mini",
      "cost": 1820.4,
      "eventCount": 22014
    },
    {
      "model": "claude-3-5-sonnet",
      "cost": 1301.78,
      "eventCount": 19219
    },
    {
      "model": null,
      "cost": 0.0,
      "eventCount": 0
    }
  ]
}
When includePriorWindow=true is set, a prior field appears at the top level with the same shape (minus its own prior):
{
  "cost": 3122.18,
  "eventCount": 41233,
  "eventCountWithNullCost": 12,
  "byAgent": [],
  "byCustomer": [],
  "bySignal": [],
  "byDay": [],
  "byPlan": [],
  "byModel": [],
  "prior": {
    "cost": 2847.62,
    "eventCount": 38015,
    "eventCountWithNullCost": 4,
    "byAgent": [],
    "byCustomer": [],
    "bySignal": [],
    "byDay": [],
    "byPlan": [],
    "byModel": []
  }
}

Understanding the response

  • cost is the total cost for the window: the sum of usageCost across every event that fell inside.
  • eventCount counts every event in the window, including events whose usageCost is blank.
  • eventCountWithNullCost is the subset whose cost could not be computed. They are in eventCount but contribute 0 to cost. Treat this as a “needs attention” indicator.
  • byAgent / byCustomer / bySignal / byPlan are one row per entity, with cost and event count for that entity in the window.
  • bySignal can include a row where signalId is null. Those are events whose signal could not be attributed.
  • byPlan can include a row where planId is null. Those are orphan events: events with no subscription, or whose subscription was deleted. They still contribute to cost.
  • byDay is one row per UTC day that had activity. date is UTC midnight. Use this to chart daily trends.
  • byModel is one row per LLM model name, pulled from the event’s payload. model: null covers non-LLM events and LLM events where the model field was missing.
  • prior appears only when you pass includePriorWindow=true. Same shape as the primary window, same length of time, immediately before the primary window.
All money fields are number, not strings.

When to use this vs. other endpoints

Use this endpoint when you want cost broken down by something: which agent, which customer, which signal, which day, which plan, which model. Use /v1/analytics/revenue when you also need revenue, margin, and pricing-strategy attribution. Use /v1/analytics/usage when you want event counts and quantity totals without pricing math.

Using the Node SDK

import { MarginFrontClient } from "@marginfront/sdk";

const mf = new MarginFrontClient(process.env.MF_API_SECRET_KEY);

const cost = await mf.analytics.costBreakdown({
  startDate: "2026-04-01",
  endDate: "2026-04-30",
  includePriorWindow: true,
});

console.log(`Cost this month: $${cost.cost.toFixed(2)}`);

if (cost.prior) {
  const delta = cost.cost - cost.prior.cost;
  console.log(`Change vs prior window: $${delta.toFixed(2)}`);
}
See the SDK analytics page for all seven analytics methods.

Common errors

  • 400 Bad Request: startDate or endDate is missing, in the wrong format, or a UUID filter is invalid.
  • 401 Unauthorized: API key missing or wrong.