How billing works
Balance is checked up front, deducted only on a successful solve, and updated live in memory. No refunds, no race conditions.
How billing works
The billing model is deliberately simple: you pay for the solves that returned a result.
Lifecycle of a /solve call
- Pre-check — The server reads your live balance from the in-memory ledger and rejects with
402if it's below the per-call cost. - Solve — The request is routed to a backend worker.
- Outcome:
- Success (2xx). The cost is deducted after the response is flushed to your socket. The deduction is permanent and persisted to MySQL via an async writer.
- Failure (4xx/5xx). Nothing happens to your balance.
Because the deduction is post-success, there is no refund path to reason about. A request either changed the balance, or it didn't.
Live balance
/balance reads the in-memory ledger directly, not the database. That means:
- You see deductions reflected within milliseconds of a successful solve.
- The persisted DB value lags by up to a few seconds (the async writer batches updates) — but the in-memory value is authoritative.
- During a graceful shutdown the server flushes any pending deductions before exit.
Don't gate calls on /balance
The balance is stale the moment you read it. Use it for monitoring and pool sizing, not as a per-call gate. The server's pre-check is faster and accurate.
Concurrency safety
The in-memory ledger allows a small bounded overdraft — at most (concurrent in-flight) × (cost per solve). The pre-check is fast enough that the overdraft is generally negligible (well under $0.01 in practice).
That tradeoff buys you:
- No DB hit on the success path of a solve.
- No lock contention between concurrent solves on the same key.
Multiple keys
You can have multiple API keys per account, each with its own:
- Balance
- Allowed captcha types
- CPM ceiling
- IP allowlist
This is the recommended way to separate projects, teams, or environments — kill one key without affecting the others.
Low-balance notifications
If your account settings have lowBalanceAlert.enabled = true, the server fires an internal notification when:
- Your balance falls to zero (always notified, regardless of threshold).
- Your balance falls at or below your configured threshold (e.g. $5).
Notifications are cooldown-limited to one per 5 minutes per account, so a burst of solves won't spam you.
What's recorded
Every solve, whether successful or not, is logged with:
- API key ID
- User ID and email (for display in the dashboard)
- Captcha type (slug form, e.g.
cloudflare-turnstile) - Target URL
- Status (
success/failed) and any error message - Source IP
- Duration in milliseconds
- Cost (zero for failures)
These appear in the admin dashboard and feed your stats endpoints.