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

# Quick start

> Make your first call

This guide walks you through your first call to the CRM API. You will exchange your credentials for an OAuth 2.0 token, create a guest with the **Create a guest** endpoint, and read the new profile back.

> [!NOTE]
>
> **No credentials yet?** Import the [API collections](/overview/resources/api-collections.md) and run any request against the mock environment straight away, with no credentials. Add your OAuth 2.0 credentials when you are ready to call the live API.

## Prerequisites

Get the following from D-EDGE before starting:

* **Token endpoint**: the URL of the D-EDGE CRM ID server that issues your tokens.
* **OAuth 2.0 credentials**: client ID and client secret.
* **API base URL**: the base URL for your environment.
* **Entity identifier**: the entity whose guest profiles you manage, a UUID.

All are delivered during the build step of your [integration journey](/overview/get-started/your-integration-journey.md), after the partnership agreement.

## 1. Install an OAuth 2.0 library

The token exchange is a plain form POST, so any HTTP client can do it. A library is still worth it: it caches the token and renews it when it expires, which matters here because tokens live 300 seconds. Skip this step if you only use cURL.

```bash Node.js theme={null}
npm install simple-oauth2
```

```bash Python theme={null}
pip install requests-oauthlib
```

```bash PHP theme={null}
composer require league/oauth2-client
```

```bash C# theme={null}
dotnet add package IdentityModel
```

```xml Java theme={null}
<dependency>
    <groupId>com.nimbusds</groupId>
    <artifactId>oauth2-oidc-sdk</artifactId>
    <version>11.10.1</version>
</dependency>
```

## 2. Make your first call

Get a token, then send a `POST` to the **Create a guest** endpoint. Each attribute pairs a `value` with a `from` field naming who provided the information, and `emails` takes an object rather than a plain string. The full field list is documented in the [Reference](/crm-api/build/reference/guest/post-guests-create.md).

```bash cURL theme={null}
# 1. exchange your credentials for a token
curl --request POST \
  --url https://{tokenUrl} \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data grant_type=client_credentials \
  --data client_id=YOUR_CLIENT_ID \
  --data client_secret=YOUR_CLIENT_SECRET

# 2. create a guest with the access_token from the response
curl --request POST \
  --url https://{apiBaseUrl}/api/guestprofile/entities/{entityId}/guests/create \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "firstname": {"value": "Martin", "from": "guest"},
    "lastname": {"value": "Dupont", "from": "guest"},
    "emails": [{"value": {"email": "martin.dupont@example.com"}, "from": "guest"}]
  }'
```

```javascript Node.js theme={null}
import { ClientCredentials } from "simple-oauth2";

const tokenUrl = new URL("https://{tokenUrl}");

const client = new ClientCredentials({
  client: {
    id: process.env.DEDGE_CLIENT_ID,
    secret: process.env.DEDGE_CLIENT_SECRET,
  },
  auth: { tokenHost: tokenUrl.origin, tokenPath: tokenUrl.pathname },
  options: { authorizationMethod: "body" },
});

const token = await client.getToken({});
const entityId = process.env.DEDGE_ENTITY_ID;

const response = await fetch(
  `https://{apiBaseUrl}/api/guestprofile/entities/${entityId}/guests/create`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${token.token.access_token}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      firstname: { value: "Martin", from: "guest" },
      lastname: { value: "Dupont", from: "guest" },
      emails: [{ value: { email: "martin.dupont@example.com" }, from: "guest" }],
    }),
  }
);

console.log(response.status, response.headers.get("location"));
```

```python Python theme={null}
import os
from oauthlib.oauth2 import BackendApplicationClient
from requests_oauthlib import OAuth2Session

client = BackendApplicationClient(client_id=os.environ["DEDGE_CLIENT_ID"])
session = OAuth2Session(client=client)
session.fetch_token(
    token_url="https://{tokenUrl}",
    client_id=os.environ["DEDGE_CLIENT_ID"],
    client_secret=os.environ["DEDGE_CLIENT_SECRET"],
)

entity_id = os.environ["DEDGE_ENTITY_ID"]

response = session.post(
    "https://{apiBaseUrl}/api/guestprofile/entities/" + entity_id + "/guests/create",
    json={
        "firstname": {"value": "Martin", "from": "guest"},
        "lastname": {"value": "Dupont", "from": "guest"},
        "emails": [{"value": {"email": "martin.dupont@example.com"}, "from": "guest"}],
    },
)

print(response.status_code)
print(response.headers.get("location"))
```

```php PHP theme={null}
require 'vendor/autoload.php';

use League\OAuth2\Client\Provider\GenericProvider;
use GuzzleHttp\Client;

$provider = new GenericProvider([
    'clientId'                => getenv('DEDGE_CLIENT_ID'),
    'clientSecret'            => getenv('DEDGE_CLIENT_SECRET'),
    'urlAccessToken'          => 'https://{tokenUrl}',
    'urlAuthorize'            => '',
    'urlResourceOwnerDetails' => '',
]);

$token = $provider->getAccessToken('client_credentials');
$entityId = getenv('DEDGE_ENTITY_ID');

$client = new Client(['base_uri' => 'https://{apiBaseUrl}/']);

