> ## Documentation Index
> Fetch the complete documentation index at: https://docs.withorb.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Product access with prepaid credits

You can use Orb to both manage prepaid credit balances for your customers and to control
access to your product based on those balances. This is useful for companies that want
to ensure that customers are only able to access their product if they've paid for it in advance.

In this guide, we'll walk through how to integrate Orb's prepaid credit management functionality
and alerting features to accurately manage product access. We'll use a model that's a very simple
version of a text message API that uses credits:

* No messages are sent unless the customer has purchased credits.
* Customers must purchase credits through your product's admin dashboard. Each credit costs \$0.01.
* The customer can purchase credits in advance, and the credits will be automatically
  deducted from their balance as messages are sent.
* Messages can be used at very high throughput, and the customer needs to be blocked from
  sending messages if they run out of credits as close to the event as possible.
* Sending messages is performance critical, so it's not possible to incur the latency
  of checking the customer's current balance before each message send takes place. Incurring this latency
  is acceptable on a very infrequent basis.

## Prerequisites

In your integration, ensure that you create an Orb customer corresponding to each of your
own customers. A customer always starts with 0 credits in each of their prepaid balances;
for the purposes of this example, we'll work in a custom prepaid credits currency called `message_credits`.

Upon creating a customer via the [create customer API](/api-reference/customer/create-customer) endpoint:

