Compare and apply counter-proposals

  • Services
  • 10 routes
How do I identify, compare, and apply a Club Med counter-proposal?

This scenario explains how Club Med exposes counter-proposals around a travel request. The flow first covers alternative date suggestions from booking criteria, then explores alternatives on an already created proposal, such as package, rate, transportation, or accommodation.

The goal is to help integrators build a reliable comparison experience: start from a reference proposal, inspect its current state, refresh it when needed, and only display alternatives that are actually applicable.

Overview

The counter-proposal concept is not handled by a single route. It relies on several resources that intervene at different moments of the booking flow:

  • before final selection, with POST/v0/proposals/date_suggestion to suggest alternative dates;
  • after proposal creation, with routes dedicated to package, rate, transportation, or accommodation alternatives.

Prerequisites

  • Have a valid x-api-key.
  • Provide accept-language on routes that require it.
  • Have booking criteria that can generate a reference proposal.
  • Have a valid proposal_id for reading, refreshing, and arbitrating proposal alternatives.
  • Prepare a bearer token when your integration context requires one.

Expected result

At the end of this flow, the application can:

  • generate a reference proposal;
  • list counter-proposals by date;
  • read and refresh the selected proposal;
  • display applicable package, rate, transportation, and accommodation alternatives;
  • apply a package or rate alternative when the corresponding route is used.

Process workflow

Legend:
Mandatory
Optional
1

Create a reference proposal

Mandatory

This route creates a reference proposal from the initial stay criteria.

Prerequisites

Prepare the stay criteria, attendees, and target product before comparing counter-proposals.

Calling CURL

curl -X POST \
  -H "x-api-key: $API_KEY" \
  -H "accept-language: en-US" \
  -H "Content-Type: application/json" \
  -d '{"product_id": "product-1", "start_date": "2026-07-05", "end_date": "2026-07-12", "attendees": [{"birthdate": "1990-03-12"}, {"birthdate": "2016-05-20"}]}' \
  "https://api.clubmed.com/v1/proposals/search/best"

Example answer

{
  "id": "proposal-1",
  "product_id": "product-1",
  "stay": {
    "start_date": "2026-07-05",
    "end_date": "2026-07-12"
  },
  "price": {
    "amount": 2890,
    "currency": "EUR"
  },
  "option_available": true
}

info: Use this proposal as the baseline when comparing all counter-proposals afterwards.


Response codes

  • 200 OK: the reference proposal is returned.
  • 400 Bad Request: invalid criteria or malformed JSON.
  • 401 Unauthorized: missing or invalid token.
  • 403 Forbidden: unauthorized commercial context.
  • 404 Not Found: unknown product.
POST/v1/proposals/search/best
See more
2

List date-based counter-proposals

Optional

This route returns counter-proposals based on alternative stay dates.

Prerequisites

Reuse the same attendee and stay criteria as the reference proposal.

Calling CURL

curl -X POST \
  -H "x-api-key: $API_KEY" \
  -H "accept-language: en-US" \
  -H "Content-Type: application/json" \
  -d '{"product_id": "product-1", "start_date": "2026-07-05", "end_date": "2026-07-12", "attendees": [{"birthdate": "1990-03-12"}, {"birthdate": "2016-05-20"}]}' \
  "https://api.clubmed.com/v0/proposals/date_suggestion"

Example answer

{
  "date_suggestion": [
    {
      "start_date": "2026-07-12",
      "end_date": "2026-07-19",
      "price": {
        "amount": 2750,
        "currency": "EUR"
      }
    }
  ],
  "price_currency": "EUR"
}

info: This view is useful to arbitrate quickly between date flexibility and price level.


Response codes

  • 200 OK: the date suggestions are returned.
  • 400 Bad Request: invalid criteria or malformed JSON.
  • 401 Unauthorized: missing or invalid token.
  • 403 Forbidden: access denied.
  • 404 Not Found: unknown product.
  • 409 Conflict: the criteria are no longer valid.
