How Alipay Web Payment Works with Stripe Webhooks in Awesome-GPT-Image-2
The Awesome-GPT-Image-2 backend processes Stripe subscriptions via webhooks while handling Alipay one-off purchases through a separate notify/query flow, both converging on shared credit-granting utilities to ensure idempotent order completion.
This open-source project implements a dual-channel payment architecture that separates subscription management from single-purchase handling. While Stripe webhooks manage recurring membership billing, Alipay web payment facilitates one-time credit pack purchases for Chinese users, with both systems storing orders in a unified payment_orders table and delegating credit allocation to common backend helpers.
Dual-Channel Payment Architecture
The repository maintains two parallel integration paths that never intersect during transaction processing but share post-payment business logic. According to the source code, Stripe handles subscription lifecycles through asynchronous events, while Alipay manages immediate payment confirmations for credit packs via server-to-server notifications.
The architectural separation is enforced at the database layer. The migration file supabase/migrations/20260721090000_alipay_webpay.sql adds provider-specific columns (alipay_amount_cents, alipay_trade_no) to the payment_orders table, allowing the same table to track both Stripe subscriptions and Alipay one-off purchases without confusion.
Alipay Web Payment Flow
Alipay integration follows the classic "create-pay-notify" pattern, implemented across dedicated endpoints under api/billing/alipay/.
Checkout Endpoint
The POST /api/billing/alipay/checkout handler in api/billing/alipay/checkout.js initiates the payment flow. It retrieves the Alipay SDK client from api/_lib/alipay.js and constructs a signed request using the alipay.trade.page.pay method.
// api/billing/alipay/checkout.js
import { getAlipayClient } from '../../_lib/alipay.js';
import { createPaymentOrder } from '../../_lib/billing.js';
export default async function handler(req, res) {
const { packId, userId } = req.body;
const product = await getCreditPack(packId);
if (!product.alipayAvailable) return res.status(400).json({ error: 'ALIPAY_NOT_AVAILABLE' });
const client = getAlipayClient();
const request = {
method: 'alipay.trade.page.pay',
biz_content: {
out_trade_no: generateOrderId(),
total_amount: (product.alipayAmountCents / 100).toFixed(2),
subject: product.name,
product_code: 'FAST_INSTANT_TRADE_PAY',
quit_url: `${appUrl}/billing/alipay/cancel`,
return_url: `${appUrl}/?billing=alipay_return&order_id=${order.id}`
}
};
const paymentHtml = client.pageExec(request.method, 'POST', request);
res.setHeader('Content-Type', 'text/html');
res.send(paymentHtml);
}
The pageExec method generates an auto-submitting HTML form that redirects the user to Alipay's gateway. The SDK automatically handles signature generation using the private key configured via environment variables (ALIPAY_APP_ID, ALIPAY_PRIVATE_KEY).
Asynchronous Notification Handling
After the user completes payment, Alipay's servers call POST /api/billing/alipay/notify as documented in api/billing/alipay/notify.js. This handler validates the cryptographic signature using client.checkNotifySign() before processing the order.
// api/billing/alipay/notify.js
import { getAlipayClient } from '../../_lib/alipay.js';
import { finalizeAlipayCreditPackOrder } from '../../_lib/billing.js';
export default async function handler(req, res) {
const client = getAlipayClient();
const { body } = req;
if (!client.checkNotifySign(body)) {
return res.status(400).json({ error: 'INVALID_SIGNATURE' });
}
const result = await client.exec('alipay.trade.notify', body);
await finalizeAlipayCreditPackOrder(supabaseClient, result);
res.json({ ok: true });
}
The finalizeAlipayCreditPackOrder function implements idempotency by checking the order status before granting credits, ensuring that duplicate notifications from Alipay do not result in multiple credit allocations.
Polling Fallback for Restricted Environments
When the server cannot expose a public notify_url, the client can poll GET /api/billing/alipay/query implemented in api/billing/alipay/query.js. This endpoint queries Alipay's trade status API and triggers the same completion logic as the notify handler, providing a fallback for local or firewalled deployments.
Stripe Webhook Integration
Unlike Alipay's synchronous payment page flow, Stripe handles recurring subscriptions through asynchronous webhooks. The POST /api/billing/webhook endpoint in api/billing/webhook.js processes events including checkout.session.completed and invoice.payment_succeeded.
// api/billing/webhook.js
import { completeCreditPackOrder, grantMembershipCredits } from '../_lib/billing.js';
export default async function handler(req, res) {
const signature = req.headers['stripe-signature'];
const rawBody = await readRawBody(req);
const event = getStripeClient().webhooks.constructEvent(
rawBody, signature, process.env.STRIPE_WEBHOOK_SECRET
);
if (event.type === 'checkout.session.completed') {
const session = event.data.object;
await completeCreditPackOrder(supabaseClient, session);
}
// Subscription renewals handled via grantMembershipCredits
}
The webhook handler constructs the event using constructEvent to verify the signature against STRIPE_WEBHOOK_SECRET, then routes to either completeCreditPackOrder for one-time purchases or grantMembershipCredits for subscription renewals.
Unified Credit Granting Layer
Both payment channels converge on shared utilities defined in api/_lib/billing.js. The completeCreditPackOrder function grants credits idempotently using the order's unique identifier, while grantMembershipCredits handles recurring subscription entitlements.
This unification ensures that whether a user pays via Stripe webhook or Alipay notification, the system executes the same validation logic:
- Verify the order exists and is in
pendingstatus - Record the payment provider (
stripeoralipay) - Atomically increment user credits
- Mark order as
completed
The api/billing/plans.js file enforces the business rule that Alipay only appears for credit packs (not subscriptions) by checking alipay_amount_cents > 0, preventing users from attempting to start recurring subscriptions through the Alipay channel.
Summary
- Stripe webhooks process recurring subscriptions through
api/billing/webhook.js, verifying signatures withconstructEventand callinggrantMembershipCreditsfor renewals. - Alipay web payments use
api/billing/alipay/checkout.jsto create orders,api/billing/alipay/notify.jsto validate signatures viacheckNotifySign, andapi/billing/alipay/query.jsfor polling fallbacks. - Shared completion logic in
api/_lib/billing.jsensures idempotent credit granting viacompleteCreditPackOrder, regardless of payment provider. - Database separation via
alipay_*columns in thepayment_orderstable prevents confusion between one-off Alipay purchases and Stripe subscriptions.
Frequently Asked Questions
How does the system prevent duplicate credit grants from Alipay notifications?
The finalizeAlipayCreditPackOrder function in api/_lib/billing.js checks the order status before granting credits. Since the order is marked completed atomically with the credit grant, subsequent Alipay notifications for the same out_trade_no find the order already fulfilled and exit without modifying the user's balance.
Can users purchase subscriptions through Alipay instead of Stripe?
No. The api/billing/plans.js logic only exposes Alipay checkout when alipay_amount_cents is defined for a credit pack. Subscriptions require Stripe's recurring billing infrastructure, so the system deliberately restricts Alipay to one-off purchases to avoid confusion between Alipay's immediate payment flow and Stripe's subscription lifecycle management.
What happens if the Alipay notify URL is unreachable?
The system provides a polling mechanism via GET /api/billing/alipay/query in api/billing/alipay/query.js. When the notify endpoint is inaccessible due to firewall restrictions or local development environments, the client can call this endpoint to query Alipay's trade status and trigger the same completion workflow that the notify handler would execute.
How are payment signatures validated differently between Stripe and Alipay?
Stripe uses stripe.webhooks.constructEvent() with a webhook secret to verify payload integrity in api/billing/webhook.js, while Alipay uses RSA signature verification through client.checkNotifySign() in api/billing/alipay/notify.js. The Alipay SDK (api/_lib/alipay.js) handles the cryptographic validation against the Alipay public key, whereas Stripe handles verification internally within their Node.js library.
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 →