Skip to content

Report metered usage

For any subscription with a usage component, you push events as your customers consume — Paylera aggregates at period close and prices the total.

The minimal call

POST /v1/usage
Idempotency-Key: <uuid>
{
"subscription_id": "sub_…",
"meter": "api_calls",
"quantity": "1",
"timestamp": "2026-05-06T12:34:56.789Z",
"external_id": "req_8f4a…"
}

That’s the entire interface. Throw away the response body — a 202 means we have it.

Always send external_id

This is your dedupe key. Two events with the same (subscription_id, meter, external_id) are merged silently. Use:

  • Your service’s request ID, for per-request metering.
  • Your job ID, for batch jobs.
  • A combination of (user_id, action, day_bucket) for daily snapshots.

If you don’t send one, retries create duplicates. There is no second chance.

Batching

Send up to 1000 events in one call:

POST /v1/usage/batch
Idempotency-Key: <uuid>
{
"events": [
{ "subscription_id": "sub_…", "meter": "api_calls", "quantity": "1", "timestamp": "", "external_id": "req_1" },
{ "subscription_id": "sub_…", "meter": "api_calls", "quantity": "1", "timestamp": "", "external_id": "req_2" },
]
}

Batched calls are atomic per call: either all events accept or none do. Use this from your aggregation pipeline, not from request-handling code.

Quantity is decimal

"quantity": "0.001" is fine. "quantity": "-1" (correction) is fine. "quantity": "1.0e3" is rejected — send "1000".

Timestamps and periods

The event’s timestamp decides which period it belongs to. Default behaviour for events landing in a closed period: see Metered usage → Late events.

For best results, send timestamp in UTC ISO-8601 with millisecond precision. The aggregator ignores sub-millisecond resolution.

Late events

Two policies, set on the usage component:

  • next_period (default) — late events apply to the next open period. Predictable, simple.
  • rebill — the closed period’s invoice is voided and re-issued with the late events folded in. Only available within 24 hours of close, and only if the invoice has not been paid.

Most teams pick next_period for the simplicity. Pick rebill only if your customers genuinely care about the right total appearing on the right month’s invoice.

Inspecting

GET /v1/subscriptions/{id}/usage?period=current
{
"period": { "start": "", "end": "" },
"meters": [
{ "meter": "api_calls", "quantity": "84219", "events": 84219 }
]
}

For a closed period: ?period=closed&closed_at=2026-04-30

Estimating cost

Mid-period, you can preview what an invoice would look like if the period closed now:

GET /v1/subscriptions/{id}/upcoming-invoice

This walks the same pricing engine, applies discounts, computes tax, and returns a draft invoice — useful for in-app “current usage” widgets.

What to send (and what not to)

Send whenDon’t send when
A countable, billable action completes successfully.The action failed or was rolled back.
A user opens a feature, if you charge per open.A page renders with the feature visible.
A scheduled job runs to completion.A scheduled job starts.
The customer’s seat count changes.Every authentication.

Error cases

StatusMeaning
202Accepted; will be aggregated.
400 usage.invalid_quantityQuantity wasn’t a decimal.
404 usage.subscription_not_foundSubscription doesn’t exist or isn’t yours.
409 usage.subscription_canceledSubscription is canceled or ended; events rejected.
422 usage.meter_not_on_subscriptionThe meter isn’t in any of the plan’s components.

Don’t drop a 409 silently — you may be metering against a subscription you’ve forgotten to deprovision, which means you’re doing work you’ll never bill for.

Webhook events

Paylera does not emit webhooks per usage event — too noisy. You’ll see usage reflected in:

EventWhen
subscription.usage_threshold_crossedIf you’ve configured per-component alerts (e.g. “ping me at 80% of included quota”).
invoice.finalizedAt period close; the invoice carries the aggregated usage line.