Usage ingestion API
Usage ingestion is a push path: your own backend sends product usage telemetry to Plutus, on your own schedule, instead of Plutus pulling it from a provider. It’s a separate mechanism from cost sources and event sources, which sync by polling a third party.
This telemetry is the denominator side of Unit economics. A unit
cost is cost ÷ usage — “cost per 1k API requests,” “infra cost per order” — and Plutus already
has the cost half from your connected cost sources. It has no way to know your request count,
order count, or any other business metric unless you send it. Connecting a usage source is how
you give a unit-economics ratio something to divide by; without it, queryUnitCost has a
numerator and no denominator, and every ratio on that metric reports null.
Generating an API key
Section titled “Generating an API key”The usage ingestion key is issued by Plutus, not supplied by you — it’s unrelated to any cloud or vendor credential. It authenticates your backend’s push requests, nothing else.
- Go to Usage sources and open the source you want to ingest under (the catalogue entry marked as a push/API source, not one of the pull-based sources like Stripe or Metronome that take a credential instead).
- Click Generate API Key.
- Copy the key immediately. It’s shown once, in full, at generation time — Plutus stores only
its hash, so it can’t be redisplayed later. The connection panel afterward shows only a
prefix (e.g.
abc123••••••••••••) to confirm which key is active. - Store the key in your backend’s own secrets, and send it as a bearer token on every ingest request.
Clicking Regenerate API Key immediately invalidates the previous key — any in-flight or future request using it starts failing right away. Revoke does the same without issuing a replacement.
POST /api/ingest/usage
Section titled “POST /api/ingest/usage”Authenticate with the key as a bearer token:
Authorization: Bearer <your usage api key>The body is a batch of up to 1,000 events:
{ "events": [ { "customer_id": "cust_8123", "customer_name": "Acme Corp", "metric": "api_requests", "unit": "requests", "quantity": 42350, "dimensions": { "region": "us-east-1" }, "timestamp": "2026-08-10T00:00:00Z" } ]}Field rules:
customer_id— required, a non-empty string up to 255 characters. This is your own identifier for the end customer this usage belongs to (Mode B unit economics — “cost per customer” — joins on this value matching a tag value you’ve defined; see Unit economics for that mapping).customer_name— optional string. If present, it’s stored alongside the customer id and updates on every event that includes it.metric— required, a non-empty string up to 100 characters. The name of what you’re counting (api_requests,orders,active_seats, whatever your unit-economics definition divides by).unit— optional string label (requests,orders). Not used in calculations, just carried through for display.quantity— required number. The amount of the metric for this event.dimensions— optional object of string-to-string key/value pairs, for slicing usage further than the metric name alone.timestamp— required, a parseable date string.
A request that isn’t structurally a {"events": [...]} array is rejected outright (400). Inside
a valid batch, each event is validated individually — one bad event (missing customer_id, a
non-numeric quantity, an unparseable timestamp) is rejected on its own rather than failing
the whole batch. The response reports both counts:
{ "accepted": 998, "rejected": 2, "errors": [ { "index": 41, "error": "quantity must be a number" }, { "index": 512, "error": "customer_id must be a non-empty string up to 255 characters" } ]}Requests are rate-limited to 1,000 per minute per usage connection (keyed off the account the API key resolves to, not your IP — so multiple end-customers funneling through the same backend share one budget rather than exhausting an IP-based limit).
Works on every tier
Section titled “Works on every tier”Usage ingestion has no plan gate. There’s no tier that blocks it and no per-tier cap on how much you can send — only the resulting event count feeds the same billing event-usage metering every other ingested event does, not a separate limit.