Booking is not a single request. It is a distributed workflow involving search sessions, inventory, changing prices, traveler data, payment and supplier confirmation. Reliability starts by treating the flow as a state machine instead of a chain of screens.

Model the booking lifecycle

Define product states such as searching, selected, repricing, details complete, payment pending, paid, confirming, confirmed and failed. Screens become projections of the current state rather than the source of truth.

Persist only the identifiers and user input needed to restore the flow. Supplier inventory and final pricing should always be refreshed from authoritative services.

Respect session and cache boundaries

Search results often depend on a session identifier and have limited lifetime. Store the session and selected offer together, surface expiry clearly, and treat a cache miss as a recoverable product event rather than an unexplained generic error.

When a result expires, return the user to a meaningful recovery path: refresh the selected offer, repeat search with preserved criteria, or explain that availability changed.

Reprice before commitment

Prices and availability can change between search and checkout. Add an explicit validation or repricing step before payment. Compare the updated result to the user’s selection and require confirmation when the commercial terms change.

Keep traveler data structured

Traveler requirements vary by product and supplier. Build form definitions from typed requirements, validate locally for immediate feedback and validate again on the backend. Preserve entered data during recoverable errors so the user does not repeat work.

Create one payment reference

Generate a payment reference before opening a gateway and use it across registration, authorization, callbacks and confirmation. This gives support and reconciliation systems one stable key.

Wallet, installment and card methods should produce a unified product result even when their gateway mechanics differ.

Treat confirmation as asynchronous

A gateway success does not always mean the supplier reservation is confirmed. Display a pending state when necessary and allow the app to poll or receive a server-driven update using the stable reference.

Never ask the user to pay again merely because the client missed a callback. Query the backend first.

Design observability with the flow

Log transitions using non-sensitive identifiers: search session, reservation reference, payment reference and supplier reference. Capture latency and failure category at each step. Avoid storing passport, card or unnecessary personal data in analytics.

Reliability checklist

  • Every request belongs to a known booking state.
  • Expired sessions have a recovery path.
  • Final price is validated before payment.
  • Payment and supplier confirmation are separate states.
  • Retries are idempotent.
  • Support can trace a flow using stable references.
AE

Amgad ElNezamy

iOS engineer working across SwiftUI, UIKit, architecture, payments and production mobile product delivery.

Back to all articles