Usage Records
App Billing
Usage Records
Record metered (usage-based) charges and inspect the current cap, accrued spend, and remaining headroom for an installation.
POST
Usage Records
The usage endpoints are the LaunchMyStore equivalent of Shopify’sDocumentation Index
Fetch the complete documentation index at: https://docs.launchmystore.io/llms.txt
Use this file to discover all available pages before exploring further.
appUsageRecordCreate. They let an installed app charge per-event —
one credit per SMS sent, per AI generation, per shipping label printed —
on top of a flat monthly subscription.
The metered component is declared on the app’s pricing plan
(pricing.usage in app.json, see
Usage Billing). Every usage event you POST is
reported to Stripe behind a unique subscription_item.id, the cost
(quantity × usageUnitAmount) is checked against the merchant-approved
cap, and a USAGE row is appended to AppBillingTransactions so it
surfaces in the merchant’s billing detail page.
Auth: app access token (OAuth). The endpoint resolves the
installation from the token’s aud claim — apps never pass
installationId in the body.
| Endpoint | Scope | Purpose |
|---|---|---|
POST /api/v1/billing/usage | write_billing | Record N units of usage |
GET /api/v1/billing/usage | read_billing | Read current cap, accrued spend, period end |
POST /api/v1/billing/usage/cap | write_billing | Lower (immediate) or raise (approval) the cap |
Usage is checked against the cap before the Stripe call. If the
projected accrual would exceed the cap, the endpoint returns
402
with code: USAGE_CAP_EXCEEDED and no usage record is created. Apps
should treat that response as a hard signal to either stop the
underlying action or call POST /usage/cap to request a raise.Record a usage event
POST /api/v1/billing/usage
Integer number of units consumed by this event. Must be
>= 1. Reject
fractional values — scale your metered unit instead (tokens rather
than kilo_tokens).Optional client-supplied key. Forwarded to Stripe as the
subscriptionItems.createUsageRecord idempotency key (namespaced to
the installation so collisions across apps are impossible). Retries
with the same key are always safe; without one, double-billing is
possible on network retries.Response
ISO timestamp Stripe used for the usage record.
Echo of the recorded quantity.
Per-unit price from the app’s pricing plan (dollars).
Cost of this event (
quantity × unitAmount × 100).Running total accrued in the current billing period after this event.
Merchant-approved cap in cents (
null if uncapped).Cap headroom after this event (
null if uncapped).Stripe
mbur_… usage-record id (also written to AppBillingTransactions.stripeUsageRecordId).Cap exceeded
When the projected accrual would exceed the cap, the endpoint returns402 and no usage is recorded:
message field is a JSON-encoded payload — parse it client-side to
decide how to respond. code: USAGE_CAP_EXCEEDED is stable; the cents
fields let you compute how much headroom is left and prompt the
merchant to raise the cap via POST /usage/cap.
Get current usage state
GET /api/v1/billing/usage
Returns the metered configuration plus the current period’s accrual.
Apps typically call this from their admin home iframe to render a
“used X of Y this month” progress bar.
Response
Human label from the pricing plan, e.g.
SMS, email, AI generation.Per-unit price in dollars.
Merchant-approved cap in cents (
null if uncapped).Cents accrued so far this billing period.
Cap headroom (
null if uncapped).ISO timestamp when the current Stripe period ends.
accruedAmountCents resets to 0 here.Stripe
si_… subscription-item id this usage attaches to.Update the usage cap
POST /api/v1/billing/usage/cap
The cap is the merchant’s per-period spending ceiling on the metered
component. It defaults to the value declared in pricing.usage.cappedAmount
when the merchant first subscribes, and can be changed afterwards:
- Lowering the cap takes effect immediately, but cannot go below
what the merchant has already accrued this period (would create an
instant
USAGE_CAP_EXCEEDEDloop). - Raising the cap requires merchant approval. The endpoint returns
a Stripe Billing Portal
confirmationUrlthe merchant must visit to authorise the new cap; the row isn’t updated until they confirm.
Requested cap in dollars (integer cents on the wire is fine —
values are rounded).
0 is allowed and effectively disables further
usage charges until the cap is raised.URL the merchant returns to after confirming a raise in the Stripe
Billing Portal. Defaults to the app developer’s TeamInfra origin.
Response — immediate (lowering)
Response — approval required (raising)
confirmationUrl in a top-level browser tab (don’t iframe — Stripe
blocks framing the billing portal). After the merchant confirms, the
backend updates the row; the next POST /usage call sees the new cap.
Idempotency guidelines
- Mint a stable
idempotencyKeyper real-world event. A message-id, a generation-id, or a UUIDv4 you record alongside the event all work. - Keys are namespaced server-side as
usage:{installationId}:{key}and passed to Stripe as the canonical idempotency key. Stripe retains idempotency keys for 24 h, so retries within that window are safe. - Without a key, network retries can produce duplicate
UsageRecordrows on Stripe and duplicateAppBillingTransactionsrows (the unique index onstripeUsageRecordIdcatches the second insert, but you’ve still double-billed the merchant on Stripe’s side).
Error codes
| Code | When |
|---|---|
400 | quantity < 1, fractional, or non-integer. |
400 | Installation has no stripeMeteredItemId (app pricing has no usage component). |
400 | App has no usageUnitAmount configured. |
400 | cappedAmount below already-accrued spend (on /usage/cap). |
401 | Missing or invalid app access token. |
402 | Subscription not active or trialing — see billingStatus. |
402 | USAGE_CAP_EXCEEDED — see body for capCents / accruedCents / remainingCents. |
403 | Token lacks write_billing (POST) or read_billing (GET) scope. |
404 | Installation or app not found. |
See also
- Usage Billing — conceptual guide to declaring
metered pricing in
app.jsonand the full event → invoice flow. - Subscriptions — flat monthly subscription state.
- Transactions — every
AppBillingTransactionrow (flat + usage + invoice).