{"openapi":"3.0.0","info":{"title":"Safiri Booking API","version":"1.0.0","description":"REST API for booking transportation services including buses, ferries, flights, and parcel delivery. This API supports both Safiri agents and third-party integrations.","contact":{"name":"Safiri Apps","url":"https://www.safiri.app","email":"support@safiri.app"},"license":{"name":"MIT","url":"https://opensource.org/licenses/MIT"}},"servers":[{"url":"https://booking-api-dev.safiri.app","description":"Development server"},{"url":"https://api.safiri.app","description":"Production server"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT token obtained from /api/logon endpoint"}},"schemas":{"ReverseProxyDomain":{"type":"object","required":["id","name","domainType","publicSuffix","redirectForName","verificationStatus","createdAt"],"properties":{"id":{"type":"string","example":"cd-abc123"},"name":{"type":"string","example":"satcoexpress.com"},"domainType":{"type":"string","enum":["apex","subdomain"]},"publicSuffix":{"type":"string","example":"com"},"redirectForName":{"type":"string","example":""},"verificationStatus":{"type":"string","enum":["verified","unverified"]},"createdAt":{"type":"string","format":"date-time"},"server":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string","example":"srv-abc123"},"name":{"type":"string","example":"reverse-proxy"}}}}},"FlightOffer":{"type":"object","properties":{"type":{"type":"string","example":"flight-offer"},"id":{"type":"string","example":"1"},"offerReference":{"type":"string","format":"uuid","description":"Opaque, user-bound reference required for reservation","example":"4d6873cb-8cc2-4f64-b7ba-566a422b7d8b"},"expiresAt":{"type":"string","format":"date-time","description":"Authoritative deadline for reviewing or reserving this search offer","example":"2027-02-01T12:15:00.000Z"},"source":{"type":"string","example":"GDS"},"instantTicketingRequired":{"type":"boolean","example":false},"nonHomogeneous":{"type":"boolean","example":false},"oneWay":{"type":"boolean","example":false},"isUpsellOffer":{"type":"boolean","example":false},"lastTicketingDate":{"type":"string","format":"date","example":"2025-06-10"},"lastTicketingDateTime":{"type":"string","example":"2025-06-10"},"numberOfBookableSeats":{"type":"number","example":9},"itineraries":{"type":"array","items":{"type":"object","properties":{"duration":{"type":"string","example":"PT1H30M"},"durations":{"type":"object","additionalProperties":true},"segments":{"type":"array","items":{"type":"object","properties":{"departure":{"type":"object","properties":{"iataCode":{"type":"string","example":"JRO"},"terminal":{"type":"string","example":"1"},"at":{"type":"string","format":"date-time","example":"2025-06-15T10:00:00"},"stop":{"type":"object","additionalProperties":true}}},"arrival":{"type":"object","properties":{"iataCode":{"type":"string","example":"DAR"},"terminal":{"type":"string","example":"3"},"at":{"type":"string","format":"date-time","example":"2025-06-15T11:30:00"},"stop":{"type":"object","additionalProperties":true}}},"carrierCode":{"type":"string","example":"TC"},"number":{"type":"string","example":"123"},"aircraft":{"type":"object","properties":{"code":{"type":"string","example":"320"}}},"operating":{"type":"object","additionalProperties":true},"transitAgency":{"type":"object","additionalProperties":true},"duration":{"type":"string","example":"PT1H30M"},"durations":{"type":"object","additionalProperties":true},"numberOfStops":{"type":"number","example":0},"cabin":{"type":"string","example":"ECONOMY"}}}}}}},"price":{"type":"object","properties":{"currency":{"type":"string","example":"USD"},"total":{"type":"string","example":"150.00"},"base":{"type":"string","example":"120.00"},"fees":{"type":"array","items":{"type":"object","properties":{"amount":{"type":"string","example":"30.00"},"type":{"type":"string","example":"SUPPLIER"}}}},"grandTotal":{"type":"string","example":"150.00"},"bookingFeeTotal":{"type":"string","description":"Total customer-visible Safiri and agent booking fees","example":"12.00"},"walletDebitTotal":{"type":"string","description":"Frozen amount debited from an agent wallet after TST creation","example":"150.00"},"walletSettlement":{"type":"object","description":"Authoritative agent-wallet payable derived from the authenticated wallet currency","required":["currency","unroundedDebit","debitTotal"],"properties":{"currency":{"type":"string","example":"TZS"},"unroundedDebit":{"type":"string","example":"582936.51"},"debitTotal":{"type":"string","example":"583000.00"},"rounding":{"type":"object","description":"Absent when the wallet currency has no cash-rounding policy","required":["policyVersion","increment","adjustment"],"properties":{"policyVersion":{"type":"string","example":"FLIGHT_WALLET_CASH_ROUNDING_V1"},"increment":{"type":"string","example":"1000"},"adjustment":{"type":"string","example":"63.49"}}}}},"pricingContext":{"type":"string","enum":["ONLINE","SAFIRI_AGENT","THIRD_PARTY_AGENT"],"example":"ONLINE"},"bookingFees":{"type":"array","items":{"type":"object","required":["amount","currency","type","recipient"],"properties":{"amount":{"type":"string","example":"12.00"},"currency":{"type":"string","example":"USD"},"type":{"type":"string","enum":["SAFIRI_COMMISSION","AGENT_COMMISSION"]},"recipient":{"type":"string","enum":["SAFIRI","SAFIRI_AGENT"]},"roundingAdjustment":{"type":"string","description":"Cash-rounding uplift already included in the Safiri commission","example":"63.49"}}}},"otherCurrencies":{"type":"object","description":"Optional display conversions; these values are never authoritative for supplier repricing","additionalProperties":{"type":"object","required":["currency","total","bookingFeeTotal","grandTotal","walletDebitTotal","bookingFees"],"properties":{"currency":{"type":"string","example":"TZS"},"total":{"type":"string","example":"390000.00"},"bookingFeeTotal":{"type":"string","example":"31200.00"},"grandTotal":{"type":"string","example":"421200.00"},"walletDebitTotal":{"type":"string","example":"390000.00"},"bookingFees":{"type":"array","items":{"type":"object","required":["amount","currency","type","recipient"],"properties":{"amount":{"type":"string","example":"31200.00"},"currency":{"type":"string","example":"TZS"},"type":{"type":"string","enum":["SAFIRI_COMMISSION","AGENT_COMMISSION"]},"recipient":{"type":"string","enum":["SAFIRI","SAFIRI_AGENT"]},"roundingAdjustment":{"type":"string","description":"Converted cash-rounding uplift already included in the Safiri commission","example":"0.03"}}}}}}}}},"pricingOptions":{"type":"object","additionalProperties":true},"validatingAirlineCodes":{"type":"array","items":{"type":"string","example":"TC"}},"travelerPricings":{"type":"array","items":{"type":"object","properties":{"travelerId":{"type":"string","example":"1"},"fareOption":{"type":"string","example":"STANDARD"},"travelerType":{"type":"string","example":"ADULT"},"price":{"type":"object","properties":{"currency":{"type":"string","example":"USD"},"total":{"type":"string","example":"150.00"},"base":{"type":"string","example":"120.00"}}},"fareDetailsBySegment":{"type":"array","items":{"type":"object","properties":{"segmentId":{"type":"string","example":"1"},"cabin":{"type":"string","example":"ECONOMY"},"fareBasis":{"type":"string","example":"Y"},"class":{"type":"string","example":"Y"},"includedCheckedBags":{"type":"object","properties":{"quantity":{"type":"number","example":1}}}}}}}}},"commission":{"type":"object","additionalProperties":true},"fareRules":{"type":"object","additionalProperties":true},"policiesAndAllowance":{"type":"object","additionalProperties":true}}},"NotificationPreferences":{"type":"object","properties":{"safiriAccountCreation":{"type":"boolean","description":"If false, suppresses Safiri account creation notifications","example":false},"ticketPurchase":{"type":"boolean","description":"If false, suppresses ticket-purchase confirmation notifications. Third-party flight bookings never receive reservation, unpaid-reminder, or cancellation notifications; their confirmation remains enabled by default unless this value is false.","example":true},"allOtherTripNotification":{"type":"boolean","description":"If false, suppresses delay, cancellation, and other trip update notifications for eligible bookings. It cannot re-enable reservation, reminder, or cancellation notifications for a third-party agent booking.","example":true}}},"PassengerDetails":{"type":"object","properties":{"firstName":{"type":"string","example":"John"},"lastName":{"type":"string","example":"Doe"},"dateOfBirth":{"type":"string","format":"date","example":"1990-01-01"},"gender":{"oneOf":[{"type":"integer","enum":[0,1]},{"type":"string","enum":["M","MALE","F","FEMALE","X","OTHER","NONBINARY","U","UNKNOWN","UNSPECIFIED"]}],"example":0,"description":"0/M/MALE = male, 1/F/FEMALE = female; X and U variants are also accepted"},"ageCategory":{"oneOf":[{"type":"integer","enum":[0,1,2]},{"type":"string","enum":["ADT","ADULT","CHD","CHILD","INF","INFANT","HELD_INFANT"]}],"example":0,"description":"0/ADT = adult, 1/CHD = child, 2/INF = infant"},"phoneNumber":{"type":"string","example":"1234567890"},"countryCode":{"type":"string","example":"255"},"countryCodeName":{"type":"string","example":"Tanzania"},"email":{"type":"string","format":"email","example":"john@example.com"},"passportNumber":{"type":"string","example":"AB123456"},"documentType":{"type":"string","enum":["P","PASSPORT","I","IDENTITY_CARD","F","A"],"example":"PASSPORT"},"passportExpiryDate":{"type":"string","format":"date","example":"2030-01-01"},"passportIssuedDate":{"type":"string","format":"date","example":"2020-01-01"},"documentIssuingCountry":{"type":"string","minLength":2,"maxLength":2,"description":"ISO 3166-1 alpha-2 document issuing country","example":"TZ"},"nationality":{"type":"string","example":"TZ"},"nationalityCountry":{"type":"string","example":"Tanzania"},"nextOfKin":{"type":"string","example":"Jane Doe"},"identificationInfo":{"type":"string","example":"PASSPORT"}},"required":["firstName","lastName","dateOfBirth","gender","ageCategory","phoneNumber","countryCode","countryCodeName","email","passportNumber","documentType","passportExpiryDate","documentIssuingCountry","nationality"]},"FlightTicket":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"ticketId":{"type":"string","example":"RVLJBT13R6IA38T"},"bookingReference":{"type":"string","example":"ABC123"},"paymentReference":{"type":"string","example":"PAY123"},"reservationId":{"type":"string","format":"uuid","example":"ebf4463e-b505-43e0-ad79-4d4499c3a5dc"},"externalUserId":{"type":"string","description":"The selling agent's own downstream user identifier","example":"agent-user-42"},"recordLocators":{"type":"array","items":{"$ref":"#/components/schemas/FlightRecordLocator"}},"providerSystem":{"type":"string","example":"FLIGHT_PROVIDER"},"providerOfficeId":{"type":"string","example":"OFFICE-1"},"lastProviderSyncAt":{"type":"string","format":"date-time"},"travelerId":{"type":"string","example":"1"},"passengerReference":{"type":"integer","example":1},"itineraryIndex":{"type":"integer","minimum":0,"example":0},"direction":{"type":"string","enum":["OUTBOUND","RETURN"],"example":"OUTBOUND"},"tstReference":{"type":"integer","example":7},"pricingRecordReference":{"type":"integer","example":1},"providerSegmentReferences":{"type":"array","items":{"type":"integer"},"example":[1,2]},"documentId":{"type":"string","example":"1:1:7"},"ticketNumber":{"type":"string","example":"1234567890123"},"documentStatus":{"type":"string","example":"ISSUED"},"providerDocumentElement":{"type":"string","enum":["FA","FH"],"example":"FA"},"validatingCarrier":{"type":"string","example":"KQ"},"coupons":{"type":"array","description":"Current status of each ticket coupon when available.","items":{"type":"object","properties":{"segmentReference":{"type":"integer","example":1},"status":{"type":"string","example":"OPEN"},"lastObservedAt":{"type":"string","format":"date-time"}}}},"issuedAt":{"type":"string","format":"date-time"},"departureDate":{"type":"string","format":"date","example":"2025-06-15"},"departureTime":{"type":"string","example":"10:00"},"from":{"type":"string","example":"Kilimanjaro International Airport"},"to":{"type":"string","example":"Julius Nyerere International Airport"},"price":{"type":"object","properties":{"total":{"type":"string","example":"150.00"},"currency":{"type":"string","example":"USD"}}},"priceScope":{"type":"string","enum":["PASSENGER_JOURNEY"],"description":"The price is the passenger total for the complete journey. For return bookings it appears on both local itinerary rows and must be aggregated once per reservation/passenger."},"boughtByUser":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid"},"fullName":{"type":"string","example":"John Doe"},"email":{"type":"string","format":"email","example":"john@example.com"},"externalUserId":{"type":"string","description":"External user ID for reference tracking","example":"user_12345"}}},"passengerDetails":{"type":"object","properties":{"fullName":{"type":"string","example":"John Doe"},"firstName":{"type":"string","example":"John"},"lastName":{"type":"string","example":"Doe"},"email":{"type":"string","format":"email","example":"john@example.com"},"phoneNumber":{"type":"string","example":"1234567890"}}},"notificationPreferences":{"$ref":"#/components/schemas/NotificationPreferences"},"status":{"type":"string","example":"CONFIRMED"}}},"AgentReserveTicketSummary":{"type":"object","properties":{"ticketId":{"type":"string","example":"RVLJBT13R6IA38T"},"bookingReference":{"type":"string","example":"ABC123"},"paymentReference":{"type":"string","example":"PAY123"},"departureDate":{"type":"string","format":"date","example":"2025-06-15"},"departureTime":{"type":"string","example":"10:00"},"from":{"type":"string","example":"Kilimanjaro International Airport"},"to":{"type":"string","example":"Julius Nyerere International Airport"},"price":{"type":"object","properties":{"total":{"type":"string","example":"150.00"},"currency":{"type":"string","example":"USD"}}},"passengerSummary":{"type":"object","properties":{"fullName":{"type":"string","example":"John Doe"}}},"paymentDeadlineAt":{"type":"string","format":"date-time","example":"2025-06-15T10:25:00.000Z"}}},"AgentReserveReservationSummary":{"type":"object","properties":{"bookingReference":{"type":"string","example":"ABC123"},"paymentReference":{"type":"string","example":"PAY123"},"paymentDeadlineAt":{"type":"string","format":"date-time","example":"2025-06-15T10:25:00.000Z"},"paymentTimeLimitInSeconds":{"type":"number","example":1500},"ticketIds":{"type":"array","items":{"type":"string","example":"RVLJBT13R6IA38T"}},"verifyUrl":{"type":"string","example":"https://safiri.app/en/ticket/review?ticketUuid=RVLJBT13R6IA38T&bookingReference=ABC123"},"id":{"type":"string","example":"order-id"},"reservationId":{"type":"string","format":"uuid","example":"ebf4463e-b505-43e0-ad79-4d4499c3a5dc"},"status":{"type":"string","example":"TST_CREATED"},"expiresAt":{"type":"string","format":"date-time"},"priceVersion":{"type":"string","example":"sha256-price-version"},"pricingRecords":{"type":"array","items":{"$ref":"#/components/schemas/FlightPricingRecord"}},"documents":{"type":"array","items":{"$ref":"#/components/schemas/FlightTicketDocument"}},"recordLocators":{"type":"array","items":{"$ref":"#/components/schemas/FlightRecordLocator"}},"associatedRecords":{"type":"array","items":{"type":"object","properties":{"reference":{"type":"string","example":"ABC123"},"creationDate":{"type":"string","format":"date-time"},"originSystemCode":{"type":"string","example":"GDS"},"flightOfferId":{"type":"string","example":"1"}}}}}},"FlightPricingRecord":{"type":"object","required":["reference","passengerReferences","supplierPrice","status"],"properties":{"reference":{"type":"integer","example":1},"passengerReferences":{"type":"array","items":{"type":"integer"},"example":[1]},"segmentReferences":{"type":"array","items":{"type":"integer"},"example":[1,2]},"tstReference":{"type":"integer","example":7},"status":{"type":"string","enum":["PRICED","TST_CREATED","FAILED"],"example":"TST_CREATED"},"supplierPrice":{"type":"object","required":["currency","total"],"properties":{"currency":{"type":"string","example":"USD"},"total":{"type":"string","example":"150.00"},"base":{"type":"string","example":"120.00"},"taxes":{"type":"string","example":"30.00"},"validatingCarrier":{"type":"string","example":"KQ"},"fareBasis":{"type":"array","items":{"type":"string"},"example":["YFLEX"]},"bookingClasses":{"type":"array","items":{"type":"string"},"example":["Y"]},"brands":{"type":"array","items":{"type":"string"},"example":["FLEX"]},"taxDetails":{"type":"array","items":{"type":"object","properties":{"amount":{"type":"string","example":"25.50"},"currency":{"type":"string","example":"USD"},"code":{"type":"string","example":"YQ"},"countryCode":{"type":"string","example":"TZ"}}}},"baggage":{"type":"array","items":{"type":"string"}},"fareRestrictions":{"type":"array","items":{"type":"string"}},"segmentFareDetails":{"type":"array","items":{"type":"object","properties":{"segmentReferences":{"type":"array","items":{"type":"integer"}},"fareBasis":{"type":"string","example":"YFLEX"},"bookingClasses":{"type":"array","items":{"type":"string"}},"brands":{"type":"array","items":{"type":"string"}},"baggage":{"type":"array","items":{"type":"string"}},"fareRestrictions":{"type":"array","items":{"type":"string"}}}}}}}}},"FlightTicketDocument":{"type":"object","required":["travelerId","passengerReference","status"],"properties":{"documentId":{"type":"string","example":"1:1:7"},"travelerId":{"type":"string","example":"1"},"passengerReference":{"type":"integer","example":1},"pricingRecordReference":{"type":"integer","example":1},"segmentReferences":{"type":"array","items":{"type":"integer"},"example":[1,2]},"tstReference":{"type":"integer","example":7},"ticketNumber":{"type":"string","example":"1234567890123"},"providerElement":{"type":"string","enum":["FA","FH"],"example":"FA"},"validatingCarrier":{"type":"string","example":"KQ"},"issuedAt":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["EXPECTED","ISSUED","UNKNOWN"],"example":"EXPECTED"}}},"FlightRecordLocator":{"type":"object","required":["controlNumber","type","scope","firstObservedAt","lastObservedAt"],"properties":{"companyId":{"type":"string","example":"KQ"},"controlNumber":{"type":"string","example":"KQ9XYZ"},"type":{"type":"string","enum":["GDS","AIRLINE"]},"scope":{"type":"string","enum":["PNR","SEGMENT"]},"segmentReferences":{"type":"array","items":{"type":"integer"},"example":[1]},"firstObservedAt":{"type":"string","format":"date-time"},"lastObservedAt":{"type":"string","format":"date-time"}}},"FlightReservationTraveler":{"type":"object","required":["id","contact"],"properties":{"id":{"type":"string","example":"1"},"dateOfBirth":{"type":"string","format":"date","example":"1990-01-01"},"name":{"type":"object","properties":{"firstName":{"type":"string","example":"John"},"lastName":{"type":"string","example":"Doe"}}},"fullName":{"type":"string","example":"John Doe"},"gender":{"type":"string","enum":["MALE","FEMALE"]},"ageCategory":{"type":"string","enum":["ADULT","CHILD","INFANT"]},"contact":{"type":"object","properties":{"emailAddress":{"type":"string","format":"email","example":"john@example.com"},"phones":{"type":"array","items":{"type":"object","properties":{"deviceType":{"type":"string","example":"MOBILE"},"countryCallingCode":{"type":"string","example":"255"},"number":{"type":"string","example":"712345678"}}}}}},"documents":{"type":"array","items":{"type":"object","properties":{"documentType":{"type":"string","example":"PASSPORT"},"number":{"type":"string","example":"AB123456"},"expiryDate":{"type":"string","format":"date","example":"2030-01-01"},"nationality":{"type":"string","example":"TZ"},"issuanceCountry":{"type":"string","example":"TZ"},"validityCountry":{"type":"string","example":"TZ"},"holder":{"type":"boolean","example":true}}}}}},"SoapFlightReservationSummary":{"type":"object","required":["reservationId","status","expiresAt"],"properties":{"id":{"type":"string","format":"uuid","example":"ebf4463e-b505-43e0-ad79-4d4499c3a5dc"},"reservationId":{"type":"string","format":"uuid","example":"ebf4463e-b505-43e0-ad79-4d4499c3a5dc"},"status":{"type":"string","enum":["CREATED","SELLING","PNR_CREATED","VALIDATION_FAILED","PRICE_CHANGED","REPRICE_UNAVAILABLE","TST_CREATED","ISSUING","ISSUED","PARTIALLY_ISSUED","CANCELLING","CANCELLED","REFUND_PENDING","REFUND_REQUIRED","RECONCILIATION_REQUIRED"],"example":"TST_CREATED"},"expiresAt":{"type":"string","format":"date-time"},"paymentTimeLimitInSeconds":{"type":"integer","example":1380},"priceVersion":{"type":"string","description":"Canonical version required when accepting a changed price"},"associatedRecords":{"type":"array","items":{"type":"object","properties":{"reference":{"type":"string","example":"ABC123"},"originSystemCode":{"type":"string","example":"FLIGHT_PROVIDER"},"flightOfferId":{"type":"string","example":"1"}}}},"recordLocators":{"type":"array","description":"Booking record locators returned for the reservation","items":{"$ref":"#/components/schemas/FlightRecordLocator"}},"flightOffers":{"type":"array","items":{"$ref":"#/components/schemas/FlightOffer"}},"travelers":{"type":"array","items":{"$ref":"#/components/schemas/FlightReservationTraveler"}},"pricingRecords":{"type":"array","items":{"$ref":"#/components/schemas/FlightPricingRecord"}},"documents":{"type":"array","items":{"$ref":"#/components/schemas/FlightTicketDocument"}}}},"ErrorResponse":{"type":"object","required":["errorCode","errorMessage","status"],"properties":{"errorCode":{"type":"string","description":"Flight errors include unavailable offers, invalid traveler data, changed prices, expiry, issuance, refund, and reconciliation outcomes.","example":"FLIGHT_PRICE_CHANGED"},"error":{"type":"object","properties":{"name":{"type":"string","example":"modal"}}},"errorMessage":{"type":"string","example":"Invalid request parameters"},"data":{"type":"object","additionalProperties":true,"description":"Structured reservation, price-change, validation, or reconciliation details"},"status":{"type":"number","example":400}}},"FlightSearchRequest":{"type":"object","required":["originLocationCode","destinationLocationCode","departureDate"],"properties":{"originLocationCode":{"type":"string","description":"IATA code of origin airport/city","example":"JRO"},"destinationLocationCode":{"type":"string","description":"IATA code of destination airport/city","example":"DAR"},"departureDate":{"type":"string","format":"date","description":"Departure date in YYYY-MM-DD format","example":"2025-06-15"},"returnDate":{"type":"string","format":"date","description":"Return date in YYYY-MM-DD format (for round trips)","example":"2025-06-20"},"adults":{"type":"number","description":"Number of adult travelers (age 12 or older)","minimum":1,"maximum":9,"default":1,"example":1},"children":{"type":"number","description":"Number of child travelers (age 2-11)","minimum":0,"maximum":9,"default":0,"example":0},"infants":{"type":"number","description":"Number of infant travelers (age 0-2)","minimum":0,"maximum":9,"default":0,"example":0},"travelClass":{"type":"string","enum":["ECONOMY","PREMIUM_ECONOMY","BUSINESS","FIRST"],"example":"ECONOMY"},"includedAirlineCodes":{"type":"array","items":{"type":"string"},"description":"Array of airline IATA codes to include","example":["TC","PW"]},"excludedAirlineCodes":{"type":"array","items":{"type":"string"},"description":"Array of airline IATA codes to exclude","example":[]},"nonStop":{"type":"boolean","description":"If true, only non-stop flights","default":false,"example":false},"currencyCode":{"type":"string","description":"Currency used for customer-visible prices.","example":"USD"},"maxPrice":{"type":"number","description":"Maximum price in the customer display currency.","example":500},"max":{"type":"number","description":"Maximum number of results. Values above 200 are accepted for backward compatibility and treated as 200.","minimum":1,"default":200,"example":200},"lookAheadDays":{"type":"integer","minimum":1,"maximum":7,"description":"When present, an empty exact-date search checks this many later date pairs and reports the earliest chronologically proven match.","example":7}}},"FlightSearchDatePair":{"type":"object","required":["departureDate"],"properties":{"departureDate":{"type":"string","format":"date","example":"2026-09-04"},"returnDate":{"type":"string","format":"date","description":"Omitted for a one-way search.","example":"2026-09-08"}}},"FlightSearchLookAhead":{"type":"object","required":["requestedDays","status","firstChecked","confirmedThrough"],"properties":{"requestedDays":{"type":"integer","minimum":1,"maximum":7},"status":{"type":"string","enum":["NOT_NEEDED","FOUND","NO_RESULTS","INCOMPLETE"]},"firstChecked":{"allOf":[{"$ref":"#/components/schemas/FlightSearchDatePair"}],"nullable":true},"confirmedThrough":{"allOf":[{"$ref":"#/components/schemas/FlightSearchDatePair"}],"nullable":true}}},"FlightSearchAvailability":{"type":"object","required":["status","requested","lookAhead","next"],"properties":{"status":{"type":"string","enum":["RESULTS_FOUND","NO_RESULTS"],"description":"Describes only the originally requested date pair."},"requested":{"$ref":"#/components/schemas/FlightSearchDatePair"},"lookAhead":{"$ref":"#/components/schemas/FlightSearchLookAhead"},"next":{"allOf":[{"$ref":"#/components/schemas/FlightSearchDatePair"}],"nullable":true}},"description":"When lookAhead.status is FOUND, next and confirmedThrough are the earliest proven date pair. For NO_RESULTS, confirmedThrough is the final checked pair; for INCOMPLETE, it is the last consecutively confirmed-empty pair or null. next is null in every non-FOUND state."},"FlightSearchResponse":{"type":"object","required":["meta","data"],"properties":{"meta":{"type":"object","required":["count"],"properties":{"count":{"type":"integer","description":"Number of offers returned for the originally requested date pair."},"availability":{"$ref":"#/components/schemas/FlightSearchAvailability"}}},"data":{"type":"array","description":"Offers for the originally requested date pair. Look-ahead candidates are never returned here.","items":{"$ref":"#/components/schemas/FlightOffer"}}}},"FlightTravelerBookingRequirements":{"type":"object","properties":{"travelerId":{"type":"string","example":"1"},"travelerType":{"type":"string","enum":["ADULT","CHILD","INFANT"]},"firstNameRequired":{"type":"boolean"},"lastNameRequired":{"type":"boolean"},"dateOfBirthRequired":{"type":"boolean"},"genderRequired":{"type":"boolean"},"documentRequired":{"type":"boolean"},"documentTypeRequired":{"type":"boolean"},"documentNumberRequired":{"type":"boolean"},"documentExpiryDateRequired":{"type":"boolean"},"documentIssuingCountryRequired":{"type":"boolean"},"nationalityRequired":{"type":"boolean"}}},"FlightBookingRequirements":{"type":"object","required":["profileVersion","journeyType","source","travelerRequirements"],"properties":{"profileVersion":{"type":"integer","example":1},"journeyType":{"type":"string","enum":["DOMESTIC","INTERNATIONAL"]},"domesticCountryCode":{"type":"string","minLength":2,"maxLength":2,"example":"TZ"},"operatingCarrierCodes":{"type":"array","items":{"type":"string"},"example":["TC"]},"source":{"type":"string","enum":["ITINERARY_DEFAULT","CARRIER_OVERRIDE","PROVIDER_ESCALATION"]},"providerRequiredFields":{"type":"array","items":{"type":"string"}},"emailAddressRequired":{"type":"boolean"},"phoneCountryCodeRequired":{"type":"boolean"},"mobilePhoneNumberRequired":{"type":"boolean"},"phoneNumberRequired":{"type":"boolean"},"travelerRequirements":{"type":"array","items":{"$ref":"#/components/schemas/FlightTravelerBookingRequirements"}}}},"FlightReservationPassenger":{"type":"object","required":["firstName","lastName","ageCategory"],"properties":{"firstName":{"type":"string","example":"John"},"lastName":{"type":"string","example":"Doe"},"email":{"type":"string","format":"email","description":"Passenger notification email. Required unless supplied by the optional top-level contact fallback.","example":"john@example.com"},"phoneNumber":{"type":"string","description":"Passenger subscriber number or full E.164 number. Required unless supplied by the optional top-level contact fallback.","example":"712345678"},"countryCode":{"type":"string","description":"Passenger international calling code. Required unless supplied by the optional top-level contact fallback.","example":"255"},"dateOfBirth":{"type":"string","format":"date","example":"1990-01-01"},"gender":{"oneOf":[{"type":"integer","enum":[0,1]},{"type":"string","enum":["M","MALE","F","FEMALE","X","OTHER","U","UNKNOWN"]}]},"ageCategory":{"oneOf":[{"type":"integer","enum":[0,1,2]},{"type":"string","enum":["ADT","ADULT","CHD","CHILD","INF","INFANT"]}]},"documentType":{"type":"string","enum":["P","PASSPORT","I","IDENTITY_CARD","F","A"]},"passportNumber":{"type":"string","example":"AB123456"},"passportExpiryDate":{"type":"string","format":"date","example":"2030-01-01"},"passportIssuedDate":{"type":"string","format":"date","example":"2020-01-01"},"documentIssuingCountry":{"type":"string","minLength":2,"maxLength":2,"example":"TZ"},"nationality":{"type":"string","example":"TZ"},"nationalityCountry":{"type":"string","example":"Tanzania"},"countryCodeName":{"type":"string","example":"Tanzania"}},"description":"Traveler fields vary by itinerary. Use bookingRequirements from /api/flight/offer to determine which document fields are required. Every passenger must ultimately have email, phoneNumber, and countryCode; the optional top-level contact object fills only missing passenger values."},"FlightReservationRequest":{"type":"object","required":["passengers"],"oneOf":[{"required":["offerReference"]},{"required":["flightOffer"]}],"properties":{"offerReference":{"type":"string","format":"uuid","description":"Opaque server-side offer reference returned by flight search"},"flightOffer":{"$ref":"#/components/schemas/FlightOffer","description":"Complete selected search offer. Only its offerReference is used; the server reloads the authoritative offer snapshot."},"passengers":{"type":"array","items":{"$ref":"#/components/schemas/FlightReservationPassenger"},"example":[{"firstName":"John","lastName":"Doe","dateOfBirth":"1990-01-01","gender":0,"ageCategory":0,"countryCodeName":"Tanzania","passportNumber":"AB123456","documentType":"PASSPORT","passportExpiryDate":"2030-01-01","passportIssuedDate":"2020-01-01","documentIssuingCountry":"TZ","nationality":"TZ","nationalityCountry":"Tanzania"}]},"contact":{"type":"object","description":"Optional booking-level fallback. Each value fills only the corresponding missing field on a passenger; passenger-specific values take precedence.","properties":{"email":{"type":"string","format":"email","description":"Fallback email for passengers without their own"},"phoneNumber":{"type":"string","description":"Fallback subscriber number or full E.164 number for passengers without their own"},"countryCode":{"type":"string","description":"Fallback international calling code, such as 255, for passengers without their own"}}},"selectedOption":{"type":"string","enum":["FLEXIBLE_FARE","NON_REFUNDABLE_FARE"],"default":"NON_REFUNDABLE_FARE","example":"NON_REFUNDABLE_FARE"},"notifications":{"$ref":"#/components/schemas/NotificationPreferences"},"priceAcceptance":{"type":"object","description":"Accepts the walletSettlement amount and currency for agent reservations, or the display grand total and currency for customer reservations","required":["priceVersion","amount","currency"],"properties":{"priceVersion":{"type":"string"},"amount":{"type":"string","example":"164.20"},"currency":{"type":"string","example":"USD"}}}}},"FlightReservationResponse":{"type":"object","properties":{"reservation":{"$ref":"#/components/schemas/AgentReserveReservationSummary"},"tickets":{"type":"array","items":{"$ref":"#/components/schemas/AgentReserveTicketSummary"}}}},"CustomerFlightReservationResponse":{"type":"object","required":["tickets","flightReservation"],"properties":{"tickets":{"type":"array","items":{"$ref":"#/components/schemas/FlightTicket"}},"flightReservation":{"$ref":"#/components/schemas/SoapFlightReservationSummary"}}},"FlightIssuanceResponse":{"type":"object","required":["reservationId","status","documents"],"properties":{"reservationId":{"type":"string","format":"uuid"},"status":{"type":"string","example":"ISSUED"},"bookingReference":{"type":"string","example":"ABC123"},"recordLocators":{"type":"array","items":{"$ref":"#/components/schemas/FlightRecordLocator"}},"documents":{"type":"array","items":{"$ref":"#/components/schemas/FlightTicketDocument"}}}},"FlightCancellationResponse":{"type":"object","required":["reservationId","state","paymentState","refundState","alreadyCancelled"],"properties":{"reservationId":{"type":"string","format":"uuid"},"ticketId":{"type":"string","example":"RVLJBT13R6IA38T"},"bookingReference":{"type":"string","example":"ABC123"},"state":{"type":"string","enum":["CANCELLED","REFUND_PENDING","REFUND_REQUIRED"]},"cancelledAt":{"type":"string","format":"date-time"},"paymentState":{"type":"string","enum":["NOT_REQUIRED","PENDING","CONFIRMED","MISMATCH","REFUND_PENDING","REFUNDED","REFUND_REQUIRED"]},"refundState":{"type":"string","nullable":true,"enum":["REFUNDED","REFUND_PENDING","REFUND_REQUIRED"]},"alreadyCancelled":{"type":"boolean","description":"True when the reservation was already cancelled before this request."}}}}},"security":[{"bearerAuth":[]}],"tags":[{"name":"Flight Booking","description":"Flight booking API endpoints"},{"name":"Authentication","description":"User authentication endpoints"},{"name":"Tickets","description":"Ticket management endpoints"},{"name":"Parcels","description":"Parcel delivery endpoints"},{"name":"Trips","description":"Trip management endpoints"},{"name":"Users","description":"User management endpoints"},{"name":"Companies","description":"Company management endpoints"},{"name":"Reverse Proxy Domains","description":"Administrative management of reverse proxy domains"},{"name":"Reverse Proxy Configurations","description":"Administrative management of tenant Nginx configurations"}],"paths":{"/api/flight/tickets":{"get":{"summary":"Retrieve flight ticket(s) by ticket ID","description":"Retrieves flight ticket details by ticket ID.\nCan be used to check ticket status, passenger details, and booking information.\n","tags":["Flight Booking"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"ticketId","required":true,"schema":{"type":"string"},"description":"The ticket ID (e.g., RVLJBT13R6IA38T)","example":"RVLJBT13R6IA38T"}],"responses":{"200":{"description":"Successful response with ticket details","content":{"application/json":{"schema":{"type":"object","properties":{"tickets":{"type":"array","items":{"$ref":"#/components/schemas/FlightTicket"}}}}}}},"400":{"description":"Bad request - Missing or invalid ticket ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing JWT token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Ticket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/flight/search":{"post":{"summary":"Search for available flight offers","description":"Searches over 400 airlines to find the cheapest flights for a given itinerary.\nThe API lets you search flights between two cities, perform multi-city searches\nfor longer itineraries and access one-way combinable fares to offer the cheapest options possible.\ncurrencyCode/Content-Currency controls the customer-visible quote.\nSet lookAheadDays from 1 through 7 to check later date pairs only when the\nrequested dates return no matching offers. Candidate offers are not returned;\nsubmit a new exact search using meta.availability.next after user confirmation.\n","tags":["Flight Booking"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightSearchRequest"},"example":{"originLocationCode":"JRO","destinationLocationCode":"DAR","departureDate":"2025-06-15","returnDate":"2025-06-20","adults":1,"children":0,"infants":0,"travelClass":"ECONOMY","includedAirlineCodes":["TC","PW"],"excludedAirlineCodes":[],"nonStop":false,"currencyCode":"USD","maxPrice":500,"max":5,"lookAheadDays":7}}}},"responses":{"200":{"description":"Requested-date offers and optional look-ahead availability evidence","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightSearchResponse"}}}},"400":{"description":"Bad request - Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing JWT token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"502":{"description":"FLIGHT_SEARCH_UNAVAILABLE, FLIGHT_INVALID_RESPONSE, or FLIGHT_SUPPLIER_CURRENCY_UNAVAILABLE","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Search cache or authoritative offer storage is temporarily unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/flight/offers/search":{"post":{"summary":"Compatibility alias for flight search","description":"Returns the same user-bound offers, offerReference values, and optional look-ahead metadata as /api/flight/search.","tags":["Flight Booking"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightSearchRequest"}}}},"responses":{"200":{"description":"Requested-date offers and optional look-ahead availability evidence","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightSearchResponse"}}}},"400":{"description":"Invalid search","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/flight/offer":{"post":{"summary":"Confirm a selected flight offer","description":"Loads the authenticated user's saved offer. Repeating the same reference returns the same offer,\nexpiry, and SSR DOCS/contact requirements while it remains valid.\n","tags":["Flight Booking"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","oneOf":[{"required":["offerReference"]},{"required":["flightOffer"]}],"properties":{"offerReference":{"type":"string","format":"uuid"},"flightOffer":{"allOf":[{"$ref":"#/components/schemas/FlightOffer"}],"description":"The complete selected search offer; its offerReference is used."}}},"example":{"flightOffer":{"id":"1","offerReference":"4d6873cb-8cc2-4f64-b7ba-566a422b7d8b"}}}}},"responses":{"200":{"description":"Stored offer and booking requirements","content":{"application/json":{"schema":{"type":"object","required":["offerReference","expiresAt","flightOffer","bookingRequirements"],"properties":{"offerReference":{"type":"string","format":"uuid"},"expiresAt":{"type":"string","format":"date-time"},"flightOffer":{"$ref":"#/components/schemas/FlightOffer"},"bookingRequirements":{"$ref":"#/components/schemas/FlightBookingRequirements"}}}}}},"400":{"description":"offerReference is missing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing JWT token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"FLIGHT_OFFER_EXPIRED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"The authoritative offer store is temporarily unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/flight/reserve":{"post":{"summary":"Reserve a selected customer flight offer","tags":["Flight Booking"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightReservationRequest"}}}},"responses":{"201":{"description":"Reservation and current price confirmed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerFlightReservationResponse"}}}},"202":{"description":"Reservation is in progress or requires reconciliation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"400":{"description":"Missing offer or passenger request data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing JWT token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"FLIGHT_PRICE_CHANGED, FLIGHT_REPRICE_UNAVAILABLE, or reservation request conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"FLIGHT_OFFER_EXPIRED or FLIGHT_RESERVATION_EXPIRED. FLIGHT_OFFER_EXPIRED carries `data.refreshSearch: true` once the supplier recommendation has been retired, with `data.reason` naming the provider refusal that retired it (FLIGHT_SELL_UNAVAILABLE, FLIGHT_RESERVATION_FAILED or FLIGHT_REPRICE_UNAVAILABLE). Its cached quote is already gone, so the client must run a new search rather than retry this offerReference.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"FLIGHT_PASSENGER_DATA_INVALID with traveler/field details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"A retryable local reservation failure occurred","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"502":{"description":"FLIGHT_SUPPLIER_CURRENCY_UNAVAILABLE","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/flight/reserve/agent":{"post":{"summary":"Create flight reservation (Agent/Third-Party)","description":"Creates a flight reservation and freezes the later float-account debit.\nThis endpoint is used by both Safiri agents and third-party API users.\nRequires SAFIRI_AGENT (222) permission level.\n\n**Flight Booking Usage:**\n- Pass `X-External-User-Id` header to track your internal user IDs\n- Use `notifications` object to control which notifications are sent\n- The reservation freezes the quoted wallet debit; the balance is checked once when purchase is admitted\n","tags":["Flight Booking"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"header","name":"X-External-User-Id","schema":{"type":"string","maxLength":128},"description":"Third-party internal user ID for reference tracking (optional). When supplied, use the same value on every retry for the selected offer.","example":"user_12345"},{"in":"header","name":"Content-Language","schema":{"type":"string","default":"en"},"description":"Language for responses"},{"in":"header","name":"Content-Currency","schema":{"type":"string","default":"USD"},"description":"Currency for pricing"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightReservationRequest"},"example":{"offerReference":"4d6873cb-8cc2-4f64-b7ba-566a422b7d8b","passengers":[{"firstName":"John","lastName":"Doe","email":"john@example.com","phoneNumber":"712345678","countryCode":"255","dateOfBirth":"1990-01-01","gender":0,"ageCategory":0,"countryCodeName":"Tanzania","documentType":"PASSPORT","passportNumber":"AB123456","passportExpiryDate":"2030-01-01","passportIssuedDate":"2020-01-01","documentIssuingCountry":"TZ","nationality":"TZ","nationalityCountry":"Tanzania"}],"selectedOption":"NON_REFUNDABLE_FARE","notifications":{"safiriAccountCreation":false,"ticketPurchase":true,"allOtherTripNotification":true}}}}},"responses":{"201":{"description":"Reservation created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightReservationResponse"}}}},"202":{"description":"Reservation is in progress, partially issued, or requires reconciliation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"400":{"description":"Bad request - Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing JWT token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"FLIGHT_PRICE_CHANGED, FLIGHT_REPRICE_UNAVAILABLE, FLIGHT_RESERVATION_FAILED, or reservation request conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"FLIGHT_OFFER_EXPIRED or FLIGHT_RESERVATION_EXPIRED. FLIGHT_OFFER_EXPIRED carries `data.refreshSearch: true` once the supplier recommendation has been retired, with `data.reason` naming the provider refusal that retired it (FLIGHT_SELL_UNAVAILABLE or FLIGHT_REPRICE_UNAVAILABLE). Its cached quote is already gone, so the client must run a new search rather than retry this offerReference.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Passenger or SSR DOCS fields are invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"A retryable local reservation failure occurred","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"502":{"description":"The offer is unavailable in the required ticketing currency","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/flight/cancel":{"post":{"summary":"Cancel an unissued flight reservation","description":"Cancels the complete reservation, including every itinerary in a return booking.\nSupply either reservationId or ticketId. Repeated calls are idempotent.\nIssued or partially issued documents require a separate ticket void/refund process.\n","tags":["Flight Booking"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","anyOf":[{"required":["reservationId"]},{"required":["ticketId"]}],"properties":{"reservationId":{"type":"string","format":"uuid"},"ticketId":{"type":"string"},"reason":{"type":"string","maxLength":500}}},"examples":{"byReservation":{"value":{"reservationId":"4d6873cb-8cc2-4f64-b7ba-566a422b7d8b","reason":"Customer changed travel plans"}},"byTicket":{"value":{"ticketId":"RVLJBT13R6IA38T"}}}}}},"responses":{"200":{"description":"The reservation was cancelled and verified, or was already cancelled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightCancellationResponse"}}}},"202":{"description":"Cancellation, refund, partial issuance, or reconciliation is in progress","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/FlightCancellationResponse"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}},"400":{"description":"Missing or conflicting reservation reference","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The reservation belongs to another account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Flight reservation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Issued ticket or reservation state cannot be cancelled automatically","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"A retryable local cancellation failure occurred","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/flight/purchase/agent":{"post":{"summary":"Synchronously issue all expected SOAP ticket documents for an admitted agent purchase","description":"Checks the current wallet balance once when the purchase is first admitted.\nSOAP issuance then completes synchronously and the 200 response is returned\nonly after every expected ticket document is verified. The frozen wallet\ndebit and customer notifications run through restart-safe idempotent\nfollow-up work. Concurrent admitted purchases may make the wallet negative.\n","tags":["Flight Booking"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ticketId"],"properties":{"ticketId":{"type":"string","example":"RVLJBT13R6IA38T"},"ticketUuids":{"type":"array","items":{"type":"string","format":"uuid"},"deprecated":true,"description":"Accepted for client compatibility but ignored; the server uses the reservation's authoritative ticket batch."}}}}}},"responses":{"200":{"description":"Every expected ticket document is confirmed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightIssuanceResponse"}}}},"202":{"description":"Concurrent, partial, refund, or reconciliation state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"400":{"description":"ticketId is missing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The reservation belongs to another account or the account is not an agent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Ticket or flight reservation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Initial wallet admission, FOP, or definite issuance failure","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"FLIGHT_RESERVATION_EXPIRED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Unexpected issuance infrastructure failure","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/flight/ticket/issue/signal":{"post":{"summary":"Confirm customer payment and start ticket issuance","tags":["Flight Booking"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"paymentReference":{"type":"string","example":"PAY123"},"ticketId":{"type":"string","example":"RVLJBT13R6IA38T"}},"description":"Supply paymentReference or ticketId."}}}},"responses":{"200":{"description":"Reservation was already fully issued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightIssuanceResponse"}}}},"202":{"description":"Confirmed payment was accepted for issuance","content":{"application/json":{"schema":{"type":"object","properties":{"signaled":{"type":"boolean","example":true},"workflowId":{"type":"string"},"ticketId":{"type":"string"},"paymentReference":{"type":"string"},"ticketUuids":{"type":"array","items":{"type":"string","format":"uuid"}}}}}}},"403":{"description":"Internal flight-issuance authorization is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Ticket or flight reservation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"PAYMENT_NOT_CONFIRMED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"FLIGHT_RESERVATION_EXPIRED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Unexpected issuance infrastructure failure","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/flight/ticket/issue/direct":{"post":{"summary":"Resume ticket issuance manually","description":"Internal Safiri recovery endpoint. Ordinary direct issuance resolves either a customer or agent reservation and bypasses the customer payment-confirmation gate. Cancelled-payment recovery is enabled when any recovery field is supplied; it requires sudo authorization, all three recovery identifiers plus the replacement ticketId, and issues against the atomically reassigned confirmed payment without bypassing payment confirmation. Before using cancelled-payment recovery, operations must independently confirm that the source PNR is inactive with no FA/FH documents, that no legacy PawaPay refund exists, and that the IATA wallet can fund issuance. The replacement issuance engine then retrieves its PNR and verifies ticket documents, FOP, ticketing authority, and FM commission before IssueTicket.","tags":["Flight Booking"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","anyOf":[{"required":["ticketId"]},{"required":["paymentReference"]}],"properties":{"ticketId":{"type":"string"},"paymentReference":{"type":"string"},"sourceTicketId":{"type":"string","description":"Cancelled source ticket whose confirmed payment is being recovered"},"paymentRequestId":{"type":"string","description":"Mongo ObjectId of the confirmed customer payment request"},"reconciliationOperationId":{"type":"string","format":"uuid","description":"Approved admin reconciliation operation authorizing this recovery"}}},"examples":{"byTicketId":{"value":{"ticketId":"TICKET-123"}},"byPaymentReference":{"value":{"paymentReference":"PAY-123"}},"cancelledPaymentRecovery":{"value":{"ticketId":"REPLACEMENT-TICKET-123","sourceTicketId":"CANCELLED-TICKET-123","paymentRequestId":"68bc5acbb6f2f09af10c19de","reconciliationOperationId":"9a1f61e0-840c-4ca1-bf96-18db58019828"}}}}}},"responses":{"200":{"description":"Every expected ticket document is confirmed issued","content":{"application/json":{"schema":{"type":"object","properties":{"issued":{"type":"boolean","example":true},"ticketId":{"type":"string"},"paymentReference":{"type":"string"},"ticketUuids":{"type":"array","items":{"type":"string","format":"uuid"}},"issuance":{"$ref":"#/components/schemas/FlightIssuanceResponse"},"paymentRecovery":{"type":"object","description":"Non-PII recovery identifiers and durable state; present only for cancelled-payment recovery","properties":{"reconciliationOperationId":{"type":"string","format":"uuid"},"sourceTicketId":{"type":"string"},"replacementTicketId":{"type":"string"},"state":{"type":"string","enum":["RESERVED","ISSUED","REFUND_REQUIRED"]},"recoveryIdempotent":{"type":"boolean"},"finalizationIdempotent":{"type":"boolean"}}}}}}}},"202":{"description":"Issuance is already active, requires safe reconciliation, or recovery was reserved and needs a later retry. A definitive no-document refund outcome may include paymentRecovery.state REFUND_REQUIRED.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightIssuanceResponse"}}}},"400":{"description":"Direct lookup is missing, or cancelled-payment recovery fields are incomplete or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Safiri admin or sudo authorization is required for ordinary direct issuance; exact sudo authorization is required for cancelled-payment recovery","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Ticket or flight reservation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The reservation cannot be issued in its current state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"The reservation is no longer safe to issue","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Unexpected issuance infrastructure failure","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/companies":{"get":{"summary":"Retrieve companies","description":"Returns all companies.\nAdd `mini=true` to return a compact response with only\n`uuid`, `tinNumber`, `name`, `tradingName`, and `companyType`.\nLegacy companies without a type return `companyType: null`.\n","tags":["Companies"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"mini","required":false,"schema":{"type":"string","enum":["true"]},"description":"Set to `true` (case-insensitive) to return a compact payload.","example":"true"}],"responses":{"200":{"description":"Successful response with companies","content":{"application/json":{"schema":{"type":"array","items":{"oneOf":[{"title":"MiniCompany","description":"Exact item shape returned when `mini=true`.","type":"object","additionalProperties":false,"required":["uuid","tinNumber","name","tradingName","companyType"],"properties":{"uuid":{"type":"string","format":"uuid"},"tinNumber":{"type":"string"},"name":{"type":"string"},"tradingName":{"type":"string","nullable":true},"companyType":{"type":"string","nullable":true}}},{"title":"FullCompany","description":"Full item shape returned when `mini` is omitted.","type":"object","additionalProperties":true}]}}}}}}}},"/api/admin/reverse-proxy/configs":{"get":{"summary":"List tenant configurations from the website Nginx template","tags":["Reverse Proxy Configurations"],"responses":{"200":{"description":"Configurations in source-file order and the GitHub blob SHA"},"401":{"description":"Authentication is required"},"403":{"description":"Administrator access is required"},"503":{"description":"GitHub access is unavailable or the template is malformed"}}},"post":{"summary":"Create and commit a canonical tenant server block","tags":["Reverse Proxy Configurations"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domain","companyUuid"],"properties":{"domain":{"type":"string"},"companyUuid":{"type":"string","format":"uuid"},"metadata":{"type":"object"}}}}}},"responses":{"201":{"description":"Configuration committed and verified on the configured branch"},"409":{"description":"Domain, server name, or GitHub blob conflict"},"503":{"description":"The Git operation is unavailable"}}}},"/api/admin/reverse-proxy/configs/{domain}":{"get":{"summary":"Get a tenant configuration by its X-Domain identity","tags":["Reverse Proxy Configurations"],"parameters":[{"in":"path","name":"domain","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Configuration with its strong revision ETag"},"404":{"description":"Configuration not found"}}},"patch":{"summary":"Update and commit tenant-only Nginx directives","tags":["Reverse Proxy Configurations"],"parameters":[{"in":"path","name":"domain","required":true,"schema":{"type":"string"}},{"in":"header","name":"If-Match","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string"},"companyUuid":{"type":"string","format":"uuid"},"metadata":{"type":"object"}}}}}},"responses":{"200":{"description":"Updated configuration, or unchanged when no commit was needed"},"412":{"description":"The supplied revision is stale"},"428":{"description":"If-Match is required"}}},"delete":{"summary":"Delete and commit a tenant server block","tags":["Reverse Proxy Configurations"],"parameters":[{"in":"path","name":"domain","required":true,"schema":{"type":"string"}},{"in":"header","name":"If-Match","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Configuration deleted and the Git commit verified"},"404":{"description":"Configuration not found"},"412":{"description":"The supplied revision is stale"},"428":{"description":"If-Match is required"}}}},"/api/admin/reverse-proxy/domains":{"get":{"summary":"List every reverse proxy custom domain","tags":["Reverse Proxy Domains"],"responses":{"200":{"description":"All domains configured on the Render reverse proxy","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ReverseProxyDomain"}}}}},"401":{"description":"Authentication is required"},"403":{"description":"Administrator access is required"}}},"post":{"summary":"Add a custom domain to the reverse proxy","tags":["Reverse Proxy Domains"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","example":"satcoexpress.com"}}}}}},"responses":{"201":{"description":"Created domain records, including the apex/www pair","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ReverseProxyDomain"}}}}},"409":{"description":"The domain conflicts with an existing Render domain"}}}},"/api/admin/reverse-proxy/domains/{customDomainNameOrId}":{"delete":{"summary":"Delete a reverse proxy custom domain","tags":["Reverse Proxy Domains"],"parameters":[{"in":"path","name":"customDomainNameOrId","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Domain deleted"},"404":{"description":"Domain not found"}}}},"/api/admin/reverse-proxy/domains/{customDomainNameOrId}/verify":{"post":{"summary":"Retrigger DNS verification for a custom domain","tags":["Reverse Proxy Domains"],"parameters":[{"in":"path","name":"customDomainNameOrId","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"Domain verification triggered"},"404":{"description":"Domain not found"}}}}}}