Safata d'esdeveniments d'integració
Per què un cobrament no va acabar en factura — els motius de descart tipats, quins t'avisen, quins aparquen l'esdeveniment perquè el puguis reprocessar, i com funciona la finestra de retenció de 30 dies.
Aquesta safata també cobreix comandes i devolucions de WooCommerce i Shopify. Filtra per proveïdor, consulta discard_reason i reprocessa un esdeveniment retingut només quan is_replayable ho permeti. Consulta el flux de botigues.
Una passarel·la de pagament envia a Factuarea un esdeveniment per tot el que passa al teu compte: un cobrament amb èxit, una devolució emesa, un cicle de subscripció cobrat, un payout que arriba. La majoria d'aquests esdeveniments produeixen alguna cosa — una factura, una rectificativa, un registre de pagament. Alguns no produeixen res, i quan això passa la pregunta interessant sempre és la mateixa: per què aquest cobrament no va acabar en factura?
La safata d'esdeveniments d'integració la respon. Cada esdeveniment que Factuarea rep queda registrat amb allò que va produir i, quan no va produir res, amb un motiu de descart tipat sortit d'un catàleg tancat. Sense endevinar als logs, sense obrir un tiquet de suport: el motiu és un valor pel qual pots filtrar i, en els motius sobre els quals pots actuar, ve amb el pas següent i, de vegades, amb la possibilitat de reprocessar l'esdeveniment.
La safata és agnòstica de la passarel·la. Registra esdeveniments de qualsevol integració que escrigui historial — incloses les passarel·les que encara no estan alliberades i els esdeveniments històrics d'una que es retiri — perquè amagar aquestes files et deixaria sense explicació per a cobraments que no es van facturar mai.
L'exposen tres endpoints:
| Operació | Endpoint | Scope |
|---|---|---|
| Llistar esdeveniments | GET /v1/integrations/events | integration_events:read |
| Obtenir un esdeveniment | GET /v1/integrations/events/{event} | integration_events:read |
| Reprocessar un esdeveniment aparcat | POST /v1/integrations/events/{event}/replay | integration_events:write |
La mateixa superfície existeix com a tools MCP — list_integrations_events,
get_integrations_event i replay_integrations_event — amb els mateixos scopes.
Recórrer la safata
Del més recent al més antic, acotat a l'empresa autenticada. Paginació per cursor
amb limit (d'1 a 100; 25 per defecte) i starting_after:
curl -G https://api.factuarea.com/v1/integrations/events \
-H "Authorization: Bearer $FACTUAREA_API_KEY" \
--data-urlencode "provider=stripe" \
--data-urlencode "status=skipped" \
--data-urlencode "limit=50"{
"data": [
{
"id": "0192f3a4-7b2c-7c1d-9e8f-1a2b3c4d5e6f",
"object": "integration_event",
"provider": "stripe",
"event_type": "invoice.paid",
"direction": "inbound",
"status": "skipped",
"discard_reason": "subscription_autoinvoicing_disabled",
"discard_reason_label": "Auto-facturación de suscripciones desactivada",
"is_actionable": true,
"is_replayable": true,
"error_message": null,
"duration_ms": 412,
"created_at": "2026-07-14T09:31:07Z"
}
],
"has_more": true,
"next_cursor": "84120"
}Tracta next_cursor com a opac: en aquest llistat és una cadena numèrica, no
un UUID v7 com els cursors dels llistats de documents. Torna'l tal qual a
starting_after.
discard_reason_label arriba sempre en castellà, l'idioma de la interfície
del producte, sigui quin sigui l'idioma de la teva integració. Si construeixes un
panell en un altre idioma, basa els teus propis textos en discard_reason —
aquest valor és l'identificador estable i tancat.
Filtres
| Filtre | Valors | Notes |
|---|---|---|
provider | stripe, gocardless, monei, slack, teams, a3, norma43, norma19, ubl, woocommerce, shopify, prestashop | Conjunt tancat |
status | success, skipped, failure | Conjunt tancat |
event_type | text lliure, coincidència exacta, fins a 100 caràcters | No és un enum — vegeu més avall |
discard_reason | un dels motius de descart documentats | Conjunt tancat |
is_parked | true / false | Vegeu la nota de més avall |
created_at[gte], created_at[lte] | ISO 8601 | Finestra inclusiva |
discard_reason és l'eix tancat; event_type no és un enum. La columna
event_type barreja a propòsit dues convencions: les branques instrumentades més
tard guarden el tipus cru de la passarel·la (charge.refunded), mentre que les
preexistents conserven el seu propi valor semàntic (autoinvoice.*). Busca'l per
coincidència exacta quan sàpigues què persegueixes, però no el modelis mai com un
conjunt tancat — estaries modelant una cosa que la columna no garanteix.
is_parked=false no és el mateix que ometre el paràmetre. El primer exclou
els esdeveniments aparcats; el segon no exclou res.
Un valor fora del seu catàleg retorna 422, i un paràmetre de consulta
desconegut retorna 400 parameter_unknown en comptes d'ignorar-se en silenci
— un filtre que cau sense avisar et lliura una pàgina que creus acotada i no ho
està.
El catàleg de motius de descart
Els motius tipats cobreixen el processament de passarel·les i botigues. passarel·les. Cadascun declara dues decisions de negoci que no són banderes decoratives:
- Accionable — pot fer-hi alguna cosa el titular del compte? Només els motius accionables avisen. Avisar algú d'un descart que no pot resoldre li ensenya a ignorar la safata, i així és com es perd l'avís que sí que importava.
- Aparcat — reprocessar el mateix contingut podria donar un altre resultat? Només els esdeveniments aparcats guarden el seu contingut xifrat i admeten un reprocessament.
La regla que hi ha darrere de la columna d'aparcament: un esdeveniment s'aparca quan el descart el va causar un estat extern que pots canviar (un ajust apagat, un compte connectat que es va desvincular, una moneda encara sense tipus de canvi). No s'aparca quan la causa és el contingut del mateix esdeveniment (mal format, duplicat, de tipus no cobert, import zero, cicle ja facturat) — reprocessar-lo prendria exactament la mateixa branca i només escriuria una segona fila. D'aquí l'invariant: tot motiu aparcat és accionable..
| Motiu | Què el provoca | Accionable | Aparcat | Què fer |
|---|---|---|---|---|
event_not_normalizable | Esdeveniment mal format, o d'un tipus que no es pot interpretar | No | No | Res — no pots arreglar el payload de la passarel·la |
duplicate_redelivery | L'esdeveniment ja es va processar; el seu efecte existeix | No | No | Res — reprocessar-lo seria un no-op per deduplicació |
connected_account_missing | El webhook està mal configurat a la passarel·la: l'esdeveniment no diu a quin compte pertany | Sí | No | Revisa a la passarel·la que el webhook s'envia des del compte que tens vinculat a Factuarea |
connected_account_unknown | El compte existeix a la passarel·la però no està vinculat a Factuarea | Sí | Sí | Torna a vincular aquest compte de la passarel·la i reprocessa l'esdeveniment |
spontaneous_payment_missing_id | El cobrament no porta id, així que no hi ha clau d'idempotència | No | No | Res — reprocessar-lo duplicaria o tornaria a fallar |
autoinvoicing_disabled | L'auto-facturació està desactivada per a aquesta integració | Sí | Sí | Activa l'auto-facturació i reprocessa, o crea la factura a mà — mai les dues coses |
unsupported_currency | El tipus de canvi del Banc Central Europeu del dia encara no està disponible | Sí | Sí | Reprocessa l'esdeveniment més tard, quan el tipus oficial del dia estigui publicat |
refund_without_items | La devolució no porta reemborsaments individuals que rectificar | No | No | Res — no hi ha res a emetre |
refund_autoinvoicing_disabled | La rectificativa automàtica està desactivada per a aquesta integració | Sí | Sí | Activa la rectificativa automàtica i reprocessa, o emet la rectificativa a mà — mai les dues coses |
subscription_missing_invoice_id | El cicle cobrat no té identificador de factura | Sí | No | Crea a mà la factura d'aquest cicle; reprocessar donaria el mateix resultat |
subscription_proration_review | S'ha cobrat un prorrateig solt i exigeix una decisió humana | Sí | No | Comprova l'import del prorrateig a la passarel·la i emet la factura a mà |
subscription_not_a_cycle | La factura de la passarel·la no correspon a un cicle de subscripció facturable | No | No | Res — el descart és correcte |
subscription_trial_skipped | Import zero o negatiu (prova o crèdit): no hi ha base imposable | No | No | Res — no hi ha res a facturar |
subscription_autoinvoicing_disabled | L'auto-facturació de subscripcions està desactivada | Sí | Sí | Activa l'auto-facturació de subscripcions i reprocessa l'esdeveniment |
subscription_already_invoiced | El cicle ja té la seva factura | No | No | Res — reprocessar-lo seria un no-op per idempotència |
payout_missing_id | El payout no porta identificador | No | No | Res — no es pot conciliar ni reprocessar amb seguretat |
payout_connected_account_missing | El compte connectat del payout no està vinculat | Sí | Sí | Vincula el compte connectat i reprocessa l'esdeveniment |
payment_failed | El cobrament ha fallat a la passarel·la | No | No | Res — no hi ha res a emetre ni a reintentar |
event_type_not_covered | Tipus d'esdeveniment fora de l'abast del producte | No | No | Res — reprocessar-lo tornaria a no fer res |
checkout_lines_retrieve_failed | Degradació, no descart: la factura sí que es va emetre, amb una única línia | No | No | Res a reprocessar; revisa les línies de la factura si t'importa el desglossament |
reversal_payment_not_found | No hi ha cap cobrament per anul·lar. Revisa el cobrament original i corregeix-lo manualment si correspon. | Sí | No | Segueix l’actuació indicada en aquesta fila. |
reversal_already_applied | El cobrament ja estava anul·lat; no requereix cap altra acció. | No | No | Sense reprocessament manual. |
dispute_in_progress | La disputa continua en curs; encara no hi ha cap actuació monetària. | No | No | Sense reprocessament manual. |
dispute_resolved | Si els diners tornen, registra un cobrament nou; el cobrament anul·lat no es reobre. | Sí | No | Segueix l’actuació indicada en aquesta fila. |
test_mode_event | El payload del proveïdor declara mode test; no correspon cap factura real. | No | No | Sense reprocessament manual. |
order_event_not_covered | Tipus d’esdeveniment de comanda no admès; reprocessar el mateix payload no afegeix suport. | No | No | Sense reprocessament manual. |
store_not_found | No es resol la botiga de l’esdeveniment; revisa la connexió del proveïdor i l’associació de botiga. | No | No | Sense reprocessament manual. |
store_environment_test | La botiga està configurada com a test; és el resultat previst. | No | No | Sense reprocessament manual. |
refund_before_order | La devolució va arribar abans. La gestiona el búfer d’ordre; no creïs cap reprocessament manual paral·lel. | No | No | Sense reprocessament manual. |
refund_reason_unmapped | Tria el motiu de rectificació i emet manualment. | Sí | No | Segueix l’actuació indicada en aquesta fila. |
recurring_invoice_overlap | Tria una font de facturació. Per facturar la comanda, pausa la recurrent solapada abans de reprocessar. | Sí | Sí | Segueix l’actuació indicada en aquesta fila. |
series_date_clamped | La factura es va emetre amb la data ajustada a la sèrie; no hi ha res per reprocessar. | No | No | Sense reprocessament manual. |
store_autoinvoicing_disabled | Activa la facturació automàtica de la botiga i reprocessa, o factura manualment; tria una via. | Sí | Sí | Segueix l’actuació indicada en aquesta fila. |
vat_residual_out_of_tolerance | Els imports de la comanda no quadren amb el cobrament; el mateix contingut tornaria a fallar. | No | No | Sense reprocessament manual. |
simplified_absolute_limit_exceeded | Demana el NIF al comprador i emet una factura completa manualment. | Sí | No | Segueix l’actuació indicada en aquesta fila. |
simplified_threshold_exceeded_without_recipient | Revisa el llindar de botiga dins del límit permès per a la teva activitat i reprocessa si correspon. | Sí | Sí | Segueix l’actuació indicada en aquesta fila. |
store_requires_tax_id | Revisa l’exigència de NIF de la botiga o obtén l’identificador per a les properes comandes. | Sí | Sí | Segueix l’actuació indicada en aquesta fila. |
order_line_amount_exceeds_column | L’import de línia supera els límits admesos; el mateix payload no es pot reprocessar amb èxit. | No | No | Sense reprocessament manual. |
order_status_unknown | Revisa el complement que produeix aquest estat i factura manualment quan correspongui. | Sí | No | Segueix l’actuació indicada en aquesta fila. |
refund_not_settled | La devolució no està liquidada; espera l’estat definitiu del proveïdor. | No | No | Sense reprocessament manual. |
protected_customer_data_unavailable | No estaven disponibles els camps del comprador perquè Shopify no ha concedit el permís necessari a l’app de Factuarea. | Sí | No | No reprocessis els camps buits desats. Quan Shopify concedeixi l’accés, una lectura nova del proveïdor recuperarà les comandes pendents. Si una comanda no pot esperar, emet-ne la factura a mà. |
Els motius informatius retornen recommended_action: null; l’API no inventa cap actuació quan no cal.
«O l'una, o l'altra» vol dir una, no les dues. Dos motius t'ofereixen dues sortides — activar l'ajust i reprocessar, o emetre el document a mà. Són excloents. La idempotència del reprocessament va per la identitat del cobrament i només reconeix els documents emesos per aquesta mateixa via automàtica, així que una factura que hagis creat a mà no el frena. Fer les dues coses deixa el mateix cobrament amb dues factures, cadascuna numerada a la seva sèrie i donada d'alta a VeriFactu — un dany fiscal que només es desfà amb una factura rectificativa.
Avisos: només el que pots arreglar
Un descart accionable avisa els administradors del compte. Un d'informatiu no avisa mai.
L'avís porta throttling: si ja existeix un avís sense llegir de la mateixa empresa, la mateixa passarel·la i el mateix motiu dins de les últimes 24 hores, no se'n crea un segon — un webhook mal configurat dispara centenars d'esdeveniments idèntics. La condició és sense llegir a propòsit: un cop l'has llegit, si continuen arribant descarts, el següent sí que avisa. Això no és soroll, vol dir que la incidència segueix viva.
L'aparcament i la finestra de 30 dies
Quan un motiu és aparcable, Factuarea guarda l'esdeveniment cru xifrat en repòs, per poder reprocessar-lo més tard. Aquest contingut no es retorna mai per l'API — ni al llistat, ni al detall. Conté dades personals dels teus clients finals i dades de pagament, i existeix per a exactament un propòsit: fer possible el reprocessament.
El contingut es purga als 30 dies d'aparcar-se l'esdeveniment. La fila
sobreviu: el seu motiu, el seu estat, la seva data i la seva marca is_parked
segueixen a la teva safata indefinidament, perquè el registre que un cobrament no
va produir factura és historial que pots necessitar molt després que el contingut
caduqui.
Un esdeveniment que segueix amb is_parked: true però ja no és
is_replayable vol dir exactament una cosa: la finestra de retenció s'ha
esgotat. La marca es deriva de si el contingut encara hi és, així que canvia
sola el dia que corre la purga. Un reprocessament intentat després retorna 422
amb el subcodi integration_event_payload_purged.
El detall: què fer a continuació
L'endpoint de detall retorna tot el del llistat, més recommended_action: una
frase en imperatiu amb el pas següent per a aquell motiu concret, o null quan el
motiu és informatiu.
curl https://api.factuarea.com/v1/integrations/events/0192f3a4-7b2c-7c1d-9e8f-1a2b3c4d5e6f \
-H "Authorization: Bearer $FACTUAREA_API_KEY"La frase distingeix a propòsit els motius reproduïbles («… i reprocessa l'esdeveniment») dels que no ho són («… emet-la a mà»), de manera que mai no t'apunta a una operació que respondria 422.
Un esdeveniment d'una altra empresa i un esdeveniment que no existeix retornen el
mateix 404 resource_not_found. L'endpoint no revela mai si un id existeix en
un altre lloc.
Reprocessar un esdeveniment aparcat
Torna a processar un esdeveniment de la passarel·la que va quedar aparcat, un cop ja no hi és la causa que li va impedir produir el seu efecte — has tornat a activar l'auto-facturació, has tornat a vincular el compte connectat, ja hi ha disponible el tipus de canvi oficial del dia.
Aquesta acció pot tenir conseqüències fiscals reals. Si la causa del descart
ja està resolta, el reprocessament pot emetre una factura real, amb el seu
número de sèrie i la seva alta a VeriFactu. No és un reintent innocu:
confirma-ho amb el titular del compte abans de cridar-lo. Per això porta el seu
propi scope d'escriptura, integration_events:write, en comptes del scope de
lectura de la safata — una credencial de només lectura no ha de poder facturar
mai.
curl -X POST https://api.factuarea.com/v1/integrations/events/0192f3a4-7b2c-7c1d-9e8f-1a2b3c4d5e6f/replay \
-H "Authorization: Bearer $FACTUAREA_API_KEY"Quatre propietats d'aquesta operació importen més que la seva firma:
- No duplica factures. El reprocessament passa pel mateixíssim control d'idempotència que l'intent original, així que si aquell cobrament ja va produir una factura, el job s'atura sol i no crea res.
- És asíncron.
202vol dir acceptat i encuat, no completat. El cos retorna l'esdeveniment tal com està ara — el seuis_replayablesegueix senttrue—, no el resultat del reintent. El resultat apareix com un esdeveniment nou a la safata, així que consultaGET /v1/integrations/eventsper veure com ha acabat. - Si la causa segueix present, l'esdeveniment es descarta un altre cop i es registra de nou. És correcte, i és observable.
- No admet entrada. Qualsevol paràmetre de consulta o clau del cos retorna
400
parameter_unknownen comptes d'ignorar-se. Enviar-ne un vol dir que et penses que estàs configurant alguna cosa del reintent — un mode, una sèrie, una data — que aquesta operació no suporta, i acceptar-ho en silenci confirmaria aquella expectativa falsa sobre una acció que pot emetre una factura. Un cos buit, o directament cap cos, és el cas normal.
Quan es rebutja un reprocessament
is_replayable: true és el contracte: quan val true, el reprocessament no
respon 422. És la conjunció de tres condicions — l'esdeveniment està aparcat,
encara conserva el seu contingut i el seu motiu admet reprocessament —, avaluades
en aquest mateix ordre pel mateix handler que guarda el reprocessament. Això és el
que et permet oferir un botó de reintent sense endevinar.
Els tres rebutjos retornen 422 business_rule_violation i et diuen quin és a
través del subcode:
subcode | Què significa | Hi ha sortida? |
|---|---|---|
integration_event_not_parked | L'esdeveniment no es va aparcar mai — o va tenir èxit, o el seu motiu no guarda el contingut | No, i mai no n'hi haurà |
integration_event_payload_purged | Es va aparcar, però el seu contingut es va esborrar en esgotar-se la finestra de 30 dies | No — resol-ho a mà |
integration_event_reason_not_replayable | Està aparcat i conserva el seu contingut, però el seu motiu tornaria a prendre exactament la mateixa branca | No — segueix en el seu lloc l'acció recomanada |
On encaixa això
el flux que produeix la majoria dels esdeveniments que trobaràs aquí.
el seu ajust és darrere de subscription_autoinvoicing_disabled.
la ingesta
de payouts que hi ha darrere de payout_missing_id i
payout_connected_account_missing.
valida el teu tractament de la
safata amb una clau fact_test_ abans de connectar un botó de reprocessament a
una credencial de producció.
l'envelope de les respostes 400, 404 i 422 citades més amunt.