Margin Data API

Get margin by end user

Returns margin data for each of your end users (the customers you attribute usage and revenue to), sorted by profitability with the least profitable first so unprofitable end users surface at the top. Call it with a GET request to /margin-data/by-end-user, authenticated with a restricted API key and the "revenue:read" scope.

GET https://api.bearlumen.com/v1/margin-data/by-end-user

Returns margin data for each of your end users (the customers you attribute usage and revenue to), sorted by profitability with the least profitable first so unprofitable end users surface at the top. Margin requires revenue data from your connected Stripe account; connect it in your dashboard under Settings then Integrations. Note that a not-yet-connected account and a genuine zero-revenue period both return "0", so verify the connection before interpreting zeros. If no revenue has been synced for the period, revenue fields return "0", margin_percent is null (division by zero is undefined), and profitability_category reflects cost-only activity (unprofitable when cost > 0, break-even when there is no activity). Revenue is recognized on an accrual basis: each revenue record's amount is attributed across its billing period. Costs are attributed to the time the usage event occurred. Requests count toward your per-API-key rate limit; sustained overruns return 429 with the standard error envelope.

Authentication and scopes

Authenticate with a restricted API key in the Authorization: Bearer <key> header. This endpoint requires the revenue:read scope.

Parameters

NameInTypeRequiredDescription
start_datequerystringYesStart of date range (ISO 8601, inclusive).
end_datequerystringYesEnd of date range (ISO 8601, exclusive).

Response example

Success response (200):

JSON
{
  "end_users": [
    {
      "cost": "894.37",
      "end_user_id": "eb77aa11-0003-7777-9a1b-2c3d4e5f6a03",
      "end_user_name": "Cobalt Labs",
      "margin_amount": "-228.249999999999999",
      "margin_percent": -34.27,
      "profitability_category": "unprofitable",
      "revenue": "666.120000000000001"
    },
    {
      "cost": "2192.15",
      "end_user_id": "eb77aa11-0002-7777-9a1b-2c3d4e5f6a02",
      "end_user_name": "Beacon Analytics",
      "margin_amount": "357.8100000000000001",
      "margin_percent": 14.03,
      "profitability_category": "break-even",
      "revenue": "2549.9600000000000001"
    },
    {
      "cost": "3435.12",
      "end_user_id": "eb77aa11-0001-7777-9a1b-2c3d4e5f6a01",
      "end_user_name": "Aurora Systems",
      "margin_amount": "4200.1999999999999975",
      "margin_percent": 55.01,
      "profitability_category": "profitable",
      "revenue": "7635.3199999999999975"
    }
  ],
  "org_total": {
    "cost_record_count": 13,
    "margin_amount": "5138.8199999999999991",
    "margin_percent": 42.5,
    "profitability_category": "profitable",
    "revenue_record_count": 5,
    "total_cost": "6952.7",
    "total_revenue": "12091.5199999999999991",
    "unattributed_cost": "431.06",
    "unattributed_revenue": "1240.12"
  },
  "warnings": [
    {
      "count": 1,
      "message": "1 revenue record(s) without customer attribution",
      "type": "unattributed_revenue"
    },
    {
      "count": 1,
      "message": "1 cost record(s) without customer attribution",
      "type": "unattributed_cost"
    },
    {
      "count": 0,
      "message": "No active Stripe revenue connection. Revenue totals reflect no connected source, not necessarily zero revenue.",
      "type": "revenue_not_connected"
    }
  ]
}

Error codes

Errors return the standard error envelope with a code, message, and a correlationId you can quote to support.

StatusWhen it happens
400Invalid query parameters. Check that start_date and end_date are valid ISO 8601 dates.
401Missing or invalid API key. Send your key as Authorization: Bearer YOUR_API_KEY.
403API key lacks the revenue:read scope. Use a key that includes the revenue:read scope.
422Date range exceeds 12 months. Narrow start_date and end_date to a span of 12 months or less.
429Rate limit exceeded. Reduce request frequency and retry after the interval indicated in the Retry-After header.

Rate limits and retries

Rate limit exceeded. Reduce request frequency and retry after the interval indicated in the Retry-After header.