Cruise Itinerary

API reference

Cruise Itinerary API

A JSON API over one base URL, https://cruise-itinerary.com/v1. Reads only, no SDK, nothing to install.

Quickstart

1. Create a free account. We email you a sign-in link; there is no password. Your first key is shown once, so copy it then.

2. Send it as a bearer token.

export CI_API_KEY=ci_live_...
curl -H "Authorization: Bearer $CI_API_KEY" \
  https://cruise-itinerary.com/v1/ships/kong-harald

3. Match your own spelling of a place to ours.

curl -H "Authorization: Bearer $CI_API_KEY" \
  'https://cruise-itinerary.com/v1/resolve?q=Port%20Canaveral&type=port'

4. Look up what you got back. Every record has a stable slug in id; use it in later calls and in your own tables.

Authentication

Send the key in either header. Keys start with ci_live_ and are 40 characters long.

Authorization: Bearer ci_live_...
X-API-Key: ci_live_...

Every endpoint needs a key. Without one, the API answers 401 key_required. A key that is malformed, unknown or revoked also gets a 401, never a silent downgrade. Keep keys on your server. If one leaks, revoke it from the dashboard and make another.

Responses

One record comes back as data and an object; a list comes back as data and an array. Both carry meta.as_of, the date of the inventory load the answer reflects (currently 2026-09-28).

Single record

{
    "data": {
        "id": "msc-cruises",
        "name": "MSC Cruises"
    },
    "meta": {
        "as_of": "2026-09-28"
    }
}

List

{
    "data": [
        {
            "id": "..."
        }
    ],
    "meta": {
        "as_of": "2026-09-28",
        "page": 1,
        "per_page": 50,
        "total": 1234,
        "has_more": true
    }
}

Dates are ISO YYYY-MM-DD. Money is a whole number of US dollars, and any object that carries fares also carries "currency": "USD". Every documented key is always present; an unknown value is null, never absent.

Pagination

List endpoints take page (from 1) and per_page (1 to 200, default 50). Read meta.has_more to know whether to ask for the next page; meta.total is the full count.

Errors

Errors use the same HTTP status as the body and are never cached.

{
    "error": {
        "status": 403,
        "code": "plan_required",
        "message": "This endpoint needs the Business plan.",
        "required_plan": "business"
    }
}
StatusCodeMeaning
400bad_requestA parameter is missing, malformed or out of range. The message names it.
401key_requiredNo key was sent. Every data endpoint needs one; a free key takes an email address at /signup.
401invalid_keyThe key is malformed, unknown or revoked. We never fall back to anonymous access on a bad key.
403account_suspendedThe account is suspended.
403plan_requiredYour plan does not include this endpoint. The body carries required_plan.
404not_foundNo such record, or no route.
405method_not_allowedThe path exists but not for this method.
429rate_limitedToo many calls this minute. Wait for Retry-After seconds.
429quota_exceededThe monthly cap for your plan is spent.
500internalOur fault. Safe to retry; if it persists, write to us.

Limits and caching

PlanCalls a minuteCalls a month
Free10500
Developer6010,000
Business300no cap
Platform600no cap
Enterprise600no cap

Minute windows are fixed, not sliding. Every response carries X-RateLimit-Limit and X-RateLimit-Remaining; plans with a monthly cap also carry X-Quota-Limit and X-Quota-Remaining. A successful response to a keyed request counts toward the month. Errors do not.

Keyed responses are private, no-store, so nothing sits between you and the data. The data changes weekly; polling more often than the Monday load buys nothing.

Webhooks

Business plans and above can have the change feed pushed to an HTTPS endpoint. Add one on the webhooks page, with optional ship, line and port filters. After each weekly load we send one delivery per endpoint, paged at 1,000 events.

Delivery

POST https://your.app/hooks/cruise
Content-Type: application/json
X-CI-Signature: t=1790900000,v1=9f2c...e1

{
    "id": 4812,
    "type": "changes.batch",
    "detected_on": "2026-09-28",
    "previous_on": "2026-09-21",
    "page": 1,
    "pages": 3,
    "events": [
        {
            "id": 90112,
            "kind": "price_drop",
            "...": "..."
        }
    ]
}

The signature is an HMAC-SHA256, hex encoded, of "<t>.<raw body>" using your endpoint's secret. Verify it against the raw bytes before parsing, and reject timestamps more than five minutes old.

Verification, Node

import { createHmac, timingSafeEqual } from 'node:crypto';

export function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(',').map((kv) => kv.split('=')));
  if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false;
  const mac = createHmac('sha256', secret).update(parts.t + '.' + rawBody).digest('hex');
  const a = Buffer.from(mac), b = Buffer.from(parts.v1 ?? '');
  return a.length === b.length && timingSafeEqual(a, b);
}

Reply with any 2xx within 10 seconds. Anything else is retried after 5 minutes, 30 minutes, 2, 6, 12 and 24 hours, then 24 hours again, for 8 attempts in all, and then marked failed. Twenty failed deliveries in a row disable the endpoint. We only deliver to public HTTPS addresses.

MCP: use it in Claude, ChatGPT and other AI tools

The API is also a remote Model Context Protocol server, so an AI assistant can query it for you. One URL, read-only tools, the same plans and limits as the REST API.

Server URL

https://cruise-itinerary.com/mcp

Connect

  • Claude (web, desktop, mobile): Customize, Connectors, Add custom connector, paste the URL. Claude detects the OAuth sign-in and asks you to sign in when you add it. Or install the plugin, which adds a research skill that knows the caveats below: github.com/BigBalli/cruise-itinerary-mcp.
  • ChatGPT: add a custom app with the URL and OAuth authentication (developer mode, until the directory listing is live).
  • Claude Code: add it, then run /mcp to sign in.

Claude Code

claude mcp add --transport http cruise-itinerary https://cruise-itinerary.com/mcp
  • Cursor, VS Code and other clients: point them at the URL. Clients that cannot sign in can send an API key instead.

mcp.json with a key

{
  "mcpServers": {
    "cruise-itinerary": {
      "url": "https://cruise-itinerary.com/mcp",
      "headers": { "Authorization": "Bearer ci_live_..." }
    }
  }
}

Sign-in

