Table of Contents

Create Package Booking

See Booking flow for the end-to-end lifecycle.

Endpoint: /bookings/create/package/{:sessionId}

METHOD: POST

Creates a held booking for the chosen package departure within an existing package search session. Reserves the selected cabin(s) and surfaces any mandatory addons that are automatically included.

Path Parameters

Name Type Required Description
sessionId string (UUID) Yes Session returned by /search/packages. Must be a package session.

Query Parameters

Name Type Required Description
user_key string Yes Unique key associated with the calling agency.

Request Body

Field Type Required Description
packageStartDate string (date-time) Yes Package start timestamp. Must match results[].startDate from the originating search and be in the future.
cabinMix array of objects Yes One entry per cabin to reserve. Total guestIds across cabins must not exceed 9, must all be unique, and must each appear as a guest in the search.
cabinMix[].code string Yes Cabin grade code from the search response. Must be available on the selected departure.
cabinMix[].guestIds array of numbers Yes Passenger IDs (from the search) assigned to this cabin. Must contain at least one passenger of type: "ADULT" or type: "SENIOR" and not exceed the grade's maximumOccupancy.

Example

Request

curl --location '{:apiBase}/bookings/create/package/{:sessionId}?user_key=abcdef' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer XXXXXXXX' \
--data '{
    "packageStartDate": "2026-01-10T20:30:00",
    "cabinMix": [
        {
            "code": "I2",
            "guestIds": [1, 2]
        }
    ]
}'

Response

{
    "sessionId": "eb86ca32-e42e-4ad0-aed4-f523cf549857",
    "market": "NO",
    "currency": "NOK",
    "departureDate": "2026-01-10T20:30:00",
    "arrivalDate": "2026-01-16T09:00:00",
    "departurePort": "BGO",
    "arrivalPort": "KKN",
    "shipCode": "NK",
    "embarkationNotification": [
        {
            "locale": "en",
            "value": "Boarding opens 60 minutes before departure. Please be at the terminal in good time."
        },
        {
            "locale": "nb-NO",
            "value": "Ombordstigning åpner 60 minutter før avgang. Vær ved terminalen i god tid."
        }
    ],
    "guests": [
        {
            "id": 1,
            "type": "ADULT"
        },
        {
            "id": 2,
            "type": "ADULT"
        }
    ],
    "cabins": [
        {
            "id": 1,
            "code": "I2",
            "cabinType": "Inside",
            "cabinNumber": null,
            "guests": [1, 2]
        }
    ],
    "addons": [
        {
            "code": "WIFI",
            "guests": [1, 2],
            "isMandatory": true
        }
    ],
    "excursions": [],
    "supplementalTours": [],
    "packageCode": "ABCDEF",
    "packageStartDate": "2026-01-08T00:00:00",
    "packageEndDate": "2026-01-16T00:00:00",
    "packageDeparturePort": "OSL",
    "packageArrivalPort": "KKN",
    "priceBreakdown": {
        "totalPrice": 5140.0,
        "cabins": [
            {
                "code": "I2",
                "guests": [
                    {
                        "guestId": 1,
                        "price": 2500.0
                    },
                    {
                        "guestId": 2,
                        "price": 2500.0
                    }
                ]
            }
        ],
        "addons": [
            {
                "code": "WIFI",
                "guests": [
                    {
                        "guestId": 1,
                        "price": 70
                    },
                    {
                        "guestId": 2,
                        "price": 70
                    }
                ]
            }
        ],
        "excursions": [],
        "supplementalTours": []
    }
}

Fields

