Book real travel from your terminal — search flights, hotels & activities, plan trips, and check out with a price-gated booking. For AI agents and travel advisors.
Search flights, hotels, and activities; compose trip plans; take them to a paid checkout — from the terminal. Everything syncs to the web app at voyagier.com.
The CLI is a shell for the Voyagier MCP server. Every trip-planning command is one MCP tool: voyagier <tool_name> --<param> <value> … --json. The command list and flags come from the server's tool list, so voyagier --help is always the current surface and voyagier <tool_name> --help is the tool's contract.
npm install -g @voyagier/cli
voyagier login # interactive — keeps the token out of shell history
# or, for scripts/agents: pipe the token via stdin (never pass it as an argument)
printf '%s' "$PAT" | voyagier auth set-token -
voyagier doctor --json # credentials + MCP connection + tool count + version
Get a PAT: voyagier.com → Settings → Personal Access Tokens → Create.
Or use env vars for CI/scripts:
export VOYAGIER_TOKEN=***
export VOYAGIER_MCP_URL=https://mcp.voyagier.com/api/mcp # optional (default)
No install permissions? Zero-install works for every command: npx @voyagier/cli doctor --json.
This skill is a quick orientation. The full, always-current integration contract ships with the CLI itself:
voyagier agent-docs # the MCP server's own guidance first, then AGENT.md: tool model, flag typing, JSON shapes, error codes
Read it once per session before non-trivial work. Everything below is a summary of that document.
MCP-native host? Connect to the hosted server directly (voyagier mcp install <client>, or https://mcp.voyagier.com/api/mcp with your PAT). It is the same tool surface the CLI wraps. Stdio-only hosts run voyagier mcp, a proxy that forwards to the same server.
A trip plan is a goal graph. create_plan scaffolds the plan + goals (flights, hotel, dates, destination, travellers); you explore inventory with search_*, put a result on a plan goal with promote_search, and pick with select_option. get_plan_status tells you what's left; get_plan_quote is the checkout truth; book_plan closes with a price-gated checkout. Trip-level state (dates, destination, airports) changes only through set_plan_dates, set_destination, set_airport and create_plan — searches never write to a plan.
Always pass --json on tool commands.
# 0. Health check
voyagier doctor --json
# 1. Advisors only: find or create the client the plan is for. Trip planners (planning your own
# travel) skip this step — create_plan puts the plan on your own client record automatically.
voyagier list_clients --query "Doe" --json
voyagier create_client --name "Doe Family" --client_type Individual --email "doe@example.com" --json
# 2. Resolve the destination, then scaffold the plan with its party
voyagier search_destinations --query "Lisbon" --json
# advisors: pass the client
voyagier create_plan --client_id <CLIENT_ID> --title "Doe — Lisbon" --travel_destination_id <DEST_ID> \
--start_date 2026-11-20 --end_date 2026-11-27 \
--travellers '[{"first_name":"Jane","last_name":"Doe","type":"Adult"}]' --json
# trip planners: omit --client_id (the plan is your own trip)
voyagier create_plan --title "Lisbon" --travel_destination_id <DEST_ID> \
--start_date 2026-11-20 --end_date 2026-11-27 \
--travellers '[{"first_name":"Jane","last_name":"Doe","type":"Adult"}]' --json
# 3. Explore (no plan is touched) → poll while status is Fetching → promote onto the plan's goal
voyagier search_flights --from BWI --to LIS --date 2026-11-20 --return 2026-11-27 --json
voyagier get_search_status --search_id <SEARCH_ID> --json
voyagier promote_search --plan_id <PLAN_ID> --search_id <SEARCH_ID> --goal_id <GOAL_ID> --json
# 4. Options → pick
voyagier get_options --selection_id <SELECTION_ID> --json
voyagier select_option --option_id <OPTION_ID> --json
# 5. Readiness — ONE call: what's blocked, what's next
voyagier get_plan_status --plan_id <PLAN_ID> --json
# Switch on .readiness: Blocked → act on blockers[] / nextActions[];
# InProgress → poll; ReadyToBook → get_plan_quote; Booked → done.
# 6. Close: quote (chargeable truth), then a price-GATED checkout
voyagier get_plan_quote --plan_id <PLAN_ID> --json
# .acceptance = { expectTotalCents, itemIds } — pass both verbatim:
voyagier book_plan --plan_id <PLAN_ID> --expect_total_cents <CENTS> --item_ids <ID> <ID> --json
{ error: true, code, message, details? } — branch on code. Exit 1 = handled, 2 = unexpected. Codes: AUTH_FAILED, PERMISSION_DENIED, RATE_LIMITED (details.retryAfterSeconds), VALIDATION, API_ERROR (the tool's own text), NETWORK, COMMAND_REMOVED.get_plan_status --json → { "tripPlanId": ..., "readiness": ..., ... }. Empty fields are omitted; jq keys when in doubt.voyagier search_tools --query "<what you want>" --json, then voyagier get_tool_details --name <tool> --json.--plan_id, --selection_id; arrays as repeated values (--item_ids a b); objects as JSON literals.book_plan requires the price gate — --expect_total_cents and --item_ids, both from get_plan_quote. Price drift → the server refuses, no checkout.book_plan — a retry mints a second payable link.Fetching means poll (get_search_status for standalone searches, get_options for plan selections). Back off between polls; the endpoint is rate limited.select_option does not hold the price.Expired.plan-trip, search flights, select, plans …). Running one prints the replacement tool and exits 1.book_plan and share_plan (real charges / real client access).~/.voyagier/credentials.json (mode 0600); the tool cache at ~/.voyagier/tools-cache.json.