Skip to content

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

MethodReturn ValueDescription
sdk.billing.getUsage()Promise<UsageInfo>Get usage quota (network request)
sdk.billing.getCachedUsage()UsageInfo | nullGet cached quota (returns null before the first call)
sdk.billing.check()BillingCheckResultSynchronously 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)() => voidListen 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:

  1. GET /ai/v5/artimind/free_trial/count?module=generator_{appKey} → Free quota
  2. credits.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 credits

Consume 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 balance

Return fields:

  • freeRemaining: current remaining free quota
  • isCredit: whether this call actually deducted credits
  • isBlacklisted: whether the user is blacklisted; when the backend returns status code 20102, this field is true. In this case, the SDK returns a structured result instead of throwing from billing.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 _freePeriodEnd timestamp; 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 MethodBackend InterfaceDescription
getUsage()GET /ai/v5/artimind/free_trial/count?module=generator_{appKey}Query free quota
getUsage()GET /ai/v1/credit/getBalanceParallel credits check (reuses credits)
consume()POST /ai/v5/artimind/free_trialBackend automatically determines free/credits deduction

The module parameter format is generator_{appKey}, which the backend uses to distinguish between different generator applications.

MIT Licensed