Signing in is OAuth 2.1 with PKCE. You enter your email and open the link we send; a new address gets a free account on the spot. Then you approve the app on a consent page that shows which app is asking and where it sends you back. You can also prove your account with an existing API key instead of the email. The app never sees your keys, and it can only read.

Tools

ToolWhat it answersPlan
resolve_entityA port, ship or line name, however spelt, to the id the other tools takeFree
cruise_price_indexThe weekly Cruise Price Index: the latest 12 weeks, or (Business) a full series by line, cabin and segmentFree
search_sailingsUpcoming sailings by ship, line, port, dates, length and fare, with the latest weekly faresDeveloper
get_itineraryA sailing's dated day-by-day itinerary, or a cruise's stop listDeveloper
get_price_historyEvery weekly fare snapshot of one sailingBusiness
port_month_capacityShip-days, distinct ships and berths at a port, month by monthBusiness

Each tool returns the same JSON as the matching REST endpoint. Each call counts as one API call toward your plan's limits. A tool your plan does not include answers with a short message and a link to pricing, so the assistant can tell you what to do.

The assistant gets the caveats with every answer. Fares are weekly snapshots. Days marked estimated can be a day out. Port capacity is monthly only, and its berths are capacity, not passengers. Coverage is strongest for North American lines; TUI Cruises/Marella, AIDA, Saga, Fred. Olsen and Hapag-Lloyd are not covered.

Reading the data

  • Fares are weekly snapshots. They are not live bookable fares. null for a cabin means it was not offered or was sold out when we looked; the source does not distinguish.
  • Itinerary days are partly estimated. The embark and disembark days are exact. Days between carry day_confidence: exact when the stops fill every day, estimated otherwise.
  • Slugs are the public identifiers. Lines, ships, ports, destinations, regions and cruises use slugs. Sailings use their integer id. Port ids that were merged in the past resolve to the surviving port.
  • The load runs Mondays. meta.as_of is the date of the last one.

Service

GET/v1Free

Service root

Name, version and links. Useful as a connectivity check for your key.

Needs a key on the Free plan or above. Lower plans receive 403 plan_required.

Example

curl 'https://cruise-itinerary.com/v1' \
  -H "Authorization: Bearer $CI_API_KEY"

Response 200

{
    "data": {
        "name": "Cruise Itinerary Data API",
        "version": "1",
        "docs": "https://cruise-itinerary.com/docs",
        "openapi": "https://cruise-itinerary.com/openapi.json",
        "as_of": "2026-09-28"
    },
    "meta": {
        "as_of": "2026-09-28"
    }
}

Also returns: 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

GET/v1/statusFree

Data status

How fresh the data is and how much of it there is. Inventory is reloaded once a week; next_scheduled_load says when.

Needs a key on the Free plan or above. Lower plans receive 403 plan_required.

Example

curl 'https://cruise-itinerary.com/v1/status' \
  -H "Authorization: Bearer $CI_API_KEY"

Response 200

{
    "data": {
        "as_of": "2026-09-28",
        "counts": {
            "sailings": 61010,
            "ships": 517,
            "ports_with_calls": 2749,
            "lines": 43
        },
        "next_scheduled_load": "2026-10-05T03:20:00-07:00"
    },
    "meta": {
        "as_of": "2026-09-28"
    }
}

Also returns: 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

Reference data

GET/v1/linesFree

List cruise lines

Every cruise line, alphabetical, with how many ships and upcoming sailings each has.

Needs a key on the Free plan or above. Lower plans receive 403 plan_required.

Parameters

NameInTypeNotes
pagequeryintegerPage number, from 1. Pages deeper than 100,000 rows are refused. Default: 1. Range: at least 1.
per_pagequeryintegerRows per page, 1 to 200. Default: 50. Range: 1 to 200.

Example

curl 'https://cruise-itinerary.com/v1/lines' \
  -H "Authorization: Bearer $CI_API_KEY"

Response 200

{
    "data": [
        {
            "id": "amawaterways",
            "name": "AmaWaterways",
            "ship_count": 38,
            "sailing_count": 3199
        },
        {
            "id": "american-cruise-lines",
            "name": "American Cruise Lines",
            "ship_count": 23,
            "sailing_count": 696
        }
    ],
    "meta": {
        "as_of": "2026-09-28",
        "page": 1,
        "per_page": 2,
        "total": 45,
        "has_more": true
    }
}

Also returns: 400 Bad request: an unknown or malformed parameter. The message names it.; 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 404 No such entity or endpoint.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

GET/v1/lines/{id}Free

Get a cruise line

One line by slug.

Needs a key on the Free plan or above. Lower plans receive 403 plan_required.

Parameters

NameInTypeNotes
idrequiredpathstringLine slug.

Example

curl 'https://cruise-itinerary.com/v1/lines/holland-america-line' \
  -H "Authorization: Bearer $CI_API_KEY"

Response 200

{
    "data": {
        "id": "holland-america-line",
        "name": "Holland America Line",
        "ship_count": 13,
        "sailing_count": 1234
    },
    "meta": {
        "as_of": "2026-09-28"
    }
}

Also returns: 400 Bad request: an unknown or malformed parameter. The message names it.; 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 404 No such entity or endpoint.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

GET/v1/shipsFree

List ships

Ships, alphabetical. q matches part of the name or an exact IMO number.

Needs a key on the Free plan or above. Lower plans receive 403 plan_required.

Parameters

NameInTypeNotes
pagequeryintegerPage number, from 1. Pages deeper than 100,000 rows are refused. Default: 1. Range: at least 1.
per_pagequeryintegerRows per page, 1 to 200. Default: 50. Range: 1 to 200.
linequerystringOnly ships of this line (slug).
qquerystringName contains, or exact IMO.

Example

curl 'https://cruise-itinerary.com/v1/ships' \
  -H "Authorization: Bearer $CI_API_KEY"

Response 200

