repull 0.2.37 → 0.2.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dd95b6f41fc43994008cdf19153e5d46dc2344917765a9f347515aa6621c89d3
4
- data.tar.gz: c3b6e119eabe3edeabe2e47193ab20451b6e8d6c2fe260c27ae1289d3a1c660d
3
+ metadata.gz: 05f8dcbf939588a31a5e66d89b6009ae1ec20c56f90f172f664b3cb3317657b4
4
+ data.tar.gz: c2083ff59fa0e0df5010ba404f922b6b94551120d7887f13df6e587543be9c77
5
5
  SHA512:
6
- metadata.gz: c16c5c6feb701118133399a5c88ab107ad464f0493c2d913f8c7159874af9cebd2a40bbaa3355e07ce138aab1f7c5fdc666b1c6d2d61b1e1634c4298243a87f5
7
- data.tar.gz: bd9b01e452b8264001d5ab150d686cf04bca97ef111f95821f9863fe355d6f1667dd1355abcc28a48cc7545dca01a439867a4dd871137b48fa4bd3ccf13fdffb
6
+ metadata.gz: 8176bc233194e36040c4f103241232c72545b716c1619d3e16bf2ed0c0f9725da0ff1b3df772237f70a519b679266432bd844e268c25955418805e140a9710f5
7
+ data.tar.gz: 152383381f99200bd26b99008c17400dd415390d7a50871e29f7af166105be9739337598317467f7a4ccad7e4067b3d49c013d3a09a264c4e274b53a5d5d3c4f
@@ -88,7 +88,7 @@ module Repull
88
88
  end
89
89
 
90
90
  # Get property availability
91
- # Channel-agnostic day-by-day availability calendar for a property over a date window. Returns a thin per-date shape — `{ date, available, price, minNights, availableUnits }` — projected from the property calendar. `availableUnits` is 1 or 0 for a single home, and the rooms of the type left for a hotel-model listing (a Mews or Cloudbeds room type). The `from` and `to` query params are **required** (ISO `YYYY-MM-DD`, inclusive) — omitting or malforming either returns 422. The window is capped at 366 days; longer ranges are truncated to the first 366 days. **`days` contains only the dates we actually hold calendar data for.** Requested dates with no calendar row are listed in `coverage.missingDates` — their availability is unknown. Never treat a missing date as bookable: this endpoint deliberately does not synthesise availability, because a fabricated open date can be double-booked. A property with no calendar still returns a real 200 (`days: []`, every date in `coverage.missingDates`), never a 404 — 404 means the property id does not exist or belongs to a different workspace. This endpoint is read-only, and the projected per-date shape carries **availability, units left, price, and min-nights only** — it does NOT expose max-stay, closed-to-arrival (CTA), closed-to-departure (CTD), or the dedicated stop-sell flag. To read or write that full restriction set on Booking.com use the channel routes: `GET`/`PUT /v1/channels/booking/availability` (with the room + rate ids from `GET /v1/channels/booking/properties/{id}/rooms`). To **write** calendar values use `PUT /v1/availability/{propertyId}` (or `PATCH /v1/availability/batch`), which updates the property calendar and pushes to its connected channels; channel-only settings stay on the channel routes. Returns `403 listing_inactive` when the listing is inactive. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated.
91
+ # Channel-agnostic day-by-day availability calendar for a property over a date window. Returns a thin per-date shape — `{ date, available, price, minNights, availableUnits }` — projected from the property calendar. `availableUnits` is 1 or 0 for a single home, and the units left for a listing with units (a Mews or Cloudbeds room type, a Guesty multi-unit listing). On such a listing each day also carries `units: [{ id, available }]` — which unit is free that night, with the ids of the listing's `units[]` and a reservation's `unit`. The `from` and `to` query params are **required** (ISO `YYYY-MM-DD`, inclusive) — omitting or malforming either returns 422. The window is capped at 366 days; longer ranges are truncated to the first 366 days. **`days` contains only the dates we actually hold calendar data for.** Requested dates with no calendar row are listed in `coverage.missingDates` — their availability is unknown. Never treat a missing date as bookable: this endpoint deliberately does not synthesise availability, because a fabricated open date can be double-booked. A property with no calendar still returns a real 200 (`days: []`, every date in `coverage.missingDates`), never a 404 — 404 means the property id does not exist or belongs to a different workspace. This endpoint is read-only, and the projected per-date shape carries **availability, units left, price, and min-nights only** — it does NOT expose max-stay, closed-to-arrival (CTA), closed-to-departure (CTD), or the dedicated stop-sell flag. To read or write that full restriction set on Booking.com use the channel routes: `GET`/`PUT /v1/channels/booking/availability` (with the room + rate ids from `GET /v1/channels/booking/properties/{id}/rooms`). To **write** calendar values use `PUT /v1/availability/{propertyId}` (or `PATCH /v1/availability/batch`), which updates the property calendar and pushes to its connected channels; channel-only settings stay on the channel routes. Returns `403 listing_inactive` when the listing is inactive. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated.
92
92
  # @param property_id [Integer] Repull property id (equal to `listings.id`; the same integer used as `propertyId` on availability and `listingId` on reservations).
93
93
  # @param from [Date] Start of the window (inclusive), ISO `YYYY-MM-DD`. Required — missing/malformed returns 422. `startDate` is accepted as an alias.
94
94
  # @param to [Date] End of the window (inclusive), ISO `YYYY-MM-DD`. Required — missing/malformed returns 422. `endDate` is accepted as an alias.
@@ -100,7 +100,7 @@ module Repull
100
100
  end
101
101
 
102
102
  # Get property availability
103
- # Channel-agnostic day-by-day availability calendar for a property over a date window. Returns a thin per-date shape — `{ date, available, price, minNights, availableUnits }` — projected from the property calendar. `availableUnits` is 1 or 0 for a single home, and the rooms of the type left for a hotel-model listing (a Mews or Cloudbeds room type). The `from` and `to` query params are **required** (ISO `YYYY-MM-DD`, inclusive) — omitting or malforming either returns 422. The window is capped at 366 days; longer ranges are truncated to the first 366 days. **`days` contains only the dates we actually hold calendar data for.** Requested dates with no calendar row are listed in `coverage.missingDates` — their availability is unknown. Never treat a missing date as bookable: this endpoint deliberately does not synthesise availability, because a fabricated open date can be double-booked. A property with no calendar still returns a real 200 (`days: []`, every date in `coverage.missingDates`), never a 404 — 404 means the property id does not exist or belongs to a different workspace. This endpoint is read-only, and the projected per-date shape carries **availability, units left, price, and min-nights only** — it does NOT expose max-stay, closed-to-arrival (CTA), closed-to-departure (CTD), or the dedicated stop-sell flag. To read or write that full restriction set on Booking.com use the channel routes: `GET`/`PUT /v1/channels/booking/availability` (with the room + rate ids from `GET /v1/channels/booking/properties/{id}/rooms`). To **write** calendar values use `PUT /v1/availability/{propertyId}` (or `PATCH /v1/availability/batch`), which updates the property calendar and pushes to its connected channels; channel-only settings stay on the channel routes. Returns `403 listing_inactive` when the listing is inactive. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated.
103
+ # Channel-agnostic day-by-day availability calendar for a property over a date window. Returns a thin per-date shape — `{ date, available, price, minNights, availableUnits }` — projected from the property calendar. `availableUnits` is 1 or 0 for a single home, and the units left for a listing with units (a Mews or Cloudbeds room type, a Guesty multi-unit listing). On such a listing each day also carries `units: [{ id, available }]` — which unit is free that night, with the ids of the listing's `units[]` and a reservation's `unit`. The `from` and `to` query params are **required** (ISO `YYYY-MM-DD`, inclusive) — omitting or malforming either returns 422. The window is capped at 366 days; longer ranges are truncated to the first 366 days. **`days` contains only the dates we actually hold calendar data for.** Requested dates with no calendar row are listed in `coverage.missingDates` — their availability is unknown. Never treat a missing date as bookable: this endpoint deliberately does not synthesise availability, because a fabricated open date can be double-booked. A property with no calendar still returns a real 200 (`days: []`, every date in `coverage.missingDates`), never a 404 — 404 means the property id does not exist or belongs to a different workspace. This endpoint is read-only, and the projected per-date shape carries **availability, units left, price, and min-nights only** — it does NOT expose max-stay, closed-to-arrival (CTA), closed-to-departure (CTD), or the dedicated stop-sell flag. To read or write that full restriction set on Booking.com use the channel routes: `GET`/`PUT /v1/channels/booking/availability` (with the room + rate ids from `GET /v1/channels/booking/properties/{id}/rooms`). To **write** calendar values use `PUT /v1/availability/{propertyId}` (or `PATCH /v1/availability/batch`), which updates the property calendar and pushes to its connected channels; channel-only settings stay on the channel routes. Returns `403 listing_inactive` when the listing is inactive. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated.
104
104
  # @param property_id [Integer] Repull property id (equal to `listings.id`; the same integer used as `propertyId` on availability and `listingId` on reservations).
