Selling software licenses on Shopify
Selling software licenses on Shopify
Connect a Shopify store to LicenseSeat and paid orders for linked products issue license keys; eligible email delivery sends them to the buyer. A refund revokes it. No Shopify app to install: the connection uses the webhooks you create yourself in your Shopify admin.
Setup takes about five minutes.
Before you start
Link the product to a license plan before testing. Automatic license emails require an eligible LicenseSeat plan, Settings → Organization → Email license keys to my customers enabled, and a valid buyer email. Issuance can succeed without sending an email. Use a separate test organization when you need complete separation: connections in one organization share product mappings by provider.
Read Email delivery, subscription expiry and event recovery for the common prerequisites and recovery procedure. Setup instructions remain available on the connection page after saving.
1. Create the connection in LicenseSeat
In the LicenseSeat dashboard sidebar open Connected platforms, click Connect Your First Platform (or Connect Another), choose Shopify, and give the connection a name. The page shows your webhook URL. Copy it. Keep it private: only paste it into Shopify.
2. Create two webhooks in Shopify
From your Shopify admin, go to Settings → Notifications, click Webhooks, then ⊕ Create webhook. Fill the dialog like this and save:
| Field | Value |
|---|---|
| Event | Order payment |
| Format | JSON |
| URL | your LicenseSeat webhook URL from step 1 |
| Webhook API version | Choose a stable version offered by Shopify and test it; repeat your rehearsal before changing versions. |
Then click ⊕ Create webhook again and repeat with the event Refund create.
Order payment fires when an order's payment goes through, and that is what issues the license. Refund create fires when you refund the order in Shopify admin, and that revokes the license. You do not need Order creation: an unpaid order never issues anything, and a paid one is already covered.
3. Paste the signing secret
Under the list of webhooks on that same Shopify page there is a line that reads "Your webhooks will be signed with" followed by a long code. Copy that code into the Signing Secret field on the LicenseSeat connection page and save.
Shopify signs every webhook with this secret, and LicenseSeat rejects anything that is not signed with it. If you created the webhooks through a custom Shopify app instead of the Notifications page, use that app's client secret.
4. Link your products
Tell LicenseSeat which license plan to issue for each Shopify product. On the connection page click Link Product, pick the plan, and enter the Shopify identifier:
- Product ID: in Shopify admin open Products, click the product, and copy the number at the end of the page URL. Use this when every variant of the product should issue the same license.
- Variant ID: open the specific variant and copy the number at the end of its URL. Use this when different variants issue different licenses (for example a personal and a studio edition of the same plugin).
- SKU: a variant's SKU also works.
Pasting the whole Shopify admin URL works; LicenseSeat keeps the number.
5. Test it
On Shopify's Webhooks page, open the ⋯ menu next to your Order payment webhook and click Send test. A verified sample appears in the connection's events. It issues only if the sample contains a product/variant/SKU you linked; otherwise it is ignored. Samples can have no buyer email and then issue ownerless licenses. Check the payload and license, rather than expecting every sample to activate the connection. Real orders can also lack email; delivery needs the prerequisites above.
For a full rehearsal, place an order in your own store. On a store without a live payment provider yet, add a manual payment method (Settings → Payments → Manual payment methods), buy the product, then open the order in Shopify admin and click Mark as paid. Then click Refund on the same order. You should see the license issued, emailed, and then revoked, in that order, on the connection's event list.
What happens on each event
| Shopify event | LicenseSeat |
|---|---|
Order payment (orders/paid) |
Issues a license for the first line item that matches a linked product, owned by the buyer's email, and emails the key. Quantity follows the line item. |
Order creation (orders/create) |
Ignored unless the order is already paid, in which case it behaves like Order payment. An order never issues twice. |
Refund create (refunds/create) |
Revokes all licenses issued for that order. Any refund does this, including a partial refund, a shipping-only refund, or a refund for a different line in the same order. |
| Order cancellation | Ignored. A cancellation that returns money also sends Refund create, which is what revokes. |
| Anything else | Ignored. Subscribing to extra events does no harm. |
Good to know
- First matching line, matching quantity. Check each line in order, trying its Variant ID, Product ID, then SKU. Issue that line’s quantity of separate licenses (1–1000). Later matching lines are not fulfilled. Use separate orders for separately licensed products; mapping a variant does not turn this into fulfillment of every cart line.
- No buyer email. Orders with no email address at all (some POS and phone-only checkouts, and Shopify's sample order) still issue a license, without an owner. An organization owner/admin can use Assign customer on the license page and optionally send the key if email delivery is enabled.
- Subscriptions. Shopify selling plans and subscription apps are not modelled. Every paid order is treated as a one-time purchase.
- Retries. Shopify retries a webhook up to eight times over four hours if it does not get a 200. LicenseSeat answers immediately and processes the event in the background, and duplicate deliveries are recognised by Shopify's webhook id, so an order is never fulfilled twice.
- Test orders. Orders placed with a test payment gateway carry
test: trueand are treated like any other paid order. Revoke the test licenses afterwards, or refund the test order.
Troubleshooting
- The connection stays "Incomplete". The signing secret is missing, or no product is linked yet. Both are on the connection page.
- The event shows as "ignored" with "no active mapping". The order's product or variant id does not match any linked product. Check the number you entered against the end of the product URL in Shopify admin, or link the variant instead of the product.
- Shopify shows a failed delivery. The signing secret does not match. Copy it again from the bottom of the Webhooks page; it is the store's secret, not your Shopify password.
- A refund did not revoke. The refund must be issued on the same order that issued the license. If no license matches, the refund is ignored and retained, without repeated failed jobs. A later matching purchase or recovered history can resolve it automatically; manual retry remains available. Recover the missing purchase or revoke manually; see the recovery guide.
References
These are Shopify's own pages. If a label or menu in Shopify admin ever differs from this guide, they are the source of truth:
-
Webhooks in Shopify admin — creating, editing, testing ("Send test") and deleting webhooks from Settings → Notifications → Webhooks.
-
Webhook topics reference — every topic, including
orders/paid,orders/createandrefunds/create, with payload descriptions. -
Verifying webhooks — the
X-Shopify-Hmac-SHA256signature, theX-Shopify-Webhook-Idduplicate key, retries and timeouts. -
Order resource — the fields in the order payload (
line_items,financial_status,email,total_price). -
Refund resource — the refund payload (
order_id,refund_line_items). -
Manual payment methods — for placing a rehearsal order without a live payment provider.
-
ISO 4217 currency data — Shopify decimal amounts are converted using currency-specific minor units, including JPY and BHD.