Metered billing

Charge customers by usage instead of a flat seat count: report events from the SDK, and let Stripe auto-charge based on that usage.

Licensing Features

Metered Billing

Metered billing lets you charge customers based on actual usage rather than a flat seat count. Your software reports a usage event every time a customer performs a billable action — calling an API, exporting a file, generating a report. PermitCore records every event and, with Stripe connected, automatically charges customers at the end of each billing period. No spreadsheets, no manual invoicing.

Usage tracked per event Stripe auto-charge Explicit usage reporting Fully automatic for Store customers
Two modes: You can use metered billing without Stripe — just to track usage in the PermitCore dashboard and invoice manually. Or connect Stripe to auto-charge customers based on the usage data. Both modes are supported.

Recording a usage event — SDK call

POST /api/v1/meter — no authentication required. Rate limited to 60 requests/minute per IP.

curl
curl -X POST https://api.permitcore.dev/api/v1/meter \
  -H "Content-Type: application/json" \
  -d '{"licenseKey":"PERMIT-XXXX-XXXX-XXXX-XXXX","eventName":"api_call","quantity":1}'
JavaScript
await fetch('https://api.permitcore.dev/api/v1/meter', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    licenseKey: 'PERMIT-XXXX-XXXX-XXXX-XXXX',
    eventName:  'api_call',
    quantity:   1
  })
});
Python
import requests
requests.post('https://api.permitcore.dev/api/v1/meter', json={
    'licenseKey': 'PERMIT-XXXX-XXXX-XXXX-XXXX',
    'eventName':  'api_call',
    'quantity':   1,
})

Request fields

FieldRequiredDescription
licenseKeyYesPlaintext license key — hashed and resolved via HMAC lookup server-side, never stored
eventNameYesBillable action slug, e.g. api_call, export, report_generated. Normalised to lowercase. Must be consistent — this same name is used to configure pricing.
quantityNoUnits consumed. Defaults to 1. Use for batch operations (e.g. 5 if processing 5 items at once).
metaNoArbitrary JSON stored with the event (e.g. file format, region). Visible in the admin event list.

Response

JSON — success
{ "recorded": true }
Handle metering failures. Await or durably queue usage reporting and inspect its result. A lost usage event can cause underbilling; blindly retrying an uncertain result can duplicate usage. The call is fast, but Stripe forwarding happens asynchronously in PermitCore — the SDK response is never delayed by Stripe latency.

Choosing event names

Event names are normalised to lowercase and matched exactly. Choose them carefully up front — they appear in your Stripe Dashboard, invoices, and customer billing pages.

GoodWhy
api_callMachine-readable, consistent, clear unit
exportOne word, noun — matches what the customer did
report_generatedVerb past-tense, unambiguous
sms_sentDescribes the unit being billed
Do not change event names after launch. The event name is the key used to match usage to Stripe Billing Meters and to PermitCore pricing config. Renaming it mid-flight means old events stop being counted and auto-charge breaks.

Meter Usage dashboard

Go to Meter Usage in the admin sidebar. The dashboard shows:

  • Total events — sum of all events in the selected period (7 / 30 / 90 days)
  • Unique event types — count of distinct event names
  • Average events / day — total ÷ days in period
  • Daily bar chart — volume per calendar day, useful for identifying traffic spikes
  • Event breakdown table — each event type, total count, and share percentage

Buttons at the top of the page:

  • Pricing — configure per-event Stripe pricing (see below)
  • Stripe Setup — retroactive backfill wizard for existing customers
Licensing Features

Stripe Auto-Charge for Metered Usage

Connect PermitCore to Stripe to have customers billed automatically based on their usage — no manual invoicing, no exports, no scripts. When a Store customer triggers their first meter event, PermitCore creates the Stripe mapping and subscription item automatically. You configure prices once and everything else runs itself.

For Store customers: zero vendor action after initial setup. Once you set a price for an event name, every customer who bought via your store is automatically billed on their first meter event. No per-customer configuration required.

