Reference
Reservations
Read connected customers' homes and stays, with measured freshness per source.
Reservations: properties and stays
Read the homes and stays of the RapidEye customers who connected your integration.
- Read-only. You do not create a workspace, send a roster or issue a recording link.
- One customer is one workspace. Its
workspace_idis ours,rwd_and 16 characters, and never changes, even when the customer disconnects and connects again. - Unlisted until the date we agree. Your key, these routes and your webhook receiver work from day one, but no customer can connect you until we list you. Until then
GET /v1/workspacesreturns an empty list and anyworkspace_idanswers404 workspace_not_provisioned.
Scopes for these routes
| Scope | Grants | On the customer's connection |
|---|---|---|
read:workspaces |
GET /v1/workspaces, GET /v1/workspaces/{workspace_id} |
Not needed |
read:properties |
GET /v1/properties: homes and full addresses |
Always |
read:reservations |
GET /v1/reservations and the two routes under it |
Always |
- A read needs the scope on your key and on the customer's connection. Otherwise it answers
403 insufficient_scope, anddetail.required_scopenames the scope. - Every other route in this guide answers a key with only these scopes with
403 insufficient_scope.
Keeping in sync
| Step | Call | Rule |
|---|---|---|
| 1. Customers | GET /v1/workspaces |
Daily. Keep each workspace_id. |
| 2. Backfill | GET /v1/reservations?workspace_id=...&updated_since=2000-01-01T00:00:00Z&limit=500 |
Once per customer, and again after a reconnect. Walk every page, until a page has no next_cursor. Backfill customers one after another, not all at once, and back off on a 429. |
| 3. Poll | GET /v1/reservations?workspace_id=...&updated_since=... |
Every 5 minutes, or every 15 if you take events. updated_since = when you started your previous poll, less 5 minutes. Walk every page. Reading a stay twice is harmless. |
| 4. Apply | Upsert each stay by reservation_id when its revision is higher than the one you hold; ignore it otherwise. A cancellation is the same stay with a higher revision and status: "cancelled", never a deletion. |
|
| 5. Homes | GET /v1/properties?workspace_id=...&updated_since=... |
About hourly, with the same 5-minute overlap. Dedupe on rapideye_property_id. |
| 6. Events | Optional. Each one is a nudge to re-read what it names (Events). |
Stubs
- When: a stay whose home is switched off, removed or deleted reads as a stub, whatever its status. A live stay there turns
out_of_scopewithin about 15 minutes, andGET /v1/propertiesshows the homeinactiveorremoved. - Fields: only
reservation_id,rapideye_property_id,source,source_reservation_id,source_property_id,status,status_basis,first_seen_at,last_confirmed_at,last_changed_atandrevision. Match a stub to your copy byreservation_id. - Not a cancellation. If the home is switched back on, its stays come back in full.
Coverage and freshness
A new booking or change reaches the API within the target below. A cancellation the source does not state takes the time in its row of the source table.
| Stays | Target |
|---|---|
| In house, or arriving or departing from yesterday through 2 days ahead | 20 minutes at p95, 60 at most |
| Arriving within 30 days | About an hour |
| Departing from 30 days ago to arriving within a year | A day |
| Source | Guest name | Status |
|---|---|---|
| Breezeway | Yes | checked_in and checked_out stated; otherwise confirmed, and cancelled once the stay leaves Breezeway (status_basis: inferred): about 30 minutes within 2 days, about 2 hours within 30 days, up to 2 nights further out |
| OwnerRez | Yes | A new booking or change reaches the API within about 3 minutes, at any date. Stated by OwnerRez: active is confirmed, a pending booking or quote hold is hold, canceled is cancelled. A booking deleted in OwnerRez becomes unknown: about 2 hours within 30 days, up to 2 nights further out |
| Track | Yes | Stated by Track, within 15 minutes. A stay deleted in Track becomes unknown: about 3 hours within 30 days, up to 3 nights further out |
| Trellis | No (source_does_not_provide) |
confirmed, and unknown once the stay leaves Trellis (status_basis: inferred): about 45 minutes within 2 days, about 3 hours within 30 days, up to 3 nights further out. Only stays with a Trellis task are visible. |
Measured freshness per customer is on GET /v1/workspaces/{workspace_id}.
Events
Optional signed deliveries that tell you about a change sooner than your next poll.
- Register: send us one HTTPS receiver URL, and the event types you want if not all. We send back its signing secret.
- Order by
revision. Deliveries arrive out of order and more than once; never order by arrival oroccurred_at. - Dedupe on
webhook-id, the payload'sevent_id, the same on every retry.
| Event | When | Payload |
|---|---|---|
workspace.enabled |
A customer connects you | workspace: the workspace object |
workspace.disabled |
A customer disconnects you, or RapidEye revokes the connection | workspace, with disabled_at set |
reservation.created |
We first see a stay | reservation: the reservation object, and changes |
reservation.updated |
Anything about the stay changed: dates, times, status, stay type, guest count, channel, home or guest. A cancellation is this event with status: "cancelled"; there is no separate one. |
reservation and changes, as in the history |
Handling an event
- Verify the signature over the raw body (Verifying our signature).
- Dedupe on
webhook-id. - Answer 2xx within 10 seconds and do the rest asynchronously. A non-2xx, a redirect or a timeout is retried after 1m, 5m, 30m, 2h and 12h, six attempts in all.
- Re-read what it names.
reservation.*:GET /v1/reservations/{reservation_id}?workspace_id=..., applied byrevision(skip it when the payload'srevisionis not higher than yours;changesis only a hint).workspace.*:GET /v1/workspaces/{workspace_id}; on aworkspace.enabledfor a workspace you hold as disabled, re-run its backfill. When many events arrive at once, run your poll early instead.
Errors on these routes
Every error uses the envelope in The error envelope. Besides each route's own codes, any route here can return:
| Error | When |
|---|---|
401 invalid_key |
The key is missing or not one we recognize. |
403 partner_disabled |
We paused your whole integration. Your key is not the problem; email support. |
403 insufficient_scope |
Your key, or the customer's connection, does not carry the scope this read needs. detail.required_scope names it. |
403 workspace_disabled |
This customer's connection to you is off: its data is not readable and its events stop. The workspace_id stays the same if it connects again. |
404 workspace_not_provisioned |
That workspace_id is not one of your customers. GET /v1/workspaces lists the ones you can read. |
429 too_many_requests |
More than 600 requests from your key in one 5-minute window of the clock. Retry once the next window starts, at most 5 minutes later; nothing is lost. |
GET/v1/workspaces#
Lists every customer connected to you (enabled) and every customer that was and no longer is (disabled). Scope: read:workspaces.
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Authorization |
header | string | yes | Bearer rapideye_pk_... |
status |
query | string | no | enabled or disabled, comma-separated for both. Default: both. |
limit |
query | integer | no | 1 to 500, default 100. |
cursor |
query | string | no | The previous page's next_cursor. |
| Field | Meaning |
|---|---|
scopes |
What this customer's connection grants (Scopes for these routes). |
enabled_at |
When the current connection began. |
active_properties |
The number of homes the customer shares. Absent on a disabled workspace. |
next_cursor |
Absent on the last page. |
| Error | When |
|---|---|
400 invalid_request |
status, limit or cursor is malformed. detail.parameter names it. |
GET /v1/workspaces?status=enabled HTTP/1.1
Host: api.rapideyeinspections.com
Authorization: Bearer rapideye_pk_...
HTTP/1.1 200 OK
Content-Type: application/json
{
"workspaces": [
{
"workspace_id": "rwd_7Hq2c9Lm4TzPx8Ab",
"customer_name": "Coastal Stays",
"status": "enabled",
"scopes": ["read:properties", "read:reservations"],
"enabled_at": "2026-10-14T15:02:11+00:00",
"disabled_at": null,
"active_properties": 142
}
]
}
GET/v1/workspaces/{workspace_id}#
Returns one customer's workspace with its measured freshness. Scope: read:workspaces.
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Authorization |
header | string | yes | Bearer rapideye_pk_... |
workspace_id |
path | string | yes | Ours, rwd_.... |
| Field | Meaning |
|---|---|
freshness |
Absent on a disabled workspace, as is active_properties. A disabled workspace still answers here with its status, scopes and times. |
reads[].kind |
window (stays within 2 days), upcoming (the next 30 days), full (the whole window) or, for Track and OwnerRez, recent (everything the source changed since our last read, standing in for window). |
reads[].last_complete_at |
When that kind of read last finished in full. For recent, which is never complete, when it last succeeded. |
last_read_at, last_read_status |
Our most recent read of the customer's PMS, of any kind: ok or failed. reads_last_24h and failed_reads_last_24h count them. |
new_booking_lag_minutes |
From when the source recorded a stay to when we first had it, over the last 7 days, split by whether the stay arrives within 2 days of being booked. |
change_lag_minutes |
From the source's last-modified time to when we saw the change. null for a source that sends no last-modified time. |
stays_in_window |
The customer's stays in the default window. |
stays_without_property |
Stays whose RapidEye home has since been deleted: we hold them but can no longer place them. A stay at a home the customer never added is not held, so not counted. |
exceptions |
In words, where this source falls short of the target. |
| Measured fields | null, not zero, if we cannot read our own measurements at that moment. The declared reads, cancellation and exceptions are still there. |
sources, note |
[] and a note for a customer whose PMS we do not read stays from. |
Errors: only the shared ones. This route never answers workspace_disabled.
GET /v1/workspaces/rwd_7Hq2c9Lm4TzPx8Ab HTTP/1.1
Host: api.rapideyeinspections.com
Authorization: Bearer rapideye_pk_...
HTTP/1.1 200 OK
Content-Type: application/json
{
"workspace_id": "rwd_7Hq2c9Lm4TzPx8Ab",
"customer_name": "Coastal Stays",
"status": "enabled",
"scopes": ["read:properties", "read:reservations"],
"enabled_at": "2026-10-14T15:02:11+00:00",
"disabled_at": null,
"active_properties": 142,
"freshness": {
"targets": { "p95_minutes": 20, "ceiling_minutes": 60, "applies_to": "stays in house, or arriving or departing from yesterday through 2 days ahead" },
"sources": [
{
"source": "breezeway",
"reads": [
{ "kind": "window", "covers": "stays in house, or arriving or departing from yesterday through 2 days ahead", "every_minutes": 15, "last_complete_at": "2026-10-20T13:35:02+00:00" },
{ "kind": "upcoming", "covers": "stays in house, or arriving or departing from yesterday through 30 days ahead", "every_minutes": 60, "last_complete_at": "2026-10-20T13:00:41+00:00" },
{ "kind": "full", "covers": "stays departing from 30 days ago to arriving within 365 days, nightly from 06:00 UTC; also run at once whenever a near or upcoming read lacks a stay we hold", "every_minutes": 1440, "last_complete_at": "2026-10-20T06:21:44+00:00" }
],
"last_read_at": "2026-10-20T13:35:02+00:00",
"last_read_status": "ok",
"reads_last_24h": 97,
"failed_reads_last_24h": 0,
"new_booking_lag_minutes": {
"window_days": 7,
"arriving_within_2_days": { "sample": 23, "p50": 7.9, "p95": 15.6 },
"arriving_later": { "sample": 230, "p50": 38.5, "p95": 702.0 }
},
"change_lag_minutes": null,
"stays_in_window": 1204,
"stays_without_property": 0,
"cancellation": "...",
"exceptions": ["..."]
}
]
}
}
GET/v1/properties#
Lists the customer's homes as RapidEye holds them. Scope: read:properties.
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Authorization |
header | string | yes | Bearer rapideye_pk_... |
workspace_id |
query | string | yes | Ours, rwd_.... |
status |
query | string | no | active, inactive, removed, comma-separated. Default: all three. |
updated_since |
query | date-time | no | Homes changed at or after this time. ISO 8601 with an offset. |
limit |
query | integer | no | 1 to 500, default 100. |
cursor |
query | string | no | The previous page's next_cursor. |
| Field | Meaning |
|---|---|
rapideye_property_id |
Ours and stable. Every stay names its home by it. |
source_property_id |
The home's id in the customer's PMS. |
source |
The PMS the home came from: breezeway, ownerrez, track, trellis, or manual for a home added by hand in RapidEye. |
status |
active, inactive (switched off in RapidEye) or removed. An inactive or removed home carries only rapideye_property_id, status, source, source_property_id and updated_at. A home the customer deletes from RapidEye no longer appears; its stays turn out_of_scope at our next read and still name it by source_property_id. |
address |
Refreshed from the PMS every night. A field we do not hold is null. |
address_complete |
false when line 1, city, region or postal code is missing. |
timezone |
The home's IANA zone. Every stay time is in it. |
coordinates |
null when the PMS sends none. |
| Error | When |
|---|---|
400 missing_parameter |
workspace_id is absent or blank. detail.parameter names it. |
400 invalid_request |
A filter is malformed, such as updated_since without an offset. detail.parameter names it; for a bad status, detail.allowed lists the accepted values; for a limit out of range, detail.limit is the maximum. |
GET /v1/properties?workspace_id=rwd_7Hq2c9Lm4TzPx8Ab&status=active HTTP/1.1
Host: api.rapideyeinspections.com
Authorization: Bearer rapideye_pk_...
HTTP/1.1 200 OK
Content-Type: application/json
{
"workspace_id": "rwd_7Hq2c9Lm4TzPx8Ab",
"properties": [
{
"rapideye_property_id": "1f0a9c22-6b1e-4a77-9b0f-2d2b0c5f7a10",
"name": "Beach House Unit 1",
"status": "active",
"source": "breezeway",
"source_property_id": "512345",
"address": {
"line1": "18 Ocean Drive",
"city": "Panama City Beach",
"region": "FL",
"postal_code": "32413",
"country_code": "US"
},
"address_complete": true,
"timezone": "America/Chicago",
"coordinates": { "latitude": 30.1766, "longitude": -85.8055 },
"updated_at": "2026-10-15T07:04:12+00:00"
}
]
}
GET/v1/reservations#
Lists one page of a customer's stays, oldest change first. Scope: read:reservations.
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Authorization |
header | string | yes | Bearer rapideye_pk_... |
workspace_id |
query | string | yes | Ours, rwd_.... |
updated_since |
query | date-time | no | Stays that changed at or after this time. ISO 8601 with an offset; a bare date answers 400 invalid_request. Removes the default window, so a change to an old stay is still returned. |
arrival_from, arrival_to |
query | date | no | Arrival date range, YYYY-MM-DD, inclusive. Removes the default window. Never returns a stub. |
rapideye_property_id |
query | string | no | One home. |
status |
query | string | no | One or more statuses (The reservation object), comma-separated. |
stay_type |
query | string | no | One or more of guest, owner, owner_guest, block, unknown, comma-separated. Never returns a stub. |
limit |
query | integer | no | 1 to 500, default 100. |
cursor |
query | string | no | The previous page's next_cursor. |
- Default window: with none of
updated_since,arrival_fromorarrival_to, stays departing from 30 days ago to arriving within 365 days. - Order:
last_changed_at, thenreservation_id. A stay that changes while you walk the pages moves to the end, and you read it again in its newer state. A write that lands just as your walk passes its time can fall behind the cursor; the 5-minute overlap in your next poll catches it.
Each stay is a reservation object (The reservation object). next_cursor is absent on the last page.
| Error | When |
|---|---|
400 missing_parameter |
workspace_id is absent or blank. detail.parameter names it. |
400 invalid_request |
A filter is malformed, such as updated_since without an offset. detail.parameter names it; for a bad status or stay_type, detail.allowed lists the accepted values; for a limit out of range, detail.limit is the maximum. |
GET /v1/reservations?workspace_id=rwd_7Hq2c9Lm4TzPx8Ab&updated_since=2026-10-19T09:00:00Z&limit=500 HTTP/1.1
Host: api.rapideyeinspections.com
Authorization: Bearer rapideye_pk_...
HTTP/1.1 200 OK
Content-Type: application/json
{
"workspace_id": "rwd_7Hq2c9Lm4TzPx8Ab",
"reservations": [
{
"reservation_id": "8c1e4b7a-90d2-4f55-a3f1-1d2e9b0c6a44",
"rapideye_property_id": "1f0a9c22-6b1e-4a77-9b0f-2d2b0c5f7a10",
"source": "breezeway",
"source_reservation_id": "107053350",
"source_property_id": "512345",
"pms_reservation_id": "HMX4QZ8KT2",
"status": "confirmed",
"status_basis": "inferred",
"stay_type": "guest",
"arrival_date": "2026-10-23",
"departure_date": "2026-10-27",
"check_in_at": "2026-10-23T16:00:00-05:00",
"check_out_at": "2026-10-27T10:00:00-05:00",
"timezone": "America/Chicago",
"booked_at": null,
"source_recorded_at": "2026-10-08T14:21:09+00:00",
"channel": "unknown",
"channel_raw": null,
"guest_count": 4,
"primary_guest": { "name": "Dana Whitfield" },
"first_seen_at": "2026-10-08T14:25:41+00:00",
"last_confirmed_at": "2026-10-20T13:35:02+00:00",
"last_changed_at": "2026-10-19T09:12:55+00:00",
"revision": 3,
"missing": {
"booked_at": "source_does_not_provide",
"channel": "source_does_not_provide"
}
}
],
"next_cursor": "MjAyNi0xMC0xOVQwOToxMjo1NS4wMDAwMDBafDhjMWU0YjdhLTkwZDItNGY1NS1hM2YxLTFkMmU5YjBjNmE0NA=="
}
GET/v1/reservations/{reservation_id}#
Returns one stay, in any window. Scope: read:reservations.
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Authorization |
header | string | yes | Bearer rapideye_pk_... |
reservation_id |
path | string | yes | Ours. |
workspace_id |
query | string | yes | Ours, rwd_.... |
The body is a reservation object. This example is a stub (Stubs); a stay at an active home has every field shown under GET /v1/reservations.
| Error | When |
|---|---|
400 missing_parameter |
workspace_id is absent or blank. |
404 reservation_not_found |
No stay with that reservation_id in that workspace. |
GET /v1/reservations/8c1e4b7a-90d2-4f55-a3f1-1d2e9b0c6a44?workspace_id=rwd_7Hq2c9Lm4TzPx8Ab HTTP/1.1
Host: api.rapideyeinspections.com
Authorization: Bearer rapideye_pk_...
HTTP/1.1 200 OK
Content-Type: application/json
{
"reservation_id": "8c1e4b7a-90d2-4f55-a3f1-1d2e9b0c6a44",
"rapideye_property_id": "1f0a9c22-6b1e-4a77-9b0f-2d2b0c5f7a10",
"source": "breezeway",
"source_reservation_id": "107053350",
"source_property_id": "512345",
"status": "out_of_scope",
"status_basis": "inferred",
"first_seen_at": "2026-10-08T14:25:41+00:00",
"last_confirmed_at": "2026-10-20T13:35:02+00:00",
"last_changed_at": "2026-10-22T08:10:31+00:00",
"revision": 5
}
GET/v1/reservations/{reservation_id}/history#
Lists every change we observed to one stay, oldest first. Scope: read:reservations.
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Authorization |
header | string | yes | Bearer rapideye_pk_... |
reservation_id |
path | string | yes | Ours. |
workspace_id |
query | string | yes | Ours, rwd_.... |
| Field | Meaning |
|---|---|
changes |
Oldest first, so the first entry is the stay as we first saw it. |
event |
created, updated, cancelled, reinstated (a stay we had marked cancelled or missing came back) or missing. |
fields |
Each changed field with its old and new value. Names are the reservation object's, except that a time changes as check_in_time or check_out_time, the home's wall-clock time ("16:00:00") that check_in_at and check_out_at are built from. Guest fields appear as "changed", never with their values. For a stub, cut to the status change. |
| Error | When |
|---|---|
400 missing_parameter |
workspace_id is absent or blank. |
404 reservation_not_found |
No stay with that reservation_id in that workspace. |
GET /v1/reservations/8c1e4b7a-90d2-4f55-a3f1-1d2e9b0c6a44/history?workspace_id=rwd_7Hq2c9Lm4TzPx8Ab HTTP/1.1
Host: api.rapideyeinspections.com
Authorization: Bearer rapideye_pk_...
HTTP/1.1 200 OK
Content-Type: application/json
{
"reservation_id": "8c1e4b7a-90d2-4f55-a3f1-1d2e9b0c6a44",
"changes": [
{ "revision": 1, "event": "created", "observed_at": "2026-10-08T14:25:41+00:00", "source_updated_at": null,
"fields": { "arrival_date": [null, "2026-10-23"], "departure_date": [null, "2026-10-26"] } },
{ "revision": 2, "event": "updated", "observed_at": "2026-10-19T09:12:55+00:00", "source_updated_at": null,
"fields": { "departure_date": ["2026-10-26", "2026-10-27"] } }
]
}
The reservation object
Date-times are ISO 8601 in UTC, except check_in_at and check_out_at, which carry the home's own offset.
| Field | Meaning |
|---|---|
reservation_id |
Ours, stable. Key your copy of a stay on it. |
rapideye_property_id |
The home, as GET /v1/properties names it. |
source, source_reservation_id |
The system we read the stay from (breezeway, ownerrez, track, trellis) and its id there. |
source_property_id |
The home's id in that system, the same id GET /v1/properties gives. Still set when the home has since been deleted from RapidEye. |
pms_reservation_id |
The booking's id in the customer's PMS or channel, usually what you match to your own records. null when the source sends none; absent from a stub. |
status |
inquiry, hold, confirmed, checked_in, checked_out, cancelled, no_show, unknown or out_of_scope (the stay moved to a home the customer does not run with RapidEye, its home was switched off or removed, or the customer connected a different account of their PMS that does not hold that home; not a cancellation, and always a stub). Refreshed on every read of the PMS. A cancellation is a status, never a deletion. |
status_basis |
source when the PMS stated the status; inferred when we derived it (Coverage and freshness). |
stay_type |
guest, owner, owner_guest (an owner's guest), block (an owner or maintenance hold, no guest) or unknown. |
arrival_date, departure_date |
The home's calendar dates. Do not convert them. |
check_in_at, check_out_at |
The home's check-in and check-out times with that date's offset, daylight time included. null when the source gives no time or we hold no zone for the home. |
timezone |
The home's IANA zone. null when we hold none, and then both times are null. |
booked_at |
When the guest booked, when the source says. |
source_recorded_at |
When the source first recorded the stay. For Breezeway, the closest thing to a booking time. |
channel, channel_raw |
airbnb, vrbo, booking_com, direct, owner, other or unknown, and the source's own value. Breezeway and Trellis do not send a channel. |
guest_count |
As the source states it. |
primary_guest |
{ "name": "..." }, the primary guest's name. Absent when the source provides no name; missing.primary_guest says why. |
first_seen_at, last_confirmed_at, last_changed_at |
When we first saw the stay, when a read last returned it, and when it last changed. last_confirmed_at is refreshed at most hourly while a stay is unchanged, so it is accurate to the hour. |
revision |
Rises by one on every change; never decreases. |
missing |
Each empty field, mapped to one of the reasons below. Absent from a stub. |
missing.*: source_does_not_provide |
The PMS never sends this field. |
missing.*: withheld_by_channel |
The booking channel withholds it. |
missing.*: timezone_unknown |
We hold no zone for the home, so the times are null. |
missing.*: missing |
The source should have sent it and did not; tell us if it is on a field you rely on. Right after a customer connects you, a stay we read before then reads this for primary_guest until our next read of it, unless its source sends no name (Trellis); the name then arrives as a higher revision. |