{
    "data": [
        {
            "id": "eurodam",
            "name": "Eurodam",
            "line": {
                "id": "holland-america-line",
                "name": "Holland America Line"
            },
            "imo": "9378448",
            "mmsi": "245206000",
            "passengers": 2104,
            "crew": 929,
            "gross_tonnage": 86273,
            "decks": 11,
            "length_ft": 936,
            "width_ft": 106,
            "maiden_voyage": "2008-07-05",
            "launched": "2008-01-01",
            "refurbished": null,
            "adults_only": false
        },
        {
            "id": "koningsdam",
            "name": "Koningsdam",
            "line": {
                "id": "holland-america-line",
                "name": "Holland America Line"
            },
            "imo": "9692557",
            "mmsi": "244830547",
            "passengers": 2650,
            "crew": 1025,
            "gross_tonnage": 99500,
            "decks": 12,
            "length_ft": 935,
            "width_ft": 115,
            "maiden_voyage": "2016-04-04",
            "launched": null,
            "refurbished": null,
            "adults_only": false
        }
    ],
    "meta": {
        "as_of": "2026-09-28",
        "page": 1,
        "per_page": 2,
        "total": 13,
        "has_more": true
    }
}

Also returns: 400 Bad request: an unknown or malformed parameter. The message names it.; 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 404 No such entity or endpoint.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

GET/v1/ships/{id}Free

Get a ship

One ship by slug.

Needs a key on the Free plan or above. Lower plans receive 403 plan_required.

Parameters

NameInTypeNotes
idrequiredpathstringShip slug.

Example

curl 'https://cruise-itinerary.com/v1/ships/eurodam' \
  -H "Authorization: Bearer $CI_API_KEY"

Response 200

{
    "data": {
        "id": "eurodam",
        "name": "Eurodam",
        "line": {
            "id": "holland-america-line",
            "name": "Holland America Line"
        },
        "imo": "9378448",
        "mmsi": "245206000",
        "passengers": 2104,
        "crew": 929,
        "gross_tonnage": 86273,
        "decks": 11,
        "length_ft": 936,
        "width_ft": 106,
        "maiden_voyage": "2008-07-05",
        "launched": "2008-01-01",
        "refurbished": null,
        "adults_only": false
    },
    "meta": {
        "as_of": "2026-09-28"
    }
}

Also returns: 400 Bad request: an unknown or malformed parameter. The message names it.; 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 404 No such entity or endpoint.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

GET/v1/portsFree

List ports

Ports and scenic stops. Use has_calls=true for ports a ship is scheduled to visit. For matching free text to a port, use /v1/resolve.

Needs a key on the Free plan or above. Lower plans receive 403 plan_required.

Parameters

NameInTypeNotes
pagequeryintegerPage number, from 1. Pages deeper than 100,000 rows are refused. Default: 1. Range: at least 1.
per_pagequeryintegerRows per page, 1 to 200. Default: 50. Range: 1 to 200.
qquerystringName or alias contains.
destinationquerystringDestination slug.
regionquerystringRegion slug.
has_callsquerystringtrue: only ports with scheduled calls; false: only those without. One of: true, false.
kindquerystringport, scenic or transit. One of: port, scenic, transit.

Example

curl 'https://cruise-itinerary.com/v1/ports' \
  -H "Authorization: Bearer $CI_API_KEY"

Response 200

{
    "data": [
        {
            "id": "miami",
            "name": "Miami",
            "kind": "port",
            "latitude": 25.7741566,
            "longitude": -80.1935973,
            "destination": {
                "id": "miami",
                "name": "Miami"
            },
            "region": {
                "id": "united-states",
                "name": "United States"
            },
            "aliases": [],
            "upcoming_calls": 2416
        }
    ],
    "meta": {
        "as_of": "2026-09-28",
        "page": 1,
        "per_page": 2,
        "total": 1,
        "has_more": false
    }
}

Also returns: 400 Bad request: an unknown or malformed parameter. The message names it.; 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 404 No such entity or endpoint.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

GET/v1/ports/{id}Free

Get a port

One port by slug. The numeric id of a port that was merged into another also works and returns the surviving port, with meta.resolved_from set to the id you sent.

Needs a key on the Free plan or above. Lower plans receive 403 plan_required.

Parameters

NameInTypeNotes
idrequiredpathstringPort slug, or the numeric id of a merged legacy port.

Example

curl 'https://cruise-itinerary.com/v1/ports/miami' \
  -H "Authorization: Bearer $CI_API_KEY"

Response 200

{
    "data": {
        "id": "miami",
        "name": "Miami",
        "kind": "port",
        "latitude": 25.7741566,
        "longitude": -80.1935973,
        "destination": {
            "id": "miami",
            "name": "Miami"
        },
        "region": {
            "id": "united-states",
            "name": "United States"
        },
        "aliases": [],
        "upcoming_calls": 2416
    },
    "meta": {
        "as_of": "2026-09-28"
    }
}

Also returns: 400 Bad request: an unknown or malformed parameter. The message names it.; 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 404 No such entity or endpoint.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

GET/v1/destinationsFree

List destinations

Destinations with their region and a representative coordinate.

Needs a key on the Free plan or above. Lower plans receive 403 plan_required.

Parameters

NameInTypeNotes
pagequeryintegerPage number, from 1. Pages deeper than 100,000 rows are refused. Default: 1. Range: at least 1.
per_pagequeryintegerRows per page, 1 to 200. Default: 50. Range: 1 to 200.

Example

curl 'https://cruise-itinerary.com/v1/destinations' \
  -H "Authorization: Bearer $CI_API_KEY"

Response 200

{
    "data": [
        {
            "id": "abu-dhabi",
            "name": "Abu Dhabi",
            "region": {
                "id": "middle-east",
                "name": "Middle East"
            },
            "latitude": 24.453884,
            "longitude": 54.3773438
        },
        {
            "id": "acapulco",
            "name": "Acapulco",
            "region": {
                "id": "mexico-region",
                "name": "Mexico region"
            },
            "latitude": 16.863611,
            "longitude": -99.8825
        }
    ],
    "meta": {
        "as_of": "2026-09-28",
        "page": 1,
        "per_page": 2,
        "total": 379,
        "has_more": true
    }
}

Also returns: 400 Bad request: an unknown or malformed parameter. The message names it.; 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 404 No such entity or endpoint.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

GET/v1/regionsFree

List regions

The 18 top-level regions.

Needs a key on the Free plan or above. Lower plans receive 403 plan_required.

Parameters

