Payments

env.PAYMENTS lets your app charge its own customers through Stripe — one-off payments, subscriptions, a hosted customer portal, and signature-verified webhooks. It's a thin, ready-wired Stripe client; you supply your Stripe keys and it handles the calls.

This is for billing your app's users. It's separate from how Cloudrizz bills you for your plan (see pricing).

Setup: your Stripe keys

Set these as app environment variables (via set_app_env):

  • STRIPE_SECRET_KEY — required for all calls. (A STRIPE_SECRET_KEY_TEST is used automatically on non-production deploys if set.)
  • STRIPE_WEBHOOK_SECRET — required only if you verify webhooks.

Checkout

Create a Checkout session and redirect the user to session.url:

// api/checkout.js
export default {
  async fetch(request, env, ctx) {
    const user = await env.AUTH.getUser(request);
    if (!user) return new Response("Unauthorized", { status: 401 });

    const session = await env.PAYMENTS.checkout.create({
      mode: "subscription",
      line_items: [{ price: "price_123", quantity: 1 }],
      success_url: "https://your-app.com/success",
      cancel_url: "https://your-app.com/pricing",
      customer_email: user.email,
    });

    return Response.json({ url: session.url });
  },
};

Subscriptions & access checks

There's no separate entitlement store — check access by reading the customer's subscriptions:

const subs = await env.PAYMENTS.subscriptions.list({ customer: customerId });
const hasAccess = subs.data?.some((s) => s.status === "active");

Also available:

  • customers.create / retrieve / update
  • subscriptions.list / retrieve / cancel
  • paymentIntents.create / retrieve
  • portal.create({ customer, return_url }) — a hosted billing portal URL.

Webhooks

Add a route for Stripe events and verify the signature — verification throws on a bad signature or replay:

// api/webhooks/stripe.js
export default {
  async fetch(request, env, ctx) {
    const event = await env.PAYMENTS.webhook.verify(request);
    if (event.type === "checkout.session.completed") {
      // grant access, record the customer id, etc.
    }
    return new Response("ok");
  },
};

Point your Stripe webhook endpoint at https://your-app.com/api/webhooks/stripe and set STRIPE_WEBHOOK_SECRET.