Skip to main content
Creem is the right pick if you sell to mainland China. Stripe / Paddle / Lemon Squeezy can’t accept Alipay or WeChat Pay at scale; Creem can. The API surface is intentionally Stripe-like, so the integration in vibestrap mirrors the Stripe provider almost line-for-line — just swap the SDK and env vars. Pick Creem if your buyers are in China (or you want to expand a Western product into China without a separate codebase).

Prerequisites

  • A Creem account (creem.io). To go live you need a Chinese business entity (营业执照) and KYC. Sandbox / test mode works without it.
  • A merchant account on Alipay and/or WeChat Pay, linked to your Creem account. Creem walks you through the binding flow during onboarding.
  • Postgres up, schema pushed.

1. Set the active provider

In src/config/site.ts:
payment: {
  provider: 'creem' as 'stripe' | 'paddle' | 'lemonsqueezy' | 'creem',
  currency: 'usd', // or 'cny' — see pitfalls below
},
For Alipay / WeChat Pay you almost always want currency: 'cny' since those rails are CNY-native. Mixing other currencies forces a forex layer.

2. Create products in Creem

In the Creem dashboard, Products → New product. Each product has an ID that you’ll pass as the priceId to checkout. Creem doesn’t separate “products” and “prices” the way Stripe does — one product = one price. For the vibestrap scaffold itself, create a promo product and a standard product.

3. Set env vars

In .env.local (variable names match src/env.ts):
CREEM_API_KEY=creem_sk_...
CREEM_WEBHOOK_SECRET=your-signing-secret

# vibestrap product IDs
CREEM_PRICE_VIBESTRAP_PROMO=prod_...
CREEM_PRICE_VIBESTRAP_STANDARD=prod_...
CREEM_PRICE_* is named PRICE for symmetry with the other providers but holds a Creem product ID under the hood.

4. Configure the webhook

In the Creem dashboard, Developers → Webhooks → New endpoint:
  • URL: https://your-domain.com/api/webhooks/creem
  • Events (minimum): checkout.completed, payment.succeeded, subscription.created, subscription.updated, subscription.canceled.
  • Signing secret: pick any random string and paste it here AND into CREEM_WEBHOOK_SECRET in your env. Creem signs the raw body with HMAC-SHA256.
For local testing, expose localhost:3000 via cloudflared or frpc (cloudflared is faster from China than ngrok).

Verify it works

  1. Use Creem’s test mode (toggle in dashboard).
  2. pnpm dev, open /pricing, click checkout — Creem’s hosted page opens.
  3. Pay with the test method shown by Creem (sandbox Alipay or WeChat).
  4. Watch the webhook arrive (terminal logs).
  5. Check the database:
    select id, provider, scene, status, amount, currency from payment
    where provider = 'creem'
    order by created_at desc limit 1;
    

Common pitfalls

  • KYC required for production — Creem requires a Chinese business entity
    • ICP filing for live merchant accounts. Sandbox mode works without it, but production launches need to complete KYC first. Plan a few weeks of lead time.
  • Currency must be CNY for Alipay / WeChat — Alipay and WeChat Pay are CNY-native rails. If you set currency: 'usd' and use those methods, Creem will either refuse the payment or apply forex with a markup. Set siteConfig.payment.currency = 'cny' and price in fen (1 yuan = 100 fen) just like cents.
  • No customer portal return URLcreem.customers.generateBillingLinks doesn’t accept a returnUrl. Customers navigate back via your app chrome.
  • Webhook secret is whatever you typed — like Lemon Squeezy, Creem doesn’t generate the signing secret. Use openssl rand -hex 32.
  • Network egress from Western infra — if you deploy on Vercel / Cloudflare with the customer in China, payment redirects work but admin pages calling creem.checkouts.create from a Western edge can be slow. Consider an Asia region for these specific routes.

Official docs