NameInTypeNotes
pagequeryintegerPage number, from 1. Pages deeper than 100,000 rows are refused. Default: 1. Range: at least 1.
per_pagequeryintegerRows per page, 1 to 200. Default: 50. Range: 1 to 200.

Example

curl 'https://cruise-itinerary.com/v1/regions' \
  -H "Authorization: Bearer $CI_API_KEY"

Response 200

{
    "data": [
        {
            "id": "africa",
            "name": "Africa"
        },
        {
            "id": "alaska-region",
            "name": "Alaska region"
        }
    ],
    "meta": {
        "as_of": "2026-09-28",
        "page": 1,
        "per_page": 2,
        "total": 18,
        "has_more": true
    }
}

Also returns: 400 Bad request: an unknown or malformed parameter. The message names it.; 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 404 No such entity or endpoint.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

Resolver

GET/v1/resolveFree

Resolve a name

Match free text such as "Port Canaveral, Florida" or "Royal Caribbean Symphony of the Seas" to ports, ships and lines. Returns up to five candidates, best first. Confidence is 1.0 for an exact name, about 0.9 to 0.97 after normalising accents, punctuation, country suffixes and aliases, and 0.85 or less for approximate matches. For many names at once, use the POST form.

Needs a key on the Free plan or above. Lower plans receive 403 plan_required.

Parameters

NameInTypeNotes
qrequiredquerystringThe text to match, up to 120 characters.
typequerystringRestrict to one kind of entity. One of: port, ship, line.

Example

curl 'https://cruise-itinerary.com/v1/resolve?q=Port%20Canaveral%2C%20Florida' \
  -H "Authorization: Bearer $CI_API_KEY"

Response 200

{
    "data": [
        {
            "type": "port",
            "id": "port-canaveral",
            "name": "Port Canaveral",
            "confidence": 0.9,
            "match": "normalized"
        }
    ],
    "meta": {
        "as_of": "2026-09-28",
        "page": 1,
        "per_page": 1,
        "total": 1,
        "has_more": false
    }
}

Also returns: 400 Bad request: an unknown or malformed parameter. The message names it.; 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 404 No such entity or endpoint.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

POST/v1/resolveFree

Resolve names in bulk

Up to 100 items per request. The response holds one entry per item, in order, each with its own candidate list.

Needs a key on the Free plan or above. Lower plans receive 403 plan_required.

Request body

{
    "items": [
        {
            "q": "Port Canaveral",
            "type": "port"
        },
        {
            "q": "Allure of the seas"
        }
    ]
}

Example

curl -X POST 'https://cruise-itinerary.com/v1/resolve' \
  -H "Authorization: Bearer $CI_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"items":[{"q":"Port Canaveral","type":"port"},{"q":"Allure of the seas"}]}'

Response 200

{
    "data": [
        {
            "q": "Port Canaveral",
            "type": "port",
            "candidates": [
                {
                    "type": "port",
                    "id": "port-canaveral",
                    "name": "Port Canaveral",
                    "confidence": 1,
                    "match": "exact"
                }
            ]
        },
        {
            "q": "Allure of the seas",
            "type": null,
            "candidates": [
                {
                    "type": "ship",
                    "id": "allure-of-the-seas",
                    "name": "Allure of the Seas",
                    "confidence": 1,
                    "match": "exact"
                }
            ]
        }
    ],
    "meta": {
        "as_of": "2026-09-28",
        "page": 1,
        "per_page": 2,
        "total": 2,
        "has_more": false
    }
}

Also returns: 400 Bad request: an unknown or malformed parameter. The message names it.; 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 403 The plan does not include this endpoint (plan_required, with required_plan), or the account is suspended (account_suspended).; 404 No such entity or endpoint.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

Sailings

GET/v1/sailingsDeveloper

Search sailings

Upcoming sailings with their latest fares. Fares are weekly snapshots from the inventory feed, not live bookable prices. port matches sailings that call at a port (itinerary days), embark_port the departure port. from and to bound the departure date.

Needs a key on the Developer plan or above. Lower plans receive 403 plan_required.

Parameters

NameInTypeNotes
pagequeryintegerPage number, from 1. Pages deeper than 100,000 rows are refused. Default: 1. Range: at least 1.
per_pagequeryintegerRows per page, 1 to 200. Default: 50. Range: 1 to 200.
shipquerystringShip slug.
linequerystringLine slug.
portquerystringPort slug; sailings that call there.
embark_portquerystringDeparture port slug.
regionquerystringRegion slug.
fromquerystring (date)Earliest departure date.
toquerystring (date)Latest departure date.
min_nightsqueryintegerMinimum length.
max_nightsqueryintegerMaximum length.
cabinquerystringRestrict to sailings with a fare in this cabin; also the cabin max_fare and sort=fare use. One of: inside, outside, balcony, suite.
max_farequeryintegerHighest fare in USD (in cabin, or in any cabin when cabin is absent).
sortquerystringdeparture (default) or fare, lowest first. One of: departure, fare.

Example

curl 'https://cruise-itinerary.com/v1/sailings' \
  -H "Authorization: Bearer $CI_API_KEY"

Response 200

{
    "data": [
        {
            "id": 14026605,
            "cruise": {
                "id": "1-night-pacific-northwest-eurodam-da8a2f",
                "title": "1 Night Pacific Northwest"
            },
            "ship": {
                "id": "eurodam",
                "name": "Eurodam"
            },
            "line": {
                "id": "holland-america-line",
                "name": "Holland America Line"
            },
            "departure_date": "2026-10-03",
            "return_date": "2026-10-04",
            "nights": 1,
            "embark_port": {
                "id": "seattle",
                "name": "Seattle"
            },
            "disembark_port": {
                "id": "vancouver",
                "name": "Vancouver"
            },
            "fares": {
                "inside": null,
                "outside": 129,
                "balcony": 129,
                "suite": 239
            },
            "currency": "USD",
            "fares_changed_on": "2026-09-14",
            "observed_on": "2026-09-28"
        },
        {
            "id": 14324436,
            "cruise": {
                "id": "21-night-panama-canal-eurodam-19a3f5",
                "title": "21 Night Panama Canal"
            },
            "ship": {
                "id": "eurodam",
                "name": "Eurodam"
            },
            "line": {
                "id": "holland-america-line",
                "name": "Holland America Line"
            },
            "departure_date": "2026-10-03",
            "return_date": "2026-10-24",
            "nights": 21,
            "embark_port": {
                "id": "seattle",
                "name": "Seattle"
            },
            "disembark_port": {
                "id": "ft-lauderdale",
                "name": "Ft. Lauderdale"
            },
            "fares": {
                "inside": null,
                "outside": null,
                "balcony": null,
                "suite": null
            },
            "currency": "USD",
            "fares_changed_on": "2026-09-07",
            "observed_on": "2026-09-28"
        }
    ],
    "meta": {
        "as_of": "2026-09-28",
        "page": 1,
        "per_page": 2,
        "total": 113,
        "has_more": true
    }
}