105
105
  # @param from [Date] Start of the window (inclusive), ISO `YYYY-MM-DD`. Required — missing/malformed returns 422. `startDate` is accepted as an alias.
106
106
  # @param to [Date] End of the window (inclusive), ISO `YYYY-MM-DD`. Required — missing/malformed returns 422. `endDate` is accepted as an alias.
@@ -77,7 +77,7 @@ module Repull
77
77
  end
78
78
 
79
79
  # Per-channel connectivity health
80
- # Reports reachability and auth state for one channel (`airbnb`, `booking`, `vrbo`). Use it to tell \"the channel is down\" apart from \"this workspace's connection expired\". `200` when `status` is `ok`, `503` when `degraded` or `down` (the body's `status` and `message` say which and why). **`vrbo`** reports the connector's own signals in a `vrbo` block: connected accounts, accounts VRBO signed out (their bookings, messages and calendar stop until reconnected — `down`), accounts whose inbox sync is late (`degraded`), and the calendar push queue backlog and its oldest wait (`degraded` past 3 hours). Its rate is calendar pushes VRBO refused over finished ones in the last 3 hours; failures inside Repull's own connector are reported apart as `vrbo.connector_errors` and do not count (`vrbo.window_hours`; `refresh_attempts_24h` / `refresh_rejections_24h` count that window for VRBO), judged only once at least 50 pushes finished and at least 5 failed — VRBO pushes run in bursts, so a day-long window would keep reporting a problem already fixed.
80
+ # Reports reachability and auth state for one channel (`airbnb`, `booking`, `vrbo`). Use it to tell \"the channel is down\" apart from \"this workspace's connection expired\". `200` when `status` is `ok`, `503` when `degraded` or `down` (the body's `status` and `message` say which and why). `unknown` (`200`) means the health numbers could not be read at that moment; `message` gives the reason. **`vrbo`** reports the connector's own signals in a `vrbo` block: connected accounts, accounts VRBO signed out (their bookings, messages and calendar stop until reconnected — `down`), accounts whose inbox sync is late (`degraded`), and the calendar push queue backlog and its oldest wait (`degraded` past 3 hours). Its rate is calendar pushes VRBO refused over finished ones in the last 3 hours; failures inside Repull's own connector are reported apart as `vrbo.connector_errors` and do not count (`vrbo.window_hours`; `refresh_attempts_24h` / `refresh_rejections_24h` count that window for VRBO), judged only once at least 50 pushes finished and at least 5 failed — VRBO pushes run in bursts, so a day-long window would keep reporting a problem already fixed.
81
81
  # @param channel [String]
82
82
  # @param [Hash] opts the optional parameters
83
83
  # @return [GetChannelHealth200Response]
@@ -87,7 +87,7 @@ module Repull
87
87
  end
88
88
 
89
89
  # Per-channel connectivity health
90
- # Reports reachability and auth state for one channel (`airbnb`, `booking`, `vrbo`). Use it to tell \"the channel is down\" apart from \"this workspace's connection expired\". `200` when `status` is `ok`, `503` when `degraded` or `down` (the body's `status` and `message` say which and why). **`vrbo`** reports the connector's own signals in a `vrbo` block: connected accounts, accounts VRBO signed out (their bookings, messages and calendar stop until reconnected — `down`), accounts whose inbox sync is late (`degraded`), and the calendar push queue backlog and its oldest wait (`degraded` past 3 hours). Its rate is calendar pushes VRBO refused over finished ones in the last 3 hours; failures inside Repull's own connector are reported apart as `vrbo.connector_errors` and do not count (`vrbo.window_hours`; `refresh_attempts_24h` / `refresh_rejections_24h` count that window for VRBO), judged only once at least 50 pushes finished and at least 5 failed — VRBO pushes run in bursts, so a day-long window would keep reporting a problem already fixed.
90
+ # Reports reachability and auth state for one channel (`airbnb`, `booking`, `vrbo`). Use it to tell \"the channel is down\" apart from \"this workspace's connection expired\". `200` when `status` is `ok`, `503` when `degraded` or `down` (the body's `status` and `message` say which and why). `unknown` (`200`) means the health numbers could not be read at that moment; `message` gives the reason. **`vrbo`** reports the connector's own signals in a `vrbo` block: connected accounts, accounts VRBO signed out (their bookings, messages and calendar stop until reconnected — `down`), accounts whose inbox sync is late (`degraded`), and the calendar push queue backlog and its oldest wait (`degraded` past 3 hours). Its rate is calendar pushes VRBO refused over finished ones in the last 3 hours; failures inside Repull's own connector are reported apart as `vrbo.connector_errors` and do not count (`vrbo.window_hours`; `refresh_attempts_24h` / `refresh_rejections_24h` count that window for VRBO), judged only once at least 50 pushes finished and at least 5 failed — VRBO pushes run in bursts, so a day-long window would keep reporting a problem already fixed.
91
91
  # @param channel [String]
92
92
  # @param [Hash] opts the optional parameters
93
93
  # @return [Array<(GetChannelHealth200Response, Integer, Hash)>] GetChannelHealth200Response data, response status code and response headers
@@ -689,8 +689,8 @@ module Repull
689
689
  return data, status_code, headers
690
690
  end
691
691
 
692
- # List a listing's units (rooms)
693
- # The physical rooms under a listing. For a hotel-model PMS (Mews, Cloudbeds) a listing is a room type: prices, restrictions and availability are set on the room type, and each reservation is assigned one of these rooms (`reservation.unit.id`). A room can belong to more than one room type. Any other listing is a single home, which is its own unit, and returns an empty list.
692
+ # List a listing's units
693
+ # The units under a listing. - **Hotel-model PMS (Mews, Cloudbeds):** the listing is a room type and these are its physical rooms. Prices, restrictions and availability are set on the room type, and each reservation is assigned one of these rooms (`reservation.unit.id`). A room can belong to more than one room type. - **Guesty multi-unit listing:** the listing is the parent channels sell, and these are its units. Each unit is also a listing of its own (`listingId`), with its own calendar and stays; a stay on a unit carries `reservation.unit`. Which unit is free on which night: `units` per day on `GET /v1/availability/{propertyId}`. Any other listing is a single home, which is its own unit, and returns an empty list.
694
694
  # @param id [Integer] Listing id.
695
695
  # @param [Hash] opts the optional parameters
696
696
  # @return [ListListingUnits200Response]
@@ -699,8 +699,8 @@ module Repull
699
699
  data
700
700
  end
701
701
 
702
- # List a listing&#39;s units (rooms)
703
- # The physical rooms under a listing. For a hotel-model PMS (Mews, Cloudbeds) a listing is a room type: prices, restrictions and availability are set on the room type, and each reservation is assigned one of these rooms (&#x60;reservation.unit.id&#x60;). A room can belong to more than one room type. Any other listing is a single home, which is its own unit, and returns an empty list.
702
+ # List a listing&#39;s units
703
+ # The units under a listing. - **Hotel-model PMS (Mews, Cloudbeds):** the listing is a room type and these are its physical rooms. Prices, restrictions and availability are set on the room type, and each reservation is assigned one of these rooms (&#x60;reservation.unit.id&#x60;). A room can belong to more than one room type. - **Guesty multi-unit listing:** the listing is the parent channels sell, and these are its units. Each unit is also a listing of its own (&#x60;listingId&#x60;), with its own calendar and stays; a stay on a unit carries &#x60;reservation.unit&#x60;. Which unit is free on which night: &#x60;units&#x60; per day on &#x60;GET /v1/availability/{propertyId}&#x60;. Any other listing is a single home, which is its own unit, and returns an empty list.
704
704
  # @param id [Integer] Listing id.
705
705
  # @param [Hash] opts the optional parameters
706
706
  # @return [Array<(ListListingUnits200Response, Integer, Hash)>] ListListingUnits200Response data, response status code and response headers
@@ -110,7 +110,7 @@ module Repull
110
110
  # @return true if the model is valid
111
111
  def valid?
112
112
  warn '[DEPRECATED] the `valid?` method is obsolete'
