Credits Mental Model

Markdown version

When talking about building credits-based pricing infrastructure, a lot of people don’t understand the complexity. After all, you only need to keep track of the customer’s balance, add and subtract from it as needed, and you’re done, right?

Well, not exactly. Even the simplest credits models are more than just a wallet. You need to think about expiration, revenue recognition, customer visibility, budget management and more.

In this article, I’ll walk you through the mental model I use when thinking about credits-based pricing, and everything you need to consider before diving into implementation. Obviously, you don’t need to implement all of these! Based on your product’s pricing and packaging strategy, you might need just a subset of these features, or even things we haven’t considered yet. I’ll also share a few tips at the end of the article to help you get started.

Credits Mental Model
The single biggest tip I can give you is - credit pipelines are decoupled by nature. You can have a very complex system for credits purchase, alongside a very simple consumption logic. This also means that work can be done in parallel, if the data structure — your ledger, is designed properly

Credits Purchase

The entry point for every credits-based pricing is credits purchase. This is where your customer converts fiat currency into your system’s credits. Even when your credits are called Dollars for example, they are still units purchased in advance.

Pricing models

Define which types of pricing models are available when buying credits, which can be anything from:

  • Per-unit - e.g 1 credit = $1, buy any amount you want
  • Volume-based - e.g 100 credits for $10, purchased in quantities of 100
  • Graduated - packs of credits with a discount for larger quantities

Or anything else your product needs. Essentially, this is very similar to any in-advance commitment pricing model your product already has. You can check out Stripe’s supported pricing models for reference.

Multi Fiat-Currencies

If you want to support multiple fiat-currencies, you’ll either need to define a manual price point for every pricing model defined, or you can use automatic pricing convertion. This is especially important if your credits are dollar equivalent, and their usage is tied to a specific cost, such as LLM tokens. Failing to define this properly can result in losses due to currency conversion ratios.

Recurring Credits

Recurring credits have two popular variations - aligned or unaligned with the subscription billing cycle. For example, Clay offer monthly and annual subscriptions with a certain amount of credits, given at the start of the subscription. Other companies such as Lovable offer daily credits, on top of the monthly recurring ones.

Prorations

When dealing with recurring credits, you should also consider what happens when the customer upgrades or downgrades their subscription mid-cycle. Downgrades are usually simple, as most companies just downgrade at the end of the billing cycle.

Upgrades can be a bit trickier - the popular option is to keep the remaining credits, bill the full amount for the new plan without prorating for the previous one, and add the new plan’s credits to the existing balance. This is different from popular subscription models, where the new plan price is prorated for the remaining time of the billing cycle, and the customer is billed for the difference. The implicit implication is that the billing anchor resets to the new plan’s start date, and if you handle other usage-based pricing models besides the credit ones, this can get tricky, and you might need to reset those as well.

Manual Top-Ups

These are a straightforward way to add credits to your balance - pay with fiat, get credits in return. When considering top-ups alongside recurring credits, you should consider the following: do you allow a maximum amount of top-ups before forcing the user to bump to the next tier? Which pricing models are available for top-ups? What expiration policy applies for them?

Cost Basis

Without getting too much into revenue recognition, when dealing with credits, revenue is deferred to the moment the credits are used or expired. Therefore, for every credits purchase, you should keep track of the cost basis, so you can accurately report revenue when the credits are used.

Promotional Grants

Not all credit grants are paid for. Promotional grants are a way to give credits for free (e.g 0 cost basis), as part of marketing, growth or customer-success adjustments. It’s important to keep an audit trail of these grants - who granted them and for what purpose, and any other details which can help you track your marketing efforts.

Credits<>Product Eligibility

A bit on the advanced side of credits. Usually, credits can apply to the entire product suite, and if needed, differentiation is done on the credit type level (e.g “Compute Credits”, “Storage Credits”). However, you might want to grant credits for a specific product - such as “only memory-optimized compute”. In this scenario, you’ll need to keep track of the product eligibility for every credit grant, so you can accurately apply the credits when the customer uses the product.

Ledger

The ledger is the heart of credits-based pricing. It’s where you keep track of every credit purchase, grant, usage, expiration, and more. These are the key things you need to consider when building your ledger:

Immutable History

Ledgers should be immutable and append-only. This means that once an event is finalized, it should never be changed or deleted. This is important for auditability and compliance, and should give you the option to get a point-in-time snapshot of the ledger at any given time.

Out of Order Events

Although the first point is immutability, you should also consider the possibility of out of order events. Consumption events should first be processed as “pending” and later committed to the ledger as they are finalized. This gives the system a grace period, which will allow for eventual consistency and handling of out of order events. This doesn’t mean that pending transactions are not accounted toward the customer’s balance - but their grant attribution and total balance calculation can change before finalization. During the grace period, you should also be able to remove and adjust pending events, to account for system failures, usage spikes and more.

