Connect Fulfillment Without Copy-Paste: Shopify Integrations Done Right

Sending every order to your fulfiller by hand costs you hours per week. And the first transposed digit in an address costs you a customer.

I've built this integration for nano., mate and MUSTAX, plus a number of Flowhouse clients. The setup looks similar every time. So do the mistakes. So here's the sequence I always use now, including the places where it breaks in practice.

What actually flows between shop and warehouse

Before you touch any tool, write down which data goes in which direction. There are exactly two directions and a handful of events.

From shop to warehouse:

From warehouse back to shop:

That's it. Everything else is optional. If you don't have this list straight, you'll build an integration that works in the normal case and goes quiet in the special case.

One point almost always slips through: stock. If you sell on several channels, the message coming back from the warehouse is your single source of truth. How we set that up is in Multichannel Inventory Management.

File transfer or API: the trade-off

Many fulfillers offer both. CSV files over SFTP (a file server with encryption) or an API (a programming interface that lets systems talk to each other directly).

CriterionFile transferAPI
Setupfast, often in a day3 to 8 days, depending on the docs
Delay1 to 24 hours depending on the scheduleseconds
Errors visibleonly on the next runimmediately in the response
Changes to the orderpractically impossiblepossible
Ongoing maintenancefield order breaks quietlyversion changes are announced

My rule of thumb: under 20 orders a day, with a fulfiller who only speaks CSV, file transfer is perfectly fine. As soon as customers ask about tracking before your file has even run, the API becomes the better choice.

The underrated downside of files is the silence, more than the delay. A broken line in a CSV gets skipped at the fulfiller without a word, and you find out three days later through a customer email. An API answers you immediately with an error code.

The events you react to

The clean way is event driven, so leave the scheduled polling alone. Shopify sends you a message the moment something happens. That's called a webhook. If the term is new to you: Webhooks Explained covers it in ten minutes.

Three webhooks are enough to start:

On the other side you need an address the fulfiller can send its shipping notification to. If it can't do that, you poll its interface every 15 minutes for new shipments. It's clumsy, and it works.

Between the two sides we run n8n. It receives the webhook, translates the fields and calls the other side. If you've never worked with it: Your First n8n Workflow is the shortest way in. What our complete order system looks like is in Order Processing Without Staff.

The fields where it falls apart

Translating between shop and warehouse is the part everyone underestimates. Four classics from our own integration:

SKUs don't match. In the shop the item is `NANO-BLK-2ER`, in the warehouse it's `1004237`. You need a mapping table, and it belongs in exactly one place. Not spread across three workflows.

The warehouse doesn't know bundles. Your two-pack is one item in the shop and two in the warehouse. Solve that during translation, not in the stock levels.

Address fields don't line up. Shopify has `address1` and `address2`, many warehouse systems separate street and house number. Splitting the street automatically fails on roughly every twentieth German address. Ask for the house number separately at checkout, or let the fulfiller split it.

Shipping methods are named differently everywhere. `Standard` on your side, `DHL_PAKET_NATIONAL` at the warehouse. That belongs in the mapping table too.

Edge cases that catch up with you later

The normal case is built in a day. The remaining days go into these four cases, and they decide whether your support stays calm.

Partial delivery. The warehouse only has two of three line items and ships anyway. If your integration then marks the order as fully shipped, the customer gets a tracking number for a parcel that's missing their favorite item. Always take the line items that actually shipped from the response, never the original order.

Cancellation after handover. At a good fulfiller, "customer cancels" and "parcel is packed" are sometimes 20 minutes apart. Your cancellation call has to handle three answers: cancelled, too late, unknown. On "too late" you have to treat the case as a return and must not simply refund the money.

Duplicate handover. Webhooks sometimes arrive twice, which is normal and not a bug. So always send the order number as a unique key and let the fulfiller reject what it already knows. Without that you'll eventually ship a parcel twice.

Address change mid-flight. The customer writes two hours after ordering. In our setup, the automation isn't allowed to decide that on its own. The workflow checks whether the parcel has already been packed, then puts the case in front of a human.

Together these four cases are maybe three percent of orders. They account for most of the support emails that come in afterwards.

How to test before real goods go out

Testing doesn't mean pushing one order through and calling it a day. This is the order I always use:

1. Ask for a test environment. Almost every fulfiller has one. If not, agree on a test SKU that never ships.

2. One order with a single line item. Check field by field against what arrives in the warehouse system. Not just "it arrived".

3. One order with a bundle, special characters and a long address. Umlauts, apostrophes and a 60-character company name surface most formatting errors.

4. The four edge cases above, one at a time. Trigger each one deliberately and watch what your system does.

5. Check the return path. Tracking number lands in Shopify, customer gets exactly one email, not three.

6. First week in shadow mode. The automation runs, and a human spends ten minutes each evening looking it over.

If the API terms in your fulfiller's docs are unfamiliar, API Basics for E-Commerce helps you read them.

Data protection: addresses are personal data

The moment you hand names and addresses to your fulfiller, you're processing personal data on someone's behalf. Three things need to be settled before the first real order flows.

Data processing agreement. Every fulfiller needs one, and so does every system in between. If your n8n runs at a hosting provider, that provider belongs in your record of processing activities too. This is the GDPR paperwork every EU shop has to keep.

Server location. We run n8n self-hosted in Germany. That isn't required, but it keeps the answer to customers short.

Minimization and retention. The fulfiller needs name, address, line items. It doesn't need payment data, order history or marketing consent. And your workflow logs shouldn't keep real names around for months. We delete execution data after 30 days.

The limits

So you don't talk yourself into anything:

Conclusion

The integration itself isn't hard. The hard part is the care that comes before it: which data flows, what the fields are called on both sides, what happens on partial delivery and cancellation.

Work through that list before you build, and the integration will run for years without you. Skip it, and you've replaced copy-paste with silent errors, which is a bad trade.

If you have your fulfiller's docs in front of you and aren't sure whether API or file is the right choice: drop us a line at Flowhouse. We'll look at it with you, without a pitch.