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.

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 fields

Fields returned in the 200 response body. Nested objects are listed under their parent. A field marked optional may be absent from the body; one marked nullable is always present but its value may be null.

FieldTypeDescription
end_usersobject[]Per-end-user margin rows, sorted by profitability with the least profitable first.
end_user_idstringBear Lumen's internal end-user ID (UUID). Pass this value as the end_user_id filter on GET /margin-data/trend. This is not the external ID you send on usage events.
end_user_namestringDisplay name of the end user.
revenuestringRevenue attributed to this end user for the period, decimal string in USD.
coststringCost attributed to this end user for the period, decimal string in USD.
margin_amountstringRevenue minus cost for this end user, decimal string in USD. Negative when cost exceeds revenue.
margin_percentnumber (double) nullableMargin percentage ((revenue - cost) / revenue * 100), rounded to 2 decimal places. Null when this end user's revenue for the period is zero.
profitability_categoryprofitable | break-even | unprofitableProfitability classification. `profitable` when the margin percentage is above 20, `break-even` between 0 and 20 (or when there is no activity at all), `unprofitable` below 0 (or when there is cost with zero revenue).
org_totalobjectOrganization total for the period. Includes ALL revenue and ALL cost (attributed plus unattributed), so its totals can exceed the sums of the end_users rows.
total_revenuestringTotal revenue for the period, decimal string in USD. Returns "0" when no revenue has been synced from your connected Stripe account.
total_coststringTotal cost for the period, decimal string in USD.
margin_amountstringRevenue minus cost for the period, decimal string in USD. Negative when cost exceeds revenue.
margin_percentnumber (double) nullableMargin percentage ((revenue - cost) / revenue * 100), rounded to 2 decimal places. Null when revenue for the period is zero (division by zero is undefined).
profitability_categoryprofitable | break-even | unprofitableProfitability classification. `profitable` when the margin percentage is above 20, `break-even` between 0 and 20 (or when there is no activity at all), `unprofitable` below 0 (or when there is cost with zero revenue).
revenue_record_countnumber (double)Number of revenue records included in total_revenue.
cost_record_countnumber (double)Number of cost records included in total_cost.
unattributed_revenuestringRevenue in the window that could not be attributed to a specific end user, decimal string in USD. Computed as a raw sum of revenue records whose recognition period starts inside the window, which is a different basis than the accrual-recognized total_revenue, so treat it as a companion diagnostic rather than a strict subset of total_revenue.
unattributed_coststringCost not attributed to any end user, decimal string in USD. Included in total_cost but absent from the per-end-user breakdown.
warningsobject[]Data-quality warnings about unattributed revenue or cost. Empty when all records are attributed.
typeunattributed_revenue | unattributed_cost | revenue_not_connectedWarning category. `unattributed_revenue` means revenue records exist that are not linked to any end user; `unattributed_cost` means cost records exist that are not linked to any end user. Unattributed amounts are included in organization totals but absent from the per-end-user breakdown. `revenue_not_connected` means your organization has no active Stripe revenue connection, so a `total_revenue` of "0" reflects a missing connection rather than a genuine zero-revenue period; connect Stripe to populate revenue and margin.
countnumber (double)Number of records affected by this warning. `0` for the `revenue_not_connected` warning, which reflects connection status rather than a set of records.
messagestringHuman-readable description of the warning.

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.