Docs/API Reference/Reservations

List reservations with filtering

Reservations · GET /v1/reservations

List reservations with filtering

GET/v1/reservations

Request

curl https://api.repull.dev/v1/reservations?limit=50 \
  -H "Authorization: Bearer $REPULL_API_KEY"

Response

{
  "data": [
    {
      "id": "123",
      "listingId": "123",
      "guestId": "123",
      "checkIn": "2026-06-01",
      "checkOut": "2026-06-01",
      "status": "confirmed",
      "source": "airbnb",
      "platform": "airbnb",
      "confirmationCode": "Example text",
      "totalPrice": "Example text",
      "currency": "USD",
      "guestDetails": {
        "numberOfPets": 0,
        "numberOfAdults": 0,
        "numberOfGuests": 0,
        "numberOfInfants": 0,
        "numberOfChildren": 0
      },
      "primaryGuest": {
        "id": "123",
        "firstName": "Example",
        "lastName": "Example",
        "phone": "+15550000000",
        "language": "Example text"
      },
      "occupancy": {
        "adults": 0,
        "children": 0,
        "infants": 0,
        "pets": 0,
        "total": 0
      },
      "financials": {
        "totalPrice": 0,
        "currency": "USD",
        "paymentStatus": "pending",
        "cancellationPolicy": "Example text",
        "host": {
          "accommodation": 0,
          "discounts": [],
          "guestFees": [
            {
              "name": "Example",
              "type": "guest_service",
              "amount": 0,
              "vat": 0
            }
          ],
          "hostFees": [
            {
              "name": "Example",
              "type": "host_service",
              "amount": 0,
              "vat": 0
            }
          ],
          "taxes": [],
          "revenue": 0
        },
        "guest": {
          "totalPrice": 0,
          "fees": [
            {
              "name": "Example",
              "type": "cleaning",
              "amount": 0
            }
          ],
          "taxes": []
        }
      },
      "createdAt": "2026-06-01T12:00:00.000Z",
      "updatedAt": "2026-06-01T12:00:00.000Z",
      "bookedAt": "2026-06-01T12:00:00.000Z",
      "guestName": "Example"
    }
  ],
  "pagination": {
    "nextCursor": "eyJpZCI6MTIzfQ==",
    "hasMore": true,
    "total": 0
  }
}

Captured from a real response. Regenerated on every release, and CI fails if this shape stops matching the API.

Query Parameters

accountstring

Only one connected account's records, as `provider:externalAccountId` (e.g. `airbnb:79730216`, `booking:10167991`, `vrbo:36`, `hostaway:…`) — the pair on every webhook `account` block, on `connect.session.completed`, and on each record's `account`. See /for-platforms.

limitinteger

Page size (max 100). Requests over the cap return 422.

cursorstring

Opaque cursor returned in the previous response's `pagination.nextCursor`. Omit to fetch the first page.

offsetinteger

First-class alias for cursor-based pagination. Mutually exclusive with `cursor` — passing both returns 422. Accepts integers in `[0, 10000]`; deeper walks must use `cursor` (constant per-page cost). The response always includes `pagination.nextCursor` so consumers can switch from offset → cursor mid-walk for deep pagination without re-keying.

platformstring

Filter by booking platform

statusstring

Filter by lifecycle status. **Case-insensitive** — `confirmed`, `Confirmed`, and `CONFIRMED` all match. Each public value expands to the full set of internal sub-states server-side: `confirmed` matches `accept`/`confirmed`/`modified`, `cancelled` matches every cancellation sub-state (`cancelled_by_host`, `declined`, `expired`, etc.), `pending` includes `inquiry`/`awaiting_payment`. `completed` is a derived state — combine `status=confirmed` with `check_out_before=<today>` to filter for past stays. `pending` lists only Airbnb booking requests that can still be answered, each with `respondBy`; one that lapsed (24 hours after the guest asked, or its check-in passed) appears under `cancelled` with `statusDetail: "request_expired"` instead.

listingIdinteger

Filter to a single listing

check_in_afterdate

Check-in date >= this value

check_in_beforedate

Check-in date <= this value

check_out_afterdate

Check-out date >= this value

check_out_beforedate

Check-out date <= this value

checkInFromdate

Deprecated alias for `check_in_after`.

checkInTodate

Deprecated alias for `check_in_before`.

checkInAfterdate

Use `check_in_after` (snake_case) instead.

checkInBeforedate

Use `check_in_before` (snake_case) instead.

checkOutAfterdate

Use `check_out_after` (snake_case) instead.

checkOutBeforedate

Use `check_out_before` (snake_case) instead.

updated_sincedate

Incremental sync: return only records whose `updatedAt` is at or after this instant. This is the only filter on record **mutation** time — every `check_*` filter targets guest **stay** dates. **Accepted formats.** ISO 8601, with `Z` or a numeric offset — both work: - `2026-08-01T00:00:00Z` - `2026-08-01T00:00:00.123Z` - `2026-08-01T00:00:00+00:00` - `2026-08-01T02:30:00-07:00` (offset colon optional: `-0700`) - `2026-08-01T00:00` (seconds optional) - `2026-08-01T00:00:00` — no zone designator, interpreted as **UTC** - `2026-08-01` — date only, means midnight UTC Anything else returns 422 `invalid_params` naming the field; the value is never silently ignored. **Ordering changes when you pass this.** Results are ordered `updatedAt ASC, id ASC` (instead of the endpoint default) and the cursor keys on the same pair. That is required for correctness: under the default ordering a record amended mid-walk can move behind the cursor and never be emitted — which is exactly the event you are polling for. Ascending mutation time is monotonic with the cursor, so anything touched during a walk resurfaces later in it or on the next poll. **Cursors are not interchangeable between the two orderings.** Keep `updated_since` on every page of an incremental walk; replaying a cursor from the other ordering returns 422 rather than a page that silently skips rows. **Watermark.** The bound is inclusive (`updatedAt >= value`), so the last row of the final page is the watermark for the next poll — re-polling with it re-emits that row. Delivery is at-least-once; upsert by `id`.

include_totalboolean

When `true` (default), the response's `pagination.total` carries the count of rows matching the current filter, across all pages. Pass `false` to skip the count for very large workspaces where the per-page COUNT(*) cost matters.

AI