Digital products, licensing, entitlement, activation, and secure download management for Medusa v2.
An installable Medusa v2 plugin for digital products, software licensing, customer entitlements, device activations, and protected file delivery.
The plugin fills the domain gap between selling a non-shippable product and operating a production licensing system. It is built as a native Medusa plugin: module data models, rollback-capable workflows, authenticated Admin and Store APIs, a product-variant module link, subscribers, a scheduled expiry job, migrations, and an Admin extension.
npm install medusa-plugin-digital-productsRegister the plugin in :
1import { defineConfig, loadEnv } from "@medusajs/framework/utils"2
3loadEnv(process.env.NODE_ENV || "development", process.cwd())4
5module.exports = defineConfig({6 // your existing projectConfig7 modules: [8 {9 resolve: "@medusajs/medusa/fulfillment",10 options: {11 providers: [12 {13 resolve: "medusa-plugin-digital-products/providers/digital-fulfillment",14 id: "digital-products",15 },16 ],17 },18 },19 ],20 plugins: [21 {22 resolve: "medusa-plugin-digital-products",23 options: {},24 },25 ],26})Configure a secret of at least 32 characters. Treat this as production key material and keep it stable; changing it invalidates credential lookups.
1DIGITAL_PRODUCTS_SECRET=replace-with-a-random-secret-at-least-32-characters2MEDUSA_BACKEND_URL=https://api.example.com3DIGITAL_PRODUCTS_ACCOUNT_URL=https://shop.example.com/account/digital-products4# Optional; defaults to seven days and is capped at thirty days.5DIGITAL_PRODUCTS_DELIVERY_TOKEN_TTL_SECONDS=604800Run the plugin migrations from the host application:
npx medusa db:migrateUse an S3-compatible File Module provider in production. Medusa's local provider is intended for development.
Configure an email-capable Notification Module provider that supports direct . Raw license keys and download tokens are only placed in the transient provider payload, never in the plugin database, fulfillment metadata, audit log, or notification record.
After registering the provider, add to the stock location that sells digital products. Create a fixed-price shipping option from its service, price it at zero, and make it available in the relevant service zone. Digital carts must select that option during checkout. This is especially important for mixed carts: the plugin explicitly selects the digital shipping option for the digital line items and leaves physical items to their own provider.
Configure linked variants as non-physical () and do not manage inventory unless you intentionally impose digital stock limits. The order must still contain the zero-priced digital shipping method so Medusa can associate its fulfillment with this provider.
For non-shippable catalog configuration, set the Medusa product/variant inventory and shipping requirements according to the official selling-products guide.
All Admin endpoints use Medusa's standard Admin authentication.
| Method | Route | Purpose |
|---|---|---|
| , | List or create digital products | |
| , , | Retrieve, update, or archive a digital product | |
| Attach a File Module asset | ||
| , | List or create policies | |
| , | List or manually grant entitlements | |
| Revoke an entitlement | ||
| Issue a license key once | ||
| Safely retry or manually trigger digital fulfillment |
Use the Medusa JS SDK so customer authentication and publishable API keys are included automatically.
| Method | Route | Purpose |
|---|---|---|
| List the authenticated customer's entitlements | ||
| Issue a license key owned by the customer | ||
| Create a short-lived download token | ||
| Consume a token and return the provider URL to an SDK client | ||
| Activate a license for a device | ||
| Validate a license/device pair | ||
| Release a device activation |
Example SDK request:
1const result = await sdk.client.fetch(2 `/store/customers/me/digital-products/${entitlementId}/downloads`,3 {4 method: "POST",5 body: { asset_id: assetId },6 }7)Emailed download links use . This browser-facing route is outside Medusa's publishable-key-protected namespace because normal link navigation cannot attach SDK headers. The high-entropy, expiring, usage-limited token is the authorization credential; successful redemption redirects to the File Module provider URL.
Guest buyers receive their license keys and protected download links at the order email. Their entitlement remains email-bound until the host application associates or claims it for a customer account.
If delivery fails—for example because the email provider is unavailable—the workflow compensates the fulfillment, licenses, grants, and newly created entitlements. Fix the provider configuration and retry with . Completed deliveries are detected from fulfillment metadata and are not duplicated.
1npm install2npm run build3npm run lint4npm test5# Requires PostgreSQL and the DB_HOST, DB_PORT, DB_USERNAME, and DB_PASSWORD variables.6npm run test:integration:modules7npm run test:package8# Requires Docker; installs the packed plugin into an isolated Medusa host.9npm run test:acceptancePublish to Medusa's local plugin registry:
npx medusa plugin:publishThen add it to a Medusa application with , register it in , run , and start the host with .
Build and inspect the package before publishing:
1npm run release:check2npm run test:integration:modules3npm pack --dry-runReleases are published through the GitHub release workflow with npm provenance. The Git tag must exactly match . See RELEASING.md for first-release and trusted-publishing setup.
This plugin targets the Other category in Medusa's npm-curated Integrations Directory. The live category includes reusable commerce-feature plugins as well as third-party services, so the package uses the current and discovery metadata. See the listing strategy for the evidence, sync checklist, and escalation path. Directory inclusion remains Medusa's decision.
Use GitHub issues for reproducible bugs and feature requests. Read SUPPORT.md before requesting help and report vulnerabilities privately as described in SECURITY.md.
MIT