finance

Abbonamenti ricorrenti Stripe (Cashier)

Subscription SaaS/membership con piani, trial, upgrade/downgrade, fatturazione ricorrente automatica e portale cliente self-service via Laravel Cashier + Stripe Billing.

Cosa fa questo modulo

Modulo «Abbonamenti ricorrenti Stripe (Cashier)»: gestione completa di abbonamenti SaaS/membership/servizi a pagamento periodico tramite integrazione `laravel/cashier-stripe` su Stripe Billing. Copre l'intero ciclo di vita: scelta piano in landing/pricing page → checkout iniziale → trial opzionale → addebiti ricorrenti automatici → upgrade/downgrade con proration → pause/cancel/resume → recupero pagamenti falliti (dunning) → portale cliente Stripe per autogestione → metriche MRR/ARR/churn per business. Architettura piani: tabella `subscription_plans` locale (slug univoco `starter`/`pro`/`enterprise`, nome pubblico, descrizione_breve marketing, descrizione_lunga con bullet feature, prezzo_mensile e prezzo_annuale entrambi mappati a `stripe_price_id_mensile`/`stripe_price_id_annuale` creati nel dashboard Stripe o via API `prices.create` con `product.id`+`unit_amount`+`recurring.interval=month|year`, valuta default EUR ma multi-currency opzionale via `prices` multipli, limiti feature in JSON `feature_limits` (es. `{max_utenti: 5, max_progetti: 10, storage_gb: 20, api_calls_month: 10000, support_priority: "standard"}`, badge marketing tipo «più scelto»/«miglior valore»/«enterprise», ordine_visualizzazione, attivo bool, archiviato_at per sostituire prezzi vecchi senza romperle nei clienti esistenti via grandfathering). Modello cliente: trait `Billable` su `User` o modello `Tenant`/`Workspace` (Cashier default su User ma estendibile, per app B2B multi-tenant l'entità abbonata è il workspace non lo user) con campi `stripe_id` (Customer Stripe), `pm_type`+`pm_last_four` (metodo pagamento default ridondante per UI senza chiamata API), `trial_ends_at`, tabella `subscriptions` Cashier (one-to-many: un cliente può avere subscription multiple separate tipo «piano-app»+«add-on-sms-pack»+«storage-extra»), tabella `subscription_items` (line items multi-prezzo per subscription, es. piano base 10€/mese + add-on storage 5€/mese stessa fattura), tabella `payments` audit pagamenti riusciti/falliti. Stati subscription: `incomplete` (Payment Intent iniziale richiede azione SCA/3DS, accesso bloccato a feature premium fino a conferma entro 23h), `incomplete_expired` (cliente non ha completato pagamento iniziale in 23h, abbonamento cancellato), `trialing` (in trial gratuito attivo, accesso pieno feature, no addebito), `active` (abbonamento corrente pagato, feature sbloccate), `past_due` (pagamento fallito ma in retry dunning, accesso temporaneamente mantenuto N giorni grazia configurabile, banner di alert), `canceled` (cliente o admin ha cancellato, accesso fino a `ends_at` fine periodo pagato), `unpaid` (retry esauriti senza successo, accesso revocato, possibilità recupero manuale). Flusso onboarding e checkout: landing `/pricing` con tabella piani (mensile/annuale toggle, sconto 20% su annuale evidenziato, feature comparison checkmark, CTA «Inizia gratis» o «Provalo 14gg»), click piano → registrazione/login utente → pagina `/checkout/{plan_slug}` con form metodo pagamento (Stripe Elements con Payment Element drop-in, supporta carte, SEPA Direct Debit, Apple/Google Pay, Bancontact, iDEAL secondo paese), creazione subscription via Cashier `$user->newSubscription('default', $priceId)->trialDays(14)->withCoupon($coupon)->create($paymentMethod)` con gestione SCA/3DS automatica via `confirmPayment` Stripe.js, fallback `incomplete` se carta richiede azione, success page con conferma + accesso immediato a workspace + welcome email #8331. Trial gratuito: configurazione per piano `trial_days` (es. 14gg default, 7gg Starter, 30gg Enterprise custom), gestione `with_payment_method` (trial con carta obbligatoria) vs `without_payment_method` (trial senza carta, addebito automatico solo se aggiunge metodo entro fine trial), tracking `trial_ends_at` con email reminder #8331 a -3gg/-1gg/-0gg con CTA «Aggiungi metodo pagamento per continuare», auto-conversione a `active` con addebito automatico se metodo presente, downgrade a piano `free` o lock workspace se metodo mancante e cliente non agisce. Upgrade/downgrade piano: pagina `/account/billing` con piano corrente evidenziato + altri piani disponibili + pulsante «Passa a Pro/Enterprise», switch immediato via `$user->subscription('default')->swap($newPriceId)` con `prorate` default abilitato (Stripe genera credit note per residuo non goduto del piano vecchio e charge proporzionale per nuovo piano fino a fine periodo, calcolo Stripe-side trasparente), comportamento downgrade configurabile (immediato con proration credit OR fine periodo via `$subscription->swapAndInvoice()` con `proration_behavior=none` per evitare credit), notifiche email #8331 di conferma cambio piano con dettaglio nuovo importo+nuova feature list+data primo addebito nuovo importo, audit log #8330 evento switch_plan. Cancellazione: pulsante «Cancella abbonamento» con modal multi-step (motivo cancellazione obbligatorio con opzioni `troppo_caro`/`non_uso_abbastanza`/`mancano_feature`/`bug_problemi`/`passo_a_competitor`/`altro` + textarea note, opzionale offerta retention dinamica «-30% per 3 mesi se resti» mostrata in base a profilo cliente alto-valore, conferma finale), cancellazione gestita via `$user->subscription('default')->cancel()` (cancella a fine periodo, mantiene accesso fino a `ends_at`) vs `cancelNow()` (immediato con eventuale rimborso pro-rata manuale admin), reverse via `resume()` se cliente cambia idea durante grace period, gestione cancellazione a fine trial via `cancelTrialing()`. Recupero pagamenti falliti (dunning): Stripe Smart Retries configurato in dashboard Stripe (retry automatici scaglionati 3gg/5gg/7gg dopo failure con AI Stripe che ottimizza orario retry), email automatiche Stripe + email custom #8331 per ogni failure con messaggio personalizzato (1° failure «si è verificato un problema con la tua carta, aggiorna il metodo» + link `billing_portal_session.create` Stripe-hosted, 2° failure più urgente con count-down, 3° failure ultimo avviso «abbonamento sospeso tra X giorni»), grace period configurabile (es. 7gg accesso mantenuto past_due) prima di revoca completa, alert in app webhook-driven con banner persistente «Pagamento fallito — aggiorna ora» linkato a portale Stripe, hard cancel automatico dopo X retry falliti con email finale «abbonamento sospeso, riattiva quando vuoi». Customer Portal Stripe (autogestione cliente): integrazione `stripe.billing_portal.sessions.create` con `customer`+`return_url` per redirect a portale Stripe-hosted dove cliente può: aggiornare metodo pagamento, scaricare ricevute/fatture in PDF, vedere storico pagamenti, gestire upgrade/downgrade (se abilitato in `billing_portal.configurations`), cancellare abbonamento (se abilitato), aggiornare dati fatturazione (ragione sociale, P.IVA, indirizzo), tutto senza scrivere UI custom (saving 5-10gg lavoro), configurazione portale in dashboard Stripe (`/settings/billing/portal`) con branding logo + colori + privacy policy URL + terms URL + flussi abilitati/disabilitati, link da app `<a href="{{ route('billing.portal') }}">Gestisci abbonamento</a>` su pagina account, alternativa UI custom in-app per controllo totale (form Stripe Elements per update payment method via `payment_methods.attach`+`customers.update default_payment_method`, list invoices via `invoices.list customer=`, download PDF da `invoice.invoice_pdf` URL). Fatturazione e ricevute: ogni rinnovo Stripe emette automaticamente `invoice` con `paid` status post-charge, PDF scaricabile da `invoice.invoice_pdf`, ricevuta email Stripe nativa (`automatic_tax.enabled` se serve), integrazione con fatturazione elettronica italiana #8322 (webhook `invoice.paid` triggera emissione fattura SDI via Aruba/FattureInCloud/Fatturapa API con dati Stripe customer come cliente fatturazione, IVA 22% calcolata su `subtotal`, causale `acconto`/`saldo`/`abbonamento_mese_X`, numero progressivo, link fattura allegato in email conferma), gestione P.IVA cliente B2B con reverse charge UE via `automatic_tax` Stripe Tax + raccolta VAT ID in checkout, eventuale split invoice per fatturazione anticipata annuale con 12 ricevute mensili. Coupon e sconti: integrazione con #8321 coupon/sconti applicabili a subscription via `$user->newSubscription()->withCoupon($code)`, Stripe-side coupon (`coupons.create` con `percent_off` o `amount_off`+`duration=once|repeating|forever`) sincronizzato con coupon locale, promo code per landing «-30% primi 3 mesi se usi `BENVENUTO30`», cap massimo sconto, validazione una-tantum per cliente, applicazione sia in checkout che retroattiva via admin. Add-on e usage-based billing: subscription multi-item con line items aggiuntivi (es. piano base + pack SMS 500 utilizzo + storage extra 50GB), prezzi `usage_type=metered` per usage-based (es. €0.01 per API call oltre soglia inclusa) con `subscription_items.create_usage_record` da app ad ogni evento (webhook attivo o invio periodico batch), invoice mensile con dettaglio voce per voce (piano base €29 + 1.234 API calls €12.34 + storage extra €5 = €46.34), upgrade add-on via aggiunta `subscription_items.create` senza creare nuova subscription. Multi-account Stripe Connect (per app B2B reseller/marketplace): se app vende abbonamenti per conto di terzi (es. piattaforma SaaS che ha sub-merchant), Stripe Connect Standard/Express con onboarding + `application_fee_percent` su subscription per fee piattaforma trattenuta + payout diretto merchant. Webhook Stripe gestiti: `customer.subscription.created` (link DB + email welcome), `customer.subscription.updated` (sync stato/piano corrente), `customer.subscription.deleted` (revoke accesso post `ends_at`), `customer.subscription.trial_will_end` (3gg prima fine trial → email reminder), `invoice.payment_succeeded` (registra pagamento, emette fattura SDI #8322, audit), `invoice.payment_failed` (avvia dunning, marca past_due), `invoice.finalized` (PDF generato, archivio), `payment_method.attached`/`detached` (sync metodi pagamento UI), `customer.updated` (sync email/billing details), endpoint `/stripe/webhook` con verifica firma `STRIPE_WEBHOOK_SECRET`, retry idempotency, queue job per processing async ed evitare timeout. Feature gating in-app: middleware `subscription:active` su route protette che verifica `$user->subscribed('default')` true + piano corrente con feature richiesta, helper `@subscribed('default')`+`@can('use-feature-x')` blade per UI conditional, gate Laravel `Gate::define('use-feature', fn($user) => $user->subscription()->onPlan('pro'))` per logica granulare, banner upgrade context-aware quando cliente Starter clicca feature Pro («Funzione disponibile solo nel piano Pro — Upgrade ora con +€20/mese»), conteggio uso vs limite piano (es. utenti workspace 8/10, progetti 23/25) con warning a 80% e blocco a 100% finché non upgrade. Pannello admin abbonamenti: datatable Livewire con filtri (piano, stato, MRR, churn risk, trial in scadenza, past_due), dettaglio singola subscription con timeline eventi Stripe (created, payment events, upgrades, cancellation), azioni manuali (rimborso parziale/totale, switch piano forzato per support, estendi trial, applica coupon retroattivo, marca paid manuale, cancella immediato, sospendi temporaneo, riattiva), report MRR/ARR breakdown per piano (new MRR, expansion MRR da upgrade, contraction MRR da downgrade, churned MRR, net new MRR), grafici (revenue mensile, churn rate %, LTV stimato, ARPU, conversion trial→paid, average time-to-upgrade), cohort analysis per mese signup, segmentazione cliente per piano+anzianità+valore. Comandi artisan: `php artisan cashier:sync-prices` (sync prezzi Stripe → DB locale per cambio listino), `php artisan subscriptions:trial-reminders` (cron giornaliero, email -3gg/-1gg/-0gg trial in scadenza), `php artisan subscriptions:report-mrr {month}` (calcolo MRR/ARR per business report), `php artisan subscriptions:dunning-followup` (cron giornaliero, follow-up custom past_due oltre dunning Stripe), `php artisan subscriptions:revoke-expired` (revoca accessi post ends_at), `php artisan subscriptions:reconcile` (verifica DB locale vs Stripe API, alert mismatch). Sicurezza: webhook con verifica firma constant-time, idempotency su create subscription, no dati carta toccati dal server (Stripe Elements PCI SAQ-A), HTTPS forzato, rate limit endpoint create subscription per anti-fraud, integrazione Stripe Radar (block test cards in prod, geo-blocking, velocity rules), validazione doppia subscription per stesso user (evita 2 subscription `default` attive sovrapposte), audit log #8330 immutabile su ogni evento subscription (created, swapped, canceled, refunded) con before/after JSON per dispute investigation. Compliance: GDPR diritto cancellazione con anonimizzazione mantenendo aggregati MRR storici, conservazione fatture 10 anni per fisco italiano (archivio S3 con WORM), invio fattura elettronica SDI #8322 entro 12gg dal pagamento, gestione VAT ID UE con reverse charge, esempi T&C subscription con clausole rinnovo automatico/recesso/MTM mensile, link policy in checkout obbligatorio con consenso checkbox tracciato. UX patterns chiave: «Sticky pricing» (prezzo grandfathered mantenuto a vita per early adopter anche se listino cambia), «Annual discount» (sconto 16-20% piano annuale vs mensile per ridurre churn cash-flow), «Pause subscription» invece di cancel (pausa fino a N mesi per riduzione churn, restano fidelizzati), «Win-back email» (a 7gg/30gg post-cancel con offerta -50% per tornare), «In-app upgrade prompt» context-aware (cliente Starter clicca limite → modal upgrade con preview Pro), «Onboarding email sequence» (#8331 drip campaign post-signup giorno 0/2/5/10/14 con tips e CTA upgrade). Metriche e KPI esposti in dashboard: MRR (Monthly Recurring Revenue) growth %, ARR (Annual Recurring Revenue), Net Revenue Retention (NRR), churn rate (customer + revenue), LTV (Lifetime Value), CAC payback period, trial-to-paid conversion rate, upgrade rate, downgrade rate, expansion MRR ratio, gross margin per piano, top motivi cancellazione, segmentazione cohort. Casi d'uso: SaaS B2B (Footility stesso pricing model, gestionali #19/#23 a sub annuale, klabhouse upgrade tier), membership/community (palestre, club, associazioni con quota mensile), corsi/formazione (membership accesso piattaforma video on-demand mese/anno), coworking (membership desk/sala riunioni con tier), software prodotto (CRM, planner, design tool), media (giornali con paywall, podcast premium, newsletter premium), API as a Service (tier base/pro/enterprise con limiti chiamate), servizio digitali ricorrenti (backup, monitoring, security audit). Differenza da pagamento una-tantum: revenue ricorrente prevedibile (MRR), fidelizzazione automatica via abbonamento, retention metrics, no riacquisizione cliente mese su mese. Differenza da #8324 caparra Stripe (one-time payment intent legato a singolo evento booking): qui ricorrenza nativa Stripe Billing con dunning + portale + proration gestita da Stripe, no slot/booking specifico. Differenza da Chargebee/Recurly (SaaS subscription management dedicato a 200-500€/mese): qui zero overhead aggiuntivo (Stripe Billing incluso senza fee extra oltre transazione), full ownership dati DB locale, integrazione diretta in app senza middleware esterno. Differenza da Stripe Checkout standalone (più semplice ma meno controllo): qui Cashier orchestrazione DB+app+Stripe con feature gating in-app e logica business custom. Estensioni future: AI churn prediction (modello ML su feature engagement → score rischio churn + email automatica trigger retention), dynamic pricing personalizzato (cliente high-engagement → offerta upgrade scontato, cliente at-risk → offerta downgrade vs cancel), bundle multi-prodotto cross-sell (subscribe a 2 prodotti = -15% bundle), referral program 2-side (referrer +1 mese gratis, referred -20% primo mese), gift subscription (regala 3 mesi Pro a un amico con codice attivazione), team/enterprise quote requests (form lead per piano custom >€500/mese senza self-service checkout). Costo: 2 giorni install Cashier + configurazione Stripe products/prices + Billable trait + migration, 2 giorni checkout flow + Stripe Elements + SCA + trial logic, 2 giorni upgrade/downgrade swap + proration + portale Stripe integration, 1 giorno dunning + recovery emails #8331 + grace period logic, 2 giorni webhook handlers + queue jobs + idempotency + sync DB, 2 giorni admin panel + MRR/ARR dashboard + cohort analytics + export #8328, 1 giorno feature gating middleware + blade helpers + limit enforcement, 1 giorno integrazione #8322 fatturazione SDI + #8321 coupon, 1 giorno testing flussi (signup, trial, upgrade, downgrade, payment failure, dunning, cancel, resume, refund, SCA challenge, multi-item add-on). Dipendenze: `laravel/cashier-stripe` v15+, account Stripe attivo con prodotti+prezzi configurati, dominio HTTPS + webhook endpoint, #8331 mail transazionali (obbligatorio per dunning + trial reminder + welcome), #8330 audit log per tracking eventi, opzionale #8322 fatturazione elettronica per integrazione SDI, opzionale #8321 coupon per sconti promo, opzionale #8326 area cliente per UI billing self-service in-app, opzionale #8328 export per report stakeholder/commercialista.

Esempi d'uso

  • finance