Credits Information

For every credit grant, you should keep track of the following information:

  • Entry type - purchase, promotional, recurring, consumption, etc
  • Start balance
  • End balance
  • Amount
  • Status - pending, committed, cancelled, etc
  • Currency - “compute”, “storage”, “usd”, etc
  • Expiration date
  • Customer ID
  • Product IDs - if the credits are product-specific
  • Priority - to allow for manual consumption order
  • Any metadata, tags, or custom fields you might need to track

This obviously varies between different products, but the general idea remains the same: the ledger should allow you full audit, with a point-in-time snapshot of the balance at any given moment.

Multiple Pools

The credit balance is the sum of all credits in the ledger. However, as mentioned above, you might want to keep track of credits in multiple pools, for different products, for examples.

Credit Hierarchy

Some products have internal entities hierarchy, such as tenant -> customer -> product. In this case, you’ll need to keep more than just the customer ID, but rather the entire hierarchy information, so you can calculate the balance for each level.

Real-Time Balance

One way to calculate the balance is to sum up all entries in the ledger. Clearly, this is not the most efficient way. That’s why it’s recommended to store the calculate balance on every entry, so the actual balance is always a simple query away. Another recommendation, if real-time enforcement is important, is to cache the balance in a separate database, and update it after every transaction.

Credits Roll-Over

Recurring credits don’t always expire at the end of the billing cycle. Some products offer a roll-over period, where the remaining credits are carried over beyond the billing cycle. This can be another week of grace, to use the remaining credits, or even multiple billing cycles.

Credits Consumption

Once we have a ledger and a balance, we can start handling the consumption of credits. Once again, many things to consider!

Async/Sync Consumption

Depending on scale, consistency and latency requirements, you’ll need to decide whether credit consumption should be handled synchronously or asynchronously. Synchronous consumption is when the credit consumption is deducted from the balance immediately, while asynchronous consumption can take up to a few seconds to complete. Handling both is possible, but can introduce race conditions and locking issues.

Events Consumption rate

Just like a price point for usage-based features, each event that consumes credits should have a specific rate. The common ones are per unit - e.g, 0.1 credits per API call, or packages - e.g, 1 credit for 1M tokens. However, you might find yourself defining more complex rates, such as graduated rates. Note that in this case, the rate is not determined on consumption, but rather on the end of the billing cycle, so it can be tricky to finalize ledger entries.

The other complexity for graduated rates is that it makes it twice as hard to calculate the actual feature price - if you buy credits in bulk, and get bulk discount on consumption, you’re actually giving the customer a double discount.

Manual Adjustments

Although usually credit consumption happens due to customer actions, we might want to manually adjust the balance, introducing synthetic consumption events. This is useful to revoke a promotional entitlement or when issuing a refund and you need some credits deducted from the balance.

Event Attribution

When a customer consumes credits, we need to attribute the consumption to an event in the system - API request, tool call, etc. This will allow both your reps and the customers to see exactly how their credits are being used, export the data, display usage over time, etc.

Withdraw Logic

When consuming credits, you want to keep a certain logic around which credit grant should be used first. Stripe for example, use the following order: priority -> expiration date -> category (promotional before paid) -> effective date -> created date.

Overages

What happens when a customer runs out of credits? You can block them from using the product until they top up their balance, but that can be a poor experience for certain product types. Different companies handle this differently - you can decide to go with automatic top-ups, or just allow for overages and bill the customer at the end of the billing cycle. Essentially, this is a trade between customer satisfaction and risk management.

Observability

Credits-based pricing creates confusion and uncertainty for the customers, so it’s no surprise that observability is a key part of it. You want your customers to feel in control of their usage, understand their spending and be able to halt it if needed.

Downstream Events

Webhooks are the bare minimnum for observability, and you should send events for every credit change - purchase, consumption, expiration, etc. You might not think about every potential edge-case, so you want to enable your customers to act on credit-related events and implement custom logic if needed.

Data Export

Unless you provide a full analytics dashboard, you should allow your customers to export any credits-related data. This includes the full ledger and attributed events. This will allow your customers to build using their own analytics tools, and will support revenue recognition and reporting.

Spend Limits & Alerts

There’s a reason Serverless Horrors exist - usage-based pricing can easily spike, and credits are no different. If you allow for overages or automatic top-ups, you should also allow your customers to set spend limits and alerts on various thresholds, so they can halt usage if needed.

Revenue Recognition

For internal purposes, you want to make sure you’re able to generate credit consumption reports acrosss all tenants, so you can recognize revenue based on your financial team’s requirements.

Summary

Hopefully this article has given you a better understanding of the complexity of credits-based pricing, and the mental model I use when thinking about it. If you have any questions or feedback, feel free to reach out to me on X or mail.