Donutwork Docs
Recurring Payments

Pagamenti Ricorrenti

Guida completa a subscription, addon seat-based, stati lifecycle, proration e calcolo rinnovi.

Pagamenti Ricorrenti e Subscription

Donutwork ti permette di gestire abbonamenti ricorrenti con un modello prevedibile:

  • definisci il catalogo piani,
  • associ il piano al cliente,
  • gestisci il pricing a seat con gli addon,
  • aggiorni il contratto nel tempo con operazioni lifecycle,
  • mantieni la compatibilita con i flussi legacy gia in uso.

Questa pagina spiega il comportamento reale del sistema, con esempi pratici.

Cosa Contiene Una Subscription

Cadenza Rinnovo

Cicli a giorni o mesi (`renewal_days` / `renewal_months`) con data prossimo rinnovo (`next_renew`).

Gestione Trial

Periodo di prova opzionale prima del primo ciclo a pagamento.

Prezzi Seat + Addon

Il seat-based usa `addons[].quantity` (numero seat) e `addons[].price` (costo unitario seat).

Sconti e Imposte

Sconti addon, sconto globale, carryover credit e tasse sono applicati in ordine deterministico.


Come Viene Calcolato Il Prossimo Rinnovo

A ogni rinnovo, Donutwork calcola l'importo in questo ordine:

  1. Prezzo base del piano.
  2. Importi addon (price * quantity) per addon con quantita attiva.
  3. Sconto addon se configurato e non scaduto (discount_until).
  4. Sconto globale (fixed o percentage, se attivo).
  5. Credito carryover (carryover_credit) da downgrade/proration precedenti.
  6. Imposte del profilo fiscale associato.

Formula (semplificata)

net_subtotal = base + addons_dopo_sconti_addon
net_post_sconto_globale = net_subtotal - sconto_globale
net_due = max(0, net_post_sconto_globale - carryover_credit_usato)
vat_due = net_due * aliquota_iva
gross_due = net_due + vat_due

Esempio

  • Piano base: 99.00
  • Addon seat: 12.00 x 8 seat = 96.00
  • Sconto addon 10% attivo => addon effettivo 86.40
  • Subtotale netto = 185.40
  • Sconto globale 15% => -27.81
  • Credito carryover applicato: 20.00
  • Netto dovuto = 137.59
  • IVA 22% = 30.27
  • Totale lordo = 167.86

Modello Seat-Based (Importante)

Il pricing a seat non usa uno schema separato. Nel modello attuale i seat sono addon:

  • costo seat: addons[].price
  • numero seat: addons[].quantity
  • importo seat: incluso automaticamente nel rinnovo

Questo approccio e stabile e retrocompatibile con i flussi esistenti.


Stati Lifecycle (Significato Billing)

StatoAddebitabileSignificato
activeSiFatturazione ricorrente normale.
trialingIn genere noFase trial prima del primo rinnovo pagato.
past_dueCondizionaleStato di recupero dopo pagamento fallito.
pausedNoBilling in pausa. Nessun addebito durante la pausa.
cancel_pendingNessun nuovo cicloChiusura programmata a fine periodo (annullabile prima del boundary).
cancelledNoSubscription chiusa.

Semantica Della Pausa

La pausa non genera arretrati automatici. Se un abbonamento viene riattivato dopo 2 mesi, i mesi in pausa non vengono addebitati retroattivamente. Il ciclo riparte dalla logica di resume.

Grafico Lifecycle


Operazioni Lifecycle Supportate

Tutte additive (nessuna rimozione route legacy):

OperazioneImmediataFine PeriodoProrationNote
PauseSiNoNoSospende i rinnovi durante la pausa.
ResumeSiNoNoresume_at opzionale per definire il nuovo boundary.
Change PlanSiSiOpzionaleSupporta upgrade e downgrade.
Change AddonsSiSiOpzionaleInclude aggiornamento quantita seat.
Cancel At Period EndSi (flag)Effetto a boundaryNoComportamento compatibile con legacy.
Undo Cancel At Period EndSiNoNoRipristina il piano attivo prima del boundary.
Next Renewal PreviewRead-onlyN/AN/AMostra breakdown completo del prossimo addebito.
Amendment HistoryN/AN/AN/AStorico completo modifiche lifecycle.