113
- status_validator = EnumAttributeValidator.new('String', ["ok", "degraded", "down"])
113
+ status_validator = EnumAttributeValidator.new('String', ["ok", "degraded", "down", "unknown"])
114
114
  return false unless status_validator.valid?(@status)
115
115
  true
116
116
  end
@@ -118,7 +118,7 @@ module Repull
118
118
  # Custom attribute writer method checking allowed values (enum).
119
119
  # @param [Object] status Object to be assigned
120
120
  def status=(status)
121
- validator = EnumAttributeValidator.new('String', ["ok", "degraded", "down"])
121
+ validator = EnumAttributeValidator.new('String', ["ok", "degraded", "down", "unknown"])
122
122
  unless validator.valid?(status)
123
123
  fail ArgumentError, "invalid value for \"status\", must be one of #{validator.allowable_values}."
124
124
  end
@@ -15,7 +15,7 @@ require 'time'
15
15
 
16
16
  module Repull
17
17
  class ListListingUnits200ResponseDataInner < ApiModelBase
18
- # The PMS's id for the room; `reservation.unit.id` refers to it.
18
+ # The PMS's id for the unit; `reservation.unit.id` and the per-night `units[].id` on `GET /v1/availability/{propertyId}` refer to it.
19
19
  attr_accessor :id
20
20
 
21
21
  attr_accessor :name
@@ -30,8 +30,12 @@ module Repull
30
30
 
31
31
  attr_accessor :floor
32
32
 
33
+ # The PMS the unit comes from: `cloudbeds`, `mews`, `guesty`, …
33
34
  attr_accessor :source
34
35
 
36
+ # The unit's own Repull listing id when the unit is a listing too (a Guesty multi-unit listing's units, each with its own calendar and stays), else null.
37
+ attr_accessor :listing_id
38
+
35
39
  # Attribute mapping from ruby-style variable name to JSON key.
36
40
  def self.attribute_map
37
41
  {
@@ -41,7 +45,8 @@ module Repull
41
45
  :'parent_id' => :'parentId',
42
46
  :'housekeeping_status' => :'housekeepingStatus',
43
47
  :'floor' => :'floor',
44
- :'source' => :'source'
48
+ :'source' => :'source',
49
+ :'listing_id' => :'listingId'
45
50
  }
46
51
  end
47
52
 
@@ -64,7 +69,8 @@ module Repull
64
69
  :'parent_id' => :'String',
65
70
  :'housekeeping_status' => :'String',
66
71
  :'floor' => :'String',
67
- :'source' => :'String'
72
+ :'source' => :'String',
73
+ :'listing_id' => :'String'
68
74
  }
69
75
  end
70
76
 
@@ -74,6 +80,7 @@ module Repull
74
80
  :'parent_id',
75
81
  :'housekeeping_status',
76
82
  :'floor',
83
+ :'listing_id'
77
84
  ])
78
85
  end
79
86
 
@@ -120,6 +127,10 @@ module Repull
120
127
  if attributes.key?(:'source')
121
128
  self.source = attributes[:'source']
122
129
  end
130
+
131
+ if attributes.key?(:'listing_id')
132
+ self.listing_id = attributes[:'listing_id']
133
+ end
123
134
  end
124
135
 
125
136
  # Show invalid properties with the reasons. Usually used together with valid?
@@ -148,7 +159,8 @@ module Repull
148
159
  parent_id == o.parent_id &&
149
160
  housekeeping_status == o.housekeeping_status &&
150
161
  floor == o.floor &&
151
- source == o.source
162
+ source == o.source &&
163
+ listing_id == o.listing_id
152
164
  end
153
165
 
154
166
  # @see the `==` method
@@ -160,7 +172,7 @@ module Repull
160
172
  # Calculates hash code according to all attributes.
161
173
  # @return [Integer] Hash code
162
174
  def hash
163
- [id, name, active, parent_id, housekeeping_status, floor, source].hash
175
+ [id, name, active, parent_id, housekeeping_status, floor, source, listing_id].hash
164
176
  end
165
177
 
166
178
  # Builds the object from hash
@@ -18,15 +18,17 @@ module Repull
18
18
  class Listing < ApiModelBase
19
19
  attr_accessor :capabilities
20
20
 
21
- # `room_type` when the listing sells several identical units (a hotel room type: `unitCount` > 1) or is a hotel PMS room type; `home` otherwise. See the Hotels & multi-unit guide.
21
+ # `room_type` when the listing sells several units (a hotel room type or a Guesty multi-unit listing: `unitCount` > 1) or is a hotel PMS room type; `home` otherwise. See the Hotels & multi-unit guide.
22
22
  attr_accessor :kind
23
23
 
24
+ attr_accessor :parent
25
+
24
26
  attr_accessor :hotel
25
27
 
26
- # How many identical units (rooms) this listing sells: the hotel PMS rooms of the room type, the room count on Booking.com, or 1 for a home. Rooms left per night are `availableUnits` on `GET /v1/availability/{propertyId}`.
28
+ # How many units (rooms) this listing sells: the hotel PMS rooms of the room type, the units of a Guesty multi-unit listing, the room count on Booking.com, or 1 for a home. Units left per night are `availableUnits` on `GET /v1/availability/{propertyId}`, and which unit is free is `units` there.
27
29
  attr_accessor :unit_count
28
30
 
29
- # `GET /v1/listings/{id}` only. The physical rooms under a hotel-model listing (a Mews or Cloudbeds room type); empty for a single home. Same items as `GET /v1/listings/{id}/units`.
31
+ # `GET /v1/listings/{id}` only. The units under the listing: a Mews or Cloudbeds room type's rooms, or a Guesty multi-unit listing's units; empty for a single home. Same items as `GET /v1/listings/{id}/units`.
30
32
  attr_accessor :units
31
33
 
32
34
  # Repull listing id
