Cart Upload per Order Store API – Headless & PWA (Shopware 6)
Note: Available from version 2.3.0
If you run your shop with your own frontend instead of the Shopware storefront – a PWA, a Next.js or Nuxt project – the complete upload flow is available through the Store API.
Every endpoint expects the sw-access-key header of your sales channel and the customer's sw-context-token.
Endpoint overview
| Method | Path | Purpose |
|---|---|---|
| HEAD/POST/PATCH/DELETE | /store-api/checkout/order-upload/{id} | tus upload (create, send data, abort) |
| GET | /store-api/checkout/order-upload/{id}/get | Status of an ongoing upload |
| POST | /store-api/checkout/order-upload-delete | Remove an uploaded file |
Note: The paths deliberately differ from the sister plugin Cart Upload per Product, which uses
item-upload. That way both plugins can be installed side by side without colliding routes.
How the upload works
Uploads use the tus protocol for resumable transfers. The flow has two steps.
1. Create the upload
A POST without file content announces the file. The cart is declared through the Upload-Metadata header — each value Base64 encoded. Unlike the sister plugin there is no lineItemId, because the upload applies to the whole order:
curl -X POST https://your-shop.com/store-api/checkout/order-upload/1 \
-H "sw-access-key: YOUR-ACCESS-KEY" \
-H "sw-context-token: YOUR-CONTEXT-TOKEN" \
-H "Tus-Resumable: 1.0.0" \
-H "Upload-Length: 20480" \
-H "Upload-Metadata: cartToken <base64>,name <base64>"The response is 201 Created with a Location header. That URL is the target for step two.
Important:
cartTokenhas to be the token of the calling context — the same value you send assw-context-token. A foreign cart is rejected with403.
2. Send the data
curl -X PATCH <Location-URL> \
-H "sw-access-key: YOUR-ACCESS-KEY" \
-H "sw-context-token: YOUR-CONTEXT-TOKEN" \
-H "Tus-Resumable: 1.0.0" \
-H "Upload-Offset: 0" \
-H "Content-Type: application/offset+octet-stream" \
--data-binary @file.pdfThe response is 204 No Content. Large files can be sent in several PATCH calls with an increasing Upload-Offset; an interrupted upload resumes at the same position.
Removing a file
curl -X POST https://your-shop.com/store-api/checkout/order-upload-delete \
-H "sw-access-key: YOUR-ACCESS-KEY" \
-H "sw-context-token: YOUR-CONTEXT-TOKEN" \
-d "id=<id of the upload>"Response on success:
{ "apiAlias": "futi_order_upload_delete", "success": true, "id": "…" }If the file belongs to another cart the route responds with 403; an unknown id returns 404.
Note: The parameter is called
idhere, notcartUploadIdas in the sister plugin. This matches the storefront route this plugin has always used.
What you still build in your frontend
The Store API covers the server side. What remains in the frontend:
- the picker and progress UI (the storefront uses Uppy with its tus plugin — that works the same way in any JavaScript frontend)
- checking allowed file types and the maximum number of files before sending, so customers do not see an error only after the upload
- rendering the already uploaded files
Allowed file types and the file limit are still maintained in the plugin configuration, see Plugin Configuration.
Order and administration
Nothing changes after checkout: files are linked to the order and remain accessible in the administration, see Download Data. The email template works unchanged as well.
Next step: Changelog →
Was this page helpful?
Support
Rented Plugins (Shopware Store)
For support with plugins rented from the Shopware Store, please open a support ticket in your Shopware account.
Create Shopware Ticket