How to Email Customers a Return Shipping Label From Shippit

When a customer requests a return, this Spojit workflow looks up the original Shopify order, generates a return label with the Shippit connector, and emails the label PDF back to the customer automatically.

What This Integration Does

Returns are one of the most repetitive jobs in any support inbox: a customer asks to send something back, an agent finds their order, books a return consignment with the carrier, downloads the label, and emails it over. This workflow collapses all of that into a single automated run. The moment a return request arrives, Spojit confirms the order really exists in Shopify, creates a reverse shipment in Shippit, retrieves the printable label, and delivers it straight to the customer's inbox. Your team only gets involved when something genuinely needs a human eye.

The workflow runs on a Webhook trigger. Your returns portal, help-desk form, or a Shopify Flow action posts a JSON body containing the order number and the customer's email, and Spojit returns a 202 with an executionId immediately. From there the run looks up the order, books the Shippit return, fetches the label URL, downloads the PDF bytes, and sends the email. No data is written back to Shopify, so the run leaves your store untouched: it is purely read-then-ship-then-notify. Because the Webhook trigger supports opt-in deduplication, a customer who double-clicks "Request return" will not be charged for two labels as long as your sender includes a stable event-id header.

Prerequisites

  • A Shopify connection with read access to orders (used by get-order).
  • A Shippit connection authorized for your merchant account (used by create-order and get-label).
  • A signing connection for the Webhook trigger (scheme Spojit, Shopify, or Custom) so incoming requests are verified by HMAC.
  • The customer's email address must be reachable: external recipients have to be on your org allowlist under Settings -> General -> Email recipients.
  • Your Shippit account configured with a return/reverse courier service and a sensible default parcel size for returns.

Step 1: Receive the return request with a Webhook trigger

Add a Trigger node and set its type to Webhook. Attach a signing connection so the request is HMAC-verified, then copy the generated URL into your returns portal or help-desk action. Have the caller POST a small JSON body like this:

{
  "orderNumber": "1042",
  "customerEmail": "alex@example.com",
  "reason": "Wrong size"
}

The parsed body is available downstream as {{ input }}, so you can reference {{ input.orderNumber }} and {{ input.customerEmail }}. To guard against duplicate submissions, configure the trigger's opt-in dedup and have your sender pass a stable event-id header (for example the return request ID).

Step 2: Look up the original Shopify order

Add a Connector node in Direct mode, choose the Shopify connector, and select the get-order tool. Map its order identifier field to {{ input.orderNumber }}. Store the result in an output variable named order.

This step does two jobs: it confirms the order exists (so you never generate a label for a bogus request), and it gives you the customer name and original delivery address, which you will reuse as the return's pickup details. If you prefer to look up by email or order name when you only have those, you can instead use list-orders and filter, but get-order is the cleanest path when the caller already knows the order number.

Step 3: Confirm the order is eligible with a Condition node

Add a Condition node to stop early if the lookup came back empty or the order is not in a returnable state. A simple check is whether {{ order.data }} contains an order at all; you can also gate on fulfillment or financial status fields returned by Shopify. Wire the false branch to a Send Email node that notifies your support address that a return request could not be matched, and the true branch onward to label creation.

This keeps bad requests from consuming a Shippit consignment and gives your team a clear signal when a portal submission references an order that does not exist.

Step 4: Create the return shipment in Shippit

Add another Connector node in Direct mode, choose the Shippit connector, and select the create-order tool. The tool takes a single order object describing the consignment. For a return, set the delivery address to your warehouse (where the parcel is going back) and the sender/user details to the customer (where it is collected from). Build the object from the Shopify lookup, for example:

{
  "courier_type": "standard",
  "delivery_address": {
    "address": "Your Returns Warehouse, 1 Dock St",
    "suburb": "Alexandria",
    "state": "NSW",
    "postcode": "2015"
  },
  "user_attributes": {
    "email": "{{ input.customerEmail }}",
    "first_name": "{{ order.data.customer.first_name }}",
    "last_name": "{{ order.data.customer.last_name }}"
  },
  "parcel_attributes": [
    { "qty": 1, "weight": 0.5 }
  ]
}