$response = $client->post("api/guestprofile/entities/$entityId/guests/create", [
    'headers' => ['Authorization' => 'Bearer ' . $token->getToken()],
    'json'    => [
        'firstname' => ['value' => 'Martin', 'from' => 'guest'],
        'lastname'  => ['value' => 'Dupont', 'from' => 'guest'],
        'emails'    => [['value' => ['email' => 'martin.dupont@example.com'], 'from' => 'guest']],
    ],
]);

echo $response->getStatusCode() . "\n";
echo $response->getHeaderLine('location');
```

```csharp C# theme={null}
using System.Net.Http.Json;
using IdentityModel.Client;

var http = new HttpClient();

var token = await http.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
{
    Address = "https://{tokenUrl}",
    ClientId = Environment.GetEnvironmentVariable("DEDGE_CLIENT_ID"),
    ClientSecret = Environment.GetEnvironmentVariable("DEDGE_CLIENT_SECRET"),
    ClientCredentialStyle = ClientCredentialStyle.PostBody
});

var entityId = Environment.GetEnvironmentVariable("DEDGE_ENTITY_ID");

var client = new HttpClient { BaseAddress = new Uri("https://{apiBaseUrl}") };
client.SetBearerToken(token.AccessToken);

var response = await client.PostAsJsonAsync(
    $"/api/guestprofile/entities/{entityId}/guests/create", new
{
    firstname = new { value = "Martin", from = "guest" },
    lastname = new { value = "Dupont", from = "guest" },
    emails = new[] { new { value = new { email = "martin.dupont@example.com" }, from = "guest" } }
});

Console.WriteLine(response.StatusCode);
Console.WriteLine(response.Headers.Location);
```

```java Java theme={null}
import com.nimbusds.oauth2.sdk.*;
import com.nimbusds.oauth2.sdk.auth.*;
import com.nimbusds.oauth2.sdk.id.ClientID;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

ClientAuthentication auth = new ClientSecretPost(
    new ClientID(System.getenv("DEDGE_CLIENT_ID")),
    new Secret(System.getenv("DEDGE_CLIENT_SECRET"))
);

TokenRequest tokenRequest = new TokenRequest(
    URI.create("https://{tokenUrl}"), auth, new ClientCredentialsGrant());
String accessToken = TokenResponse.parse(tokenRequest.toHTTPRequest().send())
    .toSuccessResponse().getTokens().getAccessToken().getValue();

String entityId = System.getenv("DEDGE_ENTITY_ID");
String body = """
    {
      "firstname": {"value": "Martin", "from": "guest"},
      "lastname": {"value": "Dupont", "from": "guest"},
      "emails": [{"value": {"email": "martin.dupont@example.com"}, "from": "guest"}]
    }
    """;

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://{apiBaseUrl}/api/guestprofile/entities/" + entityId + "/guests/create"))
    .header("Authorization", "Bearer " + accessToken)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(body))
    .build();

HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.headers().firstValue("location").orElse(""));
```

## 3. Inspect the response

A successful creation returns `200 OK` with an empty body and a `location` header holding the path of the new profile. The last path segment is the guest identifier, which is what you store on your side.

```text theme={null}
location: /api/guestprofile/entities/{entityId}/guests/55468764-64be-4fc1-a43f-e37239e012bf
```

Read the profile back with the **Get a guest** endpoint. Each attribute comes with the source that provided it and the date it last changed, and the CRM fills in what it can infer:

```json theme={null}
{
  "id": "55468764-64be-4fc1-a43f-e37239e012bf",
  "entityId": "{entityId}",
  "type": "guest",
  "createdAt": "2026-08-14T09:24:11.000000Z",
  "firstname": {
    "from": "guest",
    "value": "Martin",
    "updated": "2026-08-14T09:24:11Z"
  },
  "lastname": {
    "from": "guest",
    "value": "Dupont",
    "updated": "2026-08-14T09:24:11Z"
  },
  "emails": [
    {
      "from": "guest",
      "value": {"email": "martin.dupont@example.com"},
      "updated": "2026-08-14T09:24:11Z",
      "preferred": true
    }
  ],
  "gender": {
    "from": "system",
    "value": "M",
    "updated": "2026-08-14T09:24:11Z"
  }
}
```

See the [response schema](/crm-api/build/reference/guest/get-guest.md) for the full structure.

## Common issues

| Status | Likely cause | Where to look |
| - | - | - |
| `401` | The bearer token is missing, invalid, expired, or does not give access to the entity | [Authentication](/crm-api/build/guidelines/authentication.md) |
| `400` | Validation error: malformed body or invalid property | [Responses](/crm-api/build/guidelines/responses.md) |
| `500` | An attribute sent in the wrong shape, such as an email as a plain string instead of an object | [Requests](/crm-api/build/guidelines/requests.md) |

## Next steps

> **[Reference](/crm-api/build/reference/guest/post-guests-create.md)**
>
> Endpoint specifications, parameters, and response schemas.

> **[Guidelines](/crm-api/build/guidelines/authentication.md)**
>
> Authentication, request conventions, and response formats.

> **[Best practices](/crm-api/build/best-practices.md)**
>
> Patterns for clean profiles, from sourcing to deduplication.


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