- Parte 1, il concetto. Leggi prima questa. v3 è un rimodellamento, non una rinominazione: se mappi i vecchi endpoint uno a uno, combatterai contro l’API. Dieci minuti qui ti fanno risparmiare giorni dopo.
- Parte 2, l’API. Mappatura endpoint per endpoint, esempi di richieste, macchine a stati e una check-list di migrazione.
api.deprecation per gli avvisi di dismissione.
Contenuti. Parte 1: 1.1 perché esiste v3, 1.2 modello di oggetti, 1.3 prontezza per capability, 1.4 loop delle task, 1.5 movimentazione di denaro, 1.6 macchine a stati, 1.7 convenzioni, 1.8 percorso d’oro. Parte 2: 2.1 customers, 2.2 capabilities, 2.3 tasks e submissions, 2.4 accounts, 2.5 recipients e destinations, 2.6 quotes e transfers, 2.7 webhooks, 2.8 sandbox, 2.9 endpoint legacy, 2.10 ordine di migrazione, 2.11 check-list dei tranelli.
Parte 1, il concetto
1.1 Perché esiste v3
v1 e v2 hanno fatto crescere quattro modi sovrapposti per rendere un customer pronto ai pagamenti:/rails, /banks, /accounts/applications e la superficie aziendale rail-applications, ciascuna con il proprio vocabolario di stati. La raccolta di documenti (/documents, importazioni KYC, token SDK di verifica) era scollegata da ciò che effettivamente sbloccava. v3 condensa tutto in sei risorse: il customer più cinque cose che possiede:
1.2 Il modello di oggetti
Due regole strutturali da interiorizzare:- Le capabilities regolano tutto. Gli account sono provisioned sotto una capability
ready; le quote sono valutate contro una capability. L’onboarding equivale a portare areadyle capabilities che ti servono. - Le task si attaccano ovunque. Una capability, un account o un transfer in corso possono portare
openTaskIds. Ovunque le vedi, il loop è lo stesso: leggere la task, inviare le risposte, attendere la revisione, rileggere il genitore.
1.3 La prontezza è per capability, non per customer
v1 intrecciava la prontezza di/rails con una barriera KYC a livello di customer. In v3 non c’è uno stato di customer: un customer può essere pienamente utilizzabile su stablecoin_transfers mentre la sua capability sepa ha ancora task aperte. Le capabilities a conto pooled di solito passano a ready più rapidamente di quelle nominative, quindi inizia a operare su ciò che è ready invece di aspettare tutto.
Se il tuo codice v1 o v2 pilota i badge dell’interfaccia dallo stato di verifica del customer, riscrivilo:
- “Può operare su X?” diventa capability X
status == "ready". - “Deve fare qualcosa?” diventa qualsiasi task con stato
action_required(la capability tipicamente mostrarestrictedconstatusReason.resolution: "complete_tasks"). - “Stiamo aspettando Swipelux?” diventa tasks
in_review, capabilitypending.
1.4 Il loop delle task
Tutto ciò che faceva la vecchia superficie documenti e KYC ora è questo unico loop: Proprietà chiave:- Una task porta
requirements[], le singole richieste. Ognuna ha unrequirementIdper task, unakeystabile che nomina la richiesta (per esempio prova di indirizzo, deduplica la tua UI su di essa) e unarequesttipizzata che descrive esattamente quale input è desiderato (testo, data, selezione, documento, attestazione, e così via). - L’invio è soggetto a revisione: non muta mai direttamente lo stato della capability o dell’account, l’accettazione sì. Un’eccezione: le risposte
profilesi propagano al profilo del customer all’invio (2.3). Dopo l’invio, interroga la task o la risorsa genitore. taskRevision(eco dellarevisiondella task) è una protezione di concorrenza: se la task è cambiata dopo la lettura, rileggila e ricostruisci le tue risposte.absenceè una risposta di prima classe (“non ho questo perché…”), usala invece di lasciare i requirements in sospeso.
1.5 Movimentazione di denaro
Un unico flusso per payin, payout e movimenti di stablecoin. Nessun input di direzione, non dichiari mai payin contro payout. Le forme di valuta di ingresso e uscita derivano unadirection in sola lettura sulla quote e sul transfer: fiat_to_stablecoin (payin), stablecoin_to_fiat (payout) o stablecoin_move.
1.6 Una macchina a stati per risorsa
Ogni risorsa con stato ha il proprio enum, e ogni stato non felice porta un motivo strutturato. Account, application e transfer condividono la forma{ code, message, actor, retryable }: account e application la espongono come statusReason, i transfer come stateDetail. actor indica chi deve agire (customer, developer, provider, network, swipelux), retryable indica se riprovare può aiutare. Le capabilities usano { code, resolution, message }, dove resolution (complete_tasks, wait, contact_support, none) indica cosa fa avanzare la capability. I valori di code formano un catalogo aperto e solo additivo: fai branching su resolution (o actor più retryable) e tollera codici mai visti.
Gli stati che questa guida non attraversa (
rejected, suspended, disabled, failed, canceled) sono terminali o guidati dal supporto; le definizioni per risorsa si trovano nella specifica.
Transfer, in dettaglio:
1.7 Convenzioni
Regole di idempotenza da interiorizzare prima di scrivere codice:
- Riutilizzare una chiave con un corpo diverso produce
409 idempotency_conflictfinché la chiave è mantenuta (almeno 7 giorni), quindi non pianificare mai il riutilizzo di una chiave. Genera un UUID nuovo per operazione logica e persistilo con il tuo job. - Il replay copre anche gli errori: se la richiesta originale si è conclusa con un 4xx terminale, la stessa chiave più il corpo restituiscono la stessa risposta di problema.
- Due richieste concorrenti con la stessa chiave: una vince, l’altra riceve
409. Riprova quella perdente dopo la stabilizzazione della vincente; il replay restituisce la risposta originale.
1.8 Il percorso d’oro
Parte 2, l’API
2.1 Customers
Creazione, discriminata su
type (valori illustrativi, nomi di campo secondo la specifica):
- La creazione è progressiva:
{ "type": "individual" }da solo è una creazione valida. I dati mancanti non invalidano mai il customer, emergono in seguito come task di intake sulle capabilities che li richiedono. - Le aziende portano
businesspiù i dati di registrazione. Il CRUD degli azionisti di v1 si mappa sulle related parties, ampliato per coprire amministratori, dirigenti e proprietari: creale in linea alla creazione del customer (ognuna ottiene un id stabilerp_) o gestiscile tramite gli endpoint dedicati related-parties. - Nessun campo
statusdel customer, vedi 1.3. - I customer esistenti vengono conservati: i customer creati su v1 o v2 sono indirizzabili con lo stesso id sugli endpoint v3. La lettura v3 è una vista sanificata, i valori legacy che falliscono la validazione v3 tornano assenti. Dopo la tua prima scrittura v3 quella vista diventa permanente: i valori assenti non tornano da soli. Arricchisci presto, pianifica un passaggio unico che
PATCHil profilo completo dai tuoi record prima di affidarti alle letture v3. Ilmetadatadi v1 è un namespace separato e non viene riportato, reimpostalo in v3. externalIdè di prima classe e unico tra i tuoi customer su v3, per ambiente (409 duplicate_external_id). Archiviare un customer non rilascia il suoexternalId, cancellalo con PATCH prima di DELETE se intendi riutilizzarlo.DELETEè un archivio a cascata (nessun ripristino; gli id non vengono mai riutilizzati). È bloccato con409 customer_has_active_resourcespiùblockingResources[]finché esiste un account non archiviato o un transfer in corso.- Regole di merge PATCH:
nullesplicito cancella un campo nullable, gli array sostituiscono per intero (tranne le related parties in linea, che fanno upsert per id), le chiavi dimetadatasi fondono. Gli schemi completi e i filtri di lista sono nella specifica OpenAPI.
2.2 /rails, /banks, applications diventano Capabilities
- Una capability equivale a
method(ach,wire,rtp,pix,sepa,swift,spei,pse,transfers_3_0,faster_payments,sepa_instant,uaefts,card,stablecoin_transfers, e così via) piùaccountType(pooledonamed,nullper metodi non bancari) piùdirections(payinopayout). IlcapabilityIdpubblico è la coppia qualificata (sepa_pooled,ach_named) o il metodo semplice percardestablecoin_transfers. - Ogni richiesta di capability genera un’application, il record per tentativo sotto
.../capabilities/{capabilityId}/applications(più/{applicationId}/history), con i propri stati (1.6) estatusReason. È la traccia di audit di una richiesta; nel quotidiano, interroga la capability stessa. capabilities/supportedrestituisce disponibilità (available,betaodisabled), idoneità e istituzioni offerte. La selezione della banca avviene al momento della richiesta tramite l’array opzionaleinstitutions, non c’è una risorsa/banksseparata. Ometterlo (o inviare[]) seleziona tutte le istituzioni di default;isDefault: trueè un flag specifico di customer e capability, non globale. Una lista non vuota sovrascrive i default e una capability bancaria senza un default applicabile restituisce422 capability_institutions_required. Gli id di istituzione sono opachi, tollera quelli nuovi.stablecoin_transfersè auto-concessa alla creazione del customer e nasceready(quindi non viene mai richiesta né annullata).cardè solo per individuals.openTaskIdssulla capability è il tuo puntatore “cosa fare dopo”. Aperto equivale aaction_requiredoin_review, e il rollup include task condivise a livello di customer raggiunte tramite dipendenze attive.cancelfunziona solo dapendingorestrictede senza risorse bloccanti, altrimenti409 capability_not_cancelable, il cui corpo di problema elencablockingResources. Ri-richiedere dopo un’annullamento è una creazione nuova con una nuova chiave di idempotenza.- Interroga il GET. Lo stato della capability si aggiorna quando lo leggi; interroga
GET .../capabilities/{capabilityId}o iscriviti acapability.status_changed, non fare caching. - Richiedere un metodo può rendere disponibili contemporaneamente metodi correlati, tratta le capabilities come un insieme da rileggere, non come una singola riga da tracciare.
- Usa
tasks-previewper mostrare le richieste di onboarding prima di impegnarti in una richiesta. - La verifica non è una tantum: nuove task possono comparire su una capability già
ready(riverifica periodica o guidata da eventi). Mantieni il loop delle task attivo per tutto il ciclo di vita del customer, non solo durante l’onboarding.
2.3 Documenti e KYC diventano Tasks e Submissions
Nota sui nomi. Questi endpoint sono stati brevemente rilasciati come
requirements e fulfillments. Dal 2026-08-02 i nomi pubblici sono tasks e submissions. La rinominazione ha coperto solo le risorse e i percorsi degli endpoint, l’array requirements[] all’interno di una task e il suo requirementId mantengono quei nomi.GET /v3/customers/{customerId}/tasks, rispondi con POST .../tasks/{taskId}/submissions.
Attorno a quel loop:
- Archiviazione file grezzi:
POST/GET/DELETE /v3/customers/{customerId}/documents(più/{documentId}), carica una volta con la tua chiave API, quindi referenzia gli id documento nelle risposte di submission. Questo sostituisce ogni intake upload-token e direct-upload. - Letture completamente nuove:
GET /v3/tasks(inbox a livello di merchant),GET /v3/transfers/{transferId}/tasks,GET .../tasks/{taskId}/history,GET .../tasks/{taskId}/submissions(più/{submissionId}).
- Tipi di risposta:
profile,text,date,single_select,multi_select,boolean,attestation,document,resource_reference,absence. L’oggettorequestdi ogni requirement ti dice quale tipo si aspetta. - Una submission deve rispondere a ogni requirement azionabile del round corrente, con il
taskRevisionesatto che hai letto. Le submission parziali vengono rifiutate. - Le risposte
profilesi propagano: aggiornano il profilo del customer tramite il normale percorso di validazione e rivalutano immediatamente ogni capability che riferisce lo stesso lavoro di intake. Le task di intake sorelle i cui requirements sono tutti soddisfatti si chiudono automaticamente. - I requirements possono formare gruppi alternativi (
alternativeKey): invia esattamente uno del gruppo. changes_requestedincrementaremediationRounde portareviewFeedback. Rileggi la task, invia di nuovo con una nuova chiave di idempotenza.- Gli URL di verifica ospitata compaiono solo nel dettaglio della task per customer (
GET /v3/customers/{customerId}/tasks/{taskId}) e solo mentre la sessione è azionabile; le liste eGET /v3/tasks/{taskId}sono deliberatamente senza URL. - I termini di servizio sono anch’essi una task:
openTaskIdspuò includere una task concategory: "terms_of_service"la cui pagina di accettazione ospitata è collegata allo stesso modo (solo dettaglio per customer). Le submission generiche non possono accettare i termini, e l’approvazione KYC non implica mai l’accettazione dei termini. - Le task hanno ambito per capability, quindi la “stessa” richiesta (per esempio prova di indirizzo) può comparire una volta per capability. Deduplica nella tua UI per la
keydel requirement. - Nessun livello di traduzione: postare su
/v1/documentsnon sbloccherà le capabilities v3. Una volta che un customer è su v3, canalizza ogni richiesta tramite le task.
2.4 Account e wallet
Creazione, discriminata su
origin più type. I conti bancari issued prendono un singolo method; i conti bancari esterni prendono invece un array methods (inviare method lì viene rifiutato):
countrysui conti bancari issued è opzionale (di default per metodo); sui conti bancari esterni fornirlo esplicitamente. I conti wallet non portano paese affatto.settlement.accountIdè richiesto sui conti bancari issued: identifica il conto wallet issued che riceve i fondi liquidati dai depositi sul conto bancario.- I conti issued espongono
details(IBAN o routing più account o address),routingversionato (le coordinate di deposito possono ruotare, mostra sempre l’ultima lettura),fees,balances. - Reti:
polygon,ethereum,base,arbitrum,optimism,bsc,avalanche. - La barriera della capability si applica solo agli account issued: crearne uno contro una capability non pronta fallisce con un errore codificato per capability, richiedi prima la capability (2.2). Gli account esterni non necessitano di capability (né di approvazione del customer); ricevono solo la validazione dello schema della richiesta e delle coordinate bancarie.
- I conti bancari issued nascono
provisioningcondetails: null. Interroga il conto o ascoltaaccount.status_changedfino aready. DELETEarchivia, non elimina mai in modo definitivo. Gli account referenziati da transfer in corso restituiscono409 account_has_active_transfers. Riprova dopo che quei transfer raggiungono uno stato terminale.- Nuovo in v3: Rules, istruzioni permanenti su un conto wallet issued (
POST/GET /v3/customers/{customerId}/rules,GET/PATCH/DELETE .../rules/{ruleId}) che spazzano automaticamente i fondi in ingresso verso un altro account o una destination wallet. Nessun equivalente in v1 o v2.
2.5 Recipient e destination
v2 non aveva il concetto di recipient. Se sei su v2 e paghi terzi, questa è superficie nuova, non una rinominazione.
- Recipient equivale a chi:
individual(nome e cognome) obusiness(nome dell’azienda), conrelationshipobbligatorio (employee,contractor,vendor,subsidiary,merchant,customer,landlord,family,other). Recipient e destination sono solo per terze parti. Un payout a se stessi non usa affatto un recipient: mira a uno dei propri accountacc_del customer comedestinationIddella quote (2.6). - Destination equivale a dove: tipizzato per metodo,
sepa(iban, bic opzionale),achowire(routing più account),swift(coordinate complete più intermediario opzionale),spei(clabe),pse,transfers_3_0(cbu), e così via, più destination wallet. Ogni destination ha il proprio stato. Ascoltadestination.status_changed. - Le destination fiat richiedono l’
addresscompleto del recipient (via, città, codice postale, paese) prima della creazione. I pezzi mancanti falliscono con422 recipient_address_required. Le destination wallet saltano l’indirizzo ma richiedonoownershipdi primo livello (self_custodied, ocustodialcon un nome di custode). - L’accuratezza del nome del beneficiario è importante: le banche riceventi verificano il nome legale del conto. Invia nome e cognome legali esatti o il nome dell’azienda, non un soprannome di visualizzazione.
- Gli schemi dei campi di destination per metodo sono nella specifica OpenAPI.
2.6 Quote e transfer
destinationIdaccetta un idacc_(account del customer) odst_(destination di recipient). Le quote finanziate in fiat (payin) devono puntare a un accountacc_, un targetdst_significa sempre un payout (422 quote_direction_invalidaltrimenti).externalIdsu quote e transfer è un riferimento di correlazione non univoco (restituito nelle letture, filtrabile nelle liste). La regola di unicità per ambiente (2.1) si applica solo all’externalIddel customer.- Esegui una quote esattamente una volta, prima di
expiresAt. Una quote scaduta fallisce con409 quote_expired, una seconda esecuzione con409 quote_already_executed(il problema porta iltransferIdesistente). - L’annullamento del transfer non è ancora supportato:
POST .../cancelrestituisce409 transfer_not_cancelablein ogni stato. I transfercanceleddi oggi derivano dalla scadenza della finestra di funding su un payin non finanziato, non da questo endpoint. - I payin iniziano
awaiting_funds: mostraGET .../instructionsal pagatore, coordinate bancarie più codice di riferimento o memo per fiat, indirizzo di deposito per crypto. Il codice di riferimento è il modo in cui il deposito viene abbinato. Mostralo sempre. statepiùstateDetailper sottostati leggibili dalla macchina;action_requiredsignifica che una task di conformità è allegata (openTaskIds,GET .../tasks), rispondi tramite submission.- I depositi in ingresso rilevati sugli account issued compaiono come transfer con
origin: "inbound_deposit"(contro"quoted"). - I riferimenti della rete di pagamento sono consolidati sotto
references:transactionHash,traceNumber,imad,uetr,explorerUrl,returnedTransferId.
Due avvertimenti di migrazione:
- I transfer non attraversano le versioni. I transfer creati su v1 o v2 non sono leggibili da v3. La lista li omette e
GET /v3/transfers/{transferId}risponde 404. Passa prima la creazione, mantieni il percorso di lettura v1 finché quei transfer raggiungono stati terminali, poi eliminalo. - Nessuno swap di token.
stablecoin_moverichiede la stessa valuta in ingresso e in uscita: USDC verso USDT fallisce con422 recipient_destination_invalidcon un errore di campocurrency_mismatch. Stessa rete su entrambi i lati, senza bridging, e i movimenti wallet-to-wallet attualmente supportano solo la consegna a zero commissioni: una quote la cui commissione di piattaforma o developer non sia zero fallisce con422 amount_not_deliverable.
2.7 Webhook
Catalogo degli eventi:
customer.created, customer.updated, customer.archived, capability.created, capability.status_changed, application.status_changed, recipient.status_changed, destination.status_changed, account.created, account.status_changed, account.details_changed, transfer.created, transfer.state_changed, api.deprecation.
GET /v3/webhooks/portalrestituisce un URL di portale di gestione ospitato per log di consegna, retry e replay manuale.transfer.createdviene attualmente consegnato con la forma di payload legacy v1 (la busta v3 si attiva quando i webhook v1 saranno dismessi). Trattalo puramente come un indizio e fai GET del transfer; non costruire contro il suo corpo.- Gli eventi sono indizi: alla ricezione, fai GET della risorsa e agisci sulla lettura. Non costruire mai lo stato dai payload o dall’ordine degli eventi. La consegna è almeno una volta e può essere ritardata o riordinata. Deduplica per id di evento e recupera gli eventi persi con il filtro inclusivo
updatedAfterdi ogni lista. - Iscriviti a
api.deprecation, il canale automatico per le dismissioni di versione. - Nessun evento
task.*oggi: dopo l’invio, interroga la task o il suo genitore.
2.8 Sandbox
Stessa URL base; la chiave API sandbox seleziona l’ambiente.
Il sandbox v3 simula il loop di revisione end-to-end: crea una task, invia contro di essa,
review verso accepted o rejected, guarda la capability sbloccarsi. Prova la tua UX di rimedio prima della produzione. Sia le task create in sandbox sia le regolari task di intake che compaiono sulle capabilities richieste sono revisionabili in questo modo; come in produzione, non si attivano webhook di task, interroga (2.7).
2.9 Endpoint legacy senza sostituzione in v3
Questi non hanno sostituzione in v3. La maggior parte rimane invariata su v1 (mantieni le tue chiamate esistenti); due sono ritirati direttamente (vedi Disposizione):
Ogni altro endpoint pubblico v1 o v2 compare in una tabella di mappatura sopra.
2.10 Ordine di migrazione suggerito
Ogni passo può essere rilasciato indipendentemente; v1 o v2 e v3 girano fianco a fianco sulla stessa base di customer. Prova ogni passo contro la tua chiave sandbox (2.8) prima di ripeterlo in produzione.1
Idraulica
Idempotency-Key su tutte le richieste con effetti (POST, PATCH, PUT, DELETE; endpoint sandbox esenti); denaro come stringhe; helper di paginazione a cursore.2
Webhook
Registra gli endpoint v3 per evento, incluso
api.deprecation. La configurazione con endpoint singolo di v1 è una superficie separata, lasciala al suo posto; le due girano fianco a fianco fino al drenaggio del passo 9.3
Arricchimento del profilo
PATCH /v3/customers/{id} con il profilo completo che possiedi (v1 raccoglieva meno di quanto v3 espone) e reimposta metadata. Rendi questa deliberatamente la prima scrittura v3 per customer: riempie la vista sanificata prima che quella vista diventi permanente (2.1).4
Letture
Punta le letture di customer, capability e account su v3; riscrivi la logica di stato del customer secondo 1.3. Solo dopo il passo 3, le letture non arricchite tornano con i campi legacy-invalidi assenti.
5
Scritture di onboarding
Crea tramite
POST /v3/customers; richiedi capabilities invece di /rails, /banks o applications; costruisci il loop delle task (il maggior lavoro di UI totalmente nuovo, tasks-preview aiuta a mostrare le richieste in anticipo). Da questo punto, smetti di postare /v1/documents per i customer guidati da v3, non sbloccano le capabilities (2.3).6
Account
Emetti tramite v3; sposta gli import a
origin: external.7
Payout
Recipient più destination, poi quote e transfer.
8
Payin
Quote, transfer, istruzioni; continua a mostrare il codice di riferimento.
9
Drenaggio
I transfer non attraversano le versioni (2.6). Mantieni il percorso di lettura v1 o v2 e l’endpoint webhook v1 per i transfer creati lì, fai doppia lettura finché non raggiungono stati terminali, poi elimina il vecchio client e la configurazione webhook v1.
2.11 Check-list dei tranelli
- UUID nuovo per operazione logica, persistito con il tuo job e riutilizzato in retry; non riutilizzare mai una chiave con un corpo modificato (
409 idempotency_conflict). Gli endpoint sandbox sono esenti dall’header. - Arricchisci i customer esistenti (
PATCHil profilo completo, reimpostametadata, non viene riportato) prima di qualsiasi altra scrittura v3, la prima scrittura v3 rende permanente la vista sanificata. -
externalIdè unico per ambiente e non viene rilasciato dall’archiviazione, cancellalo conPATCHprima diDELETEse intendi riutilizzarlo. - Non esiste un campo
statusdel customer, deriva la prontezza per capability. -
action_requiredein_reviewsignificano entrambi una task aperta. - Le submission sono soggette a revisione (inviare non equivale a sbloccato) e devono rispondere a ogni requirement azionabile con il
taskRevisionesatto. In caso di disallineamento, rileggi e ricostruisci. - Non esiste webhook
task.*, interroga la task (o il suo genitore) dopo ogni invio. - Retry di
changes_requestedequivale a rileggere la task, nuove risposte, nuova chiave di idempotenza. - Postare su
/v1/documentsnon sblocca mai una capability v3, una volta che un customer è sulle task, canalizza ogni richiesta tramite le task. - Nuove task possono comparire su una capability già
ready, mantieni il loop delle task attivo dopo l’onboarding, non solo durante. -
canceldella capability funziona solo dapendingorestrictedsenza risorse bloccanti (409 capability_not_cancelable); ri-richiedere dopo l’annullamento è una creazione nuova con una nuova chiave di idempotenza. - La capability deve essere
readyprima di emettere account sotto di essa o quotare contro di essa. - La quote ha l’importo esattamente su un lato; nessun campo di direzione; esegui esattamente una volta prima di
expiresAt(409 quote_expiredo409 quote_already_executed). - I movimenti di stablecoin sono solo stessa valuta e stessa rete (USDC verso USDT fallisce
422); wallet-to-wallet supporta solo la consegna a zero commissioni. -
DELETEarchivia, non elimina mai in modo definitivo. La delete dell’account è bloccata dai transfer in corso (409 account_has_active_transfers); la delete del customer inoltre da qualsiasi account non archiviato (409 customer_has_active_resources,blockingResources[]li nomina). - I transfer v1 o v2 sono invisibili alle letture v3 (la lista li omette, GET 404s), fai doppia lettura fino al drenaggio, poi elimina i vecchi percorsi.
- Il
routingdi deposito e le istruzioni possono ruotare, mostra sempre l’ultimo GET e mostra sempre il codice di riferimento. - I webhook sono indizi; il GET è la verità, deduplica per id di evento, recupera gli eventi persi con
updatedAfter.