Save the result in an output variable called returnShipment. Shippit responds with a tracking number (it usually starts with PP), which you will reference as {{ returnShipment.data.response.tracking_number }} in the next step. Use a Transform node first if you need to reshape the Shopify address fields into the structure Shippit expects.

Step 5: Retrieve the label URL, then download the PDF

Add a Connector node in Direct mode using the Shippit connector and the get-label tool. Pass tracking_number as {{ returnShipment.data.response.tracking_number }}. Shippit returns a label URL rather than the file bytes, so store this as label and then download the actual PDF.

Add one more Connector node in Direct mode, choose the http utility connector, and select http-get. Point its URL at the label link from the previous step (for example {{ label.data.url }}) and configure it to return the body as binary/base64 so you have the raw PDF. Save this as labelFile. You now have the bytes you need to attach to an email.

Step 6: Email the label to the customer with a Send Email node

Add a Send Email node, which uses Spojit's built-in mail service so no extra connection is required. Configure it like this:

  • Recipients: {{ input.customerEmail }}
  • Subject: Your return label for order {{ input.orderNumber }}
  • Body: a short plain-text note telling the customer to print the attached label, pack the item, and drop it off, including the tracking number {{ returnShipment.data.response.tracking_number }} so they can follow the return.
  • If sending fails: choose Fail the workflow so a delivery problem is visible in your execution history rather than swallowed.

Attach the PDF you downloaded in Step 5 by feeding the base64 content from labelFile into the node's attachment field, naming the file something like return-label-{{ input.orderNumber }}.pdf. If you would rather send from your own domain, swap the Send Email node for the Resend or SMTP connector and use its send-email tool instead.

Step 7: Return a response to the caller (optional)

If your returns portal expects a synchronous confirmation, add a Response node at the end to hand back the tracking number and a success flag, for example { "status": "label_sent", "tracking": "{{ returnShipment.data.response.tracking_number }}" }. If you do not add one, the Webhook trigger's immediate 202 is all the caller receives, which is fine for fire-and-forget portals.

Tips

  • Use Direct mode for every connector step here: each call is a single predictable tool invocation, so you avoid AI credit cost and get deterministic behavior.
  • If returns can contain multiple parcels, expand parcel_attributes rather than creating several consignments, so the customer gets one label per shipment.
  • Stuck on the address mapping between Shopify and Shippit? Ask Miraxa, the intelligent layer across your automation, something like "Add a Transform node that maps {{ order.data.shipping_address }} into Shippit's delivery_address shape" and fine-tune the result in the properties panel.
  • Keep the email body plain and short. The Send Email body is plain text, and only upstream variables resolve, so reference values like {{ input.orderNumber }} rather than workflow metadata.

Common Pitfalls

  • Attaching the URL instead of the file. The get-label tool returns a label URL, not bytes. You must download it with http-get before attaching it, or the customer receives a link with nothing to print.
  • Recipient not on the allowlist. The Send Email node only delivers to external addresses that are on your org allowlist. Add customer domains under Settings -> General -> Email recipients or the email silently fails to send.
  • Duplicate labels from double submissions. Without webhook dedup, a customer clicking twice creates two Shippit consignments. Enable opt-in dedup and send a stable event-id header.
  • Wrong direction on the consignment. For a return, the warehouse is the delivery address and the customer is the pickup. Swapping them produces a forward shipment label, not a return label.

Testing

Before turning this on for real customers, test against a single known order. Send the Webhook a sample body with a real Shopify order number and your own email as the customer, then watch the run in your execution history. Confirm that get-order resolved the order, that create-order returned a tracking number, that http-get produced a non-empty PDF, and that the email arrived with a label you can actually print. Once one end-to-end run looks correct, point your returns portal at the Webhook URL and enable dedup.

Learn More

Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.