Skip to content

Download a Purchased Downloadable Product ​

Stream the file a customer bought as a downloadable product.

Endpoint ​

GET /api/shop/customer-downloadable-products/{id}/download

The {id} is the purchase id from Get Downloadable Products — not a product or order id.

Request Headers ​

HeaderRequiredDescription
X-STOREFRONT-KEYYesYour storefront API key
AuthorizationYesBearer token of the customer who bought the product

Response ​

200 OK with the raw file as the body. The content type follows the stored file, and Content-Disposition carries its original filename. Nothing about the response is JSON.

Both link types are served the same way: a file purchase streams from the store's private storage, and a url purchase is fetched by the store and passed through, so a client never receives the external address.

Each Download Is Counted ​

A successful call increments the used-download counter for the purchase, and the purchase flips to expired once nothing remains. Two separate limits apply, and each has its own error:

LimitWhen it trips
Invoiced quantityDownloads are released in step with what the store has invoiced. Using more than the invoiced share fails with Download limit exceeded. even though the purchase still shows remaining downloads.
Purchased quantityOnce used plus canceled downloads reach the bought quantity, the purchase is exhausted and fails with No more downloads available.

A purchase whose order has not been invoiced at all is pending and refuses with Download is pending. Please wait for the order to be invoiced.

Use Cases ​

  • "Download" button in the account area — call with the purchase id, then hand the returned blob to the user.
  • Show the remaining count after a download — the counter changes server-side, so re-read Get Downloadable Products rather than decrementing locally.

Best Practices ​

  • Do not put this URL in an anchor tag — a browser navigation sends no Authorization or storefront-key header, and the request fails with 401.
  • Check the status code and content type before saving — every failure answers with JSON, so writing the body blind produces a file containing an error message.
  • Do not retry a failed download automatically — a call that reaches the file consumes a download, and a blind retry loop can exhaust the customer's allowance.
  • Read remainingDownloads before offering the button — a purchase already at zero fails with 403 rather than a friendly message.

Released under the MIT License.