Esempi API

Pianificare Cambio Seat A Fine Periodo

{
  "subscription": {
    "action": "change_addons",
    "when": "period_end",
    "proration": false,
    "addons": [
      {
        "name": "workspace_seat",
        "quantity": 25,
        "price": 12
      }
    ]
  }
}

Anteprima Prossimo Rinnovo (estratto risposta)

{
  "status": "success",
  "data": {
    "subscription_id": "sub_abc123",
    "next_renewal": "2026-07-01",
    "billable": true,
    "pricing": {
      "items": [
        { "service": "Subscription Base: Pro", "net": 99, "tax_rate": 22, "tax": 21.78, "total": 120.78 },
        { "service": "Addon: workspace_seat (Qty: 25)", "net": 300, "tax_rate": 22, "tax": 66, "total": 366 }
      ],
      "net_due": 399,
      "vat_due": 87.78,
      "gross_due": 486.78
    }
  }
}

FAQ API (Combinazioni Comuni)

Le combinazioni sotto fanno riferimento alle route Customer API documentate in /it/docs/api/customer#subscription-management.

Come posso fare l'upgrade di un piano?

Usa change-plan con applicazione immediata.

{
  "lifecycle": {
    "plan_id": "PLAN_ENTERPRISE_V3",
    "when": "immediate",
    "proration": true
  }
}
  • Endpoint: PUT /customers/{customerId}/subscriptions/{subscriptionId}/lifecycle/change-plan.json
  • Se il delta proration e positivo, viene tentato un addebito immediato.
  • Se l'addebito immediato fallisce, la modifica non viene applicata.

Come posso fare il downgrade di un piano?

Usa sempre change-plan, puntando a un piano con prezzo inferiore.

{
  "lifecycle": {
    "plan_id": "PLAN_STARTER_V1",
    "when": "immediate",
    "proration": true
  }
}
  • Endpoint: PUT /customers/{customerId}/subscriptions/{subscriptionId}/lifecycle/change-plan.json
  • Con delta negativo, il sistema genera credito in carryover_credit.
  • Il credito viene scalato sui rinnovi successivi prima di nuovi addebiti.

Come posso pianificare upgrade o downgrade dal prossimo rinnovo?

{
  "lifecycle": {
    "plan_id": "PLAN_PRO_V2",
    "when": "period_end",
    "proration": false
  }
}
  • Endpoint: PUT /customers/{customerId}/subscriptions/{subscriptionId}/lifecycle/change-plan.json
  • Nessun addebito immediato: la modifica si applica al boundary di rinnovo.

Come posso modificare la quantità degli addon (seat inclusi)?

{
  "lifecycle": {
    "addons": [
      { "element": "workspace_seat", "quantity": 25 }
    ],
    "when": "immediate",
    "proration": true
  }
}
  • Endpoint: PUT /customers/{customerId}/subscriptions/{subscriptionId}/lifecycle/change-addons.json
  • Nel modello seat-based, il numero seat e addons[].quantity.

Come posso pianificare una modifica addon a fine periodo?

{
  "lifecycle": {
    "addons": [
      { "element": "workspace_seat", "quantity": 40 }
    ],
    "when": "period_end",
    "proration": false
  }
}
  • Endpoint: PUT /customers/{customerId}/subscriptions/{subscriptionId}/lifecycle/change-addons.json
  • Utile per cambi commerciali con decorrenza dal prossimo ciclo.

Come funziona pausa e ripresa dopo mesi?

  • Metti in pausa: PUT .../lifecycle/pause.json
  • Riprendi: PUT .../lifecycle/resume.json (opzionale resume_at)

Esempio reale:

  • pausa il 1 maggio 2026
  • riprendi il 1 luglio 2026
  • non vengono addebitati retroattivamente maggio/giugno; il ciclo riparte dalla logica di resume.