* Create a balance depleted and balance recovered alert [via the API](api-reference/alert/create-customer-alert#create-customer-alert).
  Ensure that you're creating these alerts in the correct currency, passing the `identifier` of the currency (in this case `message_credits`). For these
  alert types, the `thresholds` body parameter is not required, since the threshold is implicitly set to 0 and these alerts fire on either side
  of that threshold. As long as these alert configurations are created, you won't need to store the configuration ID in your data model.
* Create a subscription for the customer. Note that subscriptions in Orb do not have to be explicitly marked as prepaid, and
  the customer does not have to be specially configured to draw down from the prepaid balance. Instead, any price that's part of the
  subscription that is in the `message_credits` currency will automatically draw down from the `message_credits` prepaid balance. You can mix and match
  price currencies in a subscription, and Orb will automatically draw down from the appropriate balance.
* In your data model, create a nullable timestamp field called `messages_blocked_until`. When this field is a non-null timestamp in the future,
  the customer is blocked from sending messages. When this field is `null`, the customer is not blocked from sending messages.

## Managing new credit purchases

In order to support credit purchasing through your dashboard, your server-side logic should increment credits using the [create ledger entry endpoint](/api-reference/credit/create-ledger-entry-by-external-id),
passing in the following parameters:

* Set the currency to message\_`credits`.
* `entry_type` = `increment` signifies an increment
* `amount` represents the additional credits being bought.
* `per_unit_cost_basis` represents the cost of each token in your invoicing currency, USD. Set this to \$0.01, since each credit costs \$0.01.
* `expiry_date` represents when the `message_credit` will automatically be depleted. Set this to one year from the current grant date.
* To ensure credits are billed immediately and granted conditional on payment success, set `invoice_settings.auto_collection` to `True`,
  `invoice_settings.require_successful_payment` to True, and `invoice_settings.net_terms`to 0.

## Sending messages

In your application logic, you need to ensure that customers are only able to send messages if they have enough credits to do so by interpreting
the `messages_blocked_until` field.

Use the following logic to determine eligibility based on the value of `messages_blocked_until`:

* If the field is `null`, your application should allow the customer to send messages. This is the case where the customer has a positive credit balance.
* If this field is `MAX_DATE`, your application should block the customer from sending messages. This is the case where the customer has no known credit blocks that
  may become effective.
* If the field is a future timestamp, your application should disallow the customer from sending messages. This is the case where the customer has no positive credit balance, but
  there is a credit block that will become effective in the future.
* If the field is a non-0 timestamp in the past, your application should re-query the customer's current balance using the [current credit balance](https://docs.withorb.com/api-reference/credit/fetch-customer-credit-balance)
  and make a determination based on the new value of `messages_blocked_until`. This is the case where the customer had no positive credit balance, but
  a credit block may have become effective so a re-query is required.

Note that this check must be performed on every message send, since the customer may have purchased more credits in between messages, the customer may have exhausted their credits, or the
passage of time may have caused a credit block to expire or become effective.

## Blocking product access on depletion

Orb guarantees the delivery of a [balance depleted alert](https://docs.withorb.com/integrations-and-exports/webhooks#customer-credit-balance-depleted)
when there are 0 remaining `message_credit`s. When testing, parse this webhook and confirm that `properties.pricing_unit.name` matches `message_credit`.

Simply listening to this webhook is **insufficient**. This is because webhook systems do not provide ordering guarantees,
and you need to ensure that the customer is only blocked from sending the message under the appropriate conditions.

For example, suppose that a customer has a balance of 10 message credits, sends 10 messages and immediately purchases a new block in quick succession.
In this case, the balance depleted alert may be delivered via webhook after the block has been purchased, and the customer will be erroneously blocked from sending messages.

Instead, you should always re-query the customer's [current credit balance](https://docs.withorb.com/api-reference/credit/fetch-customer-credit-balance) using
the API when you receive a balance depleted webhook.

This API is never cached, and will always return the most up to date balance per the usage events that Orb has ingested; it will also reflect
any other operations that have been performed on the balance, such as the purchase of new credits or the expiration of existing credits. For this request,
be sure to set `include_all_blocks=False` to only query for active blocks at the current point in time.

In order to set `messages_blocked_until`, use the following logic:

* If the balance is greater than 0, set `messages_blocked_until` to `null`.
* If the balance is 0, set `messages_blocked_until` to the earliest future `effective_date` of any of the customer's credit blocks. If the customer has no
  credit blocks effective in the future, set `messages_blocked_until` to `MAX_DATE`.

## Unblocking product access

If your customer purchases more credits through your product dashboard, continue using the  [create ledger entry endpoint](/api-reference/credit/create-ledger-entry-by-external-id) as
detailed above. It's also important to ensure that new credits are set to be effective as of the **beginning of the current subscription
billing period**. You can accomplish this by setting the `effective_date` of the entry to match the `current_billing_period_start_date` of the
subscription (you'll need to make sure that you have the latest [subscription](https://docs.withorb.com/api-reference/subscription/fetch-subscription) response).

This amounts to 'backdating' the credits to the beginning of the billing period, and ensures that your customer never incurs any overages
for the current billing period. Specifically, if there are seconds or minutes of lag between the consumption of credits and your system consuming
the webhook, your customer may temporarily accrue a small overage charge until product access is blocked (and more credits are bought). When the customer
purchases more credits, the above `effective_date` strategy will ensure no charges remain on the current period invoice.

After creating the block, query again for the customer's current balance using the [current credit balance](https://docs.withorb.com/api-reference/credit/fetch-customer-credit-balance)
endpoint and use the same exact logic detailed above, setting `messages_blocked_until` to `null`, `MAX_DATE`, or a different future effective date.

## Handling balance recovered webhooks

Orb will send a balance recovered webhook when a customer's credit balance is no longer at 0. This may happen
when a customer purchases more credits, and handles the case where this action happened outside of the context above (e.g. through
a manual intervention by a customer service representative). This will also handle cases like a subscription change where a user
upgrades to a subscription that includes a recurring credit allocation, because Orb will automatically create a new credit block
and send a "balance recovered" webhook. Similar to the balance depleted webhook, this webhook will not provide ordering guarantees
so it's important to not solely depend on this webhook to unblock product access.

When you receive this webhook, you should re-query the customer's current balance using the [current credit balance](https://docs.withorb.com/api-reference/credit/fetch-customer-credit-balance).
Follow the same logic as above to determine the value of `messages_blocked_until`.

## Automated credit allocations

Orb supports the concept of a recurring allocation, which is the concept of a credit block that is automatically granted by the subscription
on a recurring basis. This is useful for companies that want to provide their customers with a certain amount of credits each month as part of their subscription.

When a customer has an active allocation, future credit blocks are created automatically by the system, and Orb guarantees that the next block will exist
while the current one is active. Because of this, the above strategy of setting `messages_blocked_until` to the earliest future effective date
will ensure that future allocations are accounted for in our message sending strategy.

## Credit expirations

In Orb, each credit block can expire at any time after it is effective. When a credit block expires, you will receive a balance depleted alert.
As per the section above, you should re-query the customer's current balance using the [current credit balance](https://docs.withorb.com/api-reference/credit/fetch-customer-credit-balance)
API and update `messages_blocked_until` accordingly. If the customer has no remaining blocks after the expiration, `messages_blocked_until` will be set to `MAX_DATE`.

## Overages due to eventual consistency

Because Orb's event ingestion system is designed to be eventually consistent and it's not feasible to wait for all events to be ingested before sending a message,
it's still possible that a customer may send a very small number of messages before they're blocked after they've exhausted all their message credits. We recommend
setting your `conversion_rate` to \$0.00 for the `message_credits` currency, since this will ensure that the customer is not charged for any overages that may occur.
In the vast majority of cases, this is an acceptable tradeoff but reach out to Orb if you want to discuss how faster SLAs may bound the potential overage costs.
