Stripe + Next.js Headless Commerce: The 2026 Integration Guide
Je eerste Stripe-webhook arriveert 847 milliseconden nadat de betaling is geslaagd. Je database toont nog steeds 'in behandeling'. De klant vernieuwt de pagina, klikt opnieuw op 'Betalen' en nu zijn ze dubbel gefactureerd. Ik heb deze race condition om 2 uur 's nachts in drie productiewinkels opgelost. Stripe's API is geëvolueerd — Checkout Sessions ondersteunen nu eenmalige Link, Payment Intents verwerken Apple Pay en Google Pay natively, en webhook-handtekeningverificatie werkt stil als je serverless-functie de raw body herschrijft. Deze gids behandelt de acht integratiepatronen die in productie standhouden: Checkout Sessions, Payment Intents, webhook-idempotentie, abonnementlifecycle-hooks, wallet payment-instellingen en de drie architectuurbeslissingen die de 847ms-nachtmerrie voorkomen. We beginnen met de webhook-handler, omdat dat is waar de meeste integraties eerst mislukken.
Half 2026 is Stripe's API op versie 2025-12-18.acacia, Next.js 15.x is stabiel met de App Router als standaard, en de @stripe/stripe-js en @stripe/react-stripe-js pakketten zijn aanzienlijk rijp geworden. Als je op oudere versies bouwt, is het meeste hiervan nog steeds van toepassing, maar sommige server action-patronen zullen verschillen.
Inhoudsopgave
- Waarom Stripe + Next.js voor Headless Commerce
- Architectuuroverzicht
- Stripe instellen in een Next.js 15-project
- Checkout Sessions: het snelle pad
- Payment Intents: volledig controlmodus
- Webhook-afhandeling die werkelijk werkt
- Abonnementen en terugkerende facturering
- Apple Pay, Google Pay en Link
- Eenmalige checkout met Link
- Beveiliging, testen en live gaan
- Prestatieoverwegingen
- Veelgestelde vragen

Waarom Stripe + Next.js voor Headless Commerce
Stripe verwerkt meer dan 1 biljoen dollar aan betalingsvolume jaarlijks. Next.js biedt macht aan een groeiend deel van ecommerce-winkels — Vercel meldt dat meer dan 40% van de nieuwe Next.js-projecten in 2026 enige vorm van commerce-functionaliteit hebben. De combinatie is logisch om enkele concrete redenen:
- Server Components en Server Actions stellen je in staat de Stripe SDK serverzijdig aan te roepen zonder een aparte API-laag op te bouwen.
- Edge en serverless deployment op Vercel, Netlify of AWS betekent dat je betalingseindpunten automatisch schalen.
- React Server Components houden je Stripe-geheime sleutel op de server waar hij hoort, zonder extra kunstjes.
- De App Router geeft je layouts, loading states en error boundaries die goed uitkomen op checkout-stromen.
Als je headless commerce-architecturen evalueert, hebben we dozijnen van deze gebouwd bij Social Animal — bekijk onze Next.js-ontwikkelingscapaciteiten en headless CMS-ontwikkeling voor meer context over hoe deze stukken in elkaar passen.
Architectuuroverzicht
Voordat we code schrijven, moeten we de architectuur correct instellen. Hier zien we hoe de stukken aansluiten in een typische headless commerce-setup:
┌─────────────────┐ ┌──────────────────┐ ┌─────────────┐
│ Next.js App │────▶│ Stripe API │────▶│ Webhooks │
│ (App Router) │◀────│ (Server-side) │ │ Endpoint │
└─────────────────┘ └──────────────────┘ └──────┬──────┘
│ │
│ ▼
▼ ┌─────────────┐
┌─────────────────┐ │ Database / │
│ Headless CMS │ │ Order Mgmt │
│ (Products) │ └─────────────┘
└─────────────────┘
De kritieke beslissing is of je Checkout Sessions (Stripe-gehost of ingebed) of Payment Intents (volledig aangepaste UI) gebruikt. Hier is wanneer je elk gebruikt:
| Functie | Checkout Sessions | Payment Intents |
|---|---|---|
| Ontwikkelingssnelheid | Snel — dagen | Langzamer — weken |
| UI-aanpassingen | Beperkt (Stripe-thema) | Volledige controle |
| PCI-nalevingsbereik | SAQ A (eenvoudigst) | SAQ A-EP |
| Ondersteuning betaalmethode | Automatisch (40+ methoden) | Handmatig per methode |
| Abonnementondersteuning | Ingebouwd | Vereist extra code |
| Apple Pay / Google Pay | Automatisch | Handmatig via Payment Request API |
| Conversieoptimalisatie | Stripe-geoptimaliseerd | Jij bent eraan overgelaten |
| Prijsimpact | Dezelfde Stripe-kosten | Dezelfde Stripe-kosten |
Mijn eerlijke aanbeveling: begin met Checkout Sessions tenzij je een specifieke reden hebt niet te doen. Je kunt later altijd naar Payment Intents migreren, en Stripe's ingebedde checkout is opmerkelijk goed geworden in 2026.
Stripe instellen in een Next.js 15-project
Laten we de fundamenten instellen. Ik ga ervan uit dat je een Next.js 15-project hebt met de App Router.
npm install stripe @stripe/stripe-js @stripe/react-stripe-js
Stel je omgevingsvariabelen in:
# .env.local
STRIPE_SECRET_KEY=sk_test_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
Stel een serverzijdige Stripe-instantie in. Ik plaats dit altijd in een lib/stripe.ts bestand:
// lib/stripe.ts
import Stripe from 'stripe';
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: '2025-12-18.acacia',
typescript: true,
});
En een clientzijdige loader:
// lib/stripe-client.ts
import { loadStripe } from '@stripe/stripe-js';
export const stripePromise = loadStripe(
process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!
);
Één ding dat mensen in de war brengt: nooit lib/stripe.ts in een client component importeren. Het stripe npm-pakket bevat je geheime sleutel en moet alleen serverzijdig werken. Next.js 15 zal een build-error gooien als je het per ongeluk in een 'use client' bestand importeert, wat eigenlijk een mooie guardrail is.