POST/v0/proposals/date_suggestion
See more
3

Read the selected proposal

Mandatory

This route reads the selected proposal to retrieve its full state before arbitration.

Prerequisites

Use the proposal identifier selected in the previous steps.

Calling CURL

curl -X GET \
  -H "x-api-key: $API_KEY" \
  "https://api.clubmed.com/v2/proposals/{proposal_id}"

Example answer

{
  "id": "proposal-1",
  "price": {
    "amount": 2890,
    "currency": "EUR"
  },
  "alternative_price": {
    "amount": 2750,
    "currency": "EUR"
  },
  "remaining_stock": 4,
  "transportation_summary": {
    "is_transportation_included": true
  }
}

info: Use this read step to secure your comparisons before applying a counter-proposal.


Response codes

  • 200 OK: the proposal is returned.
  • 400 Bad Request: invalid parameters.
  • 409 Conflict: invalid proposal or non-applicable economic conditions.
GET/v2/proposals/{proposal_id}
See more
4

Refresh the proposal before arbitration

Optional

This route refreshes the proposal to recalculate stock and price before the final decision.

Prerequisites

Call it right before arbitration if the proposal has been open for several minutes.

Calling CURL

curl -X POST \
  -H "x-api-key: $API_KEY" \
  -H "accept-language: en-US" \
  -H "Content-Type: application/json" \
  -d '{"refresh_stock": true}' \
  "https://api.clubmed.com/v1/proposals/{proposal_id}/refresh"

Example answer

{
  "id": "proposal-1",
  "remaining_stock": 3,
  "price": {
    "amount": 2910,
    "currency": "EUR"
  }
}

info: Refreshing avoids applying a counter-proposal on stale data.


Response codes

  • 200 OK: the refreshed proposal is returned.
  • 400 Bad Request: invalid JSON.
  • 401 Unauthorized: missing or invalid token.
  • 403 Forbidden: access denied.
  • 409 Conflict: a service or component is no longer available.
POST/v1/proposals/{proposal_id}/refresh
See more
5

Retrieve alternative packages

Optional

This route lists the alternative packages available for the proposal.

Prerequisites

Use an existing and still valid proposal.

Calling CURL

curl -X GET \
  -H "x-api-key: $API_KEY" \
  "https://api.clubmed.com/v0/proposals/{proposal_id}/alternative_packages"

Example answer

[
  {
    "id": "AI",
    "differential_price": {
      "amount": 42,
      "currency": "EUR"
    }
  }
]

info: The price differential helps identify a richer or more affordable package quickly.


Response codes

  • 200 OK: the alternative packages are returned.
  • 400 Bad Request: invalid parameters.
GET/v0/proposals/{proposal_id}/alternative_packages
See more
6

Apply an alternative package

Optional

This route applies the selected alternative package to the proposal.

Prerequisites

Reuse the package identifier returned by the previous step.

Calling CURL

curl -X PUT \
  -H "x-api-key: $API_KEY" \
  -H "accept-language: en-US" \
  -H "Content-Type: application/json" \
  -d '{"id": "AI"}' \
  "https://api.clubmed.com/v0/proposals/{proposal_id}/alternative_packages"

Example answer

HTTP/1.1 204 No Content

info: Success is returned without a body. Read the proposal again afterwards if you need the consolidated result.


Response codes

  • 204 No Content: the package is applied.
  • 400 Bad Request: unavailable package, failed validation, or invalid JSON.
  • 403 Forbidden: invalid API key.
  • 404 Not Found: proposal not found.
PUT/v0/proposals/{proposal_id}/alternative_packages
See more
7

Retrieve alternative rates

Optional

This route returns the alternative rates applicable to the proposal.

Prerequisites

Use a still valid proposal to compare the available pricing policies.

Calling CURL

curl -X GET \
  -H "x-api-key: $API_KEY" \
  "https://api.clubmed.com/v0/proposals/{proposal_id}/alternative_rates"

