Metered billing

Learn how to bill customers according to their usage of your product or service in OpenPay.

Metered billing is a way of charging customers based on what they actually consume, whether that's the number of hours they use a service, the amount of data they use, or how much of a product they consume. Think of it like paying for electricity: the more you use, the higher your bill.

Create & manage meters via admin consoleCopied!

Meters are linked to prices to determine the billing amount—they define how meter events are aggregated over a billing period. Meter events capture the actions customers take in your system.

For example, let's say you are a cloud service provider—your meter events would track the amount of data (GB) a customer uses in storage. The meter is the total data (GB) consumed over a month.

In the admin console, head over to the Meters tab to add a new meter.

  • Display name: the name of the meter for organization purposes (ex: Storage License)

  • Event name: the name to display in meter events when reporting usage to OpenPay (ex: storage_gb)

  • Aggregation formula: how the system will aggregate usage events

    • Sum adds up the value from each event (ex: bytes, API calls)

    • Count simply counts events (ex: number of logins)

  • Event payload customer mapping key: specifies which field in your event data identifies the customer (ex: customer_id)

  • Event payload value key: specifies which field contains the actual usage value - only relevant for sum aggregation (ex: "data_gb" for storage or "duration_seconds" for time)

Prices specify the unit cost, currency, and billing frequency.


Using the cloud service provider example, you can create a Basic product with a metered price where the cost per unit decreases as the total amount of storage used increases, billed at a monthly interval (read more on volume pricing models here).

You can create a subscription for this metered billing product either via the admin console, a checkout payment link, or the API.


To report usage via the admin console, head over to the Meters tab, click into a specific meter and select the "create meter event" button from the available dropdown options on the top left block.

In the Meters tab, click into a specific meter and look up any customer/date range to retrieve their usage.

Create meters via APICopied!

Install and import our clientCopied!

For this recipe, we will use the Python SDK, which you can install using pip install getopenpay or poetry add getopenpay

from getopenpay.client import ApiKeys, OpenPayClient
from getopenpay.models import (
  BillingMeterAggregationFormula, CalendarIntervalEnum, CreateBillingMeterEventRequest,
  CreateBillingMeterRequest, CreateCustomerRequest, CreatePriceRequest, CreateProductRequest,
  CreateSubscriptionRequest, PriceTierParams, PriceTypeEnum, PricingModel, SelectedPriceQuantity,
  UsageTypeEnum
)

OP_PUBLISHABLE_TOKEN = 'TODO_YOUR_PUBLISHABLE_TOKEN'
OP_SECRET_TOKEN = 'TODO_YOUR_SECRET_TOKEN'

api_keys = ApiKeys(publishable_key=OP_PUBLISHABLE_TOKEN, secret_key=OP_SECRET_TOKEN)

# sandbox/staging environment
sandbox_host = 'https://connto.openpaysandbox.com'

# production environment
production_host = 'https://connto.getopenpay.com'

client = OpenPayClient(api_keys=api_keys, host=sandbox_host)

Create billing meterCopied!

create_billing_meter_request = CreateBillingMeterRequest(
  event_name="TODO_EVENT_NAME",
  aggregation_formula=BillingMeterAggregationFormula.SUM,
  display_name="TODO_METER_DISPLAY_NAME",
  event_payload_customer_mapping_key="TODO_CUSTOMER_ID",
  event_payload_value_key="value",
)
billing_meter = client.billing_meters.create_billing_meter(
  create_billing_meter_request=create_billing_meter_request
)

Create a productCopied!

product = client.products.create_product(
  CreateProductRequest(
    name='Volume usage based',
    description='For personal use',
    account_sku='970000000001',
    features=['Priority support'],
    unit_label='seat',
    is_active=True
  )
)

Create a priceCopied!

create_price_request = CreatePriceRequest(
  product_id=product.id,
  is_active=True,

  unit_amount_atom=None,
  currency="usd",
  pricing_model=PricingModel.VOLUME,

  # Bill every month
  price_type=PriceTypeEnum.RECURRING,
  billing_interval=CalendarIntervalEnum.MONTH,
  billing_interval_count=1,

  # Volume based amount price.
  # First 100 units are priced at $10 each
  # Rest are priced at $50 each
  price_tiers=[
    PriceTierParams(units_from=0, units_upto=100, unit_amount_atom=1000),
    PriceTierParams(units_from=101, unit_amount_atom=5000)
  ],
  usage_type=UsageTypeEnum.METERED,
  meter_id=billing_meter.id,
)
price = client.prices.create_price_for_product(
  create_price_request=create_price_request
)

Create a customerCopied!

customer = client.customers.create_customer(
  CreateCustomerRequest(
    first_name='John',
    last_name='Doe',
    line1='123 Main St',
    city='Anytown',
    state='Anystate',
    country='US',
    zip_code='12345',
    email='john.doe@example.com'
  )
)

Create a subscriptionCopied!

# Create a subscription
create_request = CreateSubscriptionRequest(
  customer_id=customer.id,
  payment_method_id='TODO_PAYMENT_METHOD_ID',
  selected_product_price_quantity=[
    SelectedPriceQuantity(price_id=price.id, quantity=0), # initial quantity should be 0
  ],
  total_amount_atom=0
)

# Create the subscription
subscription_response = client.subscriptions.create_subscriptions(
  create_request
)
subscription = subscription_response.created[0]
print(subscription.status)

Create a billing meter eventCopied!

# now create a usage entry
create_billing_meter_event_request = CreateBillingMeterEventRequest(
  event_name=billing_meter.event_name,
  payload={
    billing_meter.event_payload_customer_mapping_key: customer.id,
    billing_meter.event_payload_value_key: 10
  }
)

_ = client.billing_meter_events.create_billing_meter_event(
  create_billing_meter_event_request=create_billing_meter_event_request
)

Preview upcoming invoiceCopied!

# preview upcoming invoice
invoice = client.invoices.preview_next_invoice(subscription.id)
print(invoice)