> ## Documentation Index
> Fetch the complete documentation index at: https://docs.d-edge.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> This site documents the D-EDGE APIs for technology partners (web agencies, OTAs, PMS and RMS vendors, booking and CRM tools). It is written for developers integrating with hotels that use the D-EDGE platform.
> Seven APIs, grouped by domain. Connectivity: Channel Manager API (distribute a hotel's inventory to your channel and send bookings back). Pricing & Availability: Best Price API (best offers to highlight), Quotation API (all bookable offers for a stay), Daily Rates API (daily availability between two dates). Booking: Booking Engine API (a hotel's full direct booking funnel), Gift Shop API (gift vouchers from catalogue to payment). Guest Management: CRM API (guest profiles).
> Pick the API by the need: to display prices, use the Best Price API or the Daily Rates API; to quote a specific stay, use the Quotation API; to book, use the Booking Engine API; to sell gift vouchers, use the Gift Shop API; to manage guest profiles, use the CRM API; to receive hotel inventory and send bookings back as a distribution channel, use the Channel Manager API.
> Base URLs, hotel identifiers, and credentials are delivered by the D-EDGE partnership team during onboarding. Do not invent base URLs, endpoints, parameters, or example credentials that do not appear on these pages.
> Authentication differs per API: OAuth 1.0 for Best Price, Quotation, Daily Rates, and Booking Engine; an X-API-KEY header for Gift Shop; OAuth 2.0 client credentials for CRM; partner-defined credentials carried in the XML message for the Channel Manager API. Read each API's Authentication page before writing code.
> A mock environment returns realistic but fictitious data without credentials. The Postman and Insomnia collections on the API collections page target it by default. Use it for exploration and tests, never for production traffic.
> Use the official names exactly: D-EDGE, D-EDGE platform, Channel Manager API, partnership team. Do not use Back Office or Extranet.
> Each API has a Changelog page. Check it for the current behaviour before relying on an older answer. For questions these pages do not answer, direct the reader to the Contact us page.

# Post-stay profile enrichment

> Walk recent stays and write back what you learn about the guest

What a guest tells you after a stay is worth more than what they filled in before it: the language they actually answer in, the floor they asked to change, the review they left. That knowledge usually stops inside the tool that collected it. Writing it back to the guest profile puts it in front of the next hotel that welcomes them.

## How it works

Three steps, each an API call:

* **Read the stays** with **Browse bookings**, which pairs every booking with the guest it belongs to.
* **Read the profile** with **Get a guest**, for the sourced attributes the index does not carry.
* **Write back** with **Partially update a guest**, which appends to array attributes instead of replacing them.

> [!NOTE]
>
> The examples reuse the bearer token from the [Quick start](/crm-api/get-started/quick-start.md). Replace `{entityId}` with your entity.

## Read the stays

**Browse bookings** lives on the bookings service, so its path starts with `/api/bookings-manager/`. It paginates with `limit` and `offset`, and the response carries a `total`, so the first call also sizes the work. The query below keeps the confirmed stays that ended in August 2026. With `>` and `<`, `departure` takes a plain `YYYY-MM-DD` date, so the API filters the window for you.

```bash theme={null}
curl --request POST \
  --url 'https://{apiBaseUrl}/api/bookings-manager/entities/{entityId}/bookings/browse' \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "limit": 100,
    "offset": 0,
    "query": {
      "logic": "AND",
      "criteria": [
        {"logic": "AND", "criteria": [
          {"field": "bookingstatus", "operator": "=", "value": "confirmed"},
          {"field": "departure", "operator": ">", "value": "2026-08-01"},
          {"field": "departure", "operator": "<", "value": "2026-09-01"}
        ]}
      ]
    }
  }'
```

```json theme={null}
{
  "bookings": [
    {
      "booking": {
        "guestId": "55468764-64be-4fc1-a43f-e37239e012bf",
        "arrival": "2026-08-24T15:00:00Z",
        "departure": "2026-08-27T11:00:00Z",
        "stayLength": 3,
        "paxAdults": 2,
        "status": "confirmed"
      },
      "guest": {
        "id": "55468764-64be-4fc1-a43f-e37239e012bf",
        "firstname": "Martin",
        "emails": "martin.dupont@example.com"
      }
    }
  ],
  "total": 148
}
```

Move the window forward on each run. The [Search criteria](/crm-api/build/guidelines/search-criteria.md) page lists the fields and operators available to narrow the stays further.

## Write back what you learned

Use `PATCH`, not `PUT`. On an array attribute it appends: the language the guest answered in joins the one the PMS wrote instead of erasing it, and a note lands next to the ones the staff already took. Set `from` to the real origin of what you write: `guest` for what the guest told you, `agent` for what a human recorded.