Prerequisites

  • A Stripe account (live or test mode)
  • Your Stripe Secret Key added to PermitCore under Settings → Company → Payment Settings
  • Customers who bought via your PermitCore Store — their Stripe cus_xxx ID is captured automatically on checkout

Step 1 — Configure pricing for each event name

Go to Meter Usage → Pricing. This page shows all event names that have been recorded, plus any you configure in advance.

Click Add Event Price and fill in:

FieldDescriptionExample
Event NameMust exactly match the eventName your SDK sends. Normalised to lowercase automatically.api_call
Display NameHuman-readable name shown in Stripe Dashboard and customer invoices.API Calls
Unit LabelThe noun Stripe uses on invoices — e.g. "per API call" on the invoice line.api calls
Price per UnitCost in the selected currency per single event unit. Supports up to 6 decimal places for micro-pricing.0.0100 ($0.01)
CurrencyUSD, EUR, or GBP. Must match the currency your Stripe subscription uses.USD

Click Save & Create in Stripe. PermitCore immediately:

  1. Calls the Stripe Billing Meters API to create a new Billing Meter with your event name, aggregation formula (sum), and value key (value).
  2. Creates a recurring metered Price linked to that meter (monthly interval).
  3. Stores the Stripe Price ID (price_xxx) in your database.

You will see a green Stripe status badge next to the event name showing the Price ID. This confirms Stripe is ready.

The Stripe Meter is created once per event name per Stripe account. If you save the same event name again (e.g. to change the price), PermitCore reuses the existing Stripe Meter and creates a new Price linked to it. Old Price IDs are replaced.

Step 2 — What happens on the first meter event (fully automatic)

After Step 1, everything else is automatic. Here is exactly what happens when a customer's software calls POST /api/v1/meter for the first time for a given event:

1
PermitCore records the event
The meter event is saved to the database immediately and { "recorded": true } is returned to your SDK. Everything else happens in the background.
2
Customer mapping is auto-created
PermitCore checks if a Stripe customer mapping already exists for this license key + event name. If not, it looks up the Order record from when the customer bought via your Store — which contains their Stripe cus_xxx ID (captured automatically from the Stripe Checkout session). A LicenseMeterStripeConfig record is created linking the license key, event name, and Stripe customer ID.
3
Metered price added to customer's subscription
PermitCore finds the customer's active Stripe subscription. It checks if the metered price (from Step 1 of setup) is already attached. If not, it calls SubscriptionItemService.CreateAsync to add the price to the subscription. From this moment, Stripe will aggregate all future meter events for this customer.
4
Usage event pushed to Stripe Billing Meters
PermitCore calls the Stripe Billing Meters API (MeterEvent.create) with the event name, the customer ID, and the quantity. Stripe records this event against the meter.
5
All subsequent events go straight to Stripe
Steps 2 and 3 only run once — when the mapping is first created. Every subsequent POST /api/v1/meter call for the same license key + event name skips directly to pushing the event to Stripe. The customer is invoiced at the end of each billing period by Stripe automatically.
Stripe Billing handles invoicing. PermitCore never touches money directly. Stripe aggregates all usage events during the billing period and auto-generates + charges the invoice. You see all of this in your Stripe Dashboard under Customers → Subscriptions → Usage.

For customers who didn't buy via the Store

If a customer's license was not sold through the PermitCore Store (e.g. sold offline, via a reseller, or via a custom flow), their Stripe customer ID (cus_xxx) is not automatically available. You need to configure the mapping manually.

Go to Licenses → View for the relevant license key. Scroll down to the Stripe Metered Billing card.

1
Click "Add Mapping"
Opens a modal. Enter the event name (must match exactly what your SDK sends) and the customer's Stripe ID in the format cus_xxx.
2
Test the connection
Click Test Connection. PermitCore calls the Stripe API to verify the customer exists and returns their name and email from Stripe — confirming the cus_xxx ID is correct before saving.
3
Save Mapping
The mapping is saved. The next meter event from this license key for this event name will trigger the auto-subscription-item step (Step 3 above) and then push to Stripe.

