- Basic Information
- What Works (POC)
- Secrets / Environment Variables
- Setup
- Development
- Documentation
- Testing
- Future / Later Features
- References
This app connects to a shopify store and the Logistra api, to create return labels for packages.
The use case is to automate the first part of self returns. By automatically accepting returns, and sending them to the customer. With some small changes, the app can work by using on return/accepted instead of return/requested.
The app is not 100% finished yet, there are alot of features to be made, but the core concept works.
In this POC version of the app the following works
- automatically accepts self serviced returns when requested
- creates labels from the Logistra XML api
- download and store pdf of shipping label on the app
- sends pdf label for each consignment in a return to the customer.
- The customer can follow the provided link and download or print out the label.
We need some variables from the Logistra/caargonizer API, For that we need the Logistra/Cargonizer api key, if the store has Cargonizer connect installed, you can find it there.
NOTE: Right now, the easiest way to access some of the needed secrets is to retrieve them from the cargonizer connect app, We need the key and sender id.
Some other variables we need is better of fetching with postman for now. Cargonizer documentation For that we need the Api key and sender id.
Inside postman you need to find the correct transport agreement id, and the return product identifier you want to use
See full list of secrets needed in the env.example file The return secrets is needed so the the package will be shipped to the correct place, the feature only works with one return store for now...
NOTE: It might be possible to get this information from shopify, it can be good to check this out!
⚠ Return Address / Consignee Clarification: The data shown in the Cargonizer sandbox dashboard and the printed label can appear inconsistent: party roles (consignee vs return address) may not match intuitive expectations. For this return product the actual delivery destination is the return address already configured in Cargonizer; providing it again in the XML is usually optional. In the current POC XML we deliberately map the store (environment variables) as
<consignee>and the customer's order shipping information as<return_addres>, which can look inverted.Recommended checks:
- Run a test consignment and confirm delivery goes to the intended store address even if
<return_addres>is omitted.- Confirm with Logistra whether your product code (
bring2_return_pickup_point) expects the parties swapped for returns.- If printed labels show incorrect recipient details, adjust the mapping in
buildConsignments. (swap the consignee and return_addres and check)
Remember to set all secrets as the app will fail without them.
Start dev server
npm run devStart test environment
npm run testGet graphql code-gen
npm run graphql-codegenThe webhook is defined in the Shopify Toml file To check that they are added, test in a devstore by requesting a return as a customer in the /account. The Webhook should trigger and run the process
Generated with TypeDoc.
Generate docs:
npm run docsConfig file: typedoc.config.json (entry points: app/utils, app/graphql, strategy: expand). Output: docs/.
Add new code under those folders for automatic inclusion. Excluded: tests, generated types, *.d.ts.
Testing uses Vitest and MSW for HTTP mocking.
Highlights:
- Strict MSW setup: unhandled external requests fail, ensuring mocks are explicit.
cargonizer.test.tscovers consignment POST + XML flow.- Label PDF fetch mocked with a hardcoded GET handler returning fake PDF bytes.
- Environment variables in tests use the
LOGISTRA_prefix (e.g.LOGISTRA_BASE_URL). - MSW handlers live in
app/tests/msw/with a setup import required at test start.
Run tests:
npm testAdd tests for:
buildConsignments(XML shape, values block, items array)prepareLabels(matching RFO IDs, file saving logic)- Error cases (missing env, failed fetch, save error)
Mocking tips:
- Use
server.use()inside a test to override a single endpoint (e.g. a specific label URL with query params). - Keep handlers minimal—return only what code paths assert.
Planned improvements:
- Multiple return locations (dynamic address resolution)
- Retry & resilience for external API failures
- Admin UI to view generated labels & statuses
- Fine‑grained logging/observability
- Improved webhook deduplication & idempotency
- Configuration UI to select sender IDs, transport agreement IDs, and return product identifiers (remove reliance on manual env edits)
- Persist selectable sender/agreement/return product settings in the database (per shop) instead of environment variables for dynamic multi‑tenant configuration
- Cargonizer docs: https://github.com/logistra/cargonizer-documentation/wiki/Transport-Agreements
- Shopify Apps: https://shopify.dev/docs/apps
- Reverse Fulfillment / Returns GraphQL: Shopify Admin API