---
uuid: 29c849c9-63ce-4145-a078-7edd0f7138c3
date_created: 2025-08-18T12:51:09.864Z
date_updated: 2026-04-02T23:25:48.094Z
seo_url: add-service
category: Services
tags: 
  - Proposal service
routes: 
  - POST /v1/proposals/search/best
  - GET /v0/additional_services
  - GET /v0/proposals/{proposal_id}/services
  - PUT /v0/proposals/{proposal_id}/services
---

# Add a service to a proposal

This scenario shows how to identify the available additional services, review the services already attached to a proposal, and update the selected proposal service list.

## Flow

```mermaid
flowchart LR
    step0["Create or retrieve the proposal"]
    step1["List available additional services"]
    step2["Review current proposal services"]
    step3["Replace the proposal service list"]
    step0 --> step1
    step1 --> step2
    step2 --> step3
```

## Overview

The sequence `POST /v0/proposals/search/best` -> `GET /v0/additional_services` -> `GET /v0/proposals/{proposal_id}/services` -> `PUT /v0/proposals/{proposal_id}/services` helps identify the additional services that can be sold, review the services already attached, and then replace the final service list kept on the proposal.

## Prerequisites

* A usable proposal must be created or retrieved at the beginning of the journey.
* The `proposal_id` returned by the first step is required to read and update services.
* The final update follows a `cancel & replace` logic: each call must carry the complete list of services that should remain on the proposal.
* The documented calls use `accept-language` and `x-api-key`.

## 1 - Create or retrieve the proposal

Use `POST /v1/proposals/search/best` to create or retrieve the working proposal that will later receive additional services.

#### Prerequisites

* Send `accept-language` and `x-api-key`.
* The body must carry the booking criteria used in your sales journey.
* Keep the returned `id` so it can be reused as `proposal_id` in the next steps.

#### Calling CURL

```bash
curl -X 'POST' \
  'https://api.clubmed.com/v1/proposals/search/best' \
  -H 'accept: application/json' \
  -H 'accept-language: en-US' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "product_id": "MPAC",
    "package_id": "PAI",
    "resort_arrival_date": "20260415",
    "duration": 7,
    "number_attendees": 2
  }'
```

#### Example answer

```json
{
  "id": "123456",
  "product_id": "MPAC",
  "package_id": "PAI",
  "resort_arrival_date": "20260415",
  "resort_departure_date": "20260422",
  "creation_date_time": "2026-04-03T10:15:00Z",
  "price": {
    "amount": 9815.4,
    "currency": "EUR"
  },
  "alternative_price": {
    "amount": 9650.4,
    "currency": "EUR"
  },
  "option_durability": {
    "expiration_date_time": "2026-04-03T18:00:00Z",
    "is_reliable": true
  }
}
```

> **info:** `search/best` returns the best usable proposal for the submitted context, which is usually faster than browsing a full proposal list in a guided sales journey.

***

**Response codes**

* **OK Response (200):** returns the created or retrieved proposal with the identifier to reuse downstream.
* **Error (400):** invalid, incomplete, or inconsistent criteria.
* **Error (401):** authentication or API key is missing, invalid, or expired.
* **Error (403):** at least one customer carried by the criteria is not allowed to continue the journey.
* **Error (404):** the requested product is unknown for the submitted context.

**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 available additional services

This route returns the list of additional services available for a given proposal or booking. Use it to identify the services that can actually be sold before building the final list to send back on the proposal.

#### Prerequisites

* `accept-language` and `x-api-key` are required.
* Provide at least one business context such as `proposal_id`, `booking_id`, or `customer_id` depending on your journey.
* `types` and `filter` can be used to narrow the search to the services you really need.

#### Calling CURL

```bash
curl -X 'GET' \
  'https://api.clubmed.com/v0/additional_services?proposal_id=123456&types=CHILDCARE' \
  -H 'accept: application/json' \
  -H 'accept-language: en-US' \
  -H 'x-api-key: YOUR_API_KEY'
```

#### Example answer

