Available events
Enable Also receive player deposit events for
deposit.* subscriptions.
Other payment lifecycle types (initiated, active, hold, canceled,
declined, failed) appear in the payload schema but are not endpoint
subscription options. Use status polling for those states.
Retries and manual replays keep the same event ID. Deduplicate using both the
Skinloop-Event-Id header and matching body id; a replay is not a new payment.
The optional data.merchantOrderId connects a hosted checkout event to your
order. The webhook body is JSON, but signature verification must use its exact
raw bytes.
Endpoint URL and signing secret
The endpoint URL is an HTTPS address your server or store platform hosts before you register it in Skinloop. It is not the merchant’s storefront URL and Skinloop does not create the receiving server for you. For a platform integration, the platform supplies the exact webhook URL to the merchant. The merchant registers it in API & Webhooks in their Skinloop dashboard and subscribes to the desired events. Skinloop generates awhsec_... signing
secret for that endpoint when it is created; copy it once into the receiver’s
secure server configuration, not browser code or a checkout URL.
A platform serving multiple stores should maintain separate merchant
credentials and webhook secrets. Route a request to the expected installation
and verify its signature with that installation’s secret before using
untrusted payload fields to identify an order. See
Store platform integration for the full setup.
Completed delivery
This is a completepayment.completed request. The hexadecimal signature shown
is illustrative; Skinloop calculates a different signature with the signing
secret for your endpoint and the exact raw body bytes.
payment.completed with data.status: "completed" and
data.fulfillmentAllowed: true permits fulfillment. Record completion and
enqueue the unique durable job before returning 2xx; do not deliver the
merchant order inside this HTTP request.
Non-completed delivery
A CS2 payment in provider hold is not ready for fulfillment:holdUntil is included only for a CS2 payment.hold event when the hold
start is known; it is not a completion time or permission to fulfill.
Field meanings
Map and deduplicate
After verifying the signature:- Confirm
Skinloop-Event-Idexactly equals the bodyid. - Insert the authenticated event using
idas a unique key. - Look up your local order using
data.merchantOrderId. - Verify
data.requiredAmountanddata.currencyexactly match the stored order. Parse decimal strings to integer cents without binary floating point. - Verify
data.amount >= data.requiredAmountanddata.overpaymentAmount === data.amount - data.requiredAmount. A greaterdata.amountis valid overpayment and must not change the order price or quantity delivered. - Apply the status transition without assuming events arrive in order.
- For completion, call the same durable enqueue operation used by status polling.
- Return 2xx after the event and any fulfillment job are committed.
data.amount directly to the original order price: that would
reject legitimate skin overpayment. Do not accept a changed requiredAmount,
currency, merchant order ID, or payment identity. If any of those fields
conflict, stop fulfillment and reconcile with the checkout status endpoint.
A retried event with the same id and same authenticated body is already
accepted: return 2xx without applying it again. The same id with different
authenticated bytes is a conflict and must not be processed automatically.
Webhook event deduplication does not replace fulfillment-job idempotency; use
both.
Your endpoint must be public HTTPS and must not rely on redirects. Return any
2xx response after authenticating and durably recording the event and any
unique fulfillment job. Do not call an external fulfillment service inside the
webhook request. Enqueue only for payment.completed; pending and hold events
are informative.
Next: implement signature verification before
testing retries and duplicates, then implement
safe fulfillment.