@@ -87,6 +89,7 @@ module Repull
87
89
  {
88
90
  :'capabilities' => :'capabilities',
89
91
  :'kind' => :'kind',
92
+ :'parent' => :'parent',
90
93
  :'hotel' => :'hotel',
91
94
  :'unit_count' => :'unitCount',
92
95
  :'units' => :'units',
@@ -127,6 +130,7 @@ module Repull
127
130
  {
128
131
  :'capabilities' => :'ListingCapabilities',
129
132
  :'kind' => :'String',
133
+ :'parent' => :'ListingParent',
130
134
  :'hotel' => :'ListingHotel',
131
135
  :'unit_count' => :'Integer',
132
136
  :'units' => :'Array<ListingUnitsInner>',
@@ -155,6 +159,7 @@ module Repull
155
159
  # List of attributes with nullable: true
156
160
  def self.openapi_nullable
157
161
  Set.new([
162
+ :'parent',
158
163
  :'hotel',
159
164
  :'public_name',
160
165
  :'thumbnail_url',
@@ -190,6 +195,10 @@ module Repull
190
195
  self.kind = attributes[:'kind']
191
196
  end
192
197
 
198
+ if attributes.key?(:'parent')
199
+ self.parent = attributes[:'parent']
200
+ end
201
+
193
202
  if attributes.key?(:'hotel')
194
203
  self.hotel = attributes[:'hotel']
195
204
  end
@@ -334,6 +343,7 @@ module Repull
334
343
  self.class == o.class &&
335
344
  capabilities == o.capabilities &&
336
345
  kind == o.kind &&
346
+ parent == o.parent &&
337
347
  hotel == o.hotel &&
338
348
  unit_count == o.unit_count &&
339
349
  units == o.units &&
@@ -367,7 +377,7 @@ module Repull
367
377
  # Calculates hash code according to all attributes.
368
378
  # @return [Integer] Hash code
369
379
  def hash
370
- [capabilities, kind, hotel, unit_count, units, id, name, public_name, address, thumbnail_url, status, channels, amenities, content, details, rooms, policies, rules, pricing, fees, taxes, photos, created_at, updated_at].hash
380
+ [capabilities, kind, parent, hotel, unit_count, units, id, name, public_name, address, thumbnail_url, status, channels, amenities, content, details, rooms, policies, rules, pricing, fees, taxes, photos, created_at, updated_at].hash
371
381
  end
372
382
 
373
383
  # Builds the object from hash
@@ -0,0 +1,159 @@
1
+ =begin
2
+ #Repull API
3
+
4
+ #The unified API for vacation rental tech. Connect to 50+ PMS platforms and 4 OTA channels through one REST API. Built-in AI operations for guest communication, pricing, and listing optimization. ## Designed for AI agents Every error response on this API includes machine-parseable fields so an LLM (Claude in MCP, Cursor, Cline, GPT, etc.) can self-recover without escalating to a human: - `error.code` — stable string identifier (e.g. `invalid_params`, `rate_limit_exceeded`) - `error.message` — human-readable cause - `error.fix` — exact recovery steps (e.g. \"Pass `check_in_after` as ISO 8601: `?check_in_after=2026-01-15`\") - `error.docs_url` — link to the canonical write-up at `https://repull.dev/docs/errors/{code}` - `error.request_id` — id to correlate with server-side logs - `error.field` / `error.value_received` / `error.valid_values` / `error.did_you_mean` — when the error is parameter-specific - `error.retry_after` — seconds to wait before retrying (rate-limit + transient upstream) `Access-Control-Expose-Headers` lists `x-request-id` and the `X-RateLimit-*` family so browsers can read them on cross-origin responses. ## Quick Start 1. Get an API key at https://repull.dev/dashboard 2. Connect a PMS: `POST /v1/connect/{provider}` 3. List properties: `GET /v1/properties` 4. Get reservations: `GET /v1/reservations` ## Authentication All requests require a Bearer token: ``` Authorization: Bearer sk_live_YOUR_API_KEY ``` ## Request Correlation (X-Request-ID) Every response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports — we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id. You may set the header on the inbound request to forward your own trace id; we will echo it back instead of generating a new one. Accepted format: `^[\\\\w.-]{1,128}$`. The id is also embedded in error envelopes as `request_id` so server-side log diffs work even when the response headers are stripped by an intermediate proxy. ## Rate Limits The public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas. **Default policy:** 600 requests per 60 seconds, per API key. Sliding window — there is no fixed-minute boundary you can burst across. Every response includes: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests permitted in the current window. | | `X-RateLimit-Remaining` | Requests left in the current window after this call. | | `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. | | `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. | | `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** | **On 429 (rate_limit_exceeded):** the response body matches the standard error envelope with `code: \"rate_limit_exceeded\"`, plus `limit`, `window_seconds`, `retry_after`, and `request_id` fields. SDKs MUST honor `Retry-After` and use exponential backoff with jitter on subsequent retries — never a tight loop. Recommended backoff: ``` sleep_ms = (Retry-After * 1000) + random(0..250) ``` Monthly + daily-AI tier quotas (`free`, `starter`, `custom`) are enforced separately and also surface as 429s; they include `tier`, `scope`, and `resetsAt` fields. ## Plan Limits (402 — `listings_limit_exceeded`) The Repull API also enforces a per-tier cap on **active listings**: | Tier | Active listings cap | |---|---| | `free` | 3 | | `starter` | unlimited (10 included, then billed per listing) | | `custom` | unlimited | When a customer's active-listing count is above their tier cap, the API returns **`402 Payment Required`** with `error.code = \"listings_limit_exceeded\"` on every route EXCEPT: - `/v1/health` — uptime probes are never gated. - `/v1/usage/*` — so dashboards can render the over-cap state. - Any `DELETE` — so the customer can trim listings to get back under the cap without paying. Unlike 429, 402 is NOT a \"wait and retry\" condition — `Retry-After` is not set. The only paths back to 200 are: 1. `DELETE` enough listings to come back under the cap, or 2. Upgrade at `https://repull.dev/dashboard/billing`. The server-side usage cache is 60s, so the first 200 after an upgrade may take up to a minute. The envelope mirrors `rate_limit_exceeded` for SDK ergonomics: `tier`, `limit`, `active_listings`, `upgrade_url`, plus the standard `code` / `message` / `fix` / `docs_url` / `request_id`.
5
+
6
+ The version of the OpenAPI document: 1.0.0
7
+
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.22.0
10
+
11
+ =end
12
+
13
+ require 'date'
14
+ require 'time'
15
+
16
+ module Repull
17
+ # The multi-unit listing this listing is one unit of (a Guesty multi-unit listing's unit, which has its own calendar and stays). The parent lists it in `units[]` with this listing's id as `units[].listingId`. `null` otherwise.
18
+ class ListingParent < ApiModelBase
19
+ # Repull listing id of the multi-unit listing.
20
+ attr_accessor :id
21
+
22
+ attr_accessor :name
23
+
24
+ # Attribute mapping from ruby-style variable name to JSON key.
25
+ def self.attribute_map
26
+ {
27
+ :'id' => :'id',
28
+ :'name' => :'name'
29
+ }
30
+ end
31
+
32
+ # Returns attribute mapping this model knows about
33
+ def self.acceptable_attribute_map
34
+ attribute_map
35
+ end
36
+
37
+ # Returns all the JSON keys this model knows about
38
+ def self.acceptable_attributes
39
+ acceptable_attribute_map.values
40
+ end
41
+
42
+ # Attribute type mapping.
43
+ def self.openapi_types
44
+ {
45
+ :'id' => :'String',
46
+ :'name' => :'String'
47
+ }
48
+ end
49
+
50
+ # List of attributes with nullable: true
51
+ def self.openapi_nullable
52
+ Set.new([
53
+ :'name'
54
+ ])
55
+ end
56
+
57
+ # Initializes the object
58
+ # @param [Hash] attributes Model attributes in the form of hash
59
+ def initialize(attributes = {})
60
+ if (!attributes.is_a?(Hash))
61
+ fail ArgumentError, "The input argument (attributes) must be a hash in `Repull::ListingParent` initialize method"
62
+ end
63
+
64
+ # check to see if the attribute exists and convert string to symbol for hash key
65
+ acceptable_attribute_map = self.class.acceptable_attribute_map
66
+ attributes = attributes.each_with_object({}) { |(k, v), h|
67
+ if (!acceptable_attribute_map.key?(k.to_sym))
68
+ fail ArgumentError, "`#{k}` is not a valid attribute in `Repull::ListingParent`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
69
+ end
70
+ h[k.to_sym] = v
71
+ }
72
+
73
+ if attributes.key?(:'id')
74
+ self.id = attributes[:'id']
75
+ end
76
+
77
+ if attributes.key?(:'name')
78
+ self.name = attributes[:'name']
79
+ end
80
+ end
81
+
82
+ # Show invalid properties with the reasons. Usually used together with valid?
83
+ # @return Array for valid properties with the reasons
84
+ def list_invalid_properties
85
+ warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
86
+ invalid_properties = Array.new
87
+ invalid_properties
88
+ end
89
+
90
+ # Check to see if the all the properties in the model are valid
91
+ # @return true if the model is valid
92
+ def valid?
93
+ warn '[DEPRECATED] the `valid?` method is obsolete'
94
+ true
95
+ end
96
+
97
+ # Checks equality by comparing each attribute.
98
+ # @param [Object] Object to be compared
99
+ def ==(o)
100
+ return true if self.equal?(o)
101
+ self.class == o.class &&
102
+ id == o.id &&
103
+ name == o.name
104
+ end
105
+
106
+ # @see the `==` method
107
+ # @param [Object] Object to be compared
108
+ def eql?(o)
109
+ self == o
110
+ end
111
+
112
+ # Calculates hash code according to all attributes.
113
+ # @return [Integer] Hash code
114
+ def hash
115
+ [id, name].hash
116
+ end
117
+
118
+ # Builds the object from hash
119
+ # @param [Hash] attributes Model attributes in the form of hash
120
+ # @return [Object] Returns the model itself
121
+ def self.build_from_hash(attributes)
122
+ return nil unless attributes.is_a?(Hash)
123
+ attributes = attributes.transform_keys(&:to_sym)
124
+ transformed_hash = {}
125
+ openapi_types.each_pair do |key, type|
126
+ if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
127
+ transformed_hash["#{key}"] = nil
128
+ elsif type =~ /\AArray<(.*)>/i
129
+ # check to ensure the input is an array given that the attribute
130
+ # is documented as an array but the input is not
131
+ if attributes[attribute_map[key]].is_a?(Array)
132
+ transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
133
+ end
134
+ elsif !attributes[attribute_map[key]].nil?
135
+ transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
136
+ end
137
+ end
138
+ new(transformed_hash)
139
+ end
140
+
141
+ # Returns the object in the form of hash
142
+ # @return [Hash] Returns the object in the form of hash
143
+ def to_hash
144
+ hash = {}
145
+ self.class.attribute_map.each_pair do |attr, param|
146
+ value = self.send(attr)
147
+ if value.nil?
148
+ is_nullable = self.class.openapi_nullable.include?(attr)
149
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
150
+ end
151
+
152
+ hash[param] = _to_hash(value)
153
+ end
154
+ hash
155
+ end
156
+
157
+ end
158
+
159
+ end
@@ -15,6 +15,7 @@ require 'time'
15
15
 
16
16
  module Repull
17
17
  class ListingUnitsInner < ApiModelBase
18
+ # Unit id — what `reservation.unit.id` and the per-night `units[].id` on availability refer to.
18
19
  attr_accessor :id
19
20
 
20
21
  attr_accessor :name
@@ -27,8 +28,12 @@ module Repull
27
28
 
28
29
  attr_accessor :floor
29
30
 
31
+ # The PMS the unit comes from: `cloudbeds`, `mews`, `guesty`, …
30
32
  attr_accessor :source
31
33
 
34
+ # The unit's own Repull listing id when the unit is a listing too (a Guesty multi-unit listing's units, each with its own calendar), else `null`.
35
+ attr_accessor :listing_id
36
+
32
37
  # Attribute mapping from ruby-style variable name to JSON key.
33
38
  def self.attribute_map
34
39
  {
@@ -38,7 +43,8 @@ module Repull
38
43
  :'parent_id' => :'parentId',
39
44
  :'housekeeping_status' => :'housekeepingStatus',
40
45
  :'floor' => :'floor',
41
- :'source' => :'source'
46
+ :'source' => :'source',
47
+ :'listing_id' => :'listingId'
42
48
  }
43
49
  end
44
50
 
@@ -61,7 +67,8 @@ module Repull
61
67
  :'parent_id' => :'String',
62
68
  :'housekeeping_status' => :'String',
63
69
  :'floor' => :'String',
64
- :'source' => :'String'
70
+ :'source' => :'String',
71
+ :'listing_id' => :'String'
65
72
  }
66
73
  end
67
74
 
@@ -71,6 +78,7 @@ module Repull
71
78
  :'parent_id',
72
79
  :'housekeeping_status',
73
80
  :'floor',
81
+ :'listing_id'
74
82
  ])
75
83
  end
76
84
 
@@ -117,6 +125,10 @@ module Repull
117
125
  if attributes.key?(:'source')
118
126
  self.source = attributes[:'source']
119
127
  end
128
+
129
+ if attributes.key?(:'listing_id')
130
+ self.listing_id = attributes[:'listing_id']
131
+ end
120
132
  end
121
133
 
122
134
  # Show invalid properties with the reasons. Usually used together with valid?
@@ -145,7 +157,8 @@ module Repull
145
157
  parent_id == o.parent_id &&
146
158
  housekeeping_status == o.housekeeping_status &&
147
159
  floor == o.floor &&
148
- source == o.source
160
+ source == o.source &&
161
+ listing_id == o.listing_id
149
162
  end
150
163
 
151
164
  # @see the `==` method
@@ -157,7 +170,7 @@ module Repull
157
170
  # Calculates hash code according to all attributes.
158
171
  # @return [Integer] Hash code
159
172
  def hash
160
- [id, name, active, parent_id, housekeeping_status, floor, source].hash
173
+ [id, name, active, parent_id, housekeeping_status, floor, source, listing_id].hash
161
174
  end
162
175
 
163
176
  # Builds the object from hash
@@ -28,9 +28,12 @@ module Repull
28
28
  # Minimum-stay requirement for a stay starting on this date. Falls back to the listing-level default min-nights when the calendar row carries none.
29
29
  attr_accessor :min_nights
30
30
 
31
- # Units still sellable that night. 1 or 0 for a single home. For a hotel-model listing (a Mews or Cloudbeds room type) the rooms of that type left, e.g. 3 of 5 — see `GET /v1/listings/{id}/units`. `available` is false whenever this is 0.
31
+ # Units still sellable that night. 1 or 0 for a single home. For a listing with units (a Mews or Cloudbeds room type, a Guesty multi-unit listing) the units left, e.g. 3 of 5 — see `GET /v1/listings/{id}/units`. `available` is false whenever this is 0.
32
32
  attr_accessor :available_units
33
33
 
34
+ # Only on a listing with units (a Mews or Cloudbeds room type, a Guesty multi-unit listing): each active unit and whether it is free that night. A unit is taken when a stay is on it, a room block covers it, or (for a unit that is a listing of its own) its own calendar is closed. Ids are the listing's `units[].id` and a reservation's `unit.id`.
35
+ attr_accessor :units
36
+
34
37
  # Attribute mapping from ruby-style variable name to JSON key.
35
38
  def self.attribute_map
36
39
  {
@@ -38,7 +41,8 @@ module Repull
38
41
  :'available' => :'available',
39
42
  :'price' => :'price',
40
43
  :'min_nights' => :'minNights',
41
- :'available_units' => :'availableUnits'
44
+ :'available_units' => :'availableUnits',
45
+ :'units' => :'units'
42
46
  }
43
47
  end
44
48
 
@@ -59,7 +63,8 @@ module Repull
59
63
  :'available' => :'Boolean',
60
64
  :'price' => :'Float',
61
65
  :'min_nights' => :'Integer',
62
- :'available_units' => :'Integer'
66
+ :'available_units' => :'Integer',
67
+ :'units' => :'Array<PropertyAvailabilityUnit>'
63
68
  }
