Dynamic packaging â hotels and flights in real time
The classic travel package was static: a printed catalogue, a season book, fixed prices. Dynamic packaging breaks with that: the agent queries flight + hotel in real time, the system assembles the package, calculates margin, and puts it in front of the customer. The difference between an 80,000 HUF and a 110,000 HUF quote is often 12 seconds with the right software.
Architecture: 3 GDS + 12 direct hotel APIs
The Travelium supplier layer currently queries three GDS (Amadeus, Sabre, Travelport) and 12 direct hotel APIs per search. Execution is parallel: 15 calls fire at once, and whatever returns within the first 2.5 seconds is rendered. Anything that arrives later is flagged with a "new result" icon.
This is deliberate: out of the 15, one or two suppliers always respond slowly (3â6 s) or not at all. If we waited for everyone, the agency search UI would be 6 seconds slow â uncompetitive.
Price and availability merge
The trickiest piece of logic: the same hotel can come back on four channels (own API + 2 GDS + one bedbank) with different prices and availability. The merge rules:
- Availability union, price minimum. If any channel has a free room and a price, the package is sellable; the agent sees the cheapest offer first.
- Source tag visible. Next to the price sits the source (
AM= Amadeus,DRT= direct). 4% commission differences become visible here. - Margin calculator. The agent sets the markup on a slider (15â35%), the system instantly shows the final selling price and the agency's commission.
The fallback when a supplier goes down
On 12 March Amadeus did not respond in the EU zone for 47 minutes. Travelium cancels these calls after 8 seconds, flags the supplier DEGRADED, and does not retry for 60 seconds (circuit breaker). In the agent UI a discreet yellow bar signals: "Amadeus temporarily unavailable, 11 other sources active."
So bookings kept flowing through the 47-minute outage â from Sabre, Travelport and the direct hotel APIs. Not a single customer saw an empty result list.
The bug we ate
And the worst moment. On 3 April, between 04:00 and 12:00, the cache layer served stale prices: a hotel was shown for 38,000 HUF for eight hours while the supplier had already moved to 52,000. 23 packages went out at the wrong price, ~340,000 HUF loss.
Root cause: cache invalidation relied on setTimeout and the Node.js process started a new instance after the overnight restart â the timer was lost, invalidation never ran. The fix is BullMQ + Redis TTL key-management; setTimeout no longer appears in the code as if it never existed.
Operational detail from the day-to-day
A typical agent's day on Travelium dynamic packaging: at 9 AM the agency's 4 agents work in parallel, each running ~18 searches an hour. That's 72 concurrent searches from one small office â and across 15 supplier APIs, 1,080 calls per hour. The token bucket works in the background here too so no one breaches the per-supplier limit.
The merge layer answers those parallel searches in 220 ms average (without waiting for the slowest supplier). Full UI render (search â result list): average time-to-first-result 1.8 seconds, time-to-interactive 3.2 seconds.
Tuning the margin slider was its own story: for 4 months we let agents adjust in 0.1% increments, and 92% of the time they picked round 5% values. We simplified to 1% steps â the UI halved in width, usage frequency stayed identical.
Lesson
Dynamic packaging is not one API plugged into a supplier. It's fan-out calls, intelligent merging, a circuit breaker, a margin slider, and â most often the hardest part â a cache layer that never forgets to expire.