Booking Summary & Pace

Bookings, nights, revenue, payout, average nightly rate, occupancy and cancellations for any period, in one small response. Group by month, listing or channel, and compare with last year like for like.

Summarize a period

GET/v1/reservations/summary
curl "https://api.repull.dev/v1/reservations/summary?from=2026-11-10&to=2027-02-09&group_by=month" \
  -H "Authorization: Bearer sk_live_YOUR_KEY"
const res = await fetch(
  'https://api.repull.dev/v1/reservations/summary?from=2026-11-10&to=2027-02-09&group_by=month',
  { headers: { Authorization: `Bearer ${process.env.REPULL_API_KEY}` } },
)
const { totals, groups } = await res.json()
console.log(totals[0].nights, totals[0].revenue, totals[0].occupancy)
{
  "from": "2026-11-10", "to": "2027-02-09", "basis": "stay", "groupBy": ["month"], "asOf": null,
  "listingCount": 19,
  "totals": [{
    "currency": "CAD", "reservations": 212, "nights": 1104, "revenue": 241380.5, "payout": 205422.1,
    "averageNightlyRate": 196.4, "averageStayNights": 5.2, "averageLeadTimeDays": 41,
    "occupancy": 0.6431, "availableNights": 1716,
    "cancelled": 18, "cancelledRevenue": 9120, "pending": 2, "ownerStays": 3, "ownerNights": 12
  }],
  "groups": [{ "month": "2026-11", "currency": "CAD", "nights": 301, "revenue": 51200.4, "occupancy": 0.7061 }]
}

Parameters

  • from, to (required): the period, both days included, up to 732 days.
  • basis: stay(default) counts the nights that fall inside the period, and splits each booking's money across its nights, so a stay that crosses the edge of the period (or of a month) brings only its share. check_in and booked count whole bookings by their check-in or booking date.
  • group_by: up to two of month, listing, channel, e.g. month,listing.
  • as_of: only what was on the books at the end of that day (see pace, below).
  • listing_id, platform, account: narrow to one listing, channel or connected account.

Compare with last year (pace)

Today's bookings for the next three months are not comparable with last year's final numbers for the same months: last year had three more months to fill. Compare with what last year had on the books on the same day instead:

# This year: what's on the books now for Nov 10 – Feb 9
curl "https://api.repull.dev/v1/reservations/summary?from=2026-11-10&to=2027-02-09" -H "Authorization: Bearer sk_live_YOUR_KEY"

# Last year, as it stood one year ago today
curl "https://api.repull.dev/v1/reservations/summary?from=2025-11-10&to=2026-02-09&as_of=2025-11-10" -H "Authorization: Bearer sk_live_YOUR_KEY"

# Last year's final result, for where this year could land
curl "https://api.repull.dev/v1/reservations/summary?from=2025-11-10&to=2026-02-09" -H "Authorization: Bearer sk_live_YOUR_KEY"

With as_of, a booking counts when it was made by that day and not yet cancelled. A booking cancelled later counts as booked. One cancelled without a cancellation date from the channel counts as cancelled.

How it counts

  • revenue is what guests paid; payout is what you receive, for bookings where the channel reports it (reservationsWithPayout says how many).
  • averageNightlyRate is the accommodation amount per night, without cleaning and other fees, when the channel gives it.
  • occupancy is guest nights divided by active listings × days. Blocked nights are not taken out. It is left empty when grouped by channel, and with basis=check_in or booked.
  • Owner stays are counted apart (ownerStays, ownerNights), never as revenue or occupancy. Pending requests are counted in pending only.
  • Money is never added across currencies: each currency gets its own row.
  • Bookings on inactive listings are left out, as on GET /v1/reservations.

For reports, not for syncing

Use the summary for dashboards, reports and AI assistants. To keep your own copy of every booking, walk GET /v1/reservations with updated_since, or receive webhooks.
AI