Skip to main content
A product marked digital is fulfilled automatically once payment is confirmed — not when the order is placed. The customer receives the digital delivery email, which carries whatever the product delivers.
Fulfilment runs inside the payment-success path, so nothing is delivered for an unpaid, pending or failed order. You do not need to build your own payment gate in front of it.

The four delivery types

codes — a pre-loaded pool

The merchant uploads a list of codes on the product. Each paid order consumes the next quantity codes from the front of the list and the pool shrinks. Simple, but you supply the codes in advance and delivery stops when the pool runs dry.

dynamicurl — generate a code per purchase

Use this when each customer needs a code minted at the moment of purchase — a licence key, a seat, a one-time redemption token. On each paid order we send a POST to the URL configured on the product:
Respond with the value to deliver under a data key:
That value is what the customer receives in the delivery email, and it is stored against the order.
The ?id=<product_id> query parameter is still sent for backwards compatibility. Existing endpoints that read only the query string keep working unchanged.
Requirements
  • Respond within 15 seconds; the request times out after that.
  • Return { "data": ... }. A response without a data key is treated as a failure and nothing is delivered for that line.
  • Your endpoint is a public URL — authenticate it yourself, for example with a secret in the query string (https://you.example.com/mint?secret=…). We preserve any query string you configure.
  • Expect retries on transient failure, so make issuance idempotent per order.id + product.id.

Building a protected post-purchase experience

Delivery is where the platform’s responsibility ends. Validating a code, enforcing single use, rate-limiting attempts, and revoking access are yours to build. The supported shape:
1

Mint the code

Configure the product as dynamicurl pointing at your endpoint. Store the returned code against order.id and customer.email in your own database.
2

Confirm the sale

Subscribe to the orders/paid webhook so you have an authoritative record of the paid order, independent of the fulfilment call.
3

Serve the protected page

Host the gated content behind an App Proxy. It appears on the merchant’s own domain and each request arrives signed, so you can trust its origin while your server performs the code check.
4

Revoke on refund

Subscribe to refunds/create and orders/cancelled, and mark the associated code invalid when either fires. See webhook topics.
There is no built-in code-redemption endpoint, no automatic revocation, and no anti-sharing or brute-force protection. If your product needs those, they belong in the backend behind your App Proxy.

Customising the delivery email

The email is merchant-editable under Store Settings → Email templates → Digital delivery. Use {{ delivery_html }} to place the delivery itself — it renders the right component for the product type and is already built to display correctly in Outlook. See Email templates for the full variable list.