51.1 Introduction
A production AI platform may eventually need paid subscriptions, usage-based billing, credits, invoices, refunds, promotional plans, organization billing, and payment-provider integrations.
Financial functionality introduces a different class of security requirements because billing data can affect:
- money;
- account privileges;
- subscription status;
- AI usage limits;
- credits;
- invoices;
- refunds;
- organizational budgets;
- payment-provider integrations.
The most important architectural principle is:
The application should not become the primary custodian of sensitive payment-card information unless there is a compelling business and compliance reason to do so.
Whenever possible, sensitive payment information should be handled by a specialized payment provider using appropriate secure integration patterns.
51.2 Billing Architecture
A high-level billing architecture can be:
User
|
AI Platform
|
Billing Service
|
Payment Provider
|
Payment Network
The AI application maintains its own business records such as:
- customer identity;
- subscription;
- plan;
- entitlement;
- usage;
- invoice references;
- payment-provider customer ID.
The payment provider handles payment processing.
51.3 Separation of Responsibilities
The billing system should separate several concepts:
Payment
Subscription
Plan
Entitlement
Usage
Credit
Invoice
Refund
Transaction
They are related but should not be treated as interchangeable.
For example:
A successful payment does not automatically mean that every application permission should be granted permanently.
Instead:
Payment Event
|
Validate
|
Update Billing State
|
Calculate Entitlements
|
Update Access
|
Audit
51.4 Plans
An AI platform may offer plans such as:
Free
Starter
Pro
Business
Enterprise
Each plan can define limits and features.
Example:
type Plan = {
id: string;
name: string;
monthlyPrice: number;
currency: string;
limits: {
imageGenerations: number;
videoGenerations: number;
storageBytes: number;
apiRequests: number;
};
};
The exact limits should be configurable rather than hard-coded throughout the application.
51.5 Entitlements
A subscription is not necessarily the same thing as an entitlement.
An entitlement answers:
What capabilities is this account currently allowed to use?
For example:
Subscription
|
+-- Pro
|
+-- Active
|
+-- Current Period
|
v
Entitlements
|
+-- HD Generation
+-- Increased Storage
+-- Higher API Limit
This separation makes the architecture more flexible.
51.6 Subscription State Machine
Subscription states should be explicit.
For example:
TRIAL
|
ACTIVE
|
PAST_DUE
|
CANCELED
|
EXPIRED
Other provider-specific states may also exist.
The application should not assume that every subscription transition happens synchronously during a user's browser request.
51.7 Payment Provider Integration
A secure integration typically looks like:
Client
|
| Request Checkout
v
Application
|
| Create Checkout Session
v
Payment Provider
|
| User Completes Payment
v
Payment Provider
|
| Webhook
v
Application
|
| Verify Event
v
Billing Database
The webhook is especially important.
The browser should not be treated as the final authority for payment success.
51.8 Why Client-Side Payment Success Is Not Enough
A malicious or malfunctioning client could potentially claim:
"Payment successful"
Therefore, application privileges should not be granted merely because the frontend reports success.
Instead:
Browser Result
|
v
Informational Only
|
Provider Event
|
Server Verification
|
Billing State
|
Entitlement
The trusted source should be the validated server-side payment-provider event.
51.9 Webhook Security
Payment webhooks are sensitive because they can modify billing state.
A webhook endpoint should implement:
- provider signature verification;
- timestamp/replay protection where supported;
- event validation;
- idempotency;
- strict schema validation;
- logging;
- appropriate rate limiting;
- safe error handling.
Conceptually:
Webhook
|
Parse
|
Verify Signature
|
Validate Event
|
Check Replay / Idempotency
|
Process
|
Record Event
Never process an unverified billing event as trusted input.
51.10 Idempotency
Payment systems frequently deliver events more than once.
For example:
EVENT_123
EVENT_123
EVENT_123
The application should safely recognize duplicate events.
A simple conceptual model:
type ProcessedBillingEvent = {
eventId: string;
receivedAt: Date;
processedAt?: Date;
status: "processed" | "failed";
};
Before processing an event:
Event ID
|
Already Processed?
|
+--+--+
| |
Yes No
| |
Stop Process
This prevents duplicate subscription changes, credit grants, or other unintended side effects.
51.11 Billing Database
A conceptual schema might contain:
customers
subscriptions
plans
entitlements
invoices
payments
refunds
usage_records
billing_events
credits
These should have clear relationships.
For example:
user
|
customer
|
subscription
|
plan
|
entitlements
And:
subscription
|
invoices
|
payments
|
refunds
51.12 Customer Mapping
The application should maintain a stable relationship between its internal identity and the payment provider's customer identity.
Example:
type BillingCustomer = {
userId: string;
providerCustomerId: string;
createdAt: Date;
};
This prevents the application from relying on user-controlled values to identify billing accounts.
51.13 Payment Records
Payment records should contain references rather than unnecessary sensitive payment details.
Example:
type PaymentRecord = {
id: string;
customerId: string;
providerPaymentId: string;
amount: number;
currency: string;
status: "pending" | "succeeded" | "failed" | "refunded";
createdAt: Date;
};
Avoid storing unnecessary card information.
51.14 Card Data Protection
A major security objective is to minimize the application's exposure to cardholder data.
Prefer architectures where:
Payment Card
|
v
Payment Provider
|
v
Provider Token / Reference
|
v
Application
The application generally needs to know the payment-provider reference and business status—not the full card number.
51.15 Never Store CVV
Sensitive authentication data such as card verification codes should not be stored by the application.
The correct architecture is to let the payment provider process payment authentication and card details.
51.16 Payment Tokens
Where supported, payment providers may issue tokens or payment-method identifiers.
These identifiers should still be treated as sensitive.
They should:
- remain server-controlled;
- never be exposed unnecessarily;
- be protected by authorization;
- be audited when used;
- be removed when no longer required.
51.17 Checkout Sessions
A secure checkout workflow may look like:
User
|
Select Plan
|
Server Validates Plan
|
Create Checkout Session
|
Provider Checkout
|
Payment
|
Provider Confirmation
|
Webhook
|
Update Subscription
The server should determine which plan the user is actually purchasing.
It should not blindly trust a price value sent by the browser.
51.18 Server-Side Price Validation
Suppose the client sends:
{
"plan": "pro",
"price": 1
}
The server should not simply accept the supplied price.
Instead:
Client Plan ID
|
Server Lookup
|
Trusted Plan Configuration
|
Provider Price ID
|
Checkout
The client can request a product or plan, but the trusted server configuration determines the actual commercial terms.
51.19 Subscription Changes
Subscription upgrades and downgrades should be handled through controlled server-side operations.
Example:
Current Plan
|
Change Request
|
Authorization
|
Validate Target Plan
|
Provider Update
|
Webhook Confirmation
|
Update Entitlement
The entitlement state should reflect the validated billing state.
51.20 Cancellation
Cancellation should be explicit.
Possible business rules include:
- cancel immediately;
- cancel at period end;
- pause subscription;
- downgrade after current period.
The application should store the actual cancellation state and effective date.
Example:
type Subscription = {
status: string;
currentPeriodEnd: Date;
cancelAtPeriodEnd: boolean;
};
51.21 Failed Payments
A failed payment should not necessarily immediately destroy the user's account.
A more robust lifecycle may be:
Payment Failure
|
Retry / Provider Recovery
|
Still Failed?
|
Past Due
|
Grace Period
|
Entitlement Reduction
Business rules should be explicit.
51.22 Credits and AI Usage
AI applications often use credits or usage quotas.
For example:
1 Image Generation = 1 Credit
1 HD Generation = 3 Credits
1 Video Generation = 10 Credits
The billing system should prevent race conditions when credits are consumed.
A conceptual transaction is:
Begin Transaction
|
Check Available Credits
|
Reserve / Deduct
|
Create Usage Record
|
Commit
51.23 Credit Ledger
Instead of storing only a mutable balance, a ledger can provide better auditability.
Example:
+100 purchase
-10 video
-1 image
+50 promotion
Then:
Current Balance = Sum(Ledger Entries)
A ledger provides a clearer history of why the balance changed.
51.24 Preventing Double-Spend of Credits
Concurrent requests can create problems.
Two generation requests might arrive simultaneously:
Balance = 5
Request A -> checks 5
Request B -> checks 5
Both consume 5
A safe system needs transactional concurrency control.
Conceptually:
Request
|
Atomic Reservation
|
Sufficient Balance?
|
+--+--+
| |
No Yes
| |
Reject Reserve
51.25 Usage Metering
AI platforms may need usage metering based on:
- tokens;
- images;
- video seconds;
- audio minutes;
- storage;
- API requests;
- compute time.
Usage records should contain enough information to support billing reconciliation.
Example:
type UsageRecord = {
userId: string;
resourceType: string;
quantity: number;
unit: string;
providerRequestId?: string;
timestamp: Date;
};
51.26 Usage Integrity
Usage should preferably be generated from trusted server-side events.
Avoid allowing the browser to simply claim:
"I used 0 tokens."
The AI gateway or backend service should produce authoritative usage records whenever possible.
51.27 AI Provider Cost Tracking
An AI platform may use multiple providers.
For example:
AI Gateway
|
+-- Provider A
|
+-- Provider B
|
+-- Local Model
|
+-- Provider C
Each inference request may have:
- provider;
- model;
- input usage;
- output usage;
- estimated cost;
- request ID.
This enables internal cost analysis.
51.28 Cost vs Customer Billing
Internal provider cost and customer billing price are different concepts.
For example:
Provider Cost: $0.01
Customer Charge: $0.05
The system should maintain separate accounting concepts rather than conflating them.
Provider Cost
Customer Revenue
Gross Margin
51.29 Refunds
Refund operations should be privileged.
A refund workflow may be:
Refund Request
|
Authorization
|
Validate Payment
|
Check Refund Policy
|
Provider Refund
|
Webhook / Confirmation
|
Update Record
|
Audit
Refund endpoints should not allow arbitrary user-controlled amounts.
51.30 Administrative Billing Controls
Administrative billing operations should require stronger authorization.
Examples:
- issuing refunds;
- changing plans;
- granting credits;
- modifying billing configuration;
- changing organization ownership.
A useful policy is:
Billing Admin
|
Billing Operations
|
Audit Required
Highly sensitive operations may require step-up authentication.
51.31 Promotional Credits
Promotional credits can be abused if implemented carelessly.
Controls should include:
- unique promotion identifiers;
- eligibility rules;
- expiration;
- redemption limits;
- organization/account restrictions;
- audit logging.
The server—not the client—should determine eligibility.
51.32 Coupons and Discounts
Discount systems should avoid accepting arbitrary values from the browser.
Instead:
Coupon Code
|
Server Validation
|
Eligibility Check
|
Trusted Discount Rule
|
Checkout
A client should never be allowed to specify:
{
"discount": 99
}
and have the server trust it.
51.33 Organization Billing
Business accounts introduce additional complexity.
Organization
|
Billing Owner
|
Subscription
|
Members
|
Usage
|
Invoices
The person who can use the AI platform does not necessarily need permission to manage billing.
This is another example of authentication and authorization being separate concerns.
51.34 Billing Authorization
Possible permissions include:
type BillingPermission =
| "billing:read"
| "billing:manage"
| "billing:refund"
| "billing:credits"
| "billing:invoices";
These permissions can be assigned to appropriate organizational roles.
51.35 Invoice Security
Invoices can contain sensitive business information.
Access should be controlled by authorization.
Users should not be able to change:
/invoices/123
to:
/invoices/124
and retrieve another customer's invoice.
Every invoice access should verify ownership or organizational authorization.
51.36 Object-Level Authorization
Billing resources require object-level authorization.
For example:
await requirePermission(
principal,
"billing:read",
invoice
);
The application should verify both:
- the user has the permission;
- the specific invoice belongs to an accessible account.
51.37 Financial Data Encryption
Sensitive financial records should receive appropriate protection.
Possible layers include:
TLS
|
Application Security
|
Database Access Control
|
Encryption at Rest
|
Key Management
Additional application-level encryption may be appropriate for especially sensitive fields.
51.38 Encryption Key Management
Encryption keys should not be hard-coded.
A secure architecture uses controlled key-management infrastructure.
Application
|
Key Management Service
|
Encryption Key
|
Protected Data
Key access should be restricted by service identity and least privilege.
51.39 Billing Audit Trail
Financial changes should be auditable.
Examples:
SUBSCRIPTION_CREATED
SUBSCRIPTION_CHANGED
SUBSCRIPTION_CANCELED
PAYMENT_SUCCEEDED
PAYMENT_FAILED
REFUND_CREATED
CREDIT_GRANTED
CREDIT_CONSUMED
INVOICE_CREATED
BILLING_ROLE_CHANGED
Audit events should contain enough information to reconstruct the business action without storing unnecessary sensitive data.
51.40 Reconciliation
A robust billing system should periodically compare:
Application Billing Database
|
vs
Payment Provider
Differences can occur because of:
- delayed webhooks;
- failed processing;
- network errors;
- duplicate events;
- operational mistakes.
Reconciliation helps detect inconsistencies.
51.41 Billing State as an Event-Driven System
A mature architecture may use events:
Payment Provider
|
Event
|
Billing Event Processor
|
+-----+-----+
| | |
DB Ledger Audit
|
Entitlements
This provides a clean separation between payment events and application permissions.
51.42 Event Ordering
Events may not always arrive in the expected order.
For example:
Subscription Updated
Payment Succeeded
Subscription Created
Therefore, event handlers should not blindly assume chronological arrival.
The system should use provider event metadata, current provider state where appropriate, and idempotent processing.
51.43 Billing Failure Recovery
If webhook processing fails:
Webhook
|
Processing Failure
|
Retry
|
Retry
|
Dead-Letter / Investigation
Failed billing events should not simply disappear.
Operational teams should have visibility into unresolved billing events.
51.44 Rate Limiting
Billing endpoints require rate limiting.
Especially sensitive endpoints include:
- checkout creation;
- coupon redemption;
- credit redemption;
- refund requests;
- payment-method changes.
Rate limiting reduces abuse and accidental overload.
51.45 Billing Threat Model
Important threats include:
Fake Payment Confirmation
Defense:
- server-side provider verification;
- signed webhooks.
Duplicate Webhook
Defense:
- idempotency.
Price Manipulation
Defense:
- server-side plan lookup.
Credit Manipulation
Defense:
- transactional ledger;
- server-side accounting.
Unauthorized Refund
Defense:
- privileged authorization;
- audit logging.
Invoice Data Exposure
Defense:
- object-level authorization.
Subscription Privilege Escalation
Defense:
- entitlement calculation from trusted billing state.
Webhook Replay
Defense:
- signature verification;
- replay protection;
- event ID tracking.
51.46 Secure Billing Service Interface
A conceptual interface could be:
interface BillingService {
createCheckout(userId: string, planId: string): Promise<CheckoutSession>;
getSubscription(userId: string): Promise<Subscription | null>;
changeSubscription(
userId: string,
planId: string
): Promise<Subscription>;
cancelSubscription(
userId: string
): Promise<Subscription>;
processWebhook(
payload: string,
signature: string
): Promise<void>;
getInvoices(userId: string): Promise<Invoice[]>;
getUsage(userId: string): Promise<UsageSummary>;
}
Implementation details should remain behind this boundary.
51.47 Example Webhook Processing
A conceptual server-side workflow:
async function handleBillingWebhook(
payload: string,
signature: string
) {
const event = verifyProviderEvent(
payload,
signature
);
if (await eventStore.exists(event.id)) {
return;
}
await billingProcessor.process(event);
await eventStore.markProcessed(event.id);
}
The actual signature verification mechanism must follow the payment provider's documented protocol.
51.48 Billing Security Architecture
A complete design can be represented as:
User
|
HTTPS
|
Web Application
|
Authentication
|
Authorization
|
Billing Service
|
+------------+------------+
| |
Billing Database Payment Provider
| |
Usage / Ledger Payment Network
|
Audit / Monitoring
The payment provider remains responsible for payment processing while the application maintains business-level billing state.
51.49 Production Billing Checklist
Before production:
- [ ] Payment processing is delegated appropriately.
- [ ] Sensitive card data is minimized.
- [ ] CVV is never stored.
- [ ] Provider webhooks are cryptographically verified.
- [ ] Webhooks are idempotent.
- [ ] Replay protection is implemented where appropriate.
- [ ] Prices are determined server-side.
- [ ] Subscription state is server-controlled.
- [ ] Entitlements derive from trusted billing state.
- [ ] Credits use transactional accounting.
- [ ] Usage is recorded server-side.
- [ ] Refunds require authorization.
- [ ] Billing permissions are separated from general permissions.
- [ ] Invoice access uses object-level authorization.
- [ ] Billing records are protected.
- [ ] Financial events are audited.
- [ ] Reconciliation procedures exist.
- [ ] Failed events can be retried.
- [ ] Billing endpoints are rate-limited.
- [ ] Secrets are stored securely.
- [ ] Payment-provider credentials can be rotated.
- [ ] Administrative billing actions receive stronger controls.
- [ ] Recovery procedures are documented.
- [ ] Billing state can be reconstructed after failure.
51.50 Final Architecture Principle
The secure billing model is:
Trusted Plan
|
Trusted Checkout
|
Trusted Payment Provider
|
Verified Event
|
Idempotent Billing Processing
|
Transactional Ledger
|
Entitlement Calculation
|
Authorized AI Access
|
Audit
The central principle is:
Never allow a client-controlled value to become the authoritative source of financial truth.
The browser can request an action.
The payment provider can process a payment.
But the backend must validate the event, maintain consistent billing state, calculate entitlements, enforce authorization, and preserve an auditable history.
This architecture provides a strong foundation for subscriptions, AI credits, usage-based billing, organizational accounts, invoices, refunds, and future financial functionality without unnecessarily exposing the core AI platform to sensitive payment data.
Top comments (0)