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

# Retrieving the guest event log for a guest

> Resolve a PMS source ID, then read the event log for a guest profile or a master profile.

The guest event log is the append-only history Casa Layer stores for a guest.
Each row is one change to one entity. Use it to replay what Casa Layer saw.

You can read the log at two grains:

* **Guest profile** — one source system's record
* **Master profile** — the golden record after identity resolution

Both paths start with a PMS **source ID**. The event log does not accept
`source_id`. Resolve the Casa Layer ID first. Then send that ID to
`GET /v1/events`.

Use a [partner API credential](/partner-credentials). Do not use a personal
API key for a third-party system.

## What you need

Select these scopes on the credential:

| Scope             | Why you need it                                                            |
| ----------------- | -------------------------------------------------------------------------- |
| `read:properties` | Property roster and [integration roster](/api-reference/list-integrations) |
| `read:guests`     | Guest lookup by PMS `source_id`                                            |
| `read:events`     | The guest event log                                                        |

You also need the PMS guest ID. Casa Layer stores it as `source_id` on the
guest profile.

If the guest lookup is empty, use the PMS reservation ID instead. See
[Searching for a master profile using PMS identifiers](/use-cases/search-master-profile-pms-ids).

## 1. Create partner credentials

Create the credential in the Casa Layer app. See
[Partner API credentials](/partner-credentials) for the full steps.

1. Open **Integrations → Partner credentials → Custom Integration**.
2. Name the credential.
3. Select `read:properties`, `read:guests`, and `read:events`.
4. Click **Create credentials**.
5. Copy the **client ID** and **client secret**.

Casa Layer shows the client secret once. Store it with the partner.

## 2. Get an access token

Exchange the client ID and client secret for a short-lived access token.

```bash theme={null}
curl -X POST https://temperate-milestone-52.authkit.app/oauth2/token \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d grant_type=client_credentials
```

Read `access_token` from the response. Cache it until `exp`. Do not mint a
token on every Casa Layer call.

Send the token as a bearer credential on every request below:

```bash theme={null}
-H "Authorization: Bearer $ACCESS_TOKEN"
```

## 3. Get property context

List the properties in the credential's group.

```bash theme={null}
curl https://api.casa-layer.com/v1/properties \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

Each row has an `id` and a `name`. Use `id` as `X-Property-Id` when you want
one property only.

```bash theme={null}
-H "X-Property-Id: 7c9e6679-7425-40de-944b-e07fc1f90ae7"
```

The property must belong to the credential's group. A property outside the
group returns `403`.

Skip the header to search the whole group.

## 4. Get integration IDs

A PMS `source_id` is unique only inside one integration. List the roster
first.

```bash theme={null}
curl https://api.casa-layer.com/v1/integrations \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

Each row is one source system mapped to a property:

| Field         | Use                                                 |
| ------------- | --------------------------------------------------- |
| `id`          | The `integration_id` you send with `source_id`      |
| `provider`    | Source system slug, for example `mews` or `apaleo`  |
| `name`        | Display name of the connection                      |
| `property_id` | Property this mapping belongs to                    |
| `source_ref`  | Source entity ID (for example a Mews Enterprise ID) |
| `status`      | `pending`, `connected`, or `error`                  |

Pick the row for the PMS and property you will query. Copy `id`.

<Warning>
  `GET /v1/guests` rejects `source_id` without `integration_id`. The error is
  `400`.
</Warning>

## 5. Resolve the guest from the PMS source ID

```bash theme={null}
curl "https://api.casa-layer.com/v1/guests?source_id=mews-guest-8842&integration_id=1f2d6c4e-1b2a-4c3d-8e9f-0a1b2c3d4e5f" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

The response is a list. A match has one row. No match has an empty `data`
array.

```json theme={null}
{
  "data": [
    {
      "id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
      "property_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
      "integration_id": "1f2d6c4e-1b2a-4c3d-8e9f-0a1b2c3d4e5f",
      "master_profile_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
      "source_id": "mews-guest-8842",
      "first_name": "Ada",
      "surname": "Lovelace"
    }
  ],
  "next_cursor": null,
  "has_more": false
}
```

Read two Casa Layer IDs from the guest row:

| Field               | What it is                                                 |
| ------------------- | ---------------------------------------------------------- |
| `id`                | Casa Layer guest profile ID. Use this for the guest grain. |
| `master_profile_id` | Casa Layer master profile ID when the guest is clustered.  |
| `source_id`         | PMS guest ID you sent                                      |

If `data` is empty, that PMS may not store a guest `source_id`. Resolve the
guest from a reservation instead. Then use the reservation's
`guest_profile_id`.

If `master_profile_id` is `null`, identity resolution has not clustered this
guest. You can still read the **guest** event log. You cannot read a master
event log yet.

## 6. Read the event log

Send **one** filter. Do not send `guest_profile_id` and `master_profile_id`
together. Both filters combine with AND.

### Path A — guest profile (one source system)

Use the guest `id` from step 5. This log is one sub-profile only.

```bash theme={null}
curl "https://api.casa-layer.com/v1/events?guest_profile_id=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

Use this path when you want what one PMS said about the guest.

### Path B — master profile (resolved guest)