64
69
  end
65
70
 
@@ -114,6 +119,12 @@ module Repull
114
119
  else
115
120
  self.available_units = nil
116
121
  end
122
+
123
+ if attributes.key?(:'units')
124
+ if (value = attributes[:'units']).is_a?(Array)
125
+ self.units = value
126
+ end
127
+ end
117
128
  end
118
129
 
119
130
  # Show invalid properties with the reasons. Usually used together with valid?
@@ -224,7 +235,8 @@ module Repull
224
235
  available == o.available &&
225
236
  price == o.price &&
226
237
  min_nights == o.min_nights &&
227
- available_units == o.available_units
238
+ available_units == o.available_units &&
239
+ units == o.units
228
240
  end
229
241
 
230
242
  # @see the `==` method
@@ -236,7 +248,7 @@ module Repull
236
248
  # Calculates hash code according to all attributes.
237
249
  # @return [Integer] Hash code
238
250
  def hash
239
- [date, available, price, min_nights, available_units].hash
251
+ [date, available, price, min_nights, available_units, units].hash
240
252
  end
241
253
 
242
254
  # Builds the object from hash
@@ -0,0 +1,193 @@
1
+ =begin
2
+ #Repull API
3
+
4
+ #The unified API for vacation rental tech. Connect to 50+ PMS platforms and 4 OTA channels through one REST API. Built-in AI operations for guest communication, pricing, and listing optimization. ## Designed for AI agents Every error response on this API includes machine-parseable fields so an LLM (Claude in MCP, Cursor, Cline, GPT, etc.) can self-recover without escalating to a human: - `error.code` — stable string identifier (e.g. `invalid_params`, `rate_limit_exceeded`) - `error.message` — human-readable cause - `error.fix` — exact recovery steps (e.g. \"Pass `check_in_after` as ISO 8601: `?check_in_after=2026-01-15`\") - `error.docs_url` — link to the canonical write-up at `https://repull.dev/docs/errors/{code}` - `error.request_id` — id to correlate with server-side logs - `error.field` / `error.value_received` / `error.valid_values` / `error.did_you_mean` — when the error is parameter-specific - `error.retry_after` — seconds to wait before retrying (rate-limit + transient upstream) `Access-Control-Expose-Headers` lists `x-request-id` and the `X-RateLimit-*` family so browsers can read them on cross-origin responses. ## Quick Start 1. Get an API key at https://repull.dev/dashboard 2. Connect a PMS: `POST /v1/connect/{provider}` 3. List properties: `GET /v1/properties` 4. Get reservations: `GET /v1/reservations` ## Authentication All requests require a Bearer token: ``` Authorization: Bearer sk_live_YOUR_API_KEY ``` ## Request Correlation (X-Request-ID) Every response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports — we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id. You may set the header on the inbound request to forward your own trace id; we will echo it back instead of generating a new one. Accepted format: `^[\\\\w.-]{1,128}$`. The id is also embedded in error envelopes as `request_id` so server-side log diffs work even when the response headers are stripped by an intermediate proxy. ## Rate Limits The public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas. **Default policy:** 600 requests per 60 seconds, per API key. Sliding window — there is no fixed-minute boundary you can burst across. Every response includes: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests permitted in the current window. | | `X-RateLimit-Remaining` | Requests left in the current window after this call. | | `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. | | `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. | | `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** | **On 429 (rate_limit_exceeded):** the response body matches the standard error envelope with `code: \"rate_limit_exceeded\"`, plus `limit`, `window_seconds`, `retry_after`, and `request_id` fields. SDKs MUST honor `Retry-After` and use exponential backoff with jitter on subsequent retries — never a tight loop. Recommended backoff: ``` sleep_ms = (Retry-After * 1000) + random(0..250) ``` Monthly + daily-AI tier quotas (`free`, `starter`, `custom`) are enforced separately and also surface as 429s; they include `tier`, `scope`, and `resetsAt` fields. ## Plan Limits (402 — `listings_limit_exceeded`) The Repull API also enforces a per-tier cap on **active listings**: | Tier | Active listings cap | |---|---| | `free` | 3 | | `starter` | unlimited (10 included, then billed per listing) | | `custom` | unlimited | When a customer's active-listing count is above their tier cap, the API returns **`402 Payment Required`** with `error.code = \"listings_limit_exceeded\"` on every route EXCEPT: - `/v1/health` — uptime probes are never gated. - `/v1/usage/*` — so dashboards can render the over-cap state. - Any `DELETE` — so the customer can trim listings to get back under the cap without paying. Unlike 429, 402 is NOT a \"wait and retry\" condition — `Retry-After` is not set. The only paths back to 200 are: 1. `DELETE` enough listings to come back under the cap, or 2. Upgrade at `https://repull.dev/dashboard/billing`. The server-side usage cache is 60s, so the first 200 after an upgrade may take up to a minute. The envelope mirrors `rate_limit_exceeded` for SDK ergonomics: `tier`, `limit`, `active_listings`, `upgrade_url`, plus the standard `code` / `message` / `fix` / `docs_url` / `request_id`.
5
+
6
+ The version of the OpenAPI document: 1.0.0
7
+
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.22.0
10
+
11
+ =end
12
+
13
+ require 'date'
14
+ require 'time'
15
+
16
+ module Repull
17
+ # One unit on one night.
18
+ class PropertyAvailabilityUnit < ApiModelBase
19
+ # The unit id: `units[].id` on the listing, `unit.id` on a reservation.
20
+ attr_accessor :id
21
+
22
+ # Whether this unit is free that night.
23
+ attr_accessor :available
24
+
25
+ # Attribute mapping from ruby-style variable name to JSON key.
26
+ def self.attribute_map
27
+ {
28
+ :'id' => :'id',
29
+ :'available' => :'available'
30
+ }
31
+ end
32
+
33
+ # Returns attribute mapping this model knows about
34
+ def self.acceptable_attribute_map
35
+ attribute_map
36
+ end
37
+
38
+ # Returns all the JSON keys this model knows about
39
+ def self.acceptable_attributes
40
+ acceptable_attribute_map.values
41
+ end
42
+
43
+ # Attribute type mapping.
44
+ def self.openapi_types
45
+ {
46
+ :'id' => :'String',
47
+ :'available' => :'Boolean'
48
+ }
49
+ end
50
+
51
+ # List of attributes with nullable: true
52
+ def self.openapi_nullable
53
+ Set.new([
54
+ ])
55
+ end
56
+
57
+ # Initializes the object
58
+ # @param [Hash] attributes Model attributes in the form of hash
59
+ def initialize(attributes = {})
60
+ if (!attributes.is_a?(Hash))
61
+ fail ArgumentError, "The input argument (attributes) must be a hash in `Repull::PropertyAvailabilityUnit` initialize method"
62
+ end
63
+
64
+ # check to see if the attribute exists and convert string to symbol for hash key
65
+ acceptable_attribute_map = self.class.acceptable_attribute_map
66
+ attributes = attributes.each_with_object({}) { |(k, v), h|
67
+ if (!acceptable_attribute_map.key?(k.to_sym))
68
+ fail ArgumentError, "`#{k}` is not a valid attribute in `Repull::PropertyAvailabilityUnit`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
69
+ end
70
+ h[k.to_sym] = v
71
+ }
72
+
73
+ if attributes.key?(:'id')
74
+ self.id = attributes[:'id']
75
+ else
76
+ self.id = nil
77
+ end
78
+
79
+ if attributes.key?(:'available')
80
+ self.available = attributes[:'available']
81
+ else
82
+ self.available = nil
83
+ end
84
+ end
85
+
86
+ # Show invalid properties with the reasons. Usually used together with valid?
87
+ # @return Array for valid properties with the reasons
88
+ def list_invalid_properties
89
+ warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
90
+ invalid_properties = Array.new
91
+ if @id.nil?
92
+ invalid_properties.push('invalid value for "id", id cannot be nil.')
93
+ end
94
+
95
+ if @available.nil?
96
+ invalid_properties.push('invalid value for "available", available cannot be nil.')
97
+ end
98
+
99
+ invalid_properties
100
+ end
101
+
102
+ # Check to see if the all the properties in the model are valid
103
+ # @return true if the model is valid
104
+ def valid?
105
+ warn '[DEPRECATED] the `valid?` method is obsolete'
106
+ return false if @id.nil?
107
+ return false if @available.nil?
108
+ true
109
+ end
110
+
111
+ # Custom attribute writer method with validation
112
+ # @param [Object] id Value to be assigned
113
+ def id=(id)
114
+ if id.nil?
115
+ fail ArgumentError, 'id cannot be nil'
116
+ end
117
+
118
+ @id = id
119
+ end
120
+
121
+ # Custom attribute writer method with validation
122
+ # @param [Object] available Value to be assigned
123
+ def available=(available)
124
+ if available.nil?
125
+ fail ArgumentError, 'available cannot be nil'
126
+ end
127
+
128
+ @available = available
129
+ end
130
+
131
+ # Checks equality by comparing each attribute.
132
+ # @param [Object] Object to be compared
133
+ def ==(o)
134
+ return true if self.equal?(o)
135
+ self.class == o.class &&
136
+ id == o.id &&
137
+ available == o.available
138
+ end
139
+
140
+ # @see the `==` method
141
+ # @param [Object] Object to be compared
142
+ def eql?(o)
143
+ self == o
144
+ end
145
+
146
+ # Calculates hash code according to all attributes.
147
+ # @return [Integer] Hash code
148
+ def hash
149
+ [id, available].hash
150
+ end
151
+
152
+ # Builds the object from hash
153
+ # @param [Hash] attributes Model attributes in the form of hash
154
+ # @return [Object] Returns the model itself
155
+ def self.build_from_hash(attributes)
156
+ return nil unless attributes.is_a?(Hash)
157
+ attributes = attributes.transform_keys(&:to_sym)
158
+ transformed_hash = {}
159
+ openapi_types.each_pair do |key, type|
160
+ if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
161
+ transformed_hash["#{key}"] = nil
162
+ elsif type =~ /\AArray<(.*)>/i
163
+ # check to ensure the input is an array given that the attribute
164
+ # is documented as an array but the input is not
165
+ if attributes[attribute_map[key]].is_a?(Array)
166
+ transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
167
+ end
168
+ elsif !attributes[attribute_map[key]].nil?
169
+ transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
170
+ end
171
+ end
172
+ new(transformed_hash)
173
+ end
174
+
175
+ # Returns the object in the form of hash
176
+ # @return [Hash] Returns the object in the form of hash
177
+ def to_hash
178
+ hash = {}
179
+ self.class.attribute_map.each_pair do |attr, param|
180
+ value = self.send(attr)
181
+ if value.nil?
182
+ is_nullable = self.class.openapi_nullable.include?(attr)
183
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
184
+ end
185
+
186
+ hash[param] = _to_hash(value)
187
+ end
188
+ hash
189
+ end
190
+
191
+ end
192
+
193
+ end
@@ -14,7 +14,7 @@ require 'date'
14
14
  require 'time'