Also returns: 400 Bad request: an unknown or malformed parameter. The message names it.; 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 403 The plan does not include this endpoint (plan_required, with required_plan), or the account is suspended (account_suspended).; 404 No such entity or endpoint.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

GET/v1/sailings/{id}Developer

Get a sailing

One sailing with its day-by-day itinerary. Embark and disembark days are exact, and so is every day where the cruise line publishes its itinerary; other days in between are estimated and labelled so.

Needs a key on the Developer plan or above. Lower plans receive 403 plan_required.

Parameters

NameInTypeNotes
idrequiredpathstringSailing id.

Example

curl 'https://cruise-itinerary.com/v1/sailings/14026605' \
  -H "Authorization: Bearer $CI_API_KEY"

Response 200

{
    "data": {
        "id": 14026605,
        "cruise": {
            "id": "1-night-pacific-northwest-eurodam-da8a2f",
            "title": "1 Night Pacific Northwest"
        },
        "ship": {
            "id": "eurodam",
            "name": "Eurodam"
        },
        "line": {
            "id": "holland-america-line",
            "name": "Holland America Line"
        },
        "departure_date": "2026-10-03",
        "return_date": "2026-10-04",
        "nights": 1,
        "embark_port": {
            "id": "seattle",
            "name": "Seattle"
        },
        "disembark_port": {
            "id": "vancouver",
            "name": "Vancouver"
        },
        "fares": {
            "inside": null,
            "outside": 129,
            "balcony": 129,
            "suite": 239
        },
        "currency": "USD",
        "fares_changed_on": "2026-09-14",
        "observed_on": "2026-09-28",
        "itinerary": [
            {
                "day_offset": 0,
                "date": "2026-10-03",
                "port": {
                    "id": "seattle",
                    "name": "Seattle",
                    "latitude": 47.6038321,
                    "longitude": -122.330062
                },
                "kind": "embark",
                "day_confidence": "exact"
            },
            {
                "day_offset": 1,
                "date": "2026-10-04",
                "port": {
                    "id": "vancouver",
                    "name": "Vancouver",
                    "latitude": 49.261226,
                    "longitude": -123.1139268
                },
                "kind": "disembark",
                "day_confidence": "exact"
            }
        ]
    },
    "meta": {
        "as_of": "2026-09-28"
    }
}

Also returns: 400 Bad request: an unknown or malformed parameter. The message names it.; 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 403 The plan does not include this endpoint (plan_required, with required_plan), or the account is suspended (account_suspended).; 404 No such entity or endpoint.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

GET/v1/sailings/{id}/pricesBusiness

Fare history of a sailing

Every weekly snapshot of the sailing's four fares, oldest first. History starts on 2026-09-06 and continues after the sailing departs.

Needs a key on the Business plan or above. Lower plans receive 403 plan_required.

Parameters

NameInTypeNotes
idrequiredpathstringSailing id.
pagequeryintegerPage number, from 1. Pages deeper than 100,000 rows are refused. Default: 1. Range: at least 1.
per_pagequeryintegerRows per page, 1 to 200. Default: 50. Range: 1 to 200.

Example

curl 'https://cruise-itinerary.com/v1/sailings/14026605/prices' \
  -H "Authorization: Bearer $CI_API_KEY"

Response 200

{
    "data": [
        {
            "observed_on": "2026-09-06",
            "fares": {
                "inside": 129,
                "outside": 129,
                "balcony": 129,
                "suite": 239
            },
            "currency": "USD"
        },
        {
            "observed_on": "2026-09-07",
            "fares": {
                "inside": 129,
                "outside": 129,
                "balcony": 129,
                "suite": 239
            },
            "currency": "USD"
        },
        {
            "observed_on": "2026-09-14",
            "fares": {
                "inside": null,
                "outside": 129,
                "balcony": 129,
                "suite": 239
            },
            "currency": "USD"
        }
    ],
    "meta": {
        "as_of": "2026-09-28",
        "page": 1,
        "per_page": 3,
        "total": 5,
        "has_more": true
    }
}

Also returns: 400 Bad request: an unknown or malformed parameter. The message names it.; 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 403 The plan does not include this endpoint (plan_required, with required_plan), or the account is suspended (account_suspended).; 404 No such entity or endpoint.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

GET/v1/cruises/{id}Developer

Get a cruise

A cruise is the product (title, ship, ordered stops); a sailing is one departure of it. Cruise slugs are permanent.

Needs a key on the Developer plan or above. Lower plans receive 403 plan_required.

Parameters

NameInTypeNotes
idrequiredpathstringCruise slug.

Example

curl 'https://cruise-itinerary.com/v1/cruises/1-night-pacific-northwest-eurodam-da8a2f' \
  -H "Authorization: Bearer $CI_API_KEY"

Response 200

{
    "data": {
        "id": "1-night-pacific-northwest-eurodam-da8a2f",
        "title": "1 Night Pacific Northwest",
        "ship": {
            "id": "eurodam",
            "name": "Eurodam"
        },
        "line": {
            "id": "holland-america-line",
            "name": "Holland America Line"
        },
        "nights": 1,
        "embark_port": {
            "id": "seattle",
            "name": "Seattle"
        },
        "disembark_port": {
            "id": "vancouver",
            "name": "Vancouver"
        },
        "itinerary_source": "official",
        "stops": [
            {
                "seq": 1,
                "day": 1,
                "port": {
                    "id": "seattle",
                    "name": "Seattle"
                }
            },
            {
                "seq": 2,
                "day": 2,
                "port": {
                    "id": "vancouver",
                    "name": "Vancouver"
                }
            }
        ],
        "next_departure": "2026-10-03",
        "sailing_count": 2
    },
    "meta": {
        "as_of": "2026-09-28"
    }
}

