Skip to content

The booking flow: lifecycle of a booking

8 min read

The booking flow is the central business process of partner integration, consisting of two primary stages: creating a booking to register passenger and seat details, and confirming ticket issuance to debit funds and reserve physical seats on the ferry operator’s booking engine. Ferry does not maintain an independent temporary hold on the operator engine; seats belong firmly to passengers only upon successful ticket confirmation.

PrerequisiteBusiness contextReference
Valid API keyAll booking creation and management operations require partner authenticationAuthentication with an API key
Voyage and seat detailsYou need the voyage code, departure date, and selected seat identifiersVoyage search and remaining seats
Knowledge of your partner NET rateThe exact amount debited upon confirming ticket issuanceTicket pricing and multi-level markup
Available organization balanceYour account and all upstream ancestors must have sufficient balance or creditPayments and balances
Webhook configuration (recommended)Register callback endpoints to receive real-time ticket issuance eventsWebhooks and events

The diagram below illustrates the interaction sequence when creating and confirming a booking:

sequenceDiagram
participant A as "Your system"
participant B as "Ferry API"
participant M as "Financial ledger"
participant O as "Operator system"
A->>B: "Create new booking (POST /bookings)"
B-->>A: "Booking ID, Requested status (2)"
Note over A,B: "Order created, no funds debited yet, payment timer started"
A->>B: "Confirm issuance (POST /bookings/confirmToIssue/{id})"
B->>M: "Verify balance and credit limit along org chain"
alt Insufficient funds
M-->>B: "Insufficient balance"
B-->>A: "Balance error, booking remains in status 2"
else Sufficient funds
M-->>B: "Hold funds based on partner NET rate"
B->>O: "Submit ticket issuance request to operator"
alt Operator issues tickets successfully
O-->>B: "Operator electronic ticket codes"
B-->>A: "Booking transitions to Issued (10)"
else Operator rejects or encounters error
O-->>B: "Issuance error response"
B-->>A: "Booking transitions to Issue Error (6), funds refunded"
end
end

The table below summarizes the actions at each step:

StepYour systemFerry APIPartner takeaway
1Search voyage and inspect layoutReturns schedules and deck seat statusesRe-check seat availability right before booking
2Call booking creation endpointCreates booking record and attaches payment timerReceives booking ID in Requested status (2)
3Check balance and payment deadlineMonitors allocated payment deadlineEnsure available balance covers partner NET rate
4Call ticket confirmation endpointLocks booking, holds funds, calls operatorExecution may take several minutes depending on operator
5Poll booking statusReturns latest updated order stateContinue periodic polling until a terminal state is reached
6Download tickets and deliver to userProvides download URLs for issued e-ticketsExecute once the booking transitions to status 10

The business status of a booking tracks order progression from initial submission to final completion or cancellation.

The diagram below illustrates the state transitions of a booking:

stateDiagram-v2
state "Draft (0)" as s0
state "Requested (2)" as s2
state "Issue Error (6)" as s6
state "Expired (8)" as s8
state "Issued (10)" as s10
state "Cancel Requested (12)" as s12
state "Cancelled (14)" as s14
state "Trip Cancelled (16)" as s16
[*] --> s0
s0 --> s2: Booking creation call
s2 --> s10: Ticket issuance confirmed
s2 --> s6: Operator reports error
s2 --> s8: Every order in the booking is cancelled
s2 --> s14: Cancelled before issuance
s10 --> s12: Cancellation request submitted
s12 --> s14: Cancellation approved
s10 --> s16: Operator cancels departure
s8 --> [*]
s14 --> [*]
s16 --> [*]

Meaning of booking statuses:

CodeStatusMeaning and next action
0DraftInternal draft, not exposed on the partner tier.
2RequestedOrder created, seats marked in Ferry; await confirmation before payment deadline.
6Issue ErrorOperator rejected issuance or connection timed out; funds refunded; retry possible.
8ExpiredEvery order in the booking has been cancelled; seats are released. Create a new booking if the customer still needs one.
10IssuedTickets successfully issued on the operator system; deliver e-tickets to passenger.
12Cancel RequestedTicket cancellation request under review; see Cancellation and refund.
14CancelledOrder cancellation completed; refunded money credited back to agency account.
16Trip CancelledOperator cancelled voyage due to weather or technical reasons; assist with refund or exchange.

Alongside the business status, each booking maintains an independent payment status axis:

The diagram below shows the payment states of a booking:

stateDiagram-v2
state "Unpaid (1)" as p1
state "Partially Paid (3)" as p3
state "Paid (4)" as p4
state "Paid with Debt (5)" as p5
state "Refunded (18)" as p18
state "Cancelled (30)" as p30
[*] --> p1
p1 --> p4: Issuance confirmed successfully
p1 --> p3: Partial payment received
p3 --> p4: Outstanding balance settled
p1 --> p5: Upstream partner extends credit
p5 --> p4: Debt fully repaid
p4 --> p18: Funds refunded after cancellation
p1 --> p30: Booking cancelled while unpaid
p4 --> p30: Booking cancelled after payment
  • Unpaid (1): Default state upon booking creation.
  • Partially Paid (3): A partial payment through the banking channel; ticket confirmation does not produce this status.
  • Paid (4): Funds debited successfully during ticket confirmation or debt settled.
  • Paid with Debt (5): Upstream parent organization authorized debt to issue tickets in advance. Once the debt is settled, Ferry automatically changes payment status from 5 to 4 without a partner call.
  • Refunded (18): Money refunded to agency balance following cancellation approval.
  • Cancelled (30): Payment transaction cancelled.

