---
uuid: a624cc14-aa0f-4fef-94ea-82a143876571
date_created: 2026-03-25T10:00:23.838Z
date_updated: 2026-04-03T17:59:13.309Z
seo_url: proposals-how-counter-proposals-work
category: Services
routes: 
  - POST /v1/proposals/search/best
  - POST /v0/proposals/date_suggestion
  - GET /v2/proposals/{proposal_id}
  - POST /v1/proposals/{proposal_id}/refresh
  - GET /v0/proposals/{proposal_id}/alternative_packages
  - PUT /v0/proposals/{proposal_id}/alternative_packages
  - GET /v0/proposals/{proposal_id}/alternative_rates
  - PUT /v0/proposals/{proposal_id}/rates
  - POST /v1/proposals/{proposal_id}/available_transports
  - GET /v1/proposals/{proposal_id}/best_accommodations
---

# Compare and apply counter-proposals

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.

## Flow

```mermaid
flowchart LR
    step0["Create a reference proposal"]
    step1["List date-based counter-proposals"]
    step2["Read the selected proposal"]
    step3["Refresh the proposal before arbitration"]
    step4["Retrieve alternative packages"]
    step5["Apply an alternative package"]
    step6["Retrieve alternative rates"]
    step7["Apply an alternative rate"]
    step8["Retrieve alternative transports"]
    step9["Retrieve the best alternative accommodations"]
    step0 --> step1
    step1 --> step2
    step2 --> step3
    step3 --> step4
    step4 --> step5
    step5 --> step6
    step6 --> step7
    step7 --> step8
    step8 --> step9
    classDef optional fill:transparent,stroke:#ffffff,color:#ffffff,stroke-width:1px,stroke-dasharray: 6\,4
    class step1 optional
    class step3 optional
    class step4 optional
    class step5 optional
    class step6 optional
    class step7 optional
    class step8 optional
    class step9 optional
```

## 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.

## 1 - Create a reference proposal

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

```bash
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

```json
{
  "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.

**Related route**: [POST https://api.clubmed.com//v1/proposals/search/best](https://api.clubmed.com/doc?search=POST%20%2Fv1%2Fproposals%2Fsearch%2Fbest)

## 2 - List date-based counter-proposals

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

#### Prerequisites

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

#### Calling CURL

```bash
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

```json
{
  "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.

**Related route**: [POST https://api.clubmed.com//v0/proposals/date\_suggestion](https://api.clubmed.com/doc?search=POST%20%2Fv0%2Fproposals%2Fdate_suggestion)

## 3 - Read the selected proposal

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

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

#### Example answer

```json
{
  "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.

**Related route**: [GET https://api.clubmed.com//v2/proposals/{proposal\_id}](https://api.clubmed.com/doc?search=GET%20%2Fv2%2Fproposals%2F%7Bproposal_id%7D)

## 4 - Refresh the proposal before arbitration

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

```bash
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

```json
{
  "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.

**Related route**: [POST https://api.clubmed.com//v1/proposals/{proposal\_id}/refresh](https://api.clubmed.com/doc?search=POST%20%2Fv1%2Fproposals%2F%7Bproposal_id%7D%2Frefresh)

## 5 - Retrieve alternative packages

This route lists the alternative packages available for the proposal.

#### Prerequisites

Use an existing and still valid proposal.

#### Calling CURL

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

#### Example answer

```json
[
  {
    "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.

**Related route**: [GET https://api.clubmed.com//v0/proposals/{proposal\_id}/alternative\_packages](https://api.clubmed.com/doc?search=GET%20%2Fv0%2Fproposals%2F%7Bproposal_id%7D%2Falternative_packages)

## 6 - Apply an alternative package

This route applies the selected alternative package to the proposal.

#### Prerequisites

Reuse the package identifier returned by the previous step.

#### Calling CURL

```bash
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
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.

**Related route**: [PUT https://api.clubmed.com//v0/proposals/{proposal\_id}/alternative\_packages](https://api.clubmed.com/doc?search=PUT%20%2Fv0%2Fproposals%2F%7Bproposal_id%7D%2Falternative_packages)

## 7 - Retrieve alternative rates

This route returns the alternative rates applicable to the proposal.

#### Prerequisites

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

#### Calling CURL

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

#### Example answer

```json
[
  {
    "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.

**Related route**: [GET https://api.clubmed.com//v0/proposals/{proposal\_id}/alternative\_rates](https://api.clubmed.com/doc?search=GET%20%2Fv0%2Fproposals%2F%7Bproposal_id%7D%2Falternative_rates)

## 8 - Apply an alternative rate

This route applies an alternative rate to the proposal.

#### Prerequisites

Reuse the selected rate type after comparing the price differences.

#### Calling CURL

```bash
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

```json
{
  "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.

**Related route**: [PUT https://api.clubmed.com//v0/proposals/{proposal\_id}/rates](https://api.clubmed.com/doc?search=PUT%20%2Fv0%2Fproposals%2F%7Bproposal_id%7D%2Frates)

## 9 - Retrieve alternative transports

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

```bash
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

```json
[
  {
    "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.

**Related route**: [POST https://api.clubmed.com//v1/proposals/{proposal\_id}/available\_transports](https://api.clubmed.com/doc?search=POST%20%2Fv1%2Fproposals%2F%7Bproposal_id%7D%2Favailable_transports)

## 10 - Retrieve the best alternative accommodations

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

```bash
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

```json
{
  "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.

**Related route**: [GET https://api.clubmed.com//v1/proposals/{proposal\_id}/best\_accommodations](https://api.clubmed.com/doc?search=GET%20%2Fv1%2Fproposals%2F%7Bproposal_id%7D%2Fbest_accommodations)