Also returns: 400 Bad request: an unknown or malformed parameter. The message names it.; 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 403 The plan does not include this endpoint (plan_required, with required_plan), or the account is suspended (account_suspended).; 404 No such entity or endpoint.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

Ships and ports

GET/v1/ships/{id}/scheduleDeveloper

Ship schedule

Where a ship is on each day: one row per stop, with sea days. When sailings overlap, the shortest one that covers a day owns it. Window limit: 400 days; default 90 days from today.

Needs a key on the Developer plan or above. Lower plans receive 403 plan_required.

Parameters

NameInTypeNotes
idrequiredpathstringShip slug.
pagequeryintegerPage number, from 1. Pages deeper than 100,000 rows are refused. Default: 1. Range: at least 1.
per_pagequeryintegerRows per page, 1 to 200. Default: 50. Range: 1 to 200.
fromquerystring (date)First day (default today).
toquerystring (date)Last day.

Example

curl 'https://cruise-itinerary.com/v1/ships/eurodam/schedule' \
  -H "Authorization: Bearer $CI_API_KEY"

Response 200

{
    "data": [
        {
            "date": "2026-10-03",
            "seq": 0,
            "kind": "embark",
            "port": {
                "id": "seattle",
                "name": "Seattle",
                "latitude": 47.6038321,
                "longitude": -122.330062
            },
            "day_confidence": "exact",
            "sailing_id": 14026605
        },
        {
            "date": "2026-10-04",
            "seq": 0,
            "kind": "turnaround",
            "port": {
                "id": "vancouver",
                "name": "Vancouver",
                "latitude": 49.261226,
                "longitude": -123.1139268
            },
            "day_confidence": "exact",
            "sailing_id": 14317445
        },
        {
            "date": "2026-10-05",
            "seq": 0,
            "kind": "sea",
            "port": null,
            "day_confidence": "exact",
            "sailing_id": 14317445
        }
    ],
    "meta": {
        "as_of": "2026-09-28",
        "page": 1,
        "per_page": 3,
        "total": 29,
        "has_more": true
    }
}

Also returns: 400 Bad request: an unknown or malformed parameter. The message names it.; 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 403 The plan does not include this endpoint (plan_required, with required_plan), or the account is suspended (account_suspended).; 404 No such entity or endpoint.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

GET/v1/ports/{id}/calendarBusiness

Port traffic calendar

Ships, lower berths and turnarounds per day. Only days with at least one ship appear; a missing day has none. Window limit: 730 days; default 90 days from today. Berths count lower-berth capacity; real headcount runs 10 to 20 percent higher.

Needs a key on the Business plan or above. Lower plans receive 403 plan_required.

Parameters

NameInTypeNotes
idrequiredpathstringPort slug (or merged legacy id).
pagequeryintegerPage number, from 1. Pages deeper than 100,000 rows are refused. Default: 1. Range: at least 1.
per_pagequeryintegerRows per page, 1 to 200. Default: 50. Range: 1 to 200.
fromquerystring (date)First day (default today).
toquerystring (date)Last day.

Example

curl 'https://cruise-itinerary.com/v1/ports/miami/calendar' \
  -H "Authorization: Bearer $CI_API_KEY"

Response 200

{
    "data": [
        {
            "date": "2026-11-01",
            "ships": 7,
            "berths": 26885,
            "ships_no_capacity": 0,
            "embark_ships": 5,
            "disembark_ships": 7,
            "turnaround_ships": 5,
            "estimated_ships": 0,
            "busy_pct": 87
        },
        {
            "date": "2026-11-02",
            "ships": 3,
            "berths": 12560,
            "ships_no_capacity": 0,
            "embark_ships": 3,
            "disembark_ships": 3,
            "turnaround_ships": 3,
            "estimated_ships": 0,
            "busy_pct": 39
        },
        {
            "date": "2026-11-05",
            "ships": 4,
            "berths": 11456,
            "ships_no_capacity": 0,
            "embark_ships": 4,
            "disembark_ships": 4,
            "turnaround_ships": 4,
            "estimated_ships": 0,
            "busy_pct": 30
        }
    ],
    "meta": {
        "as_of": "2026-09-28",
        "page": 1,
        "per_page": 3,
        "total": 27,
        "has_more": true
    }
}

Also returns: 400 Bad request: an unknown or malformed parameter. The message names it.; 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 403 The plan does not include this endpoint (plan_required, with required_plan), or the account is suspended (account_suspended).; 404 No such entity or endpoint.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

GET/v1/ports/{id}/days/{date}Business

Port day detail

The counts for one day plus the ships behind them. A day with no ships returns zero counts and an empty calls list.

Needs a key on the Business plan or above. Lower plans receive 403 plan_required.

Parameters

NameInTypeNotes
idrequiredpathstringPort slug (or merged legacy id).
daterequiredpathstringYYYY-MM-DD.

Example

curl 'https://cruise-itinerary.com/v1/ports/miami/days/2026-11-14' \
  -H "Authorization: Bearer $CI_API_KEY"

Response 200

