Skip to content

Digital products

Every product is physical or digital, set by Type in the editor. Today the flag is a modelling decision: it governs shipping and stock. The file itself, the entitlement that grants access to it, and the download route are not built.

  • Shipping. Digital lines are excluded from the parcel, not zeroed. A cart of only downloads reaches Stripe with no address collection and no shipping options; a mixed cart collects an address, priced on the physical lines. Both the weight and the subtotal a rate is matched against come from the physical lines only. Shipping explains why zeroing would be wrong.
  • Stock is always unlimited. The API refuses a finite count, because the inventory decrement would otherwise count a file down to zero and start flagging paid orders oversold.
  • Webhooks. product.published carries kind, so a fulfilment receiver can branch on it before raising a pick list.
  • Tax. Digital goods carry different tax codes in many jurisdictions. Set one on the product if you use Stripe Tax.

A merchant can mark a product digital, publish it, take money for it, and then has no mechanism to give the buyer anything. The approach has not been chosen, so it sits in docs/gaps/digital-delivery.md rather than as a numbered task.

What any solution has to handle, recorded there:

  • Files must not live under the statically served assets directory, or anyone who guesses the path can download them. A separate, non-served location streamed through an authenticated route.
  • An entitlement per order line: a hashed token, a download cap, an expiry, and a revocation on refund.
  • Granted inside the webhook’s idempotent path, delivered by a link in the order email.
  • A delivered status, since processing and shipped mean nothing for a download.

Deliver it yourself over a webhook. Subscribe to order.paid, mint a signed URL for the file that matches each line’s productId and variantId, and email it to data.email. Subscribe to order.refunded to revoke it. Sell a digital product walks through exactly that.