Skip to main content
Skinloop exposes related lifecycle views for different consumers. Do not treat their field names as interchangeable: created belongs only to a hosted session before a deposit starts. expired and reconciliation_required are checkout/deposit recovery projections, not provider payment statuses, so there is no payment.expired or payment.reconciliation_required event. The serializer and schema can represent every accepted provider transition. The merchant dashboard currently offers endpoint subscriptions for payment.pending, payment.completed, and payment.reverted. Use checkout status polling for other intermediate or unsuccessful states instead of assuming an unsubscribable event will be delivered.

State mapping

The hosted checkout projection uses the provider payment status when a payment exists. Before that, it uses the hosted-session state. The deposit projection uses the provider trade state when available and maps uncertain dispatch to reconciliation_required.

Completion authority

Only provider-verified completed produces all of these signals:
  • hosted checkout status: "completed",
  • deposit state: "completed",
  • provider payment status: "completed",
  • webhook type: "payment.completed" with data.status: "completed", and
  • fulfillmentAllowed: true.
The authoritative fulfillment decision requires completed and fulfillmentAllowed: true from an authenticated server-side status response or a verified webhook. Browser redirects, initiated, pending, active, and hold never authorize fulfillment.

Skipped, duplicate, and delayed observations

Intermediate states are observable but not guaranteed. A provider can move from initiated directly to active, hold, completed, or a failure state. Skinloop accepts same-state callbacks idempotently and ignores delayed lower-state or invalid transitions. Merchant webhook delivery is at least once, so duplicates are expected. Do not require every row in the mapping table to appear. Deduplicate webhook events, compare immutable identities, and fetch the current hosted checkout status when observations conflict. A later reverted is authoritative even after completed; if fulfillment may have occurred, stop and reconcile rather than creating another payment attempt.

Expiry is not trade cancellation

For an unattached created checkout, expiresAt is a real pre-trade deadline. After a deposit is attached, the deposit status capability remains usable beyond that deadline and the protected trade can still complete. Never map an attached pending, active, or hold trade to expired using a local timer.