{
    "data": {
        "date": "2026-11-14",
        "ships": 7,
        "berths": 27493,
        "ships_no_capacity": 0,
        "embark_ships": 7,
        "disembark_ships": 7,
        "turnaround_ships": 7,
        "estimated_ships": 0,
        "busy_pct": 88,
        "calls": [
            {
                "ship": {
                    "id": "carnival-magic",
                    "name": "Carnival Magic",
                    "passengers": 3690
                },
                "line": {
                    "id": "carnival-cruise-line",
                    "name": "Carnival Cruise Line"
                },
                "kind": "turnaround",
                "day_confidence": "exact",
                "sailing_id": 14252373
            },
            {
                "ship": {
                    "id": "carnival-sunrise",
                    "name": "Carnival Sunrise",
                    "passengers": 2984
                },
                "line": {
                    "id": "carnival-cruise-line",
                    "name": "Carnival Cruise Line"
                },
                "kind": "turnaround",
                "day_confidence": "exact",
                "sailing_id": 14252960
            },
            {
                "ship": {
                    "id": "msc-world-america",
                    "name": "MSC World America",
                    "passengers": 5240
                },
                "line": {
                    "id": "msc-cruises",
                    "name": "MSC Cruises"
                },
                "kind": "turnaround",
                "day_confidence": "exact",
                "sailing_id": 14290891
            },
            {
                "ship": {
                    "id": "norwegian-luna",
                    "name": "Norwegian Luna",
                    "passengers": 3565
                },
                "line": {
                    "id": "norwegian-cruise-line",
                    "name": "Norwegian Cruise Line"
                },
                "kind": "turnaround",
                "day_confidence": "exact",
                "sailing_id": 14221900
            },
            {
                "ship": {
                    "id": "freedom-of-the-seas",
                    "name": "Freedom of the Seas",
                    "passengers": 3634
                },
                "line": {
                    "id": "royal-caribbean",
                    "name": "Royal Caribbean"
                },
                "kind": "turnaround",
                "day_confidence": "exact",
                "sailing_id": 14240653
            },
            {
                "ship": {
                    "id": "icon-of-the-seas",
                    "name": "Icon of the Seas",
                    "passengers": 5610
                },
                "line": {
                    "id": "royal-caribbean",
                    "name": "Royal Caribbean"
                },
                "kind": "turnaround",
                "day_confidence": "exact",
                "sailing_id": 14089008
            },
            {
                "ship": {
                    "id": "scarlet-lady",
                    "name": "Scarlet Lady",
                    "passengers": 2770
                },
                "line": {
                    "id": "virgin-voyages",
                    "name": "Virgin Voyages"
                },
                "kind": "turnaround",
                "day_confidence": "exact",
                "sailing_id": 14199956
            }
        ]
    },
    "meta": {
        "as_of": "2026-09-28"
    }
}

Also returns: 400 Bad request: an unknown or malformed parameter. The message names it.; 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 403 The plan does not include this endpoint (plan_required, with required_plan), or the account is suspended (account_suspended).; 404 No such entity or endpoint.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

Changes

GET/v1/changesBusiness

Change feed

What changed between consecutive weekly loads: fare moves per cabin, cabins appearing or vanishing, sailings added or removed, itineraries swapped. Newest load first. kind takes a comma-separated list.

Needs a key on the Business plan or above. Lower plans receive 403 plan_required.

Parameters

NameInTypeNotes
pagequeryintegerPage number, from 1. Pages deeper than 100,000 rows are refused. Default: 1. Range: at least 1.
per_pagequeryintegerRows per page, 1 to 200. Default: 50. Range: 1 to 200.
sincequerystring (date)Earliest detected_on.
untilquerystring (date)Latest detected_on.
kindquerystringComma-separated: price_drop, price_rise, cabin_unavailable, cabin_available, sailing_added, sailing_removed, itinerary_changed.
shipquerystringShip slug.
linequerystringLine slug.
portquerystringPort slug; sailings that call there.

Example

curl 'https://cruise-itinerary.com/v1/changes' \
  -H "Authorization: Bearer $CI_API_KEY"

Response 200

{
    "data": [
        {
            "id": 254254,
            "detected_on": "2026-09-28",
            "previous_on": "2026-09-21",
            "kind": "price_drop",
            "sailing_id": 14038925,
            "cruise_id": "7-night-eastern-caribbean-holiday-amber-cove-and-bahamas-nieuw-amsterdam-ecb222",
            "previous_cruise_id": null,
            "ship": {
                "id": "nieuw-amsterdam",
                "name": "Nieuw Amsterdam"
            },
            "line": {
                "id": "holland-america-line",
                "name": "Holland America Line"
            },
            "departure_date": "2026-12-20",
            "cabin": "inside",
            "old_value": 749,
            "new_value": 699,
            "currency": "USD"
        },
        {
            "id": 254255,
            "detected_on": "2026-09-28",
            "previous_on": "2026-09-21",
            "kind": "price_drop",
            "sailing_id": 14038929,
            "cruise_id": "9-night-eastern-caribbean-st-maarten-antigua-and-bahamas-nieuw-amsterdam-44b3c2",
            "previous_cruise_id": null,
            "ship": {
                "id": "nieuw-amsterdam",
                "name": "Nieuw Amsterdam"
            },
            "line": {
                "id": "holland-america-line",
                "name": "Holland America Line"
            },
            "departure_date": "2026-12-11",
            "cabin": "inside",
            "old_value": 899,
            "new_value": 849,
            "currency": "USD"
        }
    ],
    "meta": {
        "as_of": "2026-09-28",
        "page": 1,
        "per_page": 2,
        "total": 869,
        "has_more": true
    }
}

Also returns: 400 Bad request: an unknown or malformed parameter. The message names it.; 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 403 The plan does not include this endpoint (plan_required, with required_plan), or the account is suspended (account_suspended).; 404 No such entity or endpoint.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

Price index

GET/v1/price-index/latestFree

Latest price index

The all-lines Cruise Price Index plus the eight largest lines, for cabin any and segment all, over the last 12 loads. Ordered all lines first, then by line name, oldest load first. The series starts on 2026-09-06 at 100.

Needs a key on the Free plan or above. Lower plans receive 403 plan_required.

Example

curl 'https://cruise-itinerary.com/v1/price-index/latest' \
  -H "Authorization: Bearer $CI_API_KEY"

Response 200

{
    "data": [
        {
            "observed_on": "2026-09-06",
            "previous_on": null,
            "line": null,
            "cabin": "any",
            "segment": "all",
            "weighting": "sailing",
            "matched": 54299,
            "index_value": 100,
            "mean_log_change": null,
            "pct_cut": null,
            "pct_raised": null,
            "pct_unavailable": null,
            "avg_per_diem": null,
            "berth_coverage_pct": null
        },
        {
            "observed_on": "2026-09-07",
            "previous_on": "2026-09-06",
            "line": null,
            "cabin": "any",
            "segment": "all",
            "weighting": "sailing",
            "matched": 54299,
            "index_value": 99.9036,
            "mean_log_change": -0.000964,
            "pct_cut": 0.62,
            "pct_raised": 0.52,
            "pct_unavailable": 0.18,
            "avg_per_diem": 464.59,
            "berth_coverage_pct": null
        }
    ],
    "meta": {
        "as_of": "2026-09-28",
        "page": 1,
        "per_page": 45,
        "total": 45,
        "has_more": false
    }
}

