# Reservation roster sync
> Source: /guides/patterns/roster-sync
> Pull reservations and guests at your venues into your own CRM or data warehouse.

This is the pattern for getting Journey's view of your stays into your own
systems — a CRM, a BI warehouse, or a reporting job.

## The sequence [#the-sequence]

<Steps>
  <Step title="List your venues">
    `GET /v1/partner/venues` tells you what this credential can reach, so the
    sync does not silently miss a property.
  </Step>
  <Step title="Page through reservations">
    `GET /v1/partner/reservations` with a `checkInFrom` / `checkInTo` window
    and `limit=100`. Follow `nextCursor` until it comes back null.
  </Step>
  <Step title="Spot-refresh individual records">
    `GET /v1/partner/reservations/{externalReservationId}` when you need one
    reservation rather than a whole page.
  </Step>
</Steps>

## Paging correctly [#paging-correctly]

`GET /v1/partner/reservations` supports a **keyset cursor**, which is what you
want for a large estate:

- Send `cursor`, read `nextCursor` from the response, repeat until it is null.
- Ordering is by check-in date, then external reservation id.
- A cursor **overrides `offset`**, and the response will echo `offset: 0`. Do
  not try to combine the two.
- A malformed cursor is ignored rather than rejected, so a silent restart from
  the beginning is the failure mode to watch for. Assert that you are making
  progress.

Other list endpoints use `limit` (1–100) and `offset`.

## Filters worth knowing [#filters-worth-knowing]

<ParamField query="checkInFrom" type="date">
  Defaults to yesterday if you omit it.
</ParamField>

<ParamField query="checkInTo" type="date">
  Defaults to roughly a month out if you omit it.
</ParamField>

<ParamField query="bookingStatus" type="string">
  One of `confirmed`, `canceled`, `inquiry`, `other`.
</ParamField>

<ParamField query="memberLinked" type="boolean">
  Narrow to stays that are linked to a Journey member.
</ParamField>

<ParamField query="propertyId" type="string">
  A single property. `propertyIds` takes several.
</ParamField>

<ParamField query="q" type="string">
  Case-insensitive search across confirmation code, PMS id, guest name and
  guest email.
</ParamField>

## Things that catch people out [#things-that-catch-people-out]

<Warning>
  **Guest name, email and phone are masked** unless your credential holds the
  guest PII read permission. If your sync is writing blanks into a CRM, that is
  why — check the scopes on your key rather than the field names.
</Warning>

- **There is no value in syncing frequently.** Reservation data refreshes in
  Core on a multi-hour cycle, so a tighter loop returns the same rows. See
  [how the data flows](/guides/reservation-and-guest-data-flow).
- **`propertyIds` outside your scope returns 403**, which is the one place the
  API tells you "not yours" rather than returning 404. Everywhere else,
  out-of-scope reads look like "not found".
- **Back off on 429.** Both per-key and edge limits exist. Treat 429 as
  expected under load and retry with exponential backoff.

## Related [#related]

`GET /v1/partner/guests` returns a roster derived from reservations. It is not
identity resolution — it reflects the guests on stays at your venues.
