Credit Billing
PaymentKit provides a flexible system for implementing credit-based or prepaid billing. This model allows you to charge customers based on their consumption of services, such as API calls, data storage, or compute time. This guide will walk you through the entire workflow, from defining what to measure to tracking usage and managing customer balances.
The credit billing system is built on four core resources:
- Meters: Define the usage you want to track.
- Credit Grants: Issue credits to your customers.
- Meter Events: Report customer usage as it happens.
- Credit Transactions: View a detailed history of credit grants and consumptions.
Credit Billing Workflow#
The following diagram illustrates the typical lifecycle of credit-based billing in PaymentKit:
1. Define Usage with Meters#
A Meter is a resource that defines how you measure usage for a specific service. You create a meter for each distinct type of usage you want to track.
Use the payment.meters.create() method to create a new meter.
Parameters
Name | Type | Description |
|---|---|---|
|
| A human-readable name for the meter (e.g., 'API Calls'). |
|
| A unique identifier for the event that this meter tracks (e.g., 'api_calls'). This is used when reporting usage. |
|
| How to aggregate usage events. Can be |
|
| The unit of measurement for the usage (e.g., 'calls', 'bytes'). |
|
| An optional description of what the meter tracks. |
Example
import payment from '@blocklet/payment-js';
async function createMeter() {
try {
const meter = await payment.meters.create({
name: 'API Calls',
event_name: 'api_calls',
aggregation_method: 'sum',
unit: 'calls',
description: 'Tracks the number of API calls made by a user.'
});
console.log('Meter created:', meter);
} catch (error) {
console.error('Error creating meter:', error.message);
}
}
createMeter();Example Response
{
"id": "mtr_xxxxxxxxxxxxxx",
"object": "meter",
"name": "API Calls",
"event_name": "api_calls",
"aggregation_method": "sum",
"status": "active",
"unit": "calls",
"description": "Tracks the number of API calls made by a user.",
"livemode": false,
"metadata": {},
"created_at": "2023-10-27T10:00:00.000Z",
"updated_at": "2023-10-27T10:00:00.000Z"
}2. Issue Credits with Credit Grants#
Once you have a meter, you can grant credits to your customers. A Credit Grant represents a specific amount of credit added to a customer's balance. Credits can be categorized as paid (purchased by the customer) or promotional (given for free).
Use payment.creditGrants.create() to issue credits.
Parameters
Name | Type | Description |
|---|---|---|
|
| The ID of the customer receiving the credits. |
|
| The number of credits to grant. |
|
| The currency of the credits. This must match a currency supported by your system. |
|
| The category of the grant. Must be |
|
| A name for the credit grant, for internal reference (e.g., 'New User Bonus'). |
|
| Optional. A Unix timestamp indicating when the credits expire. |
Example
import payment from '@blocklet/payment-js';
async function grantCredits() {
try {
const thirtyDaysFromNow = Math.floor(Date.now() / 1000) + (30 * 24 * 60 * 60);
const creditGrant = await payment.creditGrants.create({
customer_id: 'cus_xxx',
amount: '1000',
currency_id: 'pc_xxx',
category: 'promotional',
name: 'New user bonus credits',
expires_at: thirtyDaysFromNow
});
console.log('Credit Grant created:', creditGrant);
} catch (error) {
console.error('Error creating credit grant:', error.message);
}
}
grantCredits();Example Response
{
"id": "cg_xxxxxxxxxxxxxx",
"object": "credit_grant",
"amount": "1000",
"currency_id": "pc_xxx",
"customer_id": "cus_xxx",
"category": "promotional",
"status": "granted",
"remaining_amount": "1000",
"expires_at": 1729852800,
"livemode": false,
"metadata": {},
"created_at": "2023-10-27T10:05:00.000Z",
"updated_at": "2023-10-27T10:05:00.000Z"
}3. Report Usage with Meter Events#
As your customers use your service, you report their usage by creating Meter Events. PaymentKit automatically deducts the corresponding amount from the customer's credit balance.
Use payment.meterEvents.create() to report usage. It is crucial to provide a unique identifier for each event to prevent duplicate reporting (idempotency).
Parameters
Name | Type | Description |
|---|---|---|
|
| The |
|
| An object containing the usage details. |
|
| The ID of the customer who consumed the service. |
|
| The amount of usage to report. |
|
| A unique string to identify this specific usage event and prevent duplicates. |
|
| Optional. A Unix timestamp for when the usage occurred. Defaults to the current time. |
Example
import payment from '@blocklet/payment-js';
async function reportUsage() {
try {
const meterEvent = await payment.meterEvents.create({
event_name: 'api_calls',
payload: {
customer_id: 'cus_xxx',
value: '10'
},
identifier: `unique_event_${Date.now()}`,
timestamp: Math.floor(Date.now() / 1000)
});
console.log('Meter Event created:', meterEvent);
} catch (error) {
console.error('Error creating meter event:', error.message);
}
}
reportUsage();Example Response
{
"id": "mevt_xxxxxxxxxxxxxx",
"event_name": "api_calls",
"payload": {
"customer_id": "cus_xxx",
"value": "10"
},
"identifier": "unique_event_1698372300000",
"timestamp": 1698372300,
"livemode": false,
"status": "completed",
"credit_consumed": "10",
"created_at": "2023-10-27T10:10:00.000Z",
"updated_at": "2023-10-27T10:10:00.000Z"
}4. Monitor Balances and History#
You can monitor a customer's credit balance and view their transaction history to understand their usage patterns.
Check Credit Balance
Use payment.creditGrants.summary() to get a summary of a customer's available and pending credits, grouped by currency.
import payment from '@blocklet/payment-js';
async function checkBalance() {
try {
const creditSummary = await payment.creditGrants.summary({
customer_id: 'cus_xxx'
});
console.log('Credit Summary:', creditSummary);
} catch (error) {
console.error('Error fetching credit summary:', error.message);
}
}
checkBalance();Example Response
{
"customer_id": "cus_xxx",
"total_balance": {
"pc_xxx": {
"currency_id": "pc_xxx",
"total_amount": "1000",
"available_amount": "990",
"pending_amount": "0",
"currency": {
"id": "pc_xxx",
"symbol": "CRDT",
"decimal": 18
}
}
}
}View Transaction History
Use payment.creditTransactions.list() to retrieve a paginated list of all credit transactions for a customer, including grants, consumptions, and expirations.
import payment from '@blocklet/payment-js';
async function listTransactions() {
try {
const transactions = await payment.creditTransactions.list({
customer_id: 'cus_xxx',
pageSize: 10
});
console.log('Credit Transactions:', transactions.list);
} catch (error) {
console.error('Error listing credit transactions:', error.message);
}
}
listTransactions();Example Response
{
"count": 2,
"list": [
{
"id": "ctxn_xxxxxxxxxxxxxx",
"type": "consumption",
"amount": "-10",
"running_balance": "990",
"description": "Usage of API Calls",
"created_at": "2023-10-27T10:10:00.000Z"
},
{
"id": "ctxn_yyyyyyyyyyyyyy",
"type": "grant",
"amount": "1000",
"running_balance": "1000",
"description": "New user bonus credits",
"created_at": "2023-10-27T10:05:00.000Z"
}
]
}By following these steps, you can successfully implement a complete credit-based billing system. To explore all available options for each function, refer to the detailed API Reference. To receive real-time notifications for credit-related events, such as a low balance, see the Webhooks guide.