Selling Products with Stripe
Stripe exposes your entire product catalog through an API, making it easy to fetch your products at build time, generate your store pages statically, and let Stripe host the checkout. All static; no backend required.
Manage your products, prices, and payment links entirely in the Stripe Dashboard. Every time your site builds, ZeroPoint fetches the latest product data and regenerates your store pages.
How it works
- Create products and Payment Links in the Stripe Dashboard
- At build time, ZeroPoint fetches your product catalog from the Stripe API
- Your store pages are generated as static HTML — no runtime server needed
- Customers click a link and are taken to Stripe's hosted checkout page to complete their purchase
Steps
-
Create your products in Stripe
In the Stripe Dashboard, create a product for each item you want to sell. Give each product a name, description, and image.
For each product, create a Payment Link (Products → your product → Create payment link). This gives you a Stripe-hosted checkout URL. Payment Links support one-time payments, subscriptions, and donations.
-
Store your Stripe secret key
Your secret key is used only at build time to fetch your product catalog. It never appears in the generated HTML. Add it as an environment variable in your deployment platform:
- Netlify: Site configuration → Environment variables → Add variable
- Cloudflare Pages: Settings → Environment variables → Add variable
- GitHub Actions: Repository settings → Secrets and variables → Actions → New repository secret
Name the variable
STRIPE_SECRET_KEY. For local development, add it to a.envfile at the root of your project (ensure.envis in your.gitignore):STRIPE_SECRET_KEY=XXXXXXXXXXXXXXXXXXXXXXXX -
Install the Stripe SDK in ZeroPoint
npm install --save-dev stripe -
Create a Stripe data file
Create
src/data/stripe.jsto fetch your Payment Links and their associated product data from Stripe:src/data/stripe.jsimport Stripe from 'stripe'; export default async function () { const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); // Fetch all active Payment Links const { data: links } = await stripe.paymentLinks.list({ active: true }); // For each link, fetch its line items and expand the product details const products = await Promise.all( links.map(async (link) => { const { data: lineItems } = await stripe.paymentLinks.listLineItems( link.id, { expand: ['data.price.product'] } ); const item = lineItems[0]; const product = item?.price?.product; const currency = item?.price?.currency ?? 'usd'; const amount = (item?.price?.unit_amount ?? 0) / 100; return { url: link.url, name: product?.name, slug: product?.name?.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '') ?? product?.id, description: product?.description, image: product?.images?.[0] ?? null, price: new Intl.NumberFormat('en-US', { style: 'currency', currency: currency, }).format(amount), }; }) ); return products; }The
stripedata is now available to all your ZeroPoint templates. -
Create the store listing page
Create
src/content/pages/store.njkto render a grid of product cards, each linking to its own detail page:src/content/pages/store.njk--- title: Store permalink: /store/ --- <h1>Store</h1> <div class="product-grid"> {% for product in stripe %} <article class="product-card"> {% if product.image %} <a href="/store/{{ product.slug }}/"> <img src="{{ product.image }}" alt="{{ product.name }}"> </a> {% endif %} <h2><a href="/store/{{ product.slug }}/">{{ product.name }}</a></h2> <p class="product-price">{{ product.price }}</p> <a href="/store/{{ product.slug }}/" class="button button-secondary">View Product</a> </article> {% endfor %} </div> -
Generate individual product pages
Pagination can generate one page per item in a dataset. Create
src/content/pages/store-product.njk— ZeroPoint will output a separate page at/store/your-product-name/for every product in your Stripe catalog:src/content/pages/store-product.njk--- pagination: data: stripe size: 1 alias: product permalink: /store/{{ product.slug }}/ eleventyExcludeFromCollections: true --- <article class="product-single"> {% if product.image %} <div class="product-image"> <img src="{{ product.image }}" alt="{{ product.name }}"> </div> {% endif %} <div class="product-details"> <h1>{{ product.name }}</h1> {% if product.description %} <div class="product-description"> {{ product.description | markdown | safe }} </div> {% endif %} <p class="product-price">{{ product.price }}</p> <a href="{{ product.url }}"> Buy Now </a> </div> </article>Add a product in Stripe, trigger a build, and it gets a card on
/store/and its own page at/store/its-name/. Deactivate its Payment Link in Stripe and both disappear on the next build.
Going Further
- 🏷️ Stripe Tax — automatic tax calculation and collection, configurable directly on Payment Links. No code required.
- 🌍 Adaptive Pricing — Stripe automatically presents prices in your customer's local currency. One toggle per Payment Link.
- 👤 Customer Portal — a Stripe-hosted page where subscribers can manage their own billing, swap payment methods, and cancel. You redirect them to a URL; Stripe handles everything else.
- 🔔 Webhooks — receive events after a payment completes to trigger fulfillment, send confirmation emails, or update external systems. Handle them with a Netlify or Cloudflare Pages Function.