Section 09
Every partner sits behind an adapter.
VOYA's product code never speaks a partner's dialect. It speaks one canonical schema, and adapters translate. That is what makes a partner replaceable, a contract renegotiable, and a launch date independent of any single supplier signing.
Mock partner simulator
01VOYA request
Canonical search request — city, dates, party, currency AED.
02Adapter
Translates canonical request into the partner's own dialect.
03Partner API
Partner-specific endpoint, auth, rate limits, pagination.
04Normaliser
Partner response mapped back into VOYA's canonical inventory schema.
05Ranking
Itinerary fit, memory, price, quality and cancellation flexibility.
06VOYA product
One consistent object, whichever partner it came from.
Schema mapping · hotels
voya.property.idpartner.hotelCode
voya.property.namepartner.hotel_name
voya.rate.totalpartner.price.gross
voya.rate.currencyAED (converted)
voya.rate.refundablepartner.cxlPolicy.free == true
voya.rate.freeUntilpartner.cxlPolicy.deadline
voya.property.ratingpartner.starRating
Resilience contract
Timeout4 s per partner call
Retries2, exponential backoff + jitter
Circuit breakerOpens at 50% error rate / 30 s
FailoverSecondary partner in same category
IdempotencyKey per booking attempt
CompensationVoid authorisation on fulfilment failure
CachingSearch 60 s · static content 24 h
Why this matters commercially
Build starts before a single partner contract is signed. Mock adapters implement the same interface as production ones, so the marketplace is fully testable today and a real supplier is a credential swap and a certification run — not a re-architecture.
Adapter interface — the only thing a new partner has to implement
interface InventoryAdapter<TSearch, TItem> {
readonly partnerId: string
readonly category: 'hotel' | 'flight' | 'mobility' | 'food' | 'esim' | 'experience'
search(req: CanonicalSearch): Promise<CanonicalResult<TItem>[]>
availability(itemId: string, req: CanonicalSearch): Promise<Availability>
book(req: CanonicalBooking, idempotencyKey: string): Promise<CanonicalBookingRef>
cancel(ref: CanonicalBookingRef): Promise<CancellationOutcome>
health(): Promise<HealthReport>
}Six methods. Product code calls only these. MockHotelAdapter and PartnerAHotelAdapter are interchangeable at runtime by configuration.