Skip to content

Replacement collection webhooks

Merchant API 0.35 adds the opt-in event type obligation.collected. Existing subscriptions retain their eleven-event defaults. A newly registered endpoint does not receive this event until its stored subscription explicitly includes it. Read the current configuration, then submit the complete desired event set and current configuration version to POST /v1/webhooks/endpoint/configuration with an explicit idempotency key.

This is a separate version-1 event contract, obligation-collection-event.schema.json; it does not change the existing payment event contract. Its immutable data identifies obligation_id, collected_payment_id, immediate predecessor_id, the complete ordered attempt_ids, and the separate approval_event_id for the child’s existing payment.approved event. Merchant reference, amount and currency remain the original terms. No checkout capabilities or account selectors are present.

Verify Futa-Signature against the exact body before processing. Deduplicate the event ID; retries and explicit replay retain that ID and body. Handle the collection once for the original obligation. The declined root remains declined, and all original events and creation idempotency responses remain unchanged. Use the collected child’s ID for receipts/refunds and the obligation read endpoint for current lineage or investigation state. This event records a historical collection, not a perpetual no-conflict guarantee.

Only new successful replacement collections emit this event. Existing historical collections are not backfilled or rewritten. Payment and refund event delivery continues independently; never treat receiving both payment.approved and obligation.collected as two collections. A filtered event retains its original admission decision when the broker record is repeated. An authorized explicit replay can deliver it after the merchant subscribes.

Generated TypeScript models preserve the exact timestamp string and all correlation IDs. A narrowly scoped generation normalization removes incorrect open-object spreads emitted by the pinned generator for these two closed models; compile-time and exact round-trip tests enforce this. The standalone schema validates closed fields and types; the merchant inbox additionally checks ordered identity relationships. Unique attempt IDs are represented as a JavaScript Set, preserving lineage insertion order.

This remains a local synthetic feature. Real issuer guarantees, production delivery and public alternate-method controls have separate gates. Merchant portal/BFF integration follows this component.