15
15
 
16
16
  module Repull
17
- # The physical room the stay was assigned, for a hotel-model PMS (Mews, Cloudbeds) where the listing is a room type. `null` when no room is assigned yet, and for every listing that is a single home.
17
+ # The unit the stay is on: the room assigned by a hotel-model PMS (Mews, Cloudbeds) where the listing is a room type, or the unit of a Guesty multi-unit listing (the stay's `listingId` is then that unit's own listing). Matches the listing's `units[].id` and the per-night `units` on availability. `null` when no unit is assigned yet, and for every listing that is a single home.
18
18
  class ReservationUnit < ApiModelBase
19
19
  # The room id, as listed by `GET /v1/listings/{id}/units`.
20
20
  attr_accessor :id
@@ -11,5 +11,5 @@ Generator version: 7.22.0
11
11
  =end
12
12
 
13
13
  module Repull
14
- VERSION = '0.2.37'
14
+ VERSION = '0.2.39'
15
15
  end
data/lib/repull.rb CHANGED
@@ -389,6 +389,7 @@ require 'repull/models/listing_hotel'
389
389
  require 'repull/models/listing_list_response'
390
390
  require 'repull/models/listing_market_state_request'
391
391
  require 'repull/models/listing_market_state_response'
392
+ require 'repull/models/listing_parent'
392
393
  require 'repull/models/listing_photo'
