By Stendly2 min read

How to fulfill digital products after a stablecoin payment

How to verify payment events and safely deliver SaaS access, credits, files or licenses.

A payment page collects money. Fulfillment gives the buyer what was purchased. For digital products, the reliable connection between those two steps is a signed server-to-server event.

The merchant should not grant access because the browser reached a success URL. It should grant access after verifying a payment webhook and confirming that the event matches the expected product, amount and customer reference.

The webhook flow

The payment provider sends an HTTP request to the merchant endpoint after a payment changes state. The request includes an event type, payment identifiers and a signature.

The merchant reads the raw request body, verifies the signature with its webhook secret, checks the event ID against previously processed events and then applies the business action.

payment confirmed
→ signed webhook
→ signature check
→ idempotency check
→ entitlement update
→ 2xx response

If the endpoint is temporarily unavailable, the provider should retry delivery. The merchant should expose delivery history and a manual resend option during debugging.

Idempotency

Webhooks are normally delivered at least once, not exactly once. A provider may retry after a timeout even if the first request already changed the database.

The handler therefore needs a unique event ID or another stable idempotency key. The database transaction should record the event and apply fulfillment together.

begin;

insert into processed_events(event_id)
values (:event_id)
on conflict do nothing;

-- Continue only if the insert succeeded.
update subscriptions
set paid_until = :new_date
where user_id = :user_id;

commit;

The exact code varies, but the rule is constant: a repeated event cannot create repeated value.

What to validate

Signature verification proves that the request came from someone holding the webhook secret. It does not prove that the merchant is handling the correct business object.

The handler should also validate the event type, payment status, price or product ID, currency, amount and project. A public client reference should be treated as a label. A trusted customer or order reference should come from the merchant backend.

Fulfillment examples

For SaaS, extend the paid-through date or enable the purchased plan. For credits, append an entry to a credit ledger rather than changing a balance without history. For files or license keys, generate a short-lived authenticated delivery page. For a Telegram bot, update the bot's own entitlement table and then grant the role or command access.

Refunds and charge reversals need separate events and policies. On-chain transfers are not card payments, but a merchant can still issue a refund transaction.

Stendly webhooks

Stendly uses signed webhook deliveries for payment and billing events. Merchants can inspect deliveries and resend events. Payment links can carry a client_reference_id, while server-created checkout sessions support trusted merchant-side references.

The SDK documentation includes webhook verification for Node.js, Python and .NET.

Sources

Stendly webhook security guide

Stripe webhook best practices

OWASP: webhook security guidance