Billing Metrics API
EmbayLMS runs platform billing on direct Stripe Billing: Stripe is the billing engine, and the LMS owns the definition of what to bill. This endpoint exposes each tenant’s current billable metrics, computed live per call so a read is always current.
This is a server-to-server endpoint — not part of the tenant-facing public API.
This endpoint is not the billing path. The LMS sets the Stripe subscription quantity itself, ahead of each renewal, from the same figures — Stripe has no way to pull them. This API is an integration surface for an external billing orchestrator that wants the same numbers (reporting, a future alternative billing model). Reading it changes nothing; the LMS remains what pushes the quantity to Stripe.
Note: although live, this endpoint is intentionally excluded from the public OpenAPI spec at
/api/v1/docs. It authenticates with a static platform Bearer secret issued by Embay, not a tenant API key, and is only for the external billing orchestrator — this page is its canonical reference.
Finding the tenant
Call with the EmbayLMS tenant id. The Stripe Customer carries metadata.embaylms_tenant_id, so
the orchestrator can map a Stripe customer/subscription back to the tenant id to pull with.
Endpoint
GET /api/v1/billing/metrics?tenantId={uuid}embaylms_tenant_id is accepted as an alias for tenantId.
Authentication
Authorization: Bearer <platform-metrics-secret>A single platform secret, issued by Embay to the orchestrator. Missing or mismatched ⇒ 401.
The check is constant-time.
Response 200
{
"data": {
"tenantId": "eaf926b4-7bec-440a-9083-7e75ad8a193b",
"slug": "acme",
"status": "active",
"activeUsersInPeriod": 1,
"activeUsersThisMonth": 1,
"licensedUsers": 2,
"periodStart": "2026-07-15T00:00:00.000Z",
"asOf": "2026-06-24T23:54:53.089Z"
},
"meta": null,
"error": null
}| Field | Meaning |
|---|---|
activeUsersInPeriod | Billable quantity (default) — users who logged in at least once during the tenant’s current billing period (active, not deleted). |
activeUsersThisMonth | Deprecated alias of activeUsersInPeriod, same value. Kept so existing consumers do not break on the rename; the field never tracked a calendar month again after that change. Prefer activeUsersInPeriod. |
periodStart | Inclusive start of the window the count was taken over — the subscription’s current_period_start, or the first of the calendar month when Stripe has not reported a period yet. |
licensedUsers | Provisioned active accounts (seats available). |
asOf | Server timestamp when the counts were computed. |
New metrics: each billable metric is a discrete field, so a metric added later appears as a new field (there is no metric-type enum). The orchestrator decides which field a given subscription bills on.
Status codes
| Code | When |
|---|---|
200 | Authorized; metrics returned. |
400 | tenantId (or embaylms_tenant_id) missing. |
401 | Missing or invalid Bearer token, or the endpoint is not enabled on this environment. |
404 | No tenant with that id. |
409 | The tenant is never billed — a demo, sandbox or the platform Academy tenant — so there is no billable quantity to report. The error names the kind. |
Troubleshooting
- Always 401 — the orchestrator is sending a different secret from the one Embay issued, or the endpoint has not been enabled on that environment. Contact Embay to confirm.
- 404 for a known tenant — confirm the tenant id (or the Stripe customer’s
embaylms_tenant_idmetadata) matches an EmbayLMS tenant. - Counts look low — only users who logged in during the current billing period count as active; provisioned-but-never-logged-in users do not. Check
periodStartin the response to see which window was used — a tenant renewing mid-month is counted from its renewal date, not the 1st.