# How Billing and Credit Management Work in GPT-Image2: A Technical Deep Dive

> Explore GPT-Image2 billing and credit management. Learn how this technical deep dive details subscription and pay-as-you-go systems using Stripe, Alipay, Supabase, and PostgreSQL.

- Repository: [苍何/awesome-gpt-image-2](https://github.com/freestylefly/awesome-gpt-image-2)
- Tags: deep-dive
- Published: 2026-09-09

---

**TLDR:** GPT-Image2 uses a hybrid billing system that combines subscription-based memberships with pay-as-you-go credit packs, delegating all payment processing to Stripe and Alipay while storing credit balances in Supabase and updating them via atomic PostgreSQL stored procedures.

GPT-Image2 implements a robust billing engine to handle both recurring subscriptions and one-time credit purchases. The architecture, found in the `freestylefly/awesome-gpt-image-2` repository, separates product catalog management from payment processing, using Stripe for subscription lifecycle management and Alipay for regional credit pack sales, with all credit ledger operations enforced at the database level.

## Product Catalog and Pricing Structure

The system maintains a dynamic product catalog fetched directly from Supabase. In [`api/_lib/billing.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/billing.js), the `getBillingCatalog()` function retrieves active products from two distinct tables: `membership_plans` for recurring subscriptions and `credit_packs` for one-time purchases.

This function formats each row with presentation fields such as `priceLabel`, `currency`, and `credits`, enabling the frontend to render pricing tiers without hardcoding values. For memberships, the catalog also exposes `monthly_credits`, which determines how many generations a subscriber receives per billing cycle.

## Checkout Flow and Session Management

When a user initiates a purchase, the request hits [`api/billing/checkout.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/billing/checkout.js). This handler validates the incoming payload and normalizes the `productType` to either `membership` or `credit_pack`.

The checkout flow executes several sequential operations:

1.  **Product Validation** – Calls `getBillingProduct()` to verify the selected item exists and is active.
2.  **Customer Management** – Invokes `getOrCreateStripeCustomer()` to ensure a Stripe customer record exists for the user.
3.  **Order Creation** – Uses `createPaymentOrder()` to record the intended purchase (credits or plan type) in the database before payment occurs.
4.  **Session Generation** – Builds a Stripe Checkout session via `checkoutLineItem()` and returns the redirect URL to the client.

```javascript
// Initiating a credit pack purchase
await fetch('/api/billing/checkout', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ 
    productType: 'credit_pack', 
    productId: 'pack_001' 
  })
});
// Returns: { url: 'https://checkout.stripe.com/...', orderId, user }

```

## Payment Provider Integration: Stripe and Alipay

GPT-Image2 supports multiple payment backends. **Stripe** serves as the default provider, configured via the `STRIPE_SECRET_KEY` environment variable and instantiated in [`api/_lib/billing.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/billing.js).

For markets requiring **Alipay**, the system uses specialized stored procedures defined in [`supabase/migrations/20260721090000_alipay_webpay.sql`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/supabase/migrations/20260721090000_alipay_webpay.sql). These PostgreSQL functions handle order completion, refunds, and balance updates for credit pack purchases, ensuring Alipay transactions follow the same atomic guarantees as Stripe webhooks.

## Webhook Processing and Credit Fulfillment

Payment confirmation occurs asynchronously via webhooks. The endpoint in [`api/billing/webhook.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/billing/webhook.js) listens for Stripe events including `checkout.session.completed` and `invoice.paid`.

When a payment succeeds, the handler:

-   Marks the corresponding payment order as paid in the database.
-   For **memberships**: Grants the user a monthly allotment defined by the `monthly_credits` field in their subscription plan.
-   For **credit packs**: Increments the user's `credit_balance` field by the purchased amount.

```javascript
// Inside api/billing/webhook.js
if (event.type === 'checkout.session.completed') {
  await handleCheckoutCompleted(client, stripe, event.data.object);
}

```

## Credit Balance Storage and Consumption

All credit accounting resides in Supabase. The migration file [`supabase/migrations/20260509090000_membership_billing.sql`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/supabase/migrations/20260509090000_membership_billing.sql) defines the `credit_balance` integer field on the `profiles` table and implements PostgreSQL functions for atomic updates.

When the image generation pipeline processes a request (via [`api/generation/callback.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generation/callback.js)), it checks the caller's `credit_balance`. For paid generations, the system calls a stored procedure—typically via `client.rpc('deduct_credit', { user_id: userId, amount: 1 })`—which atomically decrements the balance (`set credit_balance = p.credit_balance - 1`) only if sufficient credits exist.

Free-tier users bypass the credit balance entirely; the system tracks their usage via the `free_generations_used` counter instead.

```javascript
// Atomic credit deduction during image generation
await client.rpc('deduct_credit', {
  user_id: userId,
  amount: 1
});

```

## Admin Monitoring and Metrics

Administrators can monitor the billing ecosystem through dedicated endpoints. [`api/admin/users.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/admin/users.js) exposes individual credit balances, while [`api/admin/metrics.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/admin/metrics.js) aggregates system-wide statistics including total credit balance, generated credits, purchased credits, and membership grants. These metrics derive from the same Supabase tables and aggregation queries defined in the admin metrics migrations ([`supabase/migrations/20260513095141_admin_metrics_charts.sql`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/supabase/migrations/20260513095141_admin_metrics_charts.sql)).

## Summary

-   **Hybrid Model**: GPT-Image2 supports both recurring memberships (`membership_plans`) and one-time credit packs (`credit_packs`).
-   **Payment Orchestration**: Stripe handles subscriptions and general payments; Alipay is supported for credit packs via dedicated stored procedures.
-   **Atomic Ledger**: All credit adjustments occur through PostgreSQL stored procedures in [`supabase/migrations/20260509090000_membership_billing.sql`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/supabase/migrations/20260509090000_membership_billing.sql), ensuring consistent balance updates.
-   **Webhook Fulfillment**: The [`api/billing/webhook.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/billing/webhook.js) endpoint converts Stripe payment events into credit grants or subscription activations.
-   **Consumption Logic**: Generation endpoints check `credit_balance` before processing, deducting credits atomically for paid requests while tracking `free_generations_used` for free tiers.

## Frequently Asked Questions

### How does GPT-Image2 handle different payment methods?

The system primarily uses Stripe for credit card and subscription billing, configured in [`api/_lib/billing.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/billing.js) using the `STRIPE_SECRET_KEY` environment variable. For Alipay support, the repository includes specific migrations in [`supabase/migrations/20260721090000_alipay_webpay.sql`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/supabase/migrations/20260721090000_alipay_webpay.sql) that implement server-side logic for order completion and refunds, allowing Asian markets to purchase credit packs through local payment rails.

### What happens when a user's credit balance runs out?

When [`api/generation/callback.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generation/callback.js) processes a request, it verifies the user's `credit_balance` via the Supabase client. If the balance is insufficient for a paid generation, the stored procedure `deduct_credit` (or equivalent) will fail the atomic check, and the API returns an error indicating insufficient credits. The user must then purchase a credit pack or upgrade to a membership plan via [`api/billing/checkout.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/billing/checkout.js) to continue.

### How are subscription renewals processed?

Stripe manages the subscription lifecycle through recurring billing events. When Stripe sends an `invoice.paid` webhook to [`api/billing/webhook.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/billing/webhook.js), the handler identifies the active membership and applies the `monthly_credits` allotment defined in the `membership_plans` table to the user's profile. This occurs automatically each billing cycle without requiring manual intervention.

### Where is the credit balance stored and updated?

The `credit_balance` field resides in the `profiles` table within Supabase, defined by [`supabase/migrations/20260509090000_membership_billing.sql`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/supabase/migrations/20260509090000_membership_billing.sql). Updates happen exclusively through PostgreSQL stored procedures (such as those for Alipay fulfillment or credit deduction), ensuring atomic operations. The API layer reads this value via the Supabase client in [`api/_lib/supabase.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/supabase.js) but never performs direct SQL updates to prevent race conditions.