Billing Overview
The AIQLick billing system spans two services that share a single PostgreSQL database. The backend (NestJS) owns plan management, Stripe integration, and credit allocation. The background-tasks service (FastAPI) enforces billing rules before executing AI operations and records consumption.
Architecture
Backend Responsibilities
- Plans and subscriptions -- defining subscription tiers and syncing state with Stripe.
- Credit packs -- purchasable credit bundles processed through Stripe Checkout.
- Stripe webhooks -- handling
invoice.paid,invoice.payment_failed,charge.refunded, andcheckout.session.completedevents. - Invoices -- generating and tracking invoice records tied to Stripe payment intents.
- Promo codes -- percentage or fixed-amount discounts, invitation-based codes, and reseller bundles.
- Credit replenishment -- a daily cron job at 2 AM that tops up credits on a 30-day cycle.
Background-Tasks Responsibilities
- BillingGate -- the enforcement layer that runs before every billable AI operation.
pre_check()-- verifies billing context, resolves billing mode, checks subscription status, plan limits, and credit balance.- The AI pipeline executes.
check_and_consume()-- deducts credits (PREPAID) or logs usage (POSTPAID) and writes anAIOperationLogentry.log_failure()/log_rejected()-- records failed or rejected operations for audit trail.
- Gradual rollout -- billing enforcement is controlled by the
BILLING_ENABLEDenvironment variable, allowing incremental activation across environments.
Both services read and write the same PostgreSQL database. Schema changes are managed exclusively through Prisma in the backend; background-tasks uses raw AsyncPG queries.
Billing Enforcement Status
Complete status of billing integration across all pipeline operations:
| Operation | External Service | Billable | pre_check | check_and_consume | Notes |
|---|---|---|---|---|---|
| CV Extraction | Claude Sonnet 4.5 | Yes | Yes | Yes | Reference implementation |
| Job Parsing | Claude Sonnet 4.5 | Yes | Yes | Yes | |
| Meeting Insight | Claude Haiku 4.5 | Yes | Yes | Yes | |
| Text Rewrite | Claude Haiku 4.5 | Yes | Yes | Yes | |
| Agent Chat | Amazon Nova Lite | Yes | Yes | Yes | |
| Face Extraction | AWS Rekognition | Yes | Yes | Yes | |
| User-Job Matching | None (internal scoring) | No | -- | -- | CPU-only, no external AI calls |
| Candidate-Job Matching | None (internal scoring) | No | -- | -- | CPU-only, no external AI calls |
| Basic Matching | None (internal scoring) | No | -- | -- | CPU-only, no external AI calls |
| Add Candidate | None (CPU-only pipeline) | No | -- | -- | Validation + DB operations only |
| Inbound Job Email | Claude Sonnet 4.5 | Yes | Yes | Via JobParsingService | Worker runs pre_check, billing via underlying service |
| Inbound CV Email | Claude Sonnet 4.5 | Yes | Yes | Via CVExtractionService | Worker runs pre_check, billing via underlying service |
| Transcription | AWS Transcribe | No | -- | -- | Managed AWS service, billed via AWS directly |
| Task/Metrics Subscriptions | None | No | -- | -- | System monitoring, not billable |
Gradual Rollout (BILLING_ENABLED)
The BILLING_ENABLED environment variable controls billing enforcement for PREPAID plans:
BILLING_ENABLED | PREPAID Behavior | POSTPAID Behavior |
|---|---|---|
false (default) | Operations logged with credits_cost=0 but not charged. Pre-checks pass. | Operations always logged to AIOperationLog (source of truth for invoicing). UNPAID blocking still enforced. |
true | Full enforcement: pre-check validates subscription + limits + balance. Credits deducted after execution. | Same as above -- POSTPAID always logs regardless of flag. |
Enterprise (POSTPAID) blocking is always enforced, even when BILLING_ENABLED=false. This prevents blocked companies from bypassing access control via the feature flag.
Credit Routing
Credits are routed based on the user's current view mode and company context:
| Mode | Condition | Balance Used |
|---|---|---|
| EMPLOYER | selectedCompanyId is set | Company credit balance |
| JOB_SEEKER | No company context | User's personal credit balance |
This routing applies to both consumption (background-tasks) and balance queries (backend).
Plans
Plans define subscription tiers with the following properties:
- 16 feature limits -- each field uses a consistent convention:
-1means unlimited,0means disabled, and any positive integer is the specific limit. creditsPerMonth-- the number of credits allocated on each billing cycle.- Stripe sync -- each plan maps to a Stripe Product and Price for recurring billing.
Plans are company-scoped. When a company subscribes to a plan, all users operating under that company inherit its limits.
Subscriptions
Subscriptions are company-based, not per-user. Key characteristics:
- Tied to a single
Companyentity in the database. - Status is synchronized with Stripe (
ACTIVE,PAST_DUE,CANCELED,TRIALING,INCOMPLETE). - Expiry warnings are sent at 7, 3, and 1 days before expiration via a daily cron job at 9 AM.
Credit Balance
Each credit balance record is scoped to either a company or a user, enforced by a database-level XOR constraint -- a balance row must have exactly one of companyId or userId set, never both.
| Scope | Use Case |
|---|---|
| Company balance | Employer-mode AI operations, team-shared credits |
| User balance | Job seeker AI operations, personal credit packs |
Credit Transactions
Every credit movement is recorded as an immutable CreditTransaction with one of the following types:
| Type | Description |
|---|---|
PLAN_ALLOCATION | Monthly credit top-up from the active subscription plan |
PACK_PURCHASE | One-time credit pack bought through Stripe Checkout |
CONSUMPTION | Credits deducted when an AI operation completes |
MANUAL_ADJUSTMENT | Admin-initiated balance correction |
INITIAL_GRANT | Credits granted on account creation (9 credits by default for job seekers) |
REFUND | Credits returned after a Stripe refund event |
TRANSFER | Credits moved between balances — personal↔company or company↔company — via transferCredits |
Credit Packs
Credit packs are purchasable bundles that provide a one-time credit deposit. Key rules:
- Purchased through Stripe Checkout sessions.
- Credits always land in the purchasing user's personal balance, regardless of their current company context.
- To fund a company balance, the billing owner uses the
transferCreditsmutation to move credits from their personal balance (or another company they billing-own) to the target company. Transfers run in both directions: personal↔company and company↔company. See Credit Transfers for the full matrix.
Stripe Integration
The backend processes four Stripe webhook events:
| Event | Action |
|---|---|
invoice.paid | Allocate plan credits, activate or renew subscription |
invoice.payment_failed | Mark subscription as past due, notify billing owner |
charge.refunded | Credit the refunded amount back to the appropriate balance |
checkout.session.completed | Fulfill credit pack purchase, apply promo code if present |
All webhook handlers are idempotent -- duplicate event deliveries do not produce duplicate transactions.
Promo Codes
Promo codes support three distribution models:
- Percentage discount -- reduces the price of a subscription or credit pack by a percentage.
- Fixed amount -- subtracts a fixed dollar amount from the purchase price.
- Invitation and reseller bundles -- codes tied to referral campaigns or reseller agreements that grant bonus credits or extended trials.
Credit Replenishment
A scheduled cron job runs daily at 2 AM and processes credit replenishment for all active subscriptions:
- Checks each subscription's 30-day billing cycle.
- Allocates
creditsPerMonthfrom the plan as aPLAN_ALLOCATIONtransaction. - Credits are additive, not reset -- unused credits from previous cycles carry forward.
Enterprise Post-Paid Billing
For enterprise customers, the platform supports a post-paid billing model where companies receive unlimited platform access without upfront payment. Instead of purchasing credits, enterprise companies are invoiced monthly based on actual AI usage.
Key differences from prepaid:
- Plans with
billingMode: POSTPAIDbypass all credit checks in theBillingGate. - AI operations are still logged to
AIOperationLog(source of truth for invoice generation) but no credits are deducted. - A monthly cron job generates Stripe invoices based on aggregated usage, with a 5-day payment window.
- Overdue invoices trigger automatic access blocking (
UNPAIDsubscription status). - Admin API provides full subscription, usage breakdown, and invoice management.
See Enterprise Post-Paid Billing for full details.
Job Seeker Initial Credits
New job seeker accounts receive an INITIAL_GRANT of 9 credits by default. This value is configurable and allows job seekers to use AI features before purchasing a credit pack.