Adios
BlogNext.js SaaS

Next.js SaaS

Come implementare gli abbonamenti Stripe in Next.js: Checkout, webhook e stato di fatturazione

Implementa la fatturazione degli abbonamenti Stripe in Next.js con Checkout Sessions create sul server, webhook verificati, diritti di accesso locali ed elaborazione idempotente.

Team di AdiosAggiornato 17 luglio 20268 min di lettura

Il reindirizzamento di ritorno da Checkout riguarda l'esperienza utente. Sono i webhook verificati a permettere all'applicazione di riconciliare in modo affidabile lo stato asincrono della fatturazione.

Mantieni un modello locale della fatturazione

Salva gli ID del cliente e dell'abbonamento del provider nell'account a cui appartengono, poi normalizza il piano, lo stato, il periodo corrente, lo stato di cancellazione e i diritti di accesso necessari all'applicazione. L'oggetto del provider non sostituisce un modello di accesso specifico del prodotto.

Definisci come gli stati trialing, active, past_due, canceled e incomplete influiscono sull'applicazione. Mantieni una cronologia di fatturazione e decisioni di accesso che si possano spiegare. Ogni etichetta nella pagina dei prezzi deve corrispondere a un unico ID di prezzo configurato sul server, anziché accettare un prezzo arbitrario inviato dal browser.

Crea le Checkout Sessions sul server

Autentica l'account, verifica che il piano richiesto sia tra quelli consentiti, crea o riutilizza il suo Stripe Customer e crea una Checkout Session in modalità abbonamento. Aggiungi l'ID stabile del tuo account ai metadati, così potrai riconciliare gli eventi successivi senza affidarti a un indirizzo email.

Restituisci l'URL del provider o reindirizza a quell'URL. Non esporre mai la chiave segreta al browser. Usa una chiave di idempotenza quando una richiesta ripetuta dell'applicazione non deve creare operazioni duplicate presso il provider.

"use server";

export async function startCheckout(plan: PlanId) {
  const account = await requireBillingAdmin();
  const price = PRICE_IDS[plan];
  if (!price) return { error: "Unknown plan" };

  const session = await stripe.checkout.sessions.create({
    mode: "subscription",
    customer: account.stripeCustomerId,
    line_items: [{ price, quantity: 1 }],
    success_url: SITE_URL + "/settings/billing?checkout=complete",
    cancel_url: SITE_URL + "/pricing",
    metadata: { accountId: account.id },
  });

  redirect(session.url);
}

Mostra la pagina di ritorno in attesa di conferma

Un cliente può raggiungere l'URL di conferma prima che l'applicazione abbia elaborato tutti gli eventi asincroni, e un URL copiato non dimostra che il pagamento sia avvenuto. Mostra lo stato della conferma, poi leggi il record locale dell'abbonamento e aggiornalo dopo l'elaborazione del webhook.

Non concedere accesso permanente in base a un parametro di query o a una risposta del provider sul client. I diritti di accesso devono dipendere dallo stato verificato sul server. Se la fatturazione rimane incompleta, indica chiaramente al cliente come riprovare o contattare l'assistenza.

Verifica la richiesta webhook nel formato originale

Un Route Handler di Next.js può leggere il corpo originale con request.text e la firma da request.headers. Passa il corpo grezzo, il valore di Stripe-Signature e il segreto dell'endpoint alla libreria ufficiale. Elaborare prima il JSON modifica il corpo usato per la verifica e può far fallire il controllo delle firme.

Rifiuta le firme non valide prima di elaborare la richiesta. Mantieni separati i segreti degli endpoint di test e di produzione. Restituisci rapidamente una risposta di successo dopo aver registrato il lavoro accettato; l'invio di email o le sincronizzazioni che richiedono tempo devono passare a un job.

export async function POST(request: Request) {
  const payload = await request.text();
  const signature = request.headers.get("stripe-signature");

  const event = stripe.webhooks.constructEvent(
    payload,
    signature,
    process.env.STRIPE_WEBHOOK_SECRET,
  );

  await recordBillingEvent(event);
  return new Response(null, { status: 200 });
}

Elabora gli eventi in modo idempotente

La consegna di un webhook può ripetersi e l'ordine non è garantito. Inserisci l'ID dell'evento del provider con un vincolo di unicità prima di applicarne gli effetti. Se l'evento esiste già, confermane la ricezione senza inviare un'altra email o applicare la modifica due volte.

Per gli aggiornamenti e le eliminazioni degli abbonamenti, recupera o ricava lo stato attuale ufficiale del provider quando l'ordine degli eventi potrebbe rendere obsoleto il record locale. Quando possibile, registra l'evento e aggiorna lo stato di fatturazione nella stessa transazione.

  • —Registra l'ID e il tipo dell'evento.
  • —Associalo all'account locale.
  • —Applica una sola volta lo stato normalizzato dell'abbonamento.
  • —Metti in coda le attività successive più lente dopo aver salvato le modifiche di stato in modo persistente.

Gestisci l'intero ciclo di vita dell'abbonamento

Supporta la creazione di clienti e abbonamenti, i cambi di piano, i rinnovi, i pagamenti non riusciti, le cancellazioni programmate e immediate e le eliminazioni. Usa il portale clienti quando è adatto al prodotto, anziché ricreare senza motivo la gestione dei metodi di pagamento e delle fatture.

Restano necessari i controlli di autorizzazione: solo chi ha il ruolo appropriato nell'account può avviare il checkout o aprire la gestione della fatturazione. Registra chi ha richiesto il cambio di piano e mostra la data di decorrenza, così l'assistenza potrà spiegare lo stato dell'account.

Verifica nuovi tentativi ed errori

Usa Stripe CLI o una destinazione per eventi di test per inoltrare eventi firmati. Ripeti lo stesso evento, invia un aggiornamento precedente dopo uno più recente, usa il segreto sbagliato, interrompi il database e provoca un pagamento non riuscito. Verifica che sia ancora possibile spiegare l'accesso concesso e lo stato locale.

Verifica la compilazione di produzione con le credenziali della modalità di test prima di attivare l'endpoint live. Mantieni separati gli ID live e di test ed evita che una distribuzione di anteprima si registri per errore come destinazione di produzione.

Ospita la fatturazione su una versione stabile accessibile tramite HTTPS

In produzione, Stripe richiede un endpoint webhook HTTPS accessibile pubblicamente. Adios fornisce l'ambiente di esecuzione persistente di Next.js, la rotta HTTPS generata, i domini personalizzati, TLS gestito, i riferimenti ai segreti, i controlli di integrità e i log di esecuzione necessari per gestire quell'endpoint insieme all'interfaccia SaaS.

Distribuisci e verifica Checkout in modalità di test, esamina gli errori di firma senza registrare segreti del payload nei log, poi promuovi la versione che funziona correttamente. Registra l'URL stabile del webhook di produzione, anziché quello di un'anteprima temporanea. Se una futura versione candidata non supera la compilazione o il controllo di integrità, non deve necessariamente sostituire l'endpoint di fatturazione funzionante.

env:
  STRIPE_SECRET_KEY: secret://STRIPE_SECRET_KEY
  STRIPE_WEBHOOK_SECRET: secret://STRIPE_WEBHOOK_SECRET
  DATABASE_URL: secret://DATABASE_URL

runtime:
  name: node@24
  port: 3000
  health_path: /api/health
Tutti gli articoli