Use `master_profile_id` from step 5. This log covers every clustered member
sub-profile of that master.

```bash theme={null}
curl "https://api.casa-layer.com/v1/events?master_profile_id=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

Use this path when you want the full history for the real guest.

The master filter matches guest profiles whose `master_profile_id` equals
that ID. An unclustered guest does not match. If step 5 returned
`master_profile_id: null`, use Path A.

One guest `source_id` is enough for Path B. After you have the master ID,
the log includes the other clustered sub-profiles too.

<Info>
  `master_profile_id` on `GET /v1/events` is a Casa Layer UUID. It is not a
  PMS ID.
</Info>

## Modes

`GET /v1/events` has two modes.

| Mode                 | What you get                                                      |
| -------------------- | ----------------------------------------------------------------- |
| `timeline` (default) | Full change history, oldest first. Keyset-paginated.              |
| `latest`             | Latest delta slice per entity. One page. `next_cursor` is `null`. |

`latest` is not a merged entity snapshot. It is the last observed change for
each entity.

`rollup` is a deprecated alias for `latest`. The response `mode` is always
`timeline` or `latest`.

```bash theme={null}
curl "https://api.casa-layer.com/v1/events?guest_profile_id=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d&mode=latest" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

Walk a `timeline` with `limit` and `cursor`. Default `limit` is 100. The
maximum is 500. See [Pagination](/pagination).

```bash theme={null}
curl "https://api.casa-layer.com/v1/events?guest_profile_id=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d&limit=500" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

Send the last `next_cursor` as `cursor` until `next_cursor` is `null`.

## Optional entity filters

Narrow the page after you pick a grain:

| Parameter     | Use                                                        |
| ------------- | ---------------------------------------------------------- |
| `entity_type` | One canonical type, for example `reservation` or `consent` |
| `entity_id`   | Source entity ID for that type                             |

These filters still require `guest_profile_id` or `master_profile_id` when
you want one guest.

## What a row contains

Each event is a `GuestEventLogEntry`:

| Field              | Meaning                                                      |
| ------------------ | ------------------------------------------------------------ |
| `id`               | Casa Layer event ID                                          |
| `property_id`      | Property that observed the change                            |
| `integration_id`   | Source mapping that produced the change                      |
| `guest_profile_id` | Sub-profile this change belongs to. Can be `null`.           |
| `entity_type`      | Changed entity, for example `guest_profile` or `reservation` |
| `entity_id`        | Source entity ID the delta applies to                        |
| `delta`            | Changed fields for that entity type                          |
| `observed_at`      | When the source observed the change                          |
| `created_at`       | When Casa Layer stored the row                               |

`entity_type` values include `guest_profile`, `reservation`, `transaction`,
`action`, `loyalty_program`, `membership`, `review`, `channel`, `space`,
`consent`, and `consent_retract`.

```json theme={null}
{
  "mode": "timeline",
  "data": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "property_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
      "integration_id": "1f2d6c4e-1b2a-4c3d-8e9f-0a1b2c3d4e5f",
      "guest_profile_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
      "entity_type": "guest_profile",
      "entity_id": "mews-guest-8842",
      "delta": { "first_name": "Ada" },
      "observed_at": "2026-03-01T10:15:00Z",
      "created_at": "2026-03-01T10:15:02Z"
    }
  ],
  "next_cursor": null,
  "has_more": false
}
```

On Path B, rows can show different `guest_profile_id` values. Each value is
one clustered member.

## If the lookup is empty

Work through this list:

1. Confirm `integration_id` matches that PMS and property.
2. Confirm the PMS ID is the `source_id` Casa Layer ingested.
3. Confirm ingest has finished for that guest.
4. Remove `X-Property-Id` and try the group-wide guest lookup.
5. If the guest list is empty, resolve the guest from a reservation.
6. For Path B, confirm `master_profile_id` is not `null`.
7. For Path B, confirm the guest is clustered. Unclustered guests need Path A.

A `source_id` miss on `GET /v1/guests` is not `404`. The list is empty.

An event filter that matches nothing is also an empty list, not `404`.

## Errors

| Status | Body                                | Meaning                                               |
| ------ | ----------------------------------- | ----------------------------------------------------- |
| `400`  | `source_id requires integration_id` | You sent `source_id` without `integration_id`.        |
| `400`  | `invalid_cursor`                    | The `cursor` is malformed. Start from the first page. |
| `401`  | `unauthorized`                      | Missing, unknown, or expired token.                   |
| `403`  | `forbidden`                         | Missing scope, or `X-Property-Id` outside the group.  |

## Related

<CardGroup cols={2}>
  <Card title="Partner API credentials" icon="handshake" href="/partner-credentials">
    Create, rotate, and revoke the credential.
  </Card>

  <Card title="Data model" icon="sitemap" href="/data-model#guest-event-log">
    Guest event log grain and modes.
  </Card>

  <Card title="Guest event log" icon="clock-rotate-left" href="/api-reference/guest-event-log">
    `GET /v1/events` reference.
  </Card>

  <Card title="Search by PMS identifiers" icon="magnifying-glass" href="/use-cases/search-master-profile-pms-ids">
    Resolve a guest or master from a PMS ID.
  </Card>
</CardGroup>
