Usage & Quotas
These endpoints power usage-based billing: your app reports usage events per metric, Bridge aggregates them into the workspace’s current billing period, compares them against the plan’s quotas, and (for metered metrics) replicates the rollups to Stripe. A workspace is your app’s customer account (also called a tenant); you manage plans and quotas in Control Center, Bridge’s admin dashboard.
Most apps never call these endpoints directly. The framework SDKs wrap them: bridge.usage.report(metric) batches events to the ingest endpoint through a durable, crash-safe queue, and useBridge().quota(metric) hydrates from the quota endpoint and then stays live over the quota.updated push channel. Call REST directly when you report usage from a backend without a Bridge SDK.
Authentication. Every endpoint on this page acts on the signed-in user’s own workspace and authenticates with that user’s access token, plus your app ID:
Authorization: Bearer <USER_ACCESS_TOKEN> x-app-id: <YOUR_APP_ID>The workspace is always derived from the token, never from the request body. The two operator endpoints that take a
workspaceIdpath parameter additionally require that it matches the caller’s own workspace, otherwise they returnHTTP 403.
Two quota policies exist, set per metric on the plan:
hard: the metric has a cap. When usage crosses the limit, the linked entitlement flips tofalseand the SDK gates the feature.metered: overage bills automatically through Stripe. Nothing is ever blocked.
See Usage limits for the SDK-side guide and how to configure quotas on a plan.
Report a usage event
Section titled “Report a usage event”Record one usage event for a metric on the caller’s workspace. Ingest is always-accept: the server never rejects an event because of plan state or quota level (no HTTP 402), so your product code can fire and forget. Enforcement of hard limits happens on the entitlement layer, not here.
Duplicate submissions with the same idempotencyKey are deduplicated: the event is stored once and the aggregate is bumped once. Retries are therefore always safe.
HTTP Request
Section titled “HTTP Request”POST https://api.thebridge.dev/usage/ingest
Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
metric | string | Required | The metric key to bump, e.g. ai_completions. Metric keys are defined on the plan's quotas in Control Center |
value | integer | Optional | How much to add. Integer >= 1. Defaults to 1 |
idempotencyKey | string | Optional | Unique key for safe retries. Sending the same key twice stores the event once and returns deduped: true. Auto-generated when omitted |
Response HTTP 201
Section titled “Response HTTP 201”| Field | Type | Description |
|---|---|---|
| accepted | boolean | Always true when the request validates |
| deduped | boolean | true when the idempotencyKey was seen before; the aggregate was not bumped again |
| eventId | string | The stored usage event’s ID (the original event’s ID on a dedupe) |
Request example
curl --request POST 'https://api.thebridge.dev/usage/ingest' \
--header 'Authorization: Bearer USER_ACCESS_TOKEN' \
--header 'x-app-id: YOUR_APP_ID' \
--header 'Content-Type: application/json' \
--data-raw '{
"metric": "ai_completions",
"value": 1,
"idempotencyKey": "0d6f2c9e-6d1b-4f4e-9d1a-6a1f0b8c2e77"
}'Response example:
{
"accepted": true,
"deduped": false,
"eventId": "665f2c9e6d1b4f4e9d1a6a1f"
}
The SDKs generate the idempotency key at enqueue time and persist it with the queued event, so a crash-restart replay sends the exact same key and the server drops the duplicate. Do the same if you build your own retry queue.
Get quota state for a metric
Section titled “Get quota state for a metric”The live quota snapshot for one metric on the caller’s workspace. This is the SDK’s initial-hydration endpoint: it reads this once, then keeps the value current from quota.updated pushes on the workspace channel.
Returns null (with HTTP 200) when the workspace’s plan has no quota configured for the metric. The SDK treats that as unmetered.
HTTP Request
Section titled “HTTP Request”GET https://api.thebridge.dev/usage/quota/METRIC
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
METRIC | string | Required | The metric key to read, e.g. ai_completions |
Response HTTP 200
Section titled “Response HTTP 200”| Field | Type | Description |
|---|---|---|
| metric | string | The metric key |
| used | number | Usage recorded in the current billing period |
| limit | number | The plan’s quota for this metric |
| remaining | number | limit - used (can go negative on metered metrics) |
| warningLevel | string \| null | null, approaching (>= 80% of limit), or critical (>= 95% or over the limit) |
| policy | string | hard (entitlement flips to false at cap) or metered (overage bills through Stripe) |
Request example
curl --request GET 'https://api.thebridge.dev/usage/quota/ai_completions' \
--header 'Authorization: Bearer USER_ACCESS_TOKEN' \
--header 'x-app-id: YOUR_APP_ID'Response example:
{
"metric": "ai_completions",
"used": 820,
"limit": 1000,
"remaining": 180,
"warningLevel": "approaching",
"policy": "hard"
}
Get the workspace usage snapshot
Section titled “Get the workspace usage snapshot”All metrics tracked for a workspace in the current billing period, with quota fields merged in where the plan defines one. This is what powers the usage view in Control Center’s admin UI.
The caller must belong to the workspace in the path: a mismatch returns HTTP 403.
HTTP Request
Section titled “HTTP Request”GET https://api.thebridge.dev/usage/WORKSPACE_ID
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
WORKSPACE_ID | string | Required | The workspace to read. Must be the caller's own workspace |
Response HTTP 200
Section titled “Response HTTP 200”| Field | Type | Description |
|---|---|---|
| workspaceId | string | The workspace ID |
| periodStart | string | ISO-8601 start of the current billing period |
| periodEnd | string | ISO-8601 end of the current billing period |
| metrics | array | One entry per tracked metric (see below) |
Each entry in metrics:
| Field | Type | Description |
|---|---|---|
| metric | string | The metric key |
| used | number | Usage recorded this period |
| limit | number? | The plan’s quota. Omitted when the plan has no quota for the metric |
| remaining | number? | limit - used. Omitted without a quota |
| warningLevel | string? | approaching, critical, or null. Omitted without a quota |
| policy | string? | hard or metered. Omitted without a quota |
| lastSyncedAt | string? | When this metric last synced to Stripe, or null |
| lastSyncStatus | string? | Result of the last Stripe sync, or null |
| lastSyncError | string? | Error message from the last failed sync, or null |
Request example
curl --request GET 'https://api.thebridge.dev/usage/650cd8510ccba777cc9623d0' \
--header 'Authorization: Bearer USER_ACCESS_TOKEN' \
--header 'x-app-id: YOUR_APP_ID'Response example:
{
"workspaceId": "650cd8510ccba777cc9623d0",
"periodStart": "2026-07-01T00:00:00.000Z",
"periodEnd": "2026-08-01T00:00:00.000Z",
"metrics": [
{
"metric": "ai_completions",
"used": 820,
"limit": 1000,
"remaining": 180,
"warningLevel": "approaching",
"policy": "hard",
"lastSyncedAt": null,
"lastSyncStatus": null,
"lastSyncError": null
},
{
"metric": "api_requests",
"used": 15230,
"limit": 10000,
"remaining": -5230,
"warningLevel": "critical",
"policy": "metered",
"lastSyncedAt": "2026-07-07T02:00:00.000Z",
"lastSyncStatus": "ok",
"lastSyncError": null
}
]
}
Trigger a Stripe usage sync
Section titled “Trigger a Stripe usage sync”Push the workspace’s current-period usage rollups to Stripe immediately instead of waiting for the scheduled sync. The sync uses action: 'set' semantics on Stripe usage records, so re-syncing the same period is idempotent: it replaces the Stripe-side quantity rather than adding to it.
The caller must belong to the workspace in the path: a mismatch returns HTTP 403. Workspaces without a Stripe subscription sync zero metrics.
HTTP Request
Section titled “HTTP Request”POST https://api.thebridge.dev/usage/sync/WORKSPACE_ID
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
WORKSPACE_ID | string | Required | The workspace to sync. Must be the caller's own workspace |
Response HTTP 201
Section titled “Response HTTP 201”| Field | Type | Description |
|---|---|---|
| syncedMetrics | number | How many metrics were pushed to Stripe |
| failed | string[] | Metric keys that failed to sync this run |
Request example
curl --request POST 'https://api.thebridge.dev/usage/sync/650cd8510ccba777cc9623d0' \
--header 'Authorization: Bearer USER_ACCESS_TOKEN' \
--header 'x-app-id: YOUR_APP_ID'Response example:
{
"syncedMetrics": 2,
"failed": []
}