Field Type Description
sessionId string (UUID) The booking session this held booking belongs to.
market string Market the booking was created under.
currency string Currency the booking is priced in.
packageCode string Package code (see /packages).
packageStartDate string (date-time) Package start timestamp.
packageEndDate string (date-time) Package end timestamp.
packageDeparturePort string Package start port code.
packageArrivalPort string Package end port code.
departureDate string (date-time) Underlying voyage departure timestamp. May differ from packageStartDate when the package's start does not coincide with the voyage's departure.
arrivalDate string (date-time) Underlying voyage arrival timestamp.
departurePort string Underlying voyage departure port code.
arrivalPort string Underlying voyage arrival port code.
shipCode string Ship code (see /refdata/ships).
embarkationNotification array of objects Localized embarkation instruction for the cruise departurePort (not packageDeparturePort): [{ locale, value }]. null when none applies.
guests array of objects Passengers on the booking.
guests[].id number Passenger ID (matches the IDs used in cabinMix[].guestIds).
guests[].type string One of ADULT, CHILD, INFANT, SENIOR.
cabins array of objects Cabins reserved.
cabins[].id number Identifies this cabin on the booking. Send it as cabinId when choosing a cabin number.
cabins[].code string Cabin grade code.
cabins[].cabinType string Cabin type (e.g. Inside, Outside, Suite). Categorization above the per-ship cabin grade.
cabins[].cabinNumber string The specific cabin allocated, once one has been chosen via /cabin-numbers. null while the booking holds a guarantee cabin, where the cabin is assigned before departure.
cabins[].guests array of numbers Passenger IDs assigned to this cabin.
addons array of objects Addons currently on the booking. Mandatory addons (and addons that are part of the package) are auto-included here at create time and must not be re-applied.
addons[].code string Addon code (see /bookings/{:sessionId}/addons to discover available addons for the booking).
addons[].guests array of numbers Passenger IDs the addon applies to.
addons[].isMandatory boolean true for addons auto-included by Hurtigruten or carried by the package; these cannot be removed.
excursions array of objects Excursions currently on the booking. Always present; empty when nothing is applied.
excursions[].code string Excursion code (see /bookings/create/package/{:sessionId}/excursions).
excursions[].startDate string (date-time) Excursion start timestamp.
excursions[].endDate string (date-time) Excursion end timestamp.
excursions[].isMandatory boolean true for excursions that are part of the package; these cannot be removed.
excursions[].guests array of numbers Passenger IDs the excursion applies to.
supplementalTours array of objects Supplemental tours (pre- or post-cruise extensions) currently on the booking. Always present; empty when nothing is applied.
supplementalTours[].code string Supplemental-tour code.
supplementalTours[].startDate string (date-time) Tour start timestamp.
supplementalTours[].endDate string (date-time) Tour end timestamp.
supplementalTours[].tourCategory string One of Arrival (pre-cruise) or Departure (post-cruise).
supplementalTours[].isMandatory boolean true when the tour cannot be removed.
supplementalTours[].guests array of numbers Passenger IDs the tour applies to.
supplementalTours[].tourStageSelectableRouteOverrides array of objects Per-stage route overrides chosen for the tour. Empty when no overrides apply.
supplementalTours[].tourStageSelectableRouteOverrides[].tourStageId number Tour-stage identifier.
supplementalTours[].tourStageSelectableRouteOverrides[].departureCode string Override departure port code.
supplementalTours[].tourStageSelectableRouteOverrides[].arrivalCode string Override arrival port code.
priceBreakdown object Price detail. Components sum to priceBreakdown.totalPrice.
priceBreakdown.totalPrice number Total price for the booking in the booking currency.
priceBreakdown.cabins array of objects Per-cabin pricing.
priceBreakdown.cabins[].code string Cabin grade code.
priceBreakdown.cabins[].guests array of objects Per-passenger price for this cabin.
priceBreakdown.cabins[].guests[].guestId number Passenger ID.
priceBreakdown.cabins[].guests[].price number Passenger's portion of the cabin price.
priceBreakdown.addons array of objects Per-addon pricing.
priceBreakdown.addons[].code string Addon code.
priceBreakdown.addons[].guests array of objects Per-passenger price for this addon.
priceBreakdown.addons[].guests[].guestId number Passenger ID.
priceBreakdown.addons[].guests[].price number Passenger's portion of the addon price.
priceBreakdown.excursions array of objects Per-excursion pricing.
priceBreakdown.excursions[].code string Excursion code.
priceBreakdown.excursions[].guests array of objects Per-passenger price for this excursion.
priceBreakdown.excursions[].guests[].guestId number Passenger ID.
priceBreakdown.excursions[].guests[].price number Passenger's portion of the excursion price.
priceBreakdown.supplementalTours array of objects Per-supplemental-tour pricing.
priceBreakdown.supplementalTours[].code string Supplemental-tour code.
priceBreakdown.supplementalTours[].guests array of objects Per-passenger price for this supplemental tour.
priceBreakdown.supplementalTours[].guests[].guestId number Passenger ID.
priceBreakdown.supplementalTours[].guests[].price number Passenger's portion of the supplemental-tour price.

Errors

See Error model for response-body shapes across status codes.

Status Cause
400 user_key query parameter is missing; the request body fails validation (rules listed below); or the request references a departure, cabin grade, or passenger that is not in the session.
404 The session does not exist or has expired.
409 A held booking already exists in this session (each session can hold one booking at a time; start a new search for another booking); or the session does not match this endpoint's booking type.

Validation rules. A 400 is returned when any of these rules are not met:

  • cabinMix must be non-empty.
  • Each cabin's code must be non-empty and guestIds must be non-empty, with every guestId > 0.
  • Total guestIds across all cabins must not exceed 9, and every guestId must be unique across the request.
  • packageStartDate must be in the future and must match a package start date returned by the originating search.
  • Every guestId and every cabin code must come from the search response.
  • Each cabin's guestIds count must not exceed the cabin grade's maximumOccupancy, and at least one of those passengers must be of type: "ADULT" or type: "SENIOR".

Mandatory addons. If the booking includes mandatory addons (for example, on-board Wi-Fi), they appear in addons with isMandatory: true and are already priced into priceBreakdown.totalPrice. Do not call /bookings/{:sessionId}/addons for these — re-applying a mandatory addon is not supported.