TL;DR
- Context: Technical PM at a B2B packaging e-commerce scaleup, right after Brexit.
- Problem: When shipping directly from Poland to the UK, the customer paid the customs duty. The workaround through a UK entity took ~20 days.
- What I did: I connected our internal order system with the invoicing system and the courier’s system. A three-party invoice is generated automatically, and the parcel goes straight to the customer.
- Result: Delivery takes ~7–10 days instead of ~20 (~50% faster), and customers don’t pay duty.
Diagnosis
After Brexit, shipping directly from Poland to a customer in the UK meant the customer had to pay customs duty on top. The first alternative was to ship a container to the UK entity and then send individual parcels on to customers, but that took ~20 days. The solution turned out to be much less spectacular than changing the route. All it took was a three-party invoice with the right parties in the right fields. Then the parcel clears customs and can go straight to the customer. Once our order system started generating that invoice automatically (it sent requests to the invoicing system and to the courier’s system), direct shipping made sense again. Delivery dropped to ~7–10 days, and the customer paid no duty.
flowchart TD
A1["Poland"] -->|"direct, duty on the customer"| B1["UK customer pays duty"]
A2["Poland"] -->|"container to UK entity, ~20 days"| B2["UK entity"] -->|"reship"| C2["UK customer"]
A3["Poland"] -->|"three-party invoice, ~7-10 days"| C3["UK customer, no duty"]
classDef good fill:#e6f2ea,stroke:none,color:#1f4d33,rx:14,ry:14
classDef bad fill:#faeaea,stroke:none,color:#5f2626,rx:14,ry:14
classDef accent fill:#27272a,stroke:#3f3f46,stroke-width:1px,color:#fafafa,rx:14,ry:14
class A1,B1 bad
class A2,B2,C2 bad
class A3 good
class C3 accent
linkStyle default stroke:#a8a8b3,stroke-width:1.5px
What I did
- I led the integration as a technical PM. I worked out who had to appear on the three-party invoice (the sender is the Polish entity, the buyer is the UK entity, the recipient is the UK customer) and connected three systems.
- I connected our internal order system with the invoicing system (a modern API with templates) and with the courier’s system (an old XML format). Our system sent requests to both, so invoices were created automatically at shipping.
- I led the conversations with both partners. Each had a completely different API, and those conversations weren’t easy.
- Thanks to that, parcels could once again go directly from Poland to the UK and clear customs with no duty on the customer.
Results
- Delivery: ~20 days → ~7–10 days (~50% faster, about 10 days less).
- UK customers don’t pay duty, because the three-party invoice setup allows it.
- Direct shipping came back. For these orders we dropped the container route through the UK entity.
Thanks to the three-party invoice, the parcel could take the shorter, direct route.
The problem
What did Brexit do to shipping to the UK?
After Brexit, shipping a parcel directly from Poland to a customer in the UK meant customs duty was charged to that customer. The company worked around it by shipping a container to the UK entity and sending parcels out from there. That took ~20 days. Customers waited a long time for their packaging, so their experience was poor.
Why not just ship directly?
Because customs rules made it hard. The duty couldn’t be solved by switching couriers, because it came from regulations, not from logistics. The solution had to be found in the shipping documents, specifically in what the invoice says about who ships to whom.
My role / scope
- I was the technical PM. This was product work, not design work, a different part of my role at this company.
- I led the integration from start to finish: settling how the invoice should look, connecting the systems and talking to the partners.
- I worked with the invoicing system provider, the courier company, the team behind our order system and both of our entities.
Process
- First I established that the duty was a matter of documents. The solution lay in how the invoice was structured.
- I designed the three-party invoice: the sender is the Polish entity, the buyer is the UK entity, the recipient is the UK customer. This setup let the parcel clear customs on the direct route.
- I connected our internal order system with the invoicing system (a modern API with templates) and with the courier’s system (an old XML format). Requests from our system went to both, and invoices were created automatically at shipping.
- I led the integration with both sides: three systems, two external partners and a lot of patient conversations before everything worked.
Key decisions & trade-offs
- Changing the document instead of the logistics. The duty was real, but it was charged based on how the shipment was described in the documents. The three-party invoice met the customs requirements, so the parcel could go straight to the customer without charging them duty. Shipping by container was slower and didn’t touch the heart of the problem.
- Three parties in the right fields. The sender is the Polish entity, the buyer is the UK entity, the recipient is the UK customer. Putting them in the right fields of the invoice was the core of the whole thing, because customs checks what’s written in the document.
flowchart LR
F["Three-party invoice"] --> N["Sender = PL entity"]
F --> K["Buyer = UK entity"]
F --> O["Recipient = UK customer"]
classDef info fill:#e9eff8,stroke:none,color:#1e3a5f,rx:14,ry:14
class F,N,K,O info
linkStyle default stroke:#a8a8b3,stroke-width:1.5px
- Three systems to connect. Our order system had to send requests both to the invoicing system (a modern API with templates) and to the courier’s system (old XML). Neither was built with the other in mind, and our system didn’t natively support either format. I had to work out how to connect all three and patiently get through difficult conversations with both companies until invoices started being created automatically.
flowchart LR
W["Internal order system"] -->|"API request"| A["Invoicing system<br/>modern API + templates"]
W -->|"API request"| B["Courier system<br/>old XML"]
A --> P["Connecting the systems"]
B --> P
P --> C["Three-party invoice generated automatically"]
classDef info fill:#e9eff8,stroke:none,color:#1e3a5f,rx:14,ry:14
classDef accent fill:#27272a,stroke:#3f3f46,stroke-width:1px,color:#fafafa,rx:14,ry:14
class W,A,B,P info
class C accent
linkStyle default stroke:#a8a8b3,stroke-width:1.5px
- Direct shipping instead of a container. I chose the faster route (~7–10 days instead of ~20) and paid for it with a harder integration. In my view it’s worth it when a customer is waiting for their order.
| Route | Time | Duty on the customer | Difficulty |
|---|---|---|---|
| Container through the UK entity | ~20 days | none | low (regular logistics) |
| Direct (three-party invoice) | ~7–10 days | none | integrating two different APIs |
How it turned out
Delivery to the UK dropped from ~20 days to ~7–10 (~50% faster), and customers paid no duty. The three-party invoice let the parcel clear customs on the direct route. The hardest part was the integration itself. Our order system had to talk at the same time to a modern API on one side and old XML on the other, and neither partner was prepared for the other, or for us.
What I took away
- Sometimes the solution is in the documents. Changing what was written on the invoice unblocked the whole logistics chain.
- Regulations are a design problem too. The post-Brexit customs requirements defined how the invoice had to look. Once we started from the regulations, we knew what to build.
- Connecting mismatched systems is real product work. A modern API and old XML won’t get along on their own. I have to admit that what took me the most work in this project was exactly figuring out how to connect them, and staying patient in conversations with the partners.