393
394
  require 'repull/models/listing_photo_delete_request'
394
395
  require 'repull/models/listing_photo_delete_response'
@@ -548,6 +549,7 @@ require 'repull/models/property'
548
549
  require 'repull/models/property_availability'
549
550
  require 'repull/models/property_availability_coverage'
550
551
  require 'repull/models/property_availability_day'
552
+ require 'repull/models/property_availability_unit'
551
553
  require 'repull/models/property_list_response'
552
554
  require 'repull/models/publish_section_error'
553
555
  require 'repull/models/quote'
data/openapi/v1.json CHANGED
@@ -338,8 +338,45 @@
338
338
  "availableUnits": {
339
339
  "type": "integer",
340
340
  "minimum": 0,
341
- "description": "Units still sellable that night. 1 or 0 for a single home. For a hotel-model listing (a Mews or Cloudbeds room type) the rooms of that type left, e.g. 3 of 5 \u2014 see `GET /v1/listings/{id}/units`. `available` is false whenever this is 0.",
341
+ "description": "Units still sellable that night. 1 or 0 for a single home. For a listing with units (a Mews or Cloudbeds room type, a Guesty multi-unit listing) the units left, e.g. 3 of 5 \u2014 see `GET /v1/listings/{id}/units`. `available` is false whenever this is 0.",
342
342
  "example": 1
343
+ },
344
+ "units": {
345
+ "type": "array",
346
+ "description": "Only on a listing with units (a Mews or Cloudbeds room type, a Guesty multi-unit listing): each active unit and whether it is free that night. A unit is taken when a stay is on it, a room block covers it, or (for a unit that is a listing of its own) its own calendar is closed. Ids are the listing's `units[].id` and a reservation's `unit.id`.",
347
+ "items": {
348
+ "$ref": "#/components/schemas/PropertyAvailabilityUnit"
349
+ },
350
+ "example": [
351
+ {
352
+ "id": "unit_a",
353
+ "available": true
354
+ },
355
+ {
356
+ "id": "unit_b",
357
+ "available": false
358
+ }
359
+ ]
360
+ }
361
+ }
362
+ },
363
+ "PropertyAvailabilityUnit": {
364
+ "type": "object",
365
+ "description": "One unit on one night.",
366
+ "required": [
367
+ "id",
368
+ "available"
369
+ ],
370
+ "properties": {
371
+ "id": {
372
+ "type": "string",
373
+ "description": "The unit id: `units[].id` on the listing, `unit.id` on a reservation.",
374
+ "example": "unit_b"
375
+ },
376
+ "available": {
377
+ "type": "boolean",
378
+ "description": "Whether this unit is free that night.",
379
+ "example": false
343
380
  }
344
381
  }
345
382
  },