Ferry does not hold seats on the operator booking engine while a passenger enters their details:

  1. When a booking is created (status 2), Ferry marks the seats in its internal seat map to prevent other Ferry users from selecting them.
  2. The ferry operator and other direct agents of the operator can still sell those seats until your confirmation call successfully executes against the operator.
  3. Seats firmly belong to your passenger only when the booking transitions to Issued (10).

The payment deadline (payment_expired_at) equals the creation time plus the smaller of your organization’s configured payment window, expressed in hours and converted to minutes, and the minutes remaining until the earliest departure among the booking’s legs. Without an organization setting, the deadline equals that departure time. You can filter bookings by payment_expired_at_from and payment_expired_at_to.

A scheduled task processes overdue unpaid bookings. Status 8 means every order in the booking has been cancelled; do not infer it from the deadline alone.

Background processing of overdue unpaid bookings does not send partners an advance notification. Read payment_expired_at and schedule customer reminders yourself.

Handling timeouts during booking creation (No Idempotency)

Section titled “Handling timeouts during booking creation (No Idempotency)”

Ferry does not support idempotency keys on booking creation. Sending POST /bookings twice creates two separate bookings with two distinct booking codes.

Standard procedure on network timeout or disconnect:

  1. Never immediately issue a fresh creation call.
  2. Query the booking list API, filtering by passenger phone number, voyage code, and departure date.
  3. If a matching booking is found, use its booking ID and proceed directly to confirmation.
  4. Only create a new booking if you are certain the original call never reached the system.

When calling ticket confirmation:

  • Ferry acquires an internal execution lock for up to 600 seconds per booking to prevent duplicate processing. Retrying while issuance is running returns HTTP 422 (“processing”).
  • A cooldown ceiling allows at most 5 confirmation attempts per 60 seconds per booking. Exceeding this temporarily rejects requests.
  • For certain operators, issuance can take 5–8 minutes. Set your client timeout accordingly or rely on periodic polling of the booking status.

The payment lock lasts 180 seconds. A confirmation retried while work is in progress does not replay the first call’s result. The soft per-booking confirmation limit returns a business error rather than HTTP 429. Webhooks time out after 2 seconds and are not retried, so polling remains the final confirmation. Real-time push requires a logged-in user’s JWT and cannot replace polling for API-key integrations.

Automated reconciliation of pending bookings

Section titled “Automated reconciliation of pending bookings”

If a booking has been debited but ticket response from the operator was interrupted, Ferry’s background reconciliation workers automatically verify the status with the operator and advance the booking to Issued (10) within several minutes. In this situation, avoid creating replacement orders or initiating cancellations prematurely.

Four operators in the directory do not currently support automated electronic ticket issuance via API: Binh An Ha Tien, Thanh Thoi, Hang Chau Tourist, and Saigon WaterGo. Bookings for these operators can be created, but the confirmation call will return an error. See Ticket issuance.

  • Orders are read-only for partners: Use /orders to list and inspect individual legs. Create and confirm tickets through /bookings, not through the order group.
  • Seat conflicts: SuperDong can return UnavailableSeats when another operator-side agent takes a seat between booking creation and confirmation.
  • Partial issuance: Some legs can succeed while others fail. Ferry flags the partial result and refunds the failed legs; do not assume every leg has the same outcome.
  • Booking list limits: Pages are silently capped at 50, only _id sorting is supported, and an internal failure can return HTTP 200 with an empty list. Alert on unexpectedly empty results.
  • Dynamic filters: The booking list returns a deprecation warning. Dynamic filters can still apply to allowed fields, but there is no partner-tier replacement group; do not depend on these filters. See Conventions.
  • Status number collision: Booking status 6 means issuance failed; order status 6 has a different meaning and is currently unused. Identify which resource owns a status before interpreting it.
SymptomProbable causeRecommended actionRetry safe
HTTP 422 on booking creationMissing required fields or invalid passenger payload formatInspect response error details, correct data, and re-sendYes, after correcting payload
Network disconnect during creationNetwork drop or slow upstream responseQuery bookings by phone and voyage before creating anewDo not re-create immediately
HTTP 422 reported as processingIssuance lock currently held for this bookingWait several minutes and poll booking statusWait and poll status
Rate limit error on confirmationExceeded 5 confirmation attempts within 60 secondsBack off and wait for the 60-second window to clearYes, after cooldown
Insufficient balance error on confirmationOrganization balance or credit limit insufficientTop up agency balance or request credit increase upstreamYes, after funds are available
Status Issue Error (code 6)Operator rejected order or operator connection timed outInspect operator error message; correct data and re-confirmYes, if error allows retry

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

CapabilityScalar tag
Create bookings, confirm issuance, view details, download ticketsBookings
Manage passenger information attached to ordersCustomers
Inspect details of individual leg orders in a bookingOrders

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

PageRelated topic
Voyage search and remaining seatsDiscovering voyages and inspecting seat layouts
Ticket pricing and multi-level markupOrganization markup rules and price components
Payments and balancesBalance deduction mechanics and credit limits
Ticket issuanceDetailed execution of electronic ticket issuance
Cancellation and refundSubmitting cancellation requests and refund policies
Webhooks and eventsReal-time event notifications for booking status changes