```json
[
  {
    "id": "VMOSK1",
    "product_information_id": "ACT_AGAC_baby_club_med_bis",
    "stay_index": 1,
    "time_slot": "MORNING",
    "age_in_months": {
      "min": 12,
      "max": 48
    },
    "not_compatible_with": [
      "string"
    ],
    "sold_only_with": [
      "string"
    ],
    "type": "CHILDCARE",
    "currency": "EUR",
    "schedules": [
      {
        "start_date": "20100430",
        "end_date": "20100430",
        "initial_stock": 12,
        "remaining_stock": 2,
        "attendees": [
          {
            "id": "A",
            "price": 88,
            "resort_price": 100
          }
        ]
      }
    ]
  }
]
```

> **info:** evaluate `sold_only_with` and `not_compatible_with` before any update, otherwise the final replacement call can be rejected.

***

**Response codes**

* **OK Response (200):** the available additional services were returned successfully.
* **OK Response (206):** the response is partial.
* **Error (400):** the proposal or booking context is invalid, not validated, or inconsistent with the submitted customer.
* **Error (401):** the request is unauthorized because the authentication data or API key is missing, invalid, or expired.
* **Error (403):** access is forbidden for the targeted country or the expected authentication is missing for some uses with `booking_id` and `customer_id`.
* **Error (404):** the proposal or booking was not found for the submitted context.
* **Error (409):** the proposal criteria are no longer valid when the list is requested.
* **Error (416):** the requested range or filter is not satisfiable.

**Related route**: [GET https://api.clubmed.com//v0/additional\_services](https://api.clubmed.com/doc?search=GET%20%2Fv0%2Fadditional_services)

## 3 - Review current proposal services

This route reads back the services already present on the proposal. Use this response as your source of truth before the final update, because the modification call replaces the existing list.

#### Prerequisites

* `x-api-key` is required.
* The `proposal_id` path parameter is required.
* The optional `filter` query parameter can narrow the read to specific services.

#### Calling CURL

```bash
curl -X 'GET' \
  'https://api.clubmed.com/v0/proposals/123456/services' \
  -H 'accept: application/json' \
  -H 'x-api-key: YOUR_API_KEY'
```

#### Example answer

```json
[
  {
    "id": "AHSI01",
    "time_slot": "MORNING",
    "type": "RENTAL",
    "currency": "EUR",
    "schedules": [
      {
        "start_date": "20100430",
        "end_date": "20100430",
        "attendees": [
          {
            "id": "A",
            "price": 250,
            "price_without_discount": 300,
            "discounts": [
              {
                "amount": 50,
                "offer_id": "AVA",
                "code": "PARFIL"
              }
            ]
          }
        ]
      }
    ],
    "product_information_id": "ACT_AGAC_baby_club_med_bis",
    "sold_only_with": [
      "ATIG3A"
    ],
    "not_compatible_with": [
      "ATIG3A"
    ]
  }
]
```

> **info:** build the full list to keep from this read-back, otherwise some services already present can be dropped when the `PUT` is submitted.

***

**Response codes**

* **OK Response (200):** the services currently attached to the proposal were returned successfully.
* **Error (400):** the request is invalid or the submitted filter cannot be processed.
* **Error (401):** not documented in Swagger.
* **Error (404):** not documented in Swagger.

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

## 4 - Replace the proposal service list

This route updates the list of services associated with a proposal. The behavior is `cancel & replace`: each call must contain the complete set of services that should remain attached to the proposal after the update.

#### Prerequisites

* `accept-language` and `x-api-key` are required.
* The `proposal_id` path parameter is required.
* Build the final payload from both the available-service search and the read-back of the services already attached.
* Validate incompatibility and dependency rules before submitting the update.

#### Calling CURL

```bash
curl -X 'PUT' \
  'https://api.clubmed.com/v0/proposals/123456/services' \
  -H 'accept: application/json' \
  -H 'accept-language: en-US' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '@proposal-services-body.json'
```

#### Example answer

No response body is documented on success. Swagger documents a `204 No Content` success response.

> **info:** after this `PUT`, call `GET /v0/proposals/{proposal_id}/services` again to verify the list actually kept on the proposal.

***

**Response codes**

* **OK Response (204):** the service list was updated successfully with no response body.
* **Error (400):** the payload is invalid, contains incompatible services, or omits a required service.
* **Error (401):** the request is unauthorized because the authentication data or API key is missing, invalid, or expired.
* **Error (404):** the targeted proposal cannot be found.
* **Error (409):** the proposal economic control is no longer valid at update time.

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