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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
start_date | query | string | Yes | Start of date range (ISO 8601, inclusive). |
end_date | query | string | Yes | End of date range (ISO 8601, exclusive). |
Response example
Success response (200):
{
"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.
| Status | When it happens |
|---|---|
400 | Invalid query parameters. Check that start_date and end_date are valid ISO 8601 dates. |
401 | Missing or invalid API key. Send your key as Authorization: Bearer YOUR_API_KEY. |
403 | API key lacks the revenue:read scope. Use a key that includes the revenue:read scope. |
422 | Date range exceeds 12 months. Narrow start_date and end_date to a span of 12 months or less. |
429 | Rate 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.