You can add multiple mappings per license — one per event name if different events should go to different Stripe customers (rare, but supported).

Retroactive backfill — customers who used meter before setup

If you had customers using POST /api/v1/meter before you configured pricing, those events were already recorded in PermitCore but never forwarded to Stripe. To backfill:

  1. Go to Meter Usage → Stripe Setup.
  2. The wizard shows all event names with existing meter events, how many licenses are auto-mappable (have Store orders with cus_xxx), and how many need manual setup.
  3. Click Backfill Now to auto-create LicenseMeterStripeConfig records for all historical Store-purchased licenses.
  4. Any remaining licenses with no cus_xxx are listed in Step 3 of the wizard with direct links to their license detail pages for manual mapping.
Backfill creates mappings — it does not replay historical events to Stripe. Historical meter events already recorded in PermitCore before the backfill will not be charged. Only new events going forward are forwarded to Stripe. To charge for historical usage, create a manual Stripe invoice line item in the Stripe Dashboard.

End-to-end example — $0.01 per API call

A vendor sells an API gateway product. Customers pay a base subscription plus $0.01 per API call.

1
One-time setup (vendor)
Open Meter Usage → Pricing. Add event api_call, Display Name "API Calls", Unit Label "api calls", Price $0.01, Currency USD. Click Save & Create in Stripe. Done — Stripe Meter + Price created automatically.
2
Customer purchases via Store
Customer buys through the vendor's PermitCore Store. Stripe Checkout runs, the customer's Stripe cus_xxx ID is captured and saved on the order automatically.
3
Customer integrates SDK
The customer adds one line to their code per API request:
Python
client.meter(license_key, "api_call", quantity=1)
4
First SDK call — full auto-setup in background
On the very first api_call event from this customer: PermitCore creates the customer mapping, adds the metered price to their Stripe subscription, and pushes the event. The response confirms that the event was recorded locally; it does not confirm successful delivery to Stripe.
5
End of billing period
Customer made 5,000 API calls. Stripe aggregates all meter events and auto-generates an invoice for 5,000 × $0.01 = $50. The customer is charged automatically. The vendor sees the charge in their Stripe Dashboard. No manual work needed.

How to confirm it actually worked

After sending a test POST /api/v1/meter call, check these three places — in order, since the first one confirms the fastest and the mapping/Stripe steps only run once per customer:

WhereWhat confirms success
The API response{ "recorded": true } only confirms PermitCore accepted the event locally — not that Stripe received it.
License detail page → Stripe Metered Billing cardThe mapping row now shows the Stripe Customer ID this event was routed to.
Stripe Dashboard → Billing → Meters → your meter → Event summariesThe definitive proof — an aggregated usage value against that customer for the current period. If this shows the expected total, the full pipeline worked end to end.

What you see in Stripe Dashboard

After setup, in your Stripe account you can see:

  • Billing → Meters — your meter(s) with event name, current period usage, and aggregated totals
  • Customers → [customer] → Subscriptions — the subscription now has a metered line item showing usage
  • Billing → Invoices — at period end, a draft invoice is generated then auto-paid

Stripe auto-charge API reference

EndpointAuthDescription
GET /api/meter/pricingCompanyAdminList all configured event prices. Also returns known unconfigured event names from recorded usage.
PUT /api/meter/pricingCompanyAdminCreate or update a price config. Immediately creates the Stripe Billing Meter + metered Price.
DELETE /api/meter/pricing/{eventName}CompanyAdminRemove the local price config. Does not delete the Stripe Meter or Price (Stripe resources are kept).
GET /api/meter/stripe/{licenseKeyId}CompanyAdminList manual customer mappings for a license key.
PUT /api/meter/stripe/{licenseKeyId}CompanyAdminCreate or update a manual customer mapping (eventName + stripeCustomerId).
DELETE /api/meter/stripe/{licenseKeyId}/{eventName}CompanyAdminRemove a manual customer mapping.
POST /api/meter/stripe/{licenseKeyId}/testCompanyAdminVerify a cus_xxx exists in Stripe. Returns { valid, email, name }.