Skip to content

Voyage search and remaining seats

6 min read

The voyage search flow provides departure timetables between piers for specific dates, remaining seat counts, and detailed seat maps so that passengers can select their seats before booking. Ferry serves voyage data that is periodically synchronized from ferry operators; the data represents a recent snapshot rather than the instantaneous state of the operator’s booking engine.

PrerequisiteBusiness contextReference
Valid API keySearching voyages, seat maps, and counts requires partner authenticationAuthentication with an API key
Departure and arrival pier codesVoyage lookup uses standardized pier identifiers rather than free-form namesSee public pier catalogue
Target environmentThe UAT sandbox environment disables synchronization for specific operatorsEnvironments
Pagination and date conventionsResponses are capped at 50 records per page; dates use YYYY-MM-DDGeneral conventions
Pricing rulesPrices in voyage search results include markups applied by upstream organizationsTicket pricing and multi-level markup

The diagram below illustrates the sequence of interactions between your system and Ferry during the search flow:

sequenceDiagram
autonumber
participant P as "Your system"
participant F as "Ferry API"
participant S as "Boat layout"
P->>F: "Fetch pier catalogue (public)"
F-->>P: "Pier list with pier codes"
P->>F: "Search voyages by pier pair and date"
alt "Returned list is empty"
F-->>P: "Empty array with status 200"
Note over P,F: "Empty list: no voyages or data service disruption"
P->>P: "Check alert threshold"
else "Voyages available"
F-->>P: "Voyage list with base prices"
P->>S: "Fetch boat layout by voyage ID"
S-->>P: "Seat layout with individual seat statuses"
P->>F: "Count remaining seats"
F-->>P: "Number of available seats"
end

The diagram below shows the relationship between catalogue discovery and voyage lookup:

flowchart LR
A["Fetch pier and route catalogue<br/>(no API key needed)"] --> B["Search voyages by pier and date<br/>(API key required)"]
B --> C["Fetch boat layout for voyage<br/>(API key required)"]
C --> D["Count remaining seats<br/>(API key required)"]
D --> E["Proceed to booking flow"]
A -.->|"Client-side cache"| A
B -.->|"Repeat on date or pier change"| B

The table below summarizes the actions at each step:

StepYour systemFerry APIPartner takeaway
1Fetch route and pier catalogue onceReturns shared catalogue (no key required)Cache locally; do not re-fetch on every user search
2Query voyages by pier pair and dateReturns voyages from synchronized cacheInspect the array; do not immediately assume sold-out on empty
3Fetch boat layout for selected voyageReturns deck structure and seat statusesVacant seats represent the latest sync snapshot
4Count remaining seats before selectionReturns total available seat countConfirm availability against the party size
5Pass voyage and seat data to bookingPrepare voyage, seat, and passenger payloadsSee next: The booking flow
  • Voyage lookup supports a date range for month-calendar views, not only a single day; still fetch all result pages.
  • A YYYY-MM-DD date uses the operator’s local time, with no accompanying timezone field. If your server runs elsewhere, convert to Vietnam time before building the date string.
  • Route and pier catalogues are shared across organizations and remain subject to IP rate limits despite requiring no key. Refresh catalogue caches daily; no change-frequency commitment is defined.

Ferry synchronizes voyage schedules from operators according to designated date brackets:

Date bracketTime windowSync cadence
Near-termToday to 7 days aheadEvery 30 minutes
Medium-term8 to 14 days aheadEvery 2 hours
Long-term15 to 45 days aheadEvery 4 hours
Far-term46 to 90 days ahead3 times daily
Sold-out voyagesAll datesRe-scanned every 40 minutes
Operator-disabled voyagesAll datesRe-scanned every 4 hours

Three factors influence effective data freshness:

  1. Jittered worker scheduling: Sync executions are staggered across a 5-minute window to avoid thundering herds against operator servers.
  2. Skipping unchanged far dates: For long-term schedules, if the cached copy remains valid, queries against the operator engine are skipped.
  3. Fallback during operator outages: Ferry can return the last known valid snapshot for up to 4 hours instead of an error. The response has no indicator identifying fallback data; report unusually unchanged figures to Ferry.

Partner design recommendation: Cache voyage search results on your side for no longer than 5 minutes for near dates, and always refresh the boat layout and available count right before prompting the passenger to finalize their seat.

  • Empty list with status 200: Voyage queries return an empty array if no trips are scheduled or if an internal query disruption occurs. Set up anomaly detection on key commercial routes.
  • Sort parameters are ignored: Sorting by departure time or price is silently replaced with sorting by record identifier. Fetch all pages, then sort the results in your application.
  • Record limit ceilings: Standard voyage searches are silently capped at 50 records per page. The HTML voyage table for embedding in websites or emails has a separate cap of 100. Follow pagination cursors to retrieve all data.
  • Absence of temporary hold: Viewing the seat map or creating a booking does not hold seats on the operator system. A new booking is only a Ferry record; seats and tickets are confirmed after ticket issuance succeeds.
  • Operators without automated ticketing: Voyage searches return schedules across 13 operators, but 4 of them do not currently support automated electronic ticket issuance via API. See Ticket issuance.
SymptomProbable causeRecommended actionRetry safe
Empty voyage list on an active routeBooking window not yet opened or temporary operator connection issueVerify public timetable; notify Ferry if issue persistsRetry after a backoff window
Max 50 items returned despite higher limit requestedSystem pagination ceiling clamped at 50 recordsPaginate through subsequent pages using cursorYes, request next cursor
Results not ordered by departure timeSorting parameters handled by internal identifiersRe-sort the result list in your client applicationNo, handle on client side
Seat shown as available but booking failsSeat taken by another channel prior to order creationRefresh seat layout and prompt user to pick another seatYes, after layout refresh
HTTP 403 returned on voyage searchNot a missing permission: voyage search, seat layouts, and counts require a valid key but no separate permissionsRetry once; if the error persists or is widespread, report it to Ferry operationsYes, once

To inspect exact request schemas and test calls directly, open the Scalar UI under the relevant tags:

CapabilityScalar tag
Search voyages by pier and date, timetablesVoyages
Seat map layout and seat statusBoat Layout
Remaining seat countsVoyage Counts
Route catalogue (public)Routes
Pier locations catalogue (public)Locations
Ferry operators catalogue (public)Operators

For instructions on configuring your API key in Scalar, see API Reference.

PageRelated topic
Ticket pricing and multi-level markupUnderstanding price calculations and additions
The booking flowCreating bookings and managing order lifecycles
General conventionsDate formats, currency conventions, and pagination rules
EnvironmentsData and connectivity differences between UAT and production
Ticket issuanceComplete ticket confirmation flow and issued ticket retrieval