@@ -813,7 +850,7 @@
813
850
  "unit": {
814
851
  "type": "object",
815
852
  "nullable": true,
816
- "description": "The physical room the stay was assigned, for a hotel-model PMS (Mews, Cloudbeds) where the listing is a room type. `null` when no room is assigned yet, and for every listing that is a single home.",
853
+ "description": "The unit the stay is on: the room assigned by a hotel-model PMS (Mews, Cloudbeds) where the listing is a room type, or the unit of a Guesty multi-unit listing (the stay's `listingId` is then that unit's own listing). Matches the listing's `units[].id` and the per-night `units` on availability. `null` when no unit is assigned yet, and for every listing that is a single home.",
817
854
  "properties": {
818
855
  "id": {
819
856
  "type": "string",
@@ -10298,7 +10335,22 @@
10298
10335
  },
10299
10336
  "kind": {
10300
10337
  "type": "string",
10301
- "description": "`room_type` when the listing sells several identical units (a hotel room type: `unitCount` > 1) or is a hotel PMS room type; `home` otherwise. See the Hotels & multi-unit guide."
10338
+ "description": "`room_type` when the listing sells several units (a hotel room type or a Guesty multi-unit listing: `unitCount` > 1) or is a hotel PMS room type; `home` otherwise. See the Hotels & multi-unit guide."
10339
+ },
10340
+ "parent": {
10341
+ "type": "object",
10342
+ "nullable": true,
10343
+ "description": "The multi-unit listing this listing is one unit of (a Guesty multi-unit listing's unit, which has its own calendar and stays). The parent lists it in `units[]` with this listing's id as `units[].listingId`. `null` otherwise.",
10344
+ "properties": {
10345
+ "id": {
10346
+ "type": "string",
10347
+ "description": "Repull listing id of the multi-unit listing."
10348
+ },
10349
+ "name": {
10350
+ "type": "string",
10351
+ "nullable": true
10352
+ }
10353
+ }
10302
10354
  },
10303
10355
  "hotel": {
10304
10356
  "type": "object",
@@ -10326,16 +10378,17 @@
10326
10378
  "unitCount": {
10327
10379
  "type": "integer",
10328
10380
  "minimum": 1,
10329
- "description": "How many identical units (rooms) this listing sells: the hotel PMS rooms of the room type, the room count on Booking.com, or 1 for a home. Rooms left per night are `availableUnits` on `GET /v1/availability/{propertyId}`."
10381
+ "description": "How many units (rooms) this listing sells: the hotel PMS rooms of the room type, the units of a Guesty multi-unit listing, the room count on Booking.com, or 1 for a home. Units left per night are `availableUnits` on `GET /v1/availability/{propertyId}`, and which unit is free is `units` there."
10330
10382
  },
10331
10383
  "units": {
10332
10384
  "type": "array",
10333
- "description": "`GET /v1/listings/{id}` only. The physical rooms under a hotel-model listing (a Mews or Cloudbeds room type); empty for a single home. Same items as `GET /v1/listings/{id}/units`.",
10385
+ "description": "`GET /v1/listings/{id}` only. The units under the listing: a Mews or Cloudbeds room type's rooms, or a Guesty multi-unit listing's units; empty for a single home. Same items as `GET /v1/listings/{id}/units`.",
10334
10386
  "items": {
10335
10387
  "type": "object",
10336
10388
  "properties": {
10337
10389
  "id": {
10338
- "type": "string"
10390
+ "type": "string",
10391
+ "description": "Unit id \u2014 what `reservation.unit.id` and the per-night `units[].id` on availability refer to."
10339
10392
  },
10340
10393
  "name": {
10341
10394
  "type": "string"
@@ -10356,7 +10409,13 @@
10356
10409
  "nullable": true
10357
10410
  },
10358
10411
  "source": {
10359
- "type": "string"
10412
+ "type": "string",
10413
+ "description": "The PMS the unit comes from: `cloudbeds`, `mews`, `guesty`, \u2026"
10414
+ },
10415
+ "listingId": {
10416
+ "type": "string",
10417
+ "nullable": true,
10418
+ "description": "The unit's own Repull listing id when the unit is a listing too (a Guesty multi-unit listing's units, each with its own calendar), else `null`."
10360
10419
  }
10361
10420
  }
10362
10421
  }
@@ -16829,7 +16888,7 @@
16829
16888
  "get": {
16830
16889
  "operationId": "get_availability",
16831
16890
  "summary": "Get property availability",
16832
- "description": "Channel-agnostic day-by-day availability calendar for a property over a date window. Returns a thin per-date shape \u2014 `{ date, available, price, minNights, availableUnits }` \u2014 projected from the property calendar. `availableUnits` is 1 or 0 for a single home, and the rooms of the type left for a hotel-model listing (a Mews or Cloudbeds room type).\n\nThe `from` and `to` query params are **required** (ISO `YYYY-MM-DD`, inclusive) \u2014 omitting or malforming either returns 422. The window is capped at 366 days; longer ranges are truncated to the first 366 days.\n\n**`days` contains only the dates we actually hold calendar data for.** Requested dates with no calendar row are listed in `coverage.missingDates` \u2014 their availability is unknown. Never treat a missing date as bookable: this endpoint deliberately does not synthesise availability, because a fabricated open date can be double-booked. A property with no calendar still returns a real 200 (`days: []`, every date in `coverage.missingDates`), never a 404 \u2014 404 means the property id does not exist or belongs to a different workspace.\n\nThis endpoint is read-only, and the projected per-date shape carries **availability, units left, price, and min-nights only** \u2014 it does NOT expose max-stay, closed-to-arrival (CTA), closed-to-departure (CTD), or the dedicated stop-sell flag. To read or write that full restriction set on Booking.com use the channel routes: `GET`/`PUT /v1/channels/booking/availability` (with the room + rate ids from `GET /v1/channels/booking/properties/{id}/rooms`). To **write** calendar values use `PUT /v1/availability/{propertyId}` (or `PATCH /v1/availability/batch`), which updates the property calendar and pushes to its connected channels; channel-only settings stay on the channel routes.\n\nReturns `403 listing_inactive` when the listing is inactive. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated.",
16891
+ "description": "Channel-agnostic day-by-day availability calendar for a property over a date window. Returns a thin per-date shape \u2014 `{ date, available, price, minNights, availableUnits }` \u2014 projected from the property calendar. `availableUnits` is 1 or 0 for a single home, and the units left for a listing with units (a Mews or Cloudbeds room type, a Guesty multi-unit listing). On such a listing each day also carries `units: [{ id, available }]` \u2014 which unit is free that night, with the ids of the listing's `units[]` and a reservation's `unit`.\n\nThe `from` and `to` query params are **required** (ISO `YYYY-MM-DD`, inclusive) \u2014 omitting or malforming either returns 422. The window is capped at 366 days; longer ranges are truncated to the first 366 days.\n\n**`days` contains only the dates we actually hold calendar data for.** Requested dates with no calendar row are listed in `coverage.missingDates` \u2014 their availability is unknown. Never treat a missing date as bookable: this endpoint deliberately does not synthesise availability, because a fabricated open date can be double-booked. A property with no calendar still returns a real 200 (`days: []`, every date in `coverage.missingDates`), never a 404 \u2014 404 means the property id does not exist or belongs to a different workspace.\n\nThis endpoint is read-only, and the projected per-date shape carries **availability, units left, price, and min-nights only** \u2014 it does NOT expose max-stay, closed-to-arrival (CTA), closed-to-departure (CTD), or the dedicated stop-sell flag. To read or write that full restriction set on Booking.com use the channel routes: `GET`/`PUT /v1/channels/booking/availability` (with the room + rate ids from `GET /v1/channels/booking/properties/{id}/rooms`). To **write** calendar values use `PUT /v1/availability/{propertyId}` (or `PATCH /v1/availability/batch`), which updates the property calendar and pushes to its connected channels; channel-only settings stay on the channel routes.\n\nReturns `403 listing_inactive` when the listing is inactive. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated.",
16833
16892
  "tags": [
16834
16893
  "Availability"
16835
16894
  ],
@@ -20345,7 +20404,7 @@
20345
20404
  "get": {
20346
20405
  "operationId": "getChannelHealth",
20347
20406
  "summary": "Per-channel connectivity health",
20348
- "description": "Reports reachability and auth state for one channel (`airbnb`, `booking`, `vrbo`). Use it to tell \"the channel is down\" apart from \"this workspace's connection expired\". `200` when `status` is `ok`, `503` when `degraded` or `down` (the body's `status` and `message` say which and why).\n\n**`vrbo`** reports the connector's own signals in a `vrbo` block: connected accounts, accounts VRBO signed out (their bookings, messages and calendar stop until reconnected \u2014 `down`), accounts whose inbox sync is late (`degraded`), and the calendar push queue backlog and its oldest wait (`degraded` past 3 hours). Its rate is calendar pushes VRBO refused over finished ones in the last 3 hours; failures inside Repull's own connector are reported apart as `vrbo.connector_errors` and do not count (`vrbo.window_hours`; `refresh_attempts_24h` / `refresh_rejections_24h` count that window for VRBO), judged only once at least 50 pushes finished and at least 5 failed \u2014 VRBO pushes run in bursts, so a day-long window would keep reporting a problem already fixed.",
20407
+ "description": "Reports reachability and auth state for one channel (`airbnb`, `booking`, `vrbo`). Use it to tell \"the channel is down\" apart from \"this workspace's connection expired\". `200` when `status` is `ok`, `503` when `degraded` or `down` (the body's `status` and `message` say which and why). `unknown` (`200`) means the health numbers could not be read at that moment; `message` gives the reason.\n\n**`vrbo`** reports the connector's own signals in a `vrbo` block: connected accounts, accounts VRBO signed out (their bookings, messages and calendar stop until reconnected \u2014 `down`), accounts whose inbox sync is late (`degraded`), and the calendar push queue backlog and its oldest wait (`degraded` past 3 hours). Its rate is calendar pushes VRBO refused over finished ones in the last 3 hours; failures inside Repull's own connector are reported apart as `vrbo.connector_errors` and do not count (`vrbo.window_hours`; `refresh_attempts_24h` / `refresh_rejections_24h` count that window for VRBO), judged only once at least 50 pushes finished and at least 5 failed \u2014 VRBO pushes run in bursts, so a day-long window would keep reporting a problem already fixed.",
20349
20408
  "tags": [
20350
20409
  "Health"
20351
20410
  ],
@@ -20379,7 +20438,8 @@
20379
20438
  "enum": [
20380
20439
  "ok",
20381
20440
  "degraded",
20382
- "down"
20441
+ "down",
20442
+ "unknown"
20383
20443
  ]
20384
20444
  },
20385
20445
  "vrbo": {
@@ -35939,8 +35999,8 @@
35939
35999
  "/v1/listings/{id}/units": {
35940
36000
  "get": {
35941
36001
  "operationId": "listListingUnits",
35942
- "summary": "List a listing's units (rooms)",
35943
- "description": "The physical rooms under a listing. For a hotel-model PMS (Mews, Cloudbeds) a listing is a room type: prices, restrictions and availability are set on the room type, and each reservation is assigned one of these rooms (`reservation.unit.id`). A room can belong to more than one room type.\n\nAny other listing is a single home, which is its own unit, and returns an empty list.",
36002
+ "summary": "List a listing's units",
36003
+ "description": "The units under a listing.\n\n- **Hotel-model PMS (Mews, Cloudbeds):** the listing is a room type and these are its physical rooms. Prices, restrictions and availability are set on the room type, and each reservation is assigned one of these rooms (`reservation.unit.id`). A room can belong to more than one room type.\n- **Guesty multi-unit listing:** the listing is the parent channels sell, and these are its units. Each unit is also a listing of its own (`listingId`), with its own calendar and stays; a stay on a unit carries `reservation.unit`.\n\nWhich unit is free on which night: `units` per day on `GET /v1/availability/{propertyId}`. Any other listing is a single home, which is its own unit, and returns an empty list.",
35944
36004
  "tags": [
35945
36005
  "Listings"
35946
36006
  ],
@@ -35977,7 +36037,7 @@
35977
36037
  "properties": {
35978
36038
  "id": {
35979
36039
  "type": "string",
35980
- "description": "The PMS's id for the room; `reservation.unit.id` refers to it."
36040
+ "description": "The PMS's id for the unit; `reservation.unit.id` and the per-night `units[].id` on `GET /v1/availability/{propertyId}` refer to it."
35981
36041
  },
35982
36042
  "name": {
35983
36043
  "type": "string",
@@ -36002,7 +36062,13 @@
36002
36062
  },
36003
36063
  "source": {
36004
36064
  "type": "string",
36005
- "example": "mews"
36065
+ "example": "mews",
36066
+ "description": "The PMS the unit comes from: `cloudbeds`, `mews`, `guesty`, \u2026"
36067
+ },
36068
+ "listingId": {
36069
+ "type": "string",
36070
+ "nullable": true,
36071
+ "description": "The unit's own Repull listing id when the unit is a listing too (a Guesty multi-unit listing's units, each with its own calendar and stays), else null."
36006
36072
  }
36007
36073
  }
36008
36074
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: repull
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.37
4
+ version: 0.2.39
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivan Nikolov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-31 00:00:00.000000000 Z
11
+ date: 2026-11-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: typhoeus
@@ -469,6 +469,7 @@ files:
469
469
  - lib/repull/models/listing_list_response.rb
470
470
  - lib/repull/models/listing_market_state_request.rb
471
471
  - lib/repull/models/listing_market_state_response.rb
472
+ - lib/repull/models/listing_parent.rb
472
473
  - lib/repull/models/listing_photo.rb
473
474
  - lib/repull/models/listing_photo_delete_request.rb
474
475
  - lib/repull/models/listing_photo_delete_response.rb
@@ -628,6 +629,7 @@ files:
628
629
  - lib/repull/models/property_availability.rb
629
630
  - lib/repull/models/property_availability_coverage.rb
630
631
  - lib/repull/models/property_availability_day.rb
632
+ - lib/repull/models/property_availability_unit.rb
631
633
  - lib/repull/models/property_list_response.rb
632
634
  - lib/repull/models/publish_section_error.rb
633
635
  - lib/repull/models/quote.rb