Checkout Sessions: het snelle pad
Checkout Sessions zijn de snelste manier om betalingen te accepteren. Stripe host het betalingsformulier (of je sluit het in), verwerkt PCI-naleving en ondersteunt automatisch tientallen betaalmethoden, waaronder Apple Pay, Google Pay en Link.
Een Checkout Session maken met Server Actions
// app/actions/checkout.ts
'use server';
import { stripe } from '@/lib/stripe';
import { redirect } from 'next/navigation';
export async function createCheckoutSession(formData: FormData) {
const priceId = formData.get('priceId') as string;
const quantity = Number(formData.get('quantity')) || 1;
const session = await stripe.checkout.sessions.create({
mode: 'payment',
line_items: [
{
price: priceId,
quantity,
},
],
success_url: `${process.env.NEXT_PUBLIC_URL}/checkout/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.NEXT_PUBLIC_URL}/checkout/canceled`,
automatic_tax: { enabled: true },
// Schakel alle relevante betaalmethoden in
payment_method_types: undefined, // Laat Stripe automatisch detecteren
});
redirect(session.url!);
}
Ingebedde Checkout (2026 aanbevolen aanpak)
Stripe's ingebedde checkout houdt gebruikers op je domein. Dit heeft betere conversietarieven — Stripe's eigen gegevens uit recente jaren tonen een verbetering van 10-15% ten opzichte van omleidingsgebaseerde checkout voor terugkerende klanten.
// app/checkout/embedded/page.tsx
'use client';
import { useCallback } from 'react';
import { loadStripe } from '@stripe/stripe-js';
import {
EmbeddedCheckoutProvider,
EmbeddedCheckout,
} from '@stripe/react-stripe-js';
const stripePromise = loadStripe(
process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!
);
export default function CheckoutPage() {
const fetchClientSecret = useCallback(async () => {
const res = await fetch('/api/checkout/embedded', {
method: 'POST',
body: JSON.stringify({ priceId: 'price_xxx', quantity: 1 }),
});
const { clientSecret } = await res.json();
return clientSecret;
}, []);
return (
<div className="max-w-lg mx-auto py-12">
<EmbeddedCheckoutProvider
stripe={stripePromise}
options={{ fetchClientSecret }}
>
<EmbeddedCheckout />
</EmbeddedCheckoutProvider>
</div>
);
}
En de API-route:
// app/api/checkout/embedded/route.ts
import { stripe } from '@/lib/stripe';
import { NextResponse } from 'next/server';
export async function POST(req: Request) {
const { priceId, quantity } = await req.json();
const session = await stripe.checkout.sessions.create({
mode: 'payment',
line_items: [{ price: priceId, quantity }],
ui_mode: 'embedded',
return_url: `${process.env.NEXT_PUBLIC_URL}/checkout/success?session_id={CHECKOUT_SESSION_ID}`,
});
return NextResponse.json({ clientSecret: session.client_secret });
}
Payment Intents: volledig controlmodus
Als je een volledig aangepaste checkout UI nodig hebt — misschien bouw je een éénpagina-checkout, of je ontwerpteam heeft specifieke vereisten — geven Payment Intents je volledige controle.
De afweging is echt: je schrijft meer code, verwerkt meer edge cases en neemt een iets hogere PCI-nalevingslast op je. Maar voor sommige producten is het het waard.
Serverzijde: Payment Intents maken
// app/api/payment-intent/route.ts
import { stripe } from '@/lib/stripe';
import { NextResponse } from 'next/server';
export async function POST(req: Request) {
const { amount, currency = 'usd', metadata } = await req.json();
const paymentIntent = await stripe.paymentIntents.create({
amount, // in cents
currency,
metadata,
automatic_payment_methods: {
enabled: true, // Dit schakelt Apple Pay, Google Pay, Link enzovoort in
},
});
return NextResponse.json({
clientSecret: paymentIntent.client_secret,
});
}
Clientzijde: het betalingsformulier
// components/PaymentForm.tsx
'use client';
import { useState } from 'react';
import {
PaymentElement,
useStripe,
useElements,
} from '@stripe/react-stripe-js';
export function PaymentForm() {
const stripe = useStripe();
const elements = useElements();
const [error, setError] = useState<string | null>(null);
const [processing, setProcessing] = useState(false);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!stripe || !elements) return;
setProcessing(true);
setError(null);
const { error: submitError } = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: `${window.location.origin}/checkout/success`,
},
});
if (submitError) {
setError(submitError.message ?? 'Payment failed');
setProcessing(false);
}
// Geen fout? Stripe leidt automatisch om
};
return (
<form onSubmit={handleSubmit}>
<PaymentElement
options={{
layout: 'accordion',
wallets: {
applePay: 'auto',
googlePay: 'auto',
},
}}
/>
{error && <p className="text-red-500 mt-2">{error}</p>}
<button
type="submit"
disabled={!stripe || processing}
className="mt-4 w-full bg-black text-white py-3 rounded-lg disabled:opacity-50"
>
{processing ? 'Processing...' : 'Pay now'}
</button>
</form>
);
}
Let op de automatic_payment_methods: { enabled: true } aan de serverzijde. Dit is de manier van 2026 om ondersteuning van betaalmethoden af te handelen. Stripe toont automatisch de juiste betaalmethoden op basis van het apparaat van de klant, locatie en valuta. Niet meer handmatig payment_method_types opsommen.
Webhook-afhandeling die werkelijk werkt
Webhooks zijn waar de meeste Stripe-integraties mislukken. Ik heb productiesystemen gezien die orders verliezen omdat iemand vergat de webhook-handtekening te verifiëren, of omdat de handler een fout gooide voordat een 200 werd teruggestuurd.
Hier is mijn battle-tested webhook-handler:
// app/api/webhooks/stripe/route.ts
import { stripe } from '@/lib/stripe';
import { headers } from 'next/headers';
import { NextResponse } from 'next/server';
import type Stripe from 'stripe';
export async function POST(req: Request) {
const body = await req.text();
const headersList = await headers();
const signature = headersList.get('stripe-signature');
if (!signature) {
return NextResponse.json({ error: 'Missing signature' }, { status: 400 });
}
let event: Stripe.Event;
try {
event = stripe.webhooks.constructEvent(
body,
signature,
process.env.STRIPE_WEBHOOK_SECRET!
);
} catch (err) {
console.error('Webhook signature verification failed:', err);
return NextResponse.json({ error: 'Invalid signature' }, { status: 400 });
}
try {
switch (event.type) {
case 'checkout.session.completed': {
const session = event.data.object as Stripe.Checkout.Session;
await handleCheckoutComplete(session);
break;
}
case 'payment_intent.succeeded': {
const paymentIntent = event.data.object as Stripe.PaymentIntent;
await handlePaymentSuccess(paymentIntent);
break;
}
case 'payment_intent.payment_failed': {
const paymentIntent = event.data.object as Stripe.PaymentIntent;
await handlePaymentFailure(paymentIntent);
break;
}
case 'customer.subscription.created':
case 'customer.subscription.updated':
case 'customer.subscription.deleted': {
const subscription = event.data.object as Stripe.Subscription;
await handleSubscriptionChange(subscription);
break;
}
case 'invoice.payment_failed': {
const invoice = event.data.object as Stripe.Invoice;
await handleInvoiceFailure(invoice);
break;
}
default:
console.log(`Unhandled event type: ${event.type}`);
}
} catch (err) {
console.error(`Error processing ${event.type}:`, err);
// Retourneer toch 200 om Stripe niet opnieuw in te dienen
// Log de fout voor handmatige onderzoeksing
}
return NextResponse.json({ received: true });
}
Webhook-gotchas die ik op harde manier heb geleerd
Retourneer altijd 200, zelfs als je verwerking mislukt. Anders voert Stripe opnieuw in, en je kunt dezelfde event meerdere keren verwerken. Log de fout en deal ermee asynchroon.
Maak handlers idempotent. Stripe kan en zal dezelfde event meer dan eens verzenden. Gebruik de event-ID of de metagegevens van het object om te controleren of je het al hebt verwerkt.
Gebruik
req.text()nietreq.json()voor handtekeningverificatie. De handtekening wordt berekend over de raw body-string. Als je het eerst parseert, zal verificatie altijd mislukken.Stel de Stripe CLI in voor lokaal testen. Het is niet onderhandelbaar.
stripe listen --forward-to localhost:3000/api/webhooks/stripe
- Op Vercel hebben webhook-routes specifieke configuratie nodig. Zorg ervoor dat je route niet achter middleware staat die het request body wijzigt. In Next.js 15 verwerkt API-routes in de App Router dit standaard correct, maar controleer twee keer als je custom middleware hebt.
Abonnementen en terugkerende facturering
Abonnementen voegen een laag complexiteit toe. Je verwerkt niet alleen een eenmalige betaling — je beheert een lifecycle: proefperiodes, upgrades, downgrades, annuleringen, mislukte betalingen, dunning.
Een abonnement maken via Checkout
De gemakkelijkste aanpak:
// app/actions/subscribe.ts
'use server';
import { stripe } from '@/lib/stripe';
import { redirect } from 'next/navigation';
export async function createSubscriptionCheckout(
customerId: string,
priceId: string
) {
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
customer: customerId,
line_items: [{ price: priceId, quantity: 1 }],
success_url: `${process.env.NEXT_PUBLIC_URL}/account/billing?success=true`,
cancel_url: `${process.env.NEXT_PUBLIC_URL}/pricing`,
subscription_data: {
trial_period_days: 14,
metadata: {
plan: 'pro', // Je eigen metagegevens
},
},
allow_promotion_codes: true,
tax_id_collection: { enabled: true },
});
redirect(session.url!);
}
Abonnementen beheren
Voor de klantenportal (upgrade, downgrade, annuleren, betaalmethode bijwerken) is Stripe's Customer Portal werkelijk geweldig in 2026:
// app/actions/billing.ts
'use server';
import { stripe } from '@/lib/stripe';
import { redirect } from 'next/navigation';
export async function createBillingPortalSession(customerId: string) {
const session = await stripe.billingPortal.sessions.create({
customer: customerId,
return_url: `${process.env.NEXT_PUBLIC_URL}/account/billing`,
});
redirect(session.url);
}
Sleutelabonnement-webhook-events
| Event | Wanneer het gebeurt | Wat te doen |
|---|---|---|
customer.subscription.created |
Nieuw abonnement | Toegang inrichten |
customer.subscription.updated |
Planwijziging, vernieuwing | Toegangsniveau bijwerken |
customer.subscription.deleted |
Annulering (einde van periode) | Toegang intrekken |
invoice.payment_succeeded |
Geslaagde vernieuwing | Factureringsgegevens bijwerken |
invoice.payment_failed |
Vernieuwing mislukt | Dunning-email sturen, account markeren |
customer.subscription.trial_will_end |
3 dagen voor einde trial | Herinneringsemail sturen |
Vertrouw niet alleen op de abonnementstatus van de API-oproep. Webhooks zijn de bron van waarheid voor statuswijzigingen van abonnementen. Ik heb teams gezien die in plaats daarvan de Stripe API opvraagden en het is zowel langzamer als fragiler.
Apple Pay, Google Pay en Link
Het voordeel van Stripe's 2026 Payment Element is dat wallet-betalingen meestal gewoon werken. Maar er zijn enkele installatievereisten die mensen missen.
Apple Pay-instellingen
Domeinverificatie is vereist. Je moet een
.well-known/apple-developer-merchantid-domain-associationbestand op je domeinhoofdmap hosten. Stripe voorziet dit bestand in je Dashboard onder Instellingen → Betaalmethoden → Apple Pay.Plaats in Next.js het bestand op
public/.well-known/apple-developer-merchantid-domain-association.Registreer je domein in het Stripe Dashboard.
Apple Pay verschijnt alleen op Safari/iOS. Wees niet bezorgd als het niet verschijnt in Chrome tijdens testen.
Google Pay-instellingen
Google Pay vereist minder instellingen — het werkt automatisch met het Payment Element zolang je Stripe-account correct is geconfigureerd. Het verschijnt in Chrome en op Android-apparaten.
Link (Stripe's eenmalige checkout)
Link is Stripe's antwoord op Shop Pay. Klanten slaan hun betalingsgegevens eenmaal op en kunnen met één klik in de winkelwagen gaan op elke Stripe-handelscentrale die Link gebruikt.
Als van 2026 is Link standaard ingeschakeld op nieuwe Stripe-accounts. De conversie-uplift is echt — Stripe meldt een significante verbetering in checkout-voltooiing wanneer Link beschikbaar is. Voor terugkerende Link-gebruikers is het veel hoger.
Met het Payment Element verschijnt Link automatisch. Met Checkout Sessions ook. Je hoeft niets speciaals te doen.
// Link is automatisch met Payment Element, maar je kunt aanpassen:
<PaymentElement
options={{
wallets: {
applePay: 'auto',
googlePay: 'auto',
},
// Link verschijnt automatisch in het e-mailveld
}}
/>
Eenmalige checkout met Link
Link verdient zijn eigen sectie omdat het een serieuze conversie-driver is geworden. Hier werkt het:
- Klant voert zijn e-mailadres in je checkout in.
- Als ze een Link-account hebben, ontvangen ze een verificatiecode via sms.
- Na verificatie worden hun opgeslagen adres en betaalmethode automatisch ingevuld.
- Ze klikken "Betalen" — klaar.
Het sleutelinsicht: Link werkt op alle handelscentra. Als je klant Link op een volledig ander website gebruikte, krijgen ze dezelfde eenmalige ervaring op de jouwe ook. Stripe's netwerkeffect is echt — zij rapporteren meer dan 100 miljoen Link-gebruikers sinds begin 2026.
Om Link-adoptie te maximaliseren, zorg dat het e-mailveld het eerste is waarmee klanten interageren in je checkout-stroom. Het Payment Element verwerkt dit goed met de accordion layout.
Als je nog verder wilt gaan, kun je het Express Checkout Element gebruiken om Apple Pay, Google Pay en Link als prominente knoppen boven je formulier weer te geven:
// components/ExpressCheckout.tsx
'use client';
import { ExpressCheckoutElement } from '@stripe/react-stripe-js';
export function ExpressCheckout() {
return (
<ExpressCheckoutElement
onConfirm={async (event) => {
// Verwerk de express checkout-bevestiging
console.log('Express checkout confirmed:', event);
}}
options={{
buttonType: {
applePay: 'buy',
googlePay: 'buy',
},
}}
/>
);
}
Beveiliging, testen en live gaan
Beveiligingschecklist
- Stripe-geheime sleutel wordt alleen serverzijdig gebruikt
- Webhook-handtekeningen worden op elk verzoek geverifieerd
- HTTPS wordt in productie afgedwongen
- Bedragherekeneningen gebeuren serverzijdig (vertrouw nooit bedragen verzonden door client)
- API-routes hebben snelheidsbeperkingen
- Klantgegevens worden afgehandeld volgens je privacybeleid
- CSP-headers staan Stripe's domeinen toe (
js.stripe.com,api.stripe.com)
Testen
Stripe's testmodus is uitstekend. Gebruik deze testkaartnummers:
| Kaartnummer | Scenario |
|---|---|
4242 4242 4242 4242 |
Geslaagde betaling |
4000 0000 0000 3220 |
3D Secure vereist |
4000 0000 0000 9995 |
Geweigerd |
4000 0025 0000 3155 |
Vereist authenticatie |
4000 0000 0000 0341 |
Koppelen mislukt (voor opgeslagen kaarten) |
Voor abonnementstesten, gebruik Stripe's testklokken om tijd voorbij gaan zonder werkelijk te wachten.
Live gaan
- Schakel je sleutels over van
sk_test_naarsk_live_enpk_test_naarpk_live_. - Stel je live webhook-eindpunt in het Stripe Dashboard in.
- Verifieer je Apple Pay-domein voor productie.
- Schakel de betaalmethoden in die je wilt in het Stripe Dashboard.
- Zorg ervoor dat je Stripe-account volledig is geactiveerd (identiteitsverificatie, bankrekening, enz.).
Prestatieoverwegingen
Stripe.js is ~40KB gzipped. Dat is niet niets. Hier zijn enkele tips:
Lazy load Stripe.js. Laad het niet op elke pagina — alleen op checkout-gerelateerde pagina's. De
loadStripefunctie verwerkt dit goed; het script wordt niet opgehaald totdat je het aanroept.Gebruik
@stripe/stripe-js/pureals je precies wilt controleren wanneer het script wordt geladen:
import { loadStripe } from '@stripe/stripe-js/pure';
// Script laadt niet totdat loadStripe() wordt aangeroepen
Server Components voor productpagina's. Houd Stripe-clientcode uit je product listing en detail pagina's. Breng alleen de clientcomponenten mee als de gebruiker eigenlijk checkout initieert.
Edge runtime voor API-routes. De Stripe Node.js SDK werkt op de Edge runtime. Je kunt
export const runtime = 'edge'toevoegen aan je Stripe API-routes voor lagere latentie.
Voor teams die high-performance headless-winkels bouwen, kunnen frameworks als Astro ook een geweldige fit zijn voor de content-zware pagina's, terwijl Next.js de dynamische checkout-stromen verwerkt. We hebben deze hybride aanpak voor verschillende klanten gedaan — onze Astro-ontwikkeling en Next.js-ontwikkelingsteams werken samen aan deze architecturen.
Veelgestelde vragen
Wat zijn Stripe's transactiekosten in 2026? Stripe's standaardprijs is 2,9% + $0,30 per geslaagde kaartbetaling in de VS. Voor Europese kaarten is het 1,5% + €0,25. Volumekortingen zijn beschikbaar voor bedrijven die meer dan $1M jaarlijks verwerken. Stripe berekent geen instellingskosten, maandelijkse kosten of verborgen kosten op het standaardplan. Stripe berekent een extra 0,5% voor handmatig ingevoerde kaarten en 1% voor internationale kaarten.
Moet ik Checkout Sessions of Payment Intents gebruiken? Gebruik Checkout Sessions in de meeste gevallen. Ze zijn sneller om mee te implementeren, ondersteunen automatisch 40+ betaalmethoden, handelen PCI-naleving af en Stripe optimaliseert continu het conversietarief. Gebruik Payment Intents wanneer je een volledig aangepaste checkout UI nodig hebt die niet kan worden bereikt met ingebedde Checkout, of wanneer je fijnmazig controle over de betalingsstroom nodig hebt (zoals gesplitste betalingen of handmatige vastlegging).
Hoe ga ik met webhook-fouten om in productie? Retourneer altijd een 200-statuscode van je webhook-handler, zelfs als je bedrijfslogica mislukt. Log de fout en verwerk deze asynchroon. Maak je handlers idempotent door de event-ID tegen je database te controleren voordat je verwerkt. Stripe probeert webhooks tot 3 dagen opnieuw met exponentiële backoff. Stel webhook-faalmeldingen in het Stripe Dashboard in en overweeg een wachtrij (zoals AWS SQS of Inngest) te gebruiken voor het asynchroon verwerken van webhook-payloads.
Kan ik Stripe met een headless CMS als Sanity of Contentful gebruiken? Absoluut. Het typische patroon is: product-informatie en content in je headless CMS opslaan, prijzen en betalingsgegevens in Stripe, en ze verbinden via een gedeelde product-ID of SKU. Je Next.js-frontend haalt content uit het CMS en maakt Stripe Checkout Sessions of Payment Intents wanneer de klant klaar is om te kopen. We behandelen dit patroon uitgebreid in onze headless CMS-ontwikkelingswerk.
Hoe test ik Apple Pay lokaal?
Je kunt Apple Pay op localhost niet gemakkelijk testen omdat het HTTPS en domeinverificatie vereist. De beste aanpak is Stripe's testmodus met de 4242 testkaart in het Payment Element gebruiken — het simuleert de betalingsstroom. Voor werkelijk Apple Pay-testen implementeer je naar een staging omgeving met HTTPS. De Stripe CLI ondersteunt ook webhook-events voor Apple Pay-transacties doorsturen.
Is Stripe Link het waard om in te schakelen? Ja. Link is gratis voor handelscentra — Stripe berekent geen extra voor het. Het verschijnt automatisch in het Payment Element en Checkout Sessions. Stripe meldt dat Link checkout-voltooiing gemiddeld aanzienlijk verhoogt, met hogere getallen voor terugkerende Link-gebruikers. Er is geen nadeel aan het inschakelen, en met 100M+ Link-gebruikers in 2026 is het netwerkeffect significant.
Hoe ga ik met abonnementen met gemeten facturering om in Next.js?
Maak een abonnement met een gemeten prijs in Stripe. Gebruik vervolgens de Usage Records API om gebruik van je backend te rapporteren. Aan het einde van elke factureringsperiode berekent Stripe automatisch het totaal en factureren ze de klant. Je webhook-handler moet naar invoice.payment_succeeded en invoice.payment_failed events luisteren om je systeem in sync te houden. Rapporteer gebruik serverzijdig met een cron-taak of event-driven architectuur.
Wat is de beste manier om valuta en prijzen voor internationale klanten af te handelen? Stripe Adaptive Pricing (gelanceerd 2025) converteert automatisch prijzen naar de lokale valuta van de klant bij het uitchecken. Je stelt prijzen in je basisvaluta in, en Stripe verwerkt conversie, weergave en regeling. Alternatief kunt je meerdere prijzen per product in verschillende valuta's in Stripe maken voor meer controle. Gebruik het IP-adres of de browserinstelling van de klant om te bepalen welke valuta op je productpagina's moet worden weergegeven.
Hoeveel kost het om een headless commerce-integratie met Stripe te bouwen? Het hangt af van de scope. Een basisintegratie van Checkout Sessions kan in enkele dagen worden gedaan. Een volledig uitgeruste setup met abonnementen, klantenportal, webhooks en aangepaste UI duurt meestal 2-6 weken ontwikkelingstijd. Als je je specifieke behoeften wilt bespreken, bekijk onze prijspagina of neem contact op — we hebben deze integraties gebouwd over een breed scala aan industrieën en kunnen je een realistische schatting geven.