```bash cURL theme={null}
curl --request PATCH \
  --url 'https://{apiBaseUrl}/api/guestprofile/entities/{entityId}/guests/55468764-64be-4fc1-a43f-e37239e012bf' \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "languages": [{"value": "fr", "from": "guest"}],
    "notes": [{"value": "Asked for a quiet room away from the lift.", "from": "agent"}]
  }'
```

```javascript Node.js theme={null}
const guestId = "55468764-64be-4fc1-a43f-e37239e012bf";

await fetch(
  `https://{apiBaseUrl}/api/guestprofile/entities/${entityId}/guests/${guestId}`,
  {
    method: "PATCH",
    headers: {
      Authorization: `Bearer ${accessToken}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      languages: [{ value: "fr", from: "guest" }],
      notes: [{ value: "Asked for a quiet room away from the lift.", from: "agent" }],
    }),
  }
);

// the response is empty, so read the profile back when the write matters
const stored = await (
  await fetch(
    `https://{apiBaseUrl}/api/guestprofile/entities/${entityId}/guests/${guestId}`,
    { headers: { Authorization: `Bearer ${accessToken}` } }
  )
).json();
```

```python Python theme={null}
guest_id = "55468764-64be-4fc1-a43f-e37239e012bf"
url = f"https://{{apiBaseUrl}}/api/guestprofile/entities/{entity_id}/guests/{guest_id}"
headers = {"Authorization": f"Bearer {access_token}", "Content-Type": "application/json"}

requests.patch(url, headers=headers, json={
    "languages": [{"value": "fr", "from": "guest"}],
    "notes": [{"value": "Asked for a quiet room away from the lift.", "from": "agent"}],
})

# the response is empty, so read the profile back when the write matters
stored = requests.get(url, headers=headers).json()
```

```php PHP theme={null}
$guestId = '55468764-64be-4fc1-a43f-e37239e012bf';
$path = "/api/guestprofile/entities/$entityId/guests/$guestId";

$client->patch($path, ['json' => [
    'languages' => [['value' => 'fr', 'from' => 'guest']],
    'notes' => [['value' => 'Asked for a quiet room away from the lift.', 'from' => 'agent']],
]]);

// the response is empty, so read the profile back when the write matters
$stored = json_decode($client->get($path)->getBody(), true);
```

```csharp C# theme={null}
var guestId = "55468764-64be-4fc1-a43f-e37239e012bf";
var path = $"/api/guestprofile/entities/{entityId}/guests/{guestId}";

await client.PatchAsJsonAsync(path, new
{
    languages = new[] { new { value = "fr", from = "guest" } },
    notes = new[] { new { value = "Asked for a quiet room away from the lift.", from = "agent" } }
});

// the response is empty, so read the profile back when the write matters
var stored = await client.GetFromJsonAsync<JsonElement>(path);
```

```java Java theme={null}
String guestId = "55468764-64be-4fc1-a43f-e37239e012bf";
String url = "https://{apiBaseUrl}/api/guestprofile/entities/" + entityId + "/guests/" + guestId;

String body = """
    {
      "languages": [{"value": "fr", "from": "guest"}],
      "notes": [{"value": "Asked for a quiet room away from the lift.", "from": "agent"}]
    }
    """;

client.send(HttpRequest.newBuilder()
    .uri(URI.create(url))
    .header("Authorization", "Bearer " + accessToken)
    .header("Content-Type", "application/json")
    .method("PATCH", HttpRequest.BodyPublishers.ofString(body))
    .build(), HttpResponse.BodyHandlers.ofString());

// the response is empty, so read the profile back when the write matters
HttpResponse<String> stored = client.send(HttpRequest.newBuilder()
    .uri(URI.create(url))
    .header("Authorization", "Bearer " + accessToken)
    .GET().build(), HttpResponse.BodyHandlers.ofString());
```

## Tailor the next message

**Get a guest's segments** tells you which groups a profile belongs to, so the follow-up you send matches how the hotel already thinks about that guest. Read it before composing, and fall back to a neutral message when the list comes back empty.

```bash theme={null}
curl --request GET \
  --url 'https://{apiBaseUrl}/api/guestprofile/entities/{entityId}/guests/55468764-64be-4fc1-a43f-e37239e012bf/segments' \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
```

## Tips

* **`PATCH` is not idempotent.** Array attributes append on every call, so a retried write can duplicate a note. Key your retries on your side, or read the profile before sending again.
* **Check the opt-out flags before any message.** When a channel preference has been recorded, the profile carries it under `optedOut`; the attribute is absent until something sets it, so handle both cases. Read it on the profile rather than on your own copy, since another system may have changed it since your last sync.
* **Write the real source.** A note stored as `pms` when a human wrote it makes the next partner trust it more than it deserves. The `from` field is what keeps a shared profile readable.

## Related

> **[Browse bookings](/crm-api/build/reference/search/post-bookings-browse.md)**
>
> Stays paired with their guest, page by page.

> **[Partially update a guest](/crm-api/build/reference/guest/patch-guest.md)**
>
> The append-style write.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.