Vai al contenuto
Torna a Blog

Settlement, payout e riconciliazione: pattern di reliability per marketplace e DTC

di Federico 5 min di lettura
  • finance
  • reconciliation
  • automation

Quando un marketplace o un brand DTC inizia a generare volumi significativi, la finance non si rompe per un bug clamoroso. Si rompe per accumulo: un webhook perso qui, un cambio di tasso non aggiornato lì, un payout che non torna quadrato con l’estratto Shopify a fine mese. Il problema non sono i singoli errori; è il fatto che, senza i pattern giusti, diventano invisibili finché qualcuno non apre Excel con un caffè freddo a fianco.

In questo articolo metto in fila i pattern che usiamo per rendere i flussi di settlement e payout affidabili: come si gestiscono i webhook con un outbox, come si firmano e si ritentano, come si tengono allineati i tassi di cambio multi-market, e come si riconciliano i payout Shopify con il sistema contabile. Non è una lista di tool, è un insieme di scelte di architettura.

Il contesto: cosa intendiamo per “settlement”

In un marketplace di rivendita in conto vendita, ogni vendita non è “fattura ed esci”. C’è un periodo provvisorio in cui l’incasso è bloccato (provisional), poi diventa esigibile (eligible) dopo una finestra di reso, e infine viene pagato al venditore o al brand. Nei flussi DTC più complessi succede qualcosa di simile: payout aggregati periodici da Shopify, commissioni della piattaforma, tasse, rimborsi che rientrano in finestre diverse. La complessità non è la transizione di stato in sé — è tenerla coerente tra database operativo, pagamenti reali e contabilità.

Pattern 1: il transactional outbox per i webhook

Il primo errore classico è inviare webhook direttamente da dentro la transazione che aggiorna lo stato. Se il consumer è lento o down, la tua transazione finisce in timeout. Se la rilanci, mandi l’evento due volte. Se la rollbacchi, hai aggiornato lo stato ma non hai notificato nessuno.

Il pattern outbox separa le due cose. Quando un settlement passa da provisional a eligible, dentro la stessa transazione scrivi due cose: la riga aggiornata e una riga su webhook_outbox con payload, destinazione e stato pending. La transazione committa o rollbacca atomicamente — coerenza garantita.

Un drainer separato — nel nostro caso una Edge Function Supabase schedulata via pg_cron ogni minuto — legge le righe pending, le firma con HMAC, le invia, gestisce retry con backoff esponenziale, e marca lo stato. Se il destinatario è giù per due ore, gli eventi non si perdono: si accumulano nell’outbox e ripartono quando torna su.

Esempio concreto: per un cliente del settore resale luxury, il webhook drainer fa retry con backoff 1m → 5m → 15m → 1h → 6h → 24h. Dopo 6 tentativi falliti, l’evento finisce in failed con alert su Slack. Risultato misurato negli ultimi 30 giorni: 99.7% di delivery al primo tentativo, 100% dopo retry. Zero eventi persi.

Pattern 2: HMAC per firmare ogni payload

Tutti i webhook in uscita sono firmati con HMAC-SHA256 usando un secret condiviso. L’header standard è X-Signature: sha256=<hex> più un X-Timestamp per prevenire replay attack. Il consumer verifica firma e timestamp (rifiutando eventi più vecchi di 5 minuti) prima di accettare il payload.

È una riga di codice in più che paga moltissimo. Senza HMAC, chiunque scopra l’URL del webhook può iniettare eventi finti. Con HMAC, l’autenticità è verificabile end-to-end senza bisogno di IP allowlist fragili.

Pattern 3: FX rates multi-market con refresh schedulato

Se vendi in più mercati con valute diverse, il pricing non può chiamare l’API FX in tempo reale a ogni request: latency, rate limit, costo. La soluzione è una tabella fx_rates con timestamp, refresh schedulato (per esempio ogni 6 ore via cron), e ogni settlement che “stampa” il rate usato al momento della transazione.

Questo dettaglio sembra banale ma è cruciale per la riconciliazione: quando sei sei mesi dopo e il venditore contesta un payout, devi poter dimostrare che hai usato EUR/USD = 1.0823 alle 14:32 del 12 marzo, non il rate di oggi. Senza snapshot, ogni contestazione diventa una caccia al tesoro.

Pattern 4: backfill e force-create per i casi limite

In produzione c’è sempre la giornata in cui qualcuno deve creare un payout retroattivo, importare 8.000 righe da un CSV legacy, o recuperare settlement che si sono persi durante una migrazione. Avere endpoint dedicati — non comandi SQL a mano — fa la differenza.

Per il backfill di payout mancanti usiamo una RPC Postgres che accetta un range temporale, ricostruisce gli stati a partire dagli ordini Shopify storici, e scrive in una transazione unica con un dry-run obbligatorio prima del commit. Il force-create payout è invece un’azione UI riservata a ruoli admin che logga ogni esecuzione su una tabella audit. Risultato: zero touch del database da console, full audit trail.

Pattern 5: riconciliazione Shopify ↔ contabilità

Il momento della verità è quando l’estratto Shopify Payouts arriva e devi confrontarlo riga per riga con la contabilità. La maggior parte dei team lo fa in Excel a fine mese. Il pattern che funziona:

  1. Edge Function dedicata che pulla da Shopify products, customers, orders, inventory, transactions, payouts, balance ogni 15 minuti.
  2. Tabella payout_reconciliation con join automatico per payout_id tra Shopify e settlement interni.
  3. Pagina dedicata che mostra solo i delta: payout senza match, importi non coerenti, ordini 100% gift-card che richiedono trattamento speciale.

Con questo setup, la riconciliazione di fine mese passa da una giornata di lavoro a un’ora di review delle eccezioni. La metrica realistica che ho visto su un cliente medio (circa 800 ordini/mese): drift di riconciliazione passato da 1.4% a 0.05%, con il tempo finance ridotto del 70% sull’attività mensile.

Quando ha senso costruire tutto questo

Non tutti i progetti richiedono outbox, HMAC e snapshot FX. Se gestisci 50 ordini al mese, va benissimo un Make scenario con un singolo retry. La soglia indicativa: quando inizi a vedere richieste di contestazione sui payout, o quando la riconciliazione mensile finance supera le 4 ore, è il momento di investire in questi pattern.

Quello che resta valido in ogni caso: separare scrittura di stato da side-effect (outbox), firmare ogni payload in uscita (HMAC), tenere uno snapshot dei tassi nel momento della transazione, avere endpoint di backfill testati prima che servano davvero. Sono i quattro pilastri che reggono qualunque flusso di settlement sopra il rumore di fondo.

Se stai costruendo un marketplace o un DTC che si sta complicando sul lato finance, e vuoi capire quali di questi pattern hanno senso per il tuo volume, possiamo farne un sanity check insieme. Spesso bastano 2-3 cambi mirati per togliere il 90% del rumore mensile.

Hai un processo simile da automatizzare?

Raccontaci il tuo flusso: ti diciamo con onestà se e dove l'automazione ha senso.