Posso annullare una cancellazione gia impostata a fine periodo?

Sì:

  • imposta cancellazione: PUT .../lifecycle/cancel-at-period-end.json
  • annulla cancellazione: PUT .../lifecycle/undo-cancel-at-period-end.json

Se annulli prima del boundary, la subscription torna operativa in stato active.

Come posso vedere prima l'impatto economico senza applicare modifiche?

Usa la preview lifecycle (no mutation):

{
  "lifecycle": {
    "action": "change_addons",
    "addons": [
      { "element": "workspace_seat", "quantity": 30 }
    ]
  }
}
  • Endpoint: POST /customers/{customerId}/subscriptions/{subscriptionId}/lifecycle/preview.json
  • Risposta con old_due, new_due, delta, direction.

Come gestisco retry sicuri lato integrazione?

Usa lifecycle.idempotency_key nelle chiamate mutative. In caso di retry, eviti doppie applicazioni della stessa operazione.

Dove trovo lo storico completo delle modifiche?

Usa amendment history:

  • Endpoint: GET /customers/{customerId}/subscriptions/{subscriptionId}/amendments.json
  • Include azione, quando (immediate/period_end), before/after, metadati proration.

Tabella rapida combinazioni

ObiettivoEndpointwhenproration
Upgrade piano subito.../change-plan.jsonimmediatetrue
Downgrade piano subito.../change-plan.jsonimmediatetrue
Cambio piano da prossimo ciclo.../change-plan.jsonperiod_endfalse
Aumento/diminuzione seat subito.../change-addons.jsonimmediatetrue
Cambio seat da prossimo ciclo.../change-addons.jsonperiod_endfalse
Pausa servizio.../pause.jsonN/AN/A
Ripresa servizio.../resume.jsonN/AN/A
Cancella a fine periodo.../cancel-at-period-end.jsonboundaryN/A
Annulla cancellazione.../undo-cancel-at-period-end.jsonimmediateN/A
Simulazione impatto.../preview.jsonN/AN/A
Storico modifiche.../amendments.jsonN/AN/A

Scenari Pratici

1) Pausa 2 Mesi, Poi Ripresa

  • Pausa il 1 maggio 2026
  • Riprendi il 1 luglio 2026
  • Risultato: nessun addebito arretrato per maggio/giugno, rinnovo riallineato alla ripresa.

2) Upgrade Mid-Cycle

  • Il cliente passa da 10 a 20 seat con modifica immediata.
  • Delta proration positivo => addebito immediato di conguaglio.

3) Downgrade Mid-Cycle

  • Il cliente riduce seat durante il periodo.
  • Delta negativo => credito salvato in carryover_credit.
  • Il credito viene consumato ai rinnovi successivi prima di nuovi addebiti.

4) Cancellazione In Attesa + Ripristino

  • Cliente richiede cancellazione a fine periodo.
  • Stato passa a cancel_pending.
  • Se cambia idea prima del boundary, undo riporta la subscription in stato attivo.

Backward Compatibility (No Break Changes)

I flussi panel/API legacy restano validi. Le nuove capability lifecycle sono opt-in.

AreaComportamento LegacyComportamento Attuale
Attach/detach subscriptionSupportatoAncora supportato
Route legacy update addonSupportataAncora supportata
Campo status legacyPresenteAncora presente
Modello seatAddon quantityStesso modello ufficiale
Integrazioni esistentiStabiliAdozione lifecycle progressiva

Strategia Di Adozione

Se sei gia integrato con le route legacy, puoi lasciarle invariate e attivare gradualmente le route lifecycle dove ti servono pausa/resume, proration e storico amendment.


Checklist Consigliata

Modella I Seat Con Addon

Configura costo unitario seat sull'addon e aggiorna quantity per il numero seat.

Usa Scheduled Change

Per variazioni commerciali future, preferisci `period_end`.

Aumenta Trasparenza

Usa renewal preview e amendment history per supporto e audit.


Documentazione Correlata

On this page