Also returns: 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

GET/v1/price-indexBusiness

Price index series

The full series for one line, cabin, segment and weighting, oldest first. line is a slug, or omitted (or all) for all lines. weighting=berth weights each sailing by its ship's lower berths (passengers per sailing) instead of counting each sailing once. Rows exist only where at least 30 sailings matched.

Needs a key on the Business plan or above. Lower plans receive 403 plan_required.

Parameters

NameInTypeNotes
pagequeryintegerPage number, from 1. Pages deeper than 100,000 rows are refused. Default: 1. Range: at least 1.
per_pagequeryintegerRows per page, 1 to 200. Default: 50. Range: 1 to 200.
linequerystringLine slug or all.
cabinquerystringCabin class (default any). One of: inside, outside, balcony, suite, any.
segmentquerystringall (default), w000_090, w091_180, w181_365, w366_plus, a sail quarter like q2027_1, or size_intimate, size_small, size_medium, size_large, size_mega.
weightingquerystringsailing (default) or berth. One of: sailing, berth.
fromquerystring (date)Earliest observed_on.
toquerystring (date)Latest observed_on.

Example

curl 'https://cruise-itinerary.com/v1/price-index' \
  -H "Authorization: Bearer $CI_API_KEY"

Response 200

{
    "data": [
        {
            "observed_on": "2026-09-06",
            "previous_on": null,
            "line": {
                "id": "carnival-cruise-line",
                "name": "Carnival Cruise Line"
            },
            "cabin": "balcony",
            "segment": "w000_090",
            "weighting": "sailing",
            "matched": 300,
            "index_value": 100,
            "mean_log_change": null,
            "pct_cut": null,
            "pct_raised": null,
            "pct_unavailable": null,
            "avg_per_diem": null,
            "berth_coverage_pct": null
        },
        {
            "observed_on": "2026-09-07",
            "previous_on": "2026-09-06",
            "line": {
                "id": "carnival-cruise-line",
                "name": "Carnival Cruise Line"
            },
            "cabin": "balcony",
            "segment": "w000_090",
            "weighting": "sailing",
            "matched": 300,
            "index_value": 100.3153,
            "mean_log_change": 0.003148,
            "pct_cut": 3,
            "pct_raised": 7,
            "pct_unavailable": 2.28,
            "avg_per_diem": 150.02,
            "berth_coverage_pct": null
        },
        {
            "observed_on": "2026-09-14",
            "previous_on": "2026-09-07",
            "line": {
                "id": "carnival-cruise-line",
                "name": "Carnival Cruise Line"
            },
            "cabin": "balcony",
            "segment": "w000_090",
            "weighting": "sailing",
            "matched": 255,
            "index_value": 100.3892,
            "mean_log_change": 0.000737,
            "pct_cut": 51.76,
            "pct_raised": 42.35,
            "pct_unavailable": 13.56,
            "avg_per_diem": 148.1,
            "berth_coverage_pct": null
        }
    ],
    "meta": {
        "as_of": "2026-09-28",
        "page": 1,
        "per_page": 50,
        "total": 5,
        "has_more": false
    }
}

Also returns: 400 Bad request: an unknown or malformed parameter. The message names it.; 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 403 The plan does not include this endpoint (plan_required, with required_plan), or the account is suspended (account_suspended).; 404 No such entity or endpoint.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

Bulk exports

GET/v1/exportsFree

List weekly exports

The last eight weekly bulk files, as gzipped CSV, with row counts and SHA-256 checksums. Column names match the API and ids are slugs, so files join to the identity-* files. access: free files (the identity-* files) download with any key; the rest need Platform.

Needs a key on the Free plan or above. Lower plans receive 403 plan_required.

Example

curl 'https://cruise-itinerary.com/v1/exports' \
  -H "Authorization: Bearer $CI_API_KEY"

Response 200

{
    "data": [
        {
            "date": "2026-09-28",
            "files": [
                {
                    "name": "identity-lines.csv.gz",
                    "bytes": 901,
                    "rows": 45,
                    "sha256": "88aff6f5f821b9a1aa20d69906c003c10a61971621965745846e9ca727974916",
                    "access": "free",
                    "url": "https://cruise-itinerary.com/v1/exports/2026-09-28/identity-lines.csv.gz"
                },
                {
                    "name": "identity-ships.csv.gz",
                    "bytes": 20032,
                    "rows": 646,
                    "sha256": "1bef2b4c4e2c541aafb4155dea41ebf59f0f9982f15b950e4dd8bbdbce4c2288",
                    "access": "free",
                    "url": "https://cruise-itinerary.com/v1/exports/2026-09-28/identity-ships.csv.gz"
                }
            ]
        }
    ],
    "meta": {
        "as_of": "2026-09-28",
        "page": 1,
        "per_page": 1,
        "total": 1,
        "has_more": false
    }
}

Also returns: 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.

GET/v1/exports/{date}/{file}Free

Download an export file

Streams one gzipped CSV. date may be latest. Files named identity-* (lines, ships, ports, destinations, regions) come with every plan, Free included; the rest need Platform.

Needs a key on the Free plan or above. Lower plans receive 403 plan_required.

Parameters

NameInTypeNotes
daterequiredpathstringExport date from the listing, or latest.
filerequiredpathstringFile name from the listing.

Example

curl 'https://cruise-itinerary.com/v1/exports/latest/identity-lines.csv.gz' \
  -H "Authorization: Bearer $CI_API_KEY"

Also returns: 401 No key was sent (key_required; a free key is one email away at /signup), or the key is malformed, unknown or revoked (invalid_key). A bad key is never treated as anonymous.; 403 The plan does not include this endpoint (plan_required, with required_plan), or the account is suspended (account_suspended).; 404 No such entity or endpoint.; 429 Per-minute rate limit (rate_limited, with Retry-After) or monthly quota (quota_exceeded) reached.; 500 Internal error. Safe to retry.. See errors.