Example answer

[
  {
    "type": "FLEXIBLE_RATE",
    "currency": "EUR",
    "price_difference": 42
  }
]

info: This read step helps anticipate the pricing impact before switching to another rate.


Response codes

  • 200 OK: the alternative rates are returned.
  • 400 Bad Request: invalid parameters.
GET/v0/proposals/{proposal_id}/alternative_rates
See more
8

Apply an alternative rate

Optional

This route applies an alternative rate to the proposal.

Prerequisites

Reuse the selected rate type after comparing the price differences.

Calling CURL

curl -X PUT \
  -H "x-api-key: $API_KEY" \
  -H "accept-language: en-US" \
  -H "Content-Type: application/json" \
  -d '{"type": "FLEXIBLE_RATE"}' \
  "https://api.clubmed.com/v0/proposals/{proposal_id}/rates"

Example answer

{
  "id": "proposal-1",
  "price": {
    "amount": 2890,
    "currency": "EUR"
  },
  "alternative_price": {
    "amount": 2750,
    "currency": "EUR"
  },
  "remaining_stock": 4,
  "transportation_summary": {
    "is_transportation_included": true
  }
}

info: Unlike some other apply routes, this one returns the updated proposal in the response body.


Response codes

  • 200 OK: the updated proposal is returned.
  • 400 Bad Request: invalid parameters, failed validation, or malformed JSON.
PUT/v0/proposals/{proposal_id}/rates
See more
9

Retrieve alternative transports

Optional

This route returns the applied transportation together with the available alternatives for the proposal.

Prerequisites

Use a proposal that is eligible for transportation. Keep the selected transportation identifier for the next step.

Calling CURL

curl -X POST \
  -H "x-api-key: $API_KEY" \
  -H "accept-language: en-US" \
  -H "Content-Type: application/json" \
  -d '{"journeys": [{"transport_class": "STANDARD"}]}' \
  "https://api.clubmed.com/v1/proposals/{proposal_id}/available_transports"

Example answer

[
  {
    "id": "transport-1",
    "is_applied_transportation": false,
    "time_validity_limit": "2026-07-01T10:00:00Z",
    "price": {
      "amount": 220,
      "currency": "EUR"
    },
    "total_differential_price": {
      "amount": 80,
      "currency": "EUR"
    },
    "journeys": [
      {
        "travel_sections": [
          {
            "departure_point": "Paris",
            "arrival_point": "Valmorel",
            "transport_class": "STANDARD"
          }
        ]
      }
    ]
  }
]

info: The description and cURL are aligned with the correct Swagger route: available_transports.


Response codes

  • 200 OK: the alternative transports are returned.
  • 400 Bad Request: the proposal is not eligible for transportation or the JSON body is invalid.
  • 404 Not Found: the proposal cannot be found.
POST/v1/proposals/{proposal_id}/available_transports
See more
10

Retrieve the best alternative accommodations

Optional

This route returns a curated selection of the best alternative accommodations for the proposal.

Prerequisites

You can refine the result with is_pmr_room_priority, is_family_room, or is_mixable_room depending on your business logic.

Calling CURL

curl -X GET \
  -H "x-api-key: $API_KEY" \
  -H "accept-language: en-US" \
  "https://api.clubmed.com/v1/proposals/{proposal_id}/best_accommodations?is_family_room=true"

Example answer

{
  "alternative_accommodations": [
    {
      "id": "room-2",
      "label": "Family Superior Room"
    }
  ],
  "price": {
    "amount": 120,
    "currency": "EUR"
  }
}

info: Use this read step to propose a justified accommodation alternative without leaving the current proposal.


Response codes

  • 200 OK: the best alternative accommodations are returned.
  • 400 Bad Request: invalid parameters.
  • 401 Unauthorized: missing or invalid token.
GET/v1/proposals/{proposal_id}/best_accommodations
See more