Configure prepaid credits
In contrast to the in-arrears model of billing, where usage is invoiced at the end of a billing cycle after costs have been incurred, Orb supports deducting from a prepaid credit balance as usage occurs automatically.
Prepaid credits are designed with the following principles:
- Real-time: By default, Orb reflects changes to the credit balance as soon as events are ingested, with minimal latency. Depending on your desired deduction behavior, deductions to the balance can be configured to happen less frequently (e.g. if an hour’s worth of events are required before a deduction takes place).
- Auditable: Orb provides a trace of every change to the customer credit balance, down to each event and its contribution.
- Immutable: Orb provides an append-only ledger of transactions that affect the credit balance, which are immutable once finalized. Orb is able to accommodate late and out-of-order event reporting by allowing pending transactions for a fixed reporting grace period.
- Flexible: Orb supports multiple pools of credits per customer, and prepurchase is fully compatible with all plan types and metrics.
Structure of the credit balance
Each customer has a credit balance in one currency unit, which could be a custom currency (“Acme Inc. credits”) or a real-world currency (e.g. “USD”). Structurally, the credit balance consists of blocks, which are initialized with an amount
and expiry_date
. At any given time, the total credit balance for a customer is the sum of the remaining amount in their unexpired credit blocks.
Custom pricing units
In addition to supporting commitments in a real currency (e.g. a $50K commitment), Orb allows you to configure multiple custom pricing units, each with a corresponding ledger. This is useful for separating credits for different SKUs, allowing your customers to purchase credits for different products or services. For example, you might have a pricing unit for "Compute credits" and another for "Storage credits".
When creating a plan, you can specify which pricing unit to use for each of the plan's prices, such that multiple separate line items might be priced in a combination of credit units, whereas the other might be in USD. On the customer page, you'll be able to see the current balance for each pricing unit, and the ledger will be filtered to only show transactions for that pricing unit. Each pricing unit will be set to have its own conversion rate to the plan's invoicing currency (e.g. USD). This conversion rate will be used to convert any overage usage to a chargeable currency.
To set up a custom pricing unit and enable its ledger, navigate to the "Pricing units" page in "Settings" and click "Enable custom pricing units". You'll be able to specify the identifier, display name, and short name of the pricing unit so Orb can display it properly in the UI and on invoices.
Cost basis
Each credit balance block also tracks an optional cost basis, which can help you track the original amount your customer paid for that balance. For example, a trial credit balance that is provided upon provisioning might have a cost basis of $0, whereas regular credit balance bought during the course of the customer lifecycle might have a cost basis of $50 per unit. Providing the cost basis enables Orb's Revenue Reporting functionality, which allows you to understand how your revenue is utilized over time.
Payment for credit balance
Orb provides a single API to both charge customers via a connected payment provider (e.g. Stripe) and increment a customer's credit balance. This is useful for several reasons:
- Provides a single action for triggering payment, avoiding inconsistent and tedious integrations with multiple payment providers.
- Eliminates possible inconsistency and revenue reporting issues by ensuring that credit balance is available for customer use as soon as revenue is received. Without this functionality, if credit balance is added after payment is booked, end-of-month revenue recognition can be difficult or prone to errors.
- Uses Orb metadata to directly tie an increment ledger entry to a payment provider action.
Granting conditional on payment
If successful payment is a requirement for credits to be effective, then pass invoice_settings.require_successful_payment
when creating a credit increment. Note that this is an option within the invoice_settings
dictionary because invoice creation is necessary for this behavior.
With this option enabled, the credit block will be initialized with a status
of pending_payment
until the relevant invoice is paid. Although the block will be returned when fetching the customer credit balance, it will not be eligible to be drawn from until it's in status=active
.
If you're using Orb invoicing with a payment gateway integration, Orb is responsible for listening to the gateway webhooks and will automatically mark the block as active once the payment is successful. If the invoice is in a synced
state (e.g. a different invoicing provider is used), it will need to be manually marked as paid via the API for the credit block to be considered part of the balance.
Note that this option is also available when creating a credit top-up and is configured when first creating the top-up via the API.
Running out of credit balance
When a customer runs out of their credit balance, any excess usage they incur will be charged at the end of the month on the invoice. Instead, you might want to block customers from using your product until they do that. To do that, set up an alert:
- Navigate to the customer’s page
- In the Credits section, click Manage alerts
- Add an alert for credit balance depleted if you want an alert when the customer’s credit balance reaches 0, or credit balance dropped if you want a non-zero threshold.
Now, Orb will emit a customer.credit_balance_depleted
or customer.credit_balance_dropped
webhook anytime the customer’s credit balance goes below the specified threshold.
To quickly test that the webhook is working, you can:
- Click “Adjust credits” in the Credits section
- Change the Adjustment type to “Subtract credits”
- Enter the amount as the current credit balance for the customer and hit "Save"
You should receive a credit balance depleted or dropped webhook, depending on the alert you configured.
Automatic top-ups
Orb supports automatic top-ups, which are triggered when a customer's credit balance falls below a certain threshold. This is useful for ensuring that customers have enough credit balance to cover their usage, and can be configured to automatically top-up by a fixed amount at a specific cost basis, including issuing an invoice. Automatic top-ups can be configured on a per-customer basis, and can be managed in the Orb web app or API.
Native top-ups prevent you from having to build your own webhooks based top-up logic, which can be prone to race conditions and cause correctness problems (or unexpected overages for the customer). With Orb's native top-ups, you can be sure that the credit balance is always available for your customers to use and there are no in-arrears charges.
Periodically topping up credits
Putting all of this together, you could write a simple consumer that consumes the credit_balance_dropped webhook and automatically bills your customer for 100 credits.
An example, using Flask:
from flask import Flask, request
import hmac
from hashlib import sha256
import requests
app = Flask(__name__)
# Example Using Flask
@app.route('/webhook-handler', methods=['POST'])
def handle_webhook():
# parse webhook JSON
webhook_event = request.json
if webhook_event is None:
# could not parse request
return ('Unable to parse notification.', 400)
# Validate signatures, see webhooks documentation
if webhook_event["type"] == "customer.credit_balance_dropped":
customer_id = webhook_event["customer"]["id"]
request_data = {"entry_type": "increment", "amount": 100, "per_unit_cost_basis": "2.50", "invoice_settings": {"auto_collection": True, "net_terms": 0}}
response = requests.post(url=f"https://api.withorb.com/v1/customers/{customer_id}/credits/ledger_entry", data=request_data, headers={"Bearer": <YOUR_API_KEY>})
return ('Successfully processed webhook!', 200)
Allocations
In addition to allowing on-demand credit purchases, customers can receive an allocation of credits – of one or more currency units – automatically as part of their subscription. Allocations can be configured in the ‘create plan’ flow and overridden on a per-subscription basis, with an amount, optional rollover behavior, and cadence.
Whereas the set of prices on the subscription determine how Orb will deduct credits from the balance (or accrue them as overages on the invoice), allocations allow you to set up a recurring schedule of increments on the customer’s credit ledger. Because allocations are configured at a plan-level, Orb allows you to standardize credit treatment and ensure consistency across thousands of customers.
Just like a price, allocations can be configured to specify their cadence, or how often credits should be added. Once configured, a recurring allocation will immediately add future-effective credit blocks for the customer (corresponding to the billing date of the subscription), which can be previewed on the subscribed customer’s page.
Because allocations are tied to the subscription lifecycle, canceling a subscription will automatically prevent the customer from receiving new allocations and void any future credit blocks. Any backdated subscription actions (e.g. creation, cancellation, plan change) will affect the available credit balance according to the subscription timeline: the ledger will be replayed from the backdated modification point onwards, and past usage data will be deducted from allocated blocks active in the past.
The credit amount that a customer receives per billing cycle for an allocation is not prorated on billing cycle length, and the cost basis for an allocation is always assumed to be $0 (representing an inclusion).
Relatedly, if you remove an allocation from a subscription by editing the relevant interval on the subscription, credits will only be removed if the relevant period's line item no longer exists at all. This means that ending an allocation interval early in the billing period will not clawback a prorated subset of credits.
Prepaid ledger
Orb provides a ledger abstraction that acts as a log of a customer's credit balance over time. A ledger entry always indicates the starting and ending credit balance, as well as the time at which the transaction took place.
New ledger entries are added in the following scenarios:
- Automatic deductions: When usage is ingested, Orb will automatically deduct an amount from the credit balance if appropriate. To determine how much an incremental event should deduct from the credit balance, Orb uses both the billable metric (this determines the quantity of usage implied by the event) and its associated price (which determines the amount based on the quantity). Automatic deductions are tagged with a
price_id
since all deductions are associated with a specific price. - Manual increments & decrements: Through the Orb web app and API, you can manually add blocks from the balance (optionally specifying metadata like an expiry date), or deplete it. To allow tracing these manual operations, Orb keeps track of the user or key that initiated the action, and also provides a
description
field for business-specific attribution. - Block expiration: When a block expires because its expiry date has passed, the credit balance is automatically depleted by the remaining
amount
in the newly expired block. - Expiry changes: It’s possible to change the expiration of all or part of a block manually; this will show up as a ledger entry but will not change the overall credit balance amount.
Automatic usage deductions
In order to be compatible with all price models, Orb's credits ledger will contain a daily entry per price that the customer is subscribed to which has non-zero usage. The effective_date
of an automatic deduction is the beginning of the day in the customer's timezone. This means that a given credit block must be effective before the beginning of the day in order to be eligible for usage drawdown for that day's usage. In most circumstances, Orb recommends creating credit blocks aligned to the previous day boundary in the customer's timezone.
In-arrears fixed fees
Fixed fees set to bill in-arrears will also draw down from the customer's credit balance. The total amount is divided evenly across the fixed fee's billing period, with an equal amount deducted from the credit ledger each day. This can be used to represent scenarios like enterprise contracts with a support fee that deducts from a customer's prepurchase commitment.
Pending and committed ledger entries
Events may be reported to Orb out of order and with significant lag, meaning that the reporting time does not necessarily match the timestamp
, which is the time the usage occurred. To account for this, Orb maintains pending ledger entries until the reporting grace period has passed. After this point, Orb commits the entry, making it immutable.
This is important to the fidelity of the ledger because the ordering of operations can have a significant impact to the credit balance. For example, if an event with timestamp = 2022-02-02T23:00:00
is reported 10 hours later and a block expires at timestamp = 2022-02-03T00:00:00
, Orb will automatically create the deduction ledger entry for the event before the block expiry, properly allowing it to deduct credit balance from an eligible block.
Note that an entry that is pending is not the same as a block that is not active. The status
of a block is only relevant when payment is a condition to adding credits; in contrast, a pending entry is related to the grace period of the ledger.
Exporting the ledger
In the admin web application, Orb provides a detailed ledger view. This view can be accessed from any customer page by clicking "View full credit ledger", and the ledger can be drilled down to specific operations, actors that took the action, and a cost basis threshold.
This view also supports exporting these ledger entries to CSV format, which can be useful for further investigation or digging.
Amendments to the credit balance
In cases where manual adjustments need to be made to a customer’s credit balance, you can use manual increments and decrements. This is useful in cases such as:
- Providing extra credits for trial purposes so that your customer has more usage to evaluate your offering
- Compensating for downtime or reporting errors by adding a fixed amount to the credit balance
In addition to these one-off adjustments, the prepaid credit balance will also reflect changes when historical usage is amended. For example, if you use Orb’s amendment functionality to overwrite events that previously led to credit balance deductions, Orb will automatically add or decrement credits to account for the difference between old and new events.
Although historical amendments will lead to changes in the credit ledger, note that these amendments will not reflect in any issued invoices automatically. As a result, Orb does not recommend making amendments or backfills that overlap with issued invoices.
Amendments to revenue recognition
In cases where the customer requests a refund or in the case of a data input error, Orb supports amending the credit ledger in a manner that also maintains the consistency of the downstream revenue recognition workflows.
For refunding a credit increment to your customer, Orb supports refunding a credit block via the "Void credits" operation on the dashboard and selecting the "Mark as refund" option. These show up in the ledger as "Refund" operations.
For voiding a credit increment due to a potential client issue or data input error, Orb supports voiding a credit block via the "Void credits" operation and not selecting the "Mark as refund" option. These show up in the ledger as "Void" operations.