How the Membership Billing System Handles Stripe Subscription Dates in awesome-gpt-image-2
The membership billing system captures Stripe subscription dates by listening to webhook events, converting Unix timestamps to ISO-8601 strings via a utility function, and persisting them to a Supabase database table.
The freestylefly/awesome-gpt-image-2 repository implements a complete membership billing workflow that synchronizes Stripe subscription periods with an internal database. By converting Stripe's Unix timestamps into standardized ISO date strings, the system ensures accurate tracking of billing cycles across webhook events and customer portal interactions.
Webhook Event Processing for Date Synchronization
The primary mechanism for capturing subscription dates resides in api/billing/webhook.js, which listens for Stripe lifecycle events. When Stripe triggers checkout.session.completed or invoice.paid events, the system retrieves full subscription details and extracts period boundaries.
Processing Checkout Session Completion
Upon receiving a checkout completion event, the handler retrieves the subscription object using the Stripe SDK, then extracts the current_period_start and current_period_end timestamps. According to the awesome-gpt-image-2 source code, the implementation follows this pattern:
// api/billing/webhook.js
const subscription = await stripe.subscriptions.retrieve(subscriptionId);
// Convert Stripe Unix timestamps to ISO strings
const isoStart = stripeTimestampToIso(subscription.current_period_start);
const isoEnd = stripeTimestampToIso(subscription.current_period_end);
// Persist to Supabase membership table
await supabaseClient
.from('membership')
.update({
stripe_subscription_id: subscription.id,
current_period_start: isoStart,
current_period_end: isoEnd,
status: subscription.status
})
.eq('stripe_session_id', session.id);
Handling Invoice Payment Events
For recurring billing cycles, the invoice.paid webhook triggers similar date extraction logic. The system updates the existing membership record with new period boundaries when Stripe processes automatic renewals, ensuring the database always reflects the active subscription window.
Unix Timestamp Conversion Utility
Before database storage, all Stripe timestamps undergo transformation through the stripeTimestampToIso helper function located in api/_lib/billing.js. This utility standardizes date formats by converting Stripe's Unix seconds-based timestamps into JavaScript Date objects and emitting ISO-8601 strings:
// api/_lib/billing.js
export function stripeTimestampToIso(value) {
return new Date(value * 1000).toISOString();
}
This conversion is critical because Stripe returns timestamps in seconds, while Supabase and frontend applications expect millisecond-precision ISO strings for proper date arithmetic and display formatting.
Database Schema and Storage Format
The subscription dates are stored in the membership table defined in the Supabase migration files. The schema utilizes text columns to store the ISO-8601 formatted date strings, allowing the system to track both the start and end of the current billing period:
-- supabase/migrations/20260509090000_membership_billing.sql (schema excerpt)
create table membership (
user_id uuid references auth.users not null,
stripe_subscription_id text,
stripe_customer_id text,
current_period_start text,
current_period_end text,
status text,
primary key (user_id)
);
By storing these values as ISO strings rather than Unix timestamps, the system enables direct compatibility with JavaScript Date parsing and human-readable querying without additional conversion overhead.
Customer Lifecycle and Portal Integration
The billing system ensures date consistency throughout the customer lifecycle through the getOrCreateStripeCustomer function in api/_lib/billing.js. When initiating checkout sessions via api/billing/checkout.js, the system first establishes or retrieves the Stripe customer record, then correlates the subsequent subscription dates with the correct user profile.
For existing subscribers, api/billing/portal.js reads the stored current_period_start and current_period_end values directly from the Supabase membership table when generating customer portal links. This allows the frontend to display accurate billing cycle information without querying Stripe's API on every page load, reducing latency and API quota consumption.
Summary
- Webhook-driven updates: The system listens to
checkout.session.completedandinvoice.paidevents inapi/billing/webhook.jsto capture subscription date changes. - Timestamp conversion: The
stripeTimestampToIsofunction inapi/_lib/billing.jstransforms Stripe's Unix timestamps into ISO-8601 strings by multiplying seconds by 1000. - Database persistence: Subscription periods are stored as ISO strings in the
membershiptable columnscurrent_period_startandcurrent_period_end. - Lifecycle integration: Customer creation in
api/_lib/billing.jsand portal generation inapi/billing/portal.jsboth rely on these stored dates to provide consistent billing cycle visibility.
Frequently Asked Questions
How does the system convert Stripe's Unix timestamps to usable dates?
The system uses the stripeTimestampToIso utility function located in api/_lib/billing.js. This function multiplies the Stripe timestamp (provided in seconds) by 1000 to convert it to milliseconds, then generates an ISO-8601 formatted string using JavaScript's Date object and toISOString() method.
What database columns store the subscription period information?
According to the migration schema in supabase/migrations/20260509090000_membership_billing.sql, the membership table contains two text columns named current_period_start and current_period_end. These columns store ISO-8601 date strings representing the active subscription window.
Which Stripe webhook events trigger date updates?
The system processes subscription dates primarily through two webhook events handled in api/billing/webhook.js: checkout.session.completed for initial subscriptions and invoice.paid for recurring billing cycles. Both events trigger calls to stripe.subscriptions.retrieve() followed by timestamp conversion and database updates.
How does the customer portal utilize stored subscription dates?
The billing portal endpoint in api/billing/portal.js queries the Supabase membership table to retrieve the stored current_period_start and current_period_end values. This allows the application to display accurate subscription timing to users without making additional API calls to Stripe, improving performance and reliability.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →