Billing Module (Unified Billing)
The Billing module is a high-level unified wrapper for free quota + credits deduction. It integrates three backend interfaces internally, so developers don't need to call them separately.
Billing Priority: Free period (repeated operations within 30s are free) → Free quota → Credits deduction
API List
| Method | Return Value | Description |
|---|---|---|
sdk.billing.getUsage() | Promise<UsageInfo> | Get usage quota (network request) |
sdk.billing.getCachedUsage() | UsageInfo | null | Get cached quota (returns null before the first call) |
sdk.billing.check() | BillingCheckResult | Synchronously check if the operation is allowed (no charge) |
sdk.billing.consume(options?) | Promise<BillingConsumeResult> | Consume once |
sdk.billing.refreshCredits() | Promise<void> | Manually refresh credits balance |
sdk.billing.onChange(callback) | () => void | Listen for quota changes |
Detailed Usage
Get Usage Quota
typescript
const usage = await sdk.billing.getUsage()
// {
// isEnabled: true, Whether billing is enabled for the current module
// freeRemaining: 5, Remaining free quota
// freeTotal: 10, Total free quota
// creditsPerUse: 6, Credits required per use (after free quota is exhausted)
// creditsBalance: 78633, Current credits balance
// inFreePeriod: false, Whether currently in a free period
// freePeriodRemaining: 0, Remaining seconds in the free period
// }Internal parallel requests:
GET /ai/v5/artimind/free_trial/count?module=generator_{appKey}→ Free quotacredits.getBalance()→ Credits balance
The returned isEnabled field comes directly from the backend free_trial/count response is_enabled, and can be used to determine whether the current generator module has billing enabled.
Check if Operation is Allowed
typescript
const check = sdk.billing.check()
// { canProceed: true, reason: 'free_period' } Within free period
// { canProceed: true, reason: 'free_count' } Has free quota
// { canProceed: true, reason: 'credits' } Will deduct credits
// { canProceed: false, reason: 'insufficient' } Insufficient creditsConsume Once
typescript
const result = await sdk.billing.consume({
externalId: 'download_123', // Optional, business idempotency ID; SDK generates a UUID if not provided
})
// { freeRemaining: 4, isCredit: false, isBlacklisted: false } Free quota deducted
// { freeRemaining: 0, isCredit: true, isBlacklisted: false } Credits deducted
// { freeRemaining: 4, isCredit: false, isBlacklisted: true } Blacklisted user
// When isCredit=true, the SDK automatically calls credits.getBalance() to refresh the balanceReturn fields:
freeRemaining: current remaining free quotaisCredit: whether this call actually deducted creditsisBlacklisted: whether the user is blacklisted; when the backend returns status code20102, this field istrue. In this case, the SDK returns a structured result instead of throwing frombilling.consume()
Listen for Quota Changes
typescript
const unsubscribe = sdk.billing.onChange((usage) => {
renderBillingUI(usage)
})Free Period Mechanism
After a successful consume(), the next 30 seconds are considered a free period:
- Calling
consume()again during this time will not trigger a backend request and will return success immediately. - Useful for "free re-export within a short time" experience.
- Managed internally via
_freePeriodEndtimestamp; no need for developers to maintain timers.
typescript
function renderBilling(usage) {
if (usage.inFreePeriod) {
btn.textContent = `Free Re-export ${usage.freePeriodRemaining}s`
} else if (usage.freeRemaining > 0) {
btn.textContent = `Download (Free ${usage.freeRemaining}/${usage.freeTotal})`
} else {
btn.textContent = `Download (${usage.creditsPerUse} credits)`
}
}Free Period Countdown Implementation Example
javascript
let timer = null
sdk.billing.onChange((usage) => {
clearInterval(timer)
if (usage.inFreePeriod) {
timer = setInterval(() => {
const cached = sdk.billing.getCachedUsage()
if (cached) updateUI(cached)
if (!cached?.inFreePeriod) clearInterval(timer)
}, 1000)
}
})Backend Interface Mapping
| SDK Method | Backend Interface | Description |
|---|---|---|
getUsage() | GET /ai/v5/artimind/free_trial/count?module=generator_{appKey} | Query free quota |
getUsage() | GET /ai/v1/credit/getBalance | Parallel credits check (reuses credits) |
consume() | POST /ai/v5/artimind/free_trial | Backend automatically determines free/credits deduction |
The module parameter format is generator_{appKey}, which the backend uses to distinguish between different generator applications.