Skip to content

The ferry CLI

6 min read

ferry is Ferry’s official command-line tool for people who work with the partner API without writing code: search voyages and prices, view seat maps, build a booking from a passenger list in Excel, then issue tickets or send a cancellation request. The CLI lives in the open-source repository ferry-vn/ferry-sdk and shares its core with the SDK.

The CLI is on npm and needs Node.js 22.12 or later:

Terminal window
npm install -g @ferryvn/cli

To run it once without installing, use npx @ferryvn/cli <command>. Verify with ferry --version: it prints the CLI version together with the bundled SDK version, for example 1.0.0 (sdk 1.0.0). Pier lookups such as ferry locations "phu quoc" work even before you log in, because the pier catalogue is public data.

ferry login asks you to paste the API key (hidden on screen), verifies the key with Ferry, and stores it in a profile. An agency admin creates the key in the Dashboard; see Authentication with an API key.

Terminal window
ferry login
ferry whoami --check
ferry doctor

ferry whoami --check confirms the key still works; ferry doctor checks configuration, connectivity, and the key.

To work against UAT, create a second profile with a UAT key and pick the profile when you run a command:

Terminal window
ferry login --profile uat --env uat
ferry --profile uat voyages search --from "Rạch Giá" --to "Phú Quốc" --date tomorrow
ferry profiles use uat

UAT is not a sandbox: issuing tickets there still books real tickets and spends real money; see Environments. When settings overlap, the order of priority is command-line flags, then environment variables (FERRY_PROFILE, FERRY_ENV, FERRY_API_KEY), then the profile, and finally production. Avoid --api-key because flags stay in your shell history.

The usual flow goes from lookup to ticket issuance. The lookup commands only read data; creating a booking, issuing tickets, and cancelling write data:

Terminal window
ferry voyages search --from "Rạch Giá" --to "Phú Quốc" --date tomorrow
ferry calendar --from "Rạch Giá" --to "Phú Quốc" --days 14
ferry prices --from "Rạch Giá" --to "Phú Quốc" --date 2026-11-01 --live 3
ferry seats <voyageId>
ferry customers --search 0901234567
ferry booking draft --customer 1001 --orderer-name "Nguyễn Văn A" --email a@example.com \
--voyage <voyageId> --seats A1,A2 --passengers khach.csv --out booking.json
ferry booking create --file booking.json
ferry booking issue <id>
  1. Look up voyages, calendar, and prices: voyages search finds voyages; calendar shows how many voyages run each day; prices shows selling prices per voyage, seat type, and ticket type (--live 3 re-prices the first 3 voyages from their seat maps; otherwise prices can lag the operator).
  2. Check seats and customers: seats lists the free seats of a voyage; customers --search finds a customer from the text you type, for example a phone number, and gives the customer id (--customer) used when building the booking.
  3. Build a draft booking: booking draft takes seat names and a passenger list, picks each ticket type from age using the operator’s rules, matches prices, checks seats and duplicate ID numbers, and writes the result to booking.json. Nothing is sent.
  4. Create the booking: booking create --file booking.json sends the booking; alternatively add --create to booking draft to do both steps at once. Add --dry-run to only validate. Creating a booking attaches the seats and passengers to it and charges nothing; the booking is Requested and unpaid, with a payment deadline (see Bookings).
  5. Issue tickets: booking issue <id> charges the balance and credit and then orders real tickets from the operator. The command asks for confirmation: the --yes flag, or typing the booking id back on an interactive terminal; before you confirm, the CLI prints the total and your reservable credit. With automated operators this step can take minutes.
  6. Cancel tickets: ferry cancel request --order <id> --positions 101,102 --reason "…" holds the cancellation fee immediately and marks the tickets cancelled; it asks for confirmation just like issuance.

The remaining commands are booking get, booking list, booking tickets, orders, cancel list, account, transactions, debts, vouchers, and disruptions. The ferry api command sends a raw request with your credentials and asks before sending a write. The full list of flags is in the CLI package README.

booking draft reads a CSV exported from Excel or Google Sheets, or a JSON file. Example CSV:

name,date_of_birth,social_id,home_town,gender
Nguyễn Văn A,1990-05-01,079090000001,Cần Thơ,nam
Nguyễn Văn B,2018-03-02,079090000001,Cần Thơ,nam
ColumnMeaning
namePassenger’s full name (the headers ho_ten or Họ tên are accepted)
date_of_birthDate of birth as YYYY-MM-DD (ngay_sinh or Ngày sinh accepted)
social_idNational ID or passport number (cccd or Số CCCD accepted)
home_townHome town (que_quan accepted)
gendermale or female, nam or nữ, 1 or 0 (gioi_tinh accepted)
national_idOptional; defaults to Vietnam; list the values with ferry operators nationals
ticket_type_idOptional; by default chosen from age
plate_number, passport_expired_atOptional; vehicle plate and passport expiry date

When you save from Excel, choose CSV UTF-8 so Vietnamese text is not corrupted; the CLI refuses files that are not UTF-8 and points you to this format. The separator is ,, or ; when the header row uses semicolons (Excel with a Vietnamese locale). ID numbers must differ between passengers, except on the child ticket types that the operator exempts.

The --output flag (short -o) accepts table, json, ndjson, or csv; --json is a shorthand. CSV output carries a UTF-8 BOM so Excel opens Vietnamese text correctly, and cells that start like a formula are neutralised to prevent formula injection. Example exports of pending bookings and transactions for accounting:

Terminal window
ferry booking list --status Requested --output csv > don.csv
ferry transactions --output csv > giao-dich.csv

Use --all to fetch every page instead of the first. Other shared flags are --timeout, --base-url, and --debug (writes the HTTP log to stderr with the key redacted).

CodeMeaning
0Success
1API, server, or network error (also doctor with failed checks)
2Usage error: bad flags, invalid input, or you did not confirm
3Authentication or permission: 401, 403
4Not found: 404
5Rate limited: 429

Profiles and keys live in a config.json file with mode 0600:

Operating systemDirectory
Linux~/.config/ferry/ (honours XDG_CONFIG_HOME when set)
macOS~/Library/Application Support/ferry/
Windows%APPDATA%\ferry\

Set the FERRY_CONFIG_DIR variable to use another directory.

MisconceptionRealityCorrect practice
One profile can serve both UAT and productionThe two environments need two keysferry login --profile uat --env uat, then pick it with --profile
UAT is as safe as a sandboxIssuing on UAT places real orders and spends real moneyOnly issue on voyages agreed with Ferry
booking draft already created the bookingBy default it only writes a draft fileAdd --create or run booking create once you have checked the draft
Saving the CSV from Excel in the default encodingThe CLI refuses files that are not UTF-8Choose CSV UTF-8 when saving
Re-running booking create after a network errorThe API has no idempotency key, a rerun can create a second orderRun ferry booking list --search … to check first
Typing the key with --api-keyShell history keeps the keyUse ferry login or the FERRY_API_KEY variable

The full list of commands and flags is in the CLI package README on GitHub; the repository also ships sample files examples/passengers.csv and examples/booking.json. The raw HTTP reference is on Scalar UI.

What to look upWhere
Commands and flagsThe CLI package README on GitHub
Sample CSV and JSON filesThe examples folder of the ferry-sdk repository
HTTP routes and schemas behind each commandScalar, groups Bookings, Voyages, Cancel Ticket Requests
PageWhen to read
TypeScript SDKThe same booking-building logic when you want to write code
The booking flowUnderstand the booking states the commands produce
Ticket issuanceUnderstand what happens when you run booking issue
Cancellation and refundsUnderstand the consequences of cancel request