repull 0.2.14 → 0.2.16

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.
Files changed (227) hide show
  1. checksums.yaml +4 -4
  2. data/lib/repull/api/airbnb_api.rb +1387 -152
  3. data/lib/repull/api/availability_api.rb +2 -2
  4. data/lib/repull/api/billing_api.rb +4 -4
  5. data/lib/repull/api/booking_com_api.rb +36 -27
  6. data/lib/repull/api/connect_api.rb +4 -4
  7. data/lib/repull/api/conversations_api.rb +398 -4
  8. data/lib/repull/api/guests_api.rb +2 -2
  9. data/lib/repull/api/listings_api.rb +97 -13
  10. data/lib/repull/api/reservations_api.rb +157 -6
  11. data/lib/repull/api/webhooks_api.rb +10 -3
  12. data/lib/repull/models/accept_reservation_request200_response.rb +321 -0
  13. data/lib/repull/models/account_created_event.rb +95 -31
  14. data/lib/repull/models/account_disconnected_event.rb +95 -31
  15. data/lib/repull/models/ai_operation_completed_event.rb +95 -31
  16. data/lib/repull/models/ai_operation_failed_event.rb +95 -31
  17. data/lib/repull/models/airbnb_account_freshness.rb +239 -0
  18. data/lib/repull/models/airbnb_alteration.rb +46 -2
  19. data/lib/repull/models/airbnb_alteration_create_request.rb +264 -0
  20. data/lib/repull/models/airbnb_connection.rb +69 -2
  21. data/lib/repull/models/airbnb_connection_host.rb +1 -1
  22. data/lib/repull/models/airbnb_content_write_response.rb +275 -0
  23. data/lib/repull/models/airbnb_data_freshness.rb +22 -10
  24. data/lib/repull/models/airbnb_description_write_request.rb +192 -0
  25. data/lib/repull/models/airbnb_description_write_request_description.rb +365 -0
  26. data/lib/repull/models/airbnb_listing.rb +12 -1
  27. data/lib/repull/models/airbnb_listing_action200_response.rb +105 -0
  28. data/lib/repull/models/airbnb_listing_action200_response_one_of.rb +157 -0
  29. data/lib/repull/models/airbnb_listing_action200_response_one_of1.rb +175 -0
  30. data/lib/repull/models/airbnb_listing_action_request.rb +2 -2
  31. data/lib/repull/models/airbnb_listing_details_response.rb +284 -0
  32. data/lib/repull/models/airbnb_listing_details_write_request.rb +209 -0
  33. data/lib/repull/models/airbnb_listing_details_write_request_check_in_option.rb +214 -0
  34. data/lib/repull/models/airbnb_listing_details_write_request_quiet_hours_inner.rb +190 -0
  35. data/lib/repull/models/airbnb_listing_lifecycle_response.rb +196 -0
  36. data/lib/repull/models/airbnb_permits_response.rb +163 -0
  37. data/lib/repull/models/airbnb_permits_response_cached_inner.rb +200 -0
  38. data/lib/repull/models/airbnb_permits_write_request.rb +176 -0
  39. data/lib/repull/models/airbnb_permits_write_request_permits_inner.rb +228 -0
  40. data/lib/repull/models/airbnb_permits_write_request_permits_inner_answers_inner.rb +198 -0
  41. data/lib/repull/models/airbnb_photo_position.rb +159 -0
  42. data/lib/repull/models/airbnb_publish_result.rb +263 -0
  43. data/lib/repull/models/airbnb_reservation.rb +23 -1
  44. data/lib/repull/models/{create_airbnb_alteration_request.rb → airbnb_reservation_action200_response.rb} +12 -50
  45. data/lib/repull/models/airbnb_reservation_action_request.rb +248 -0
  46. data/lib/repull/models/airbnb_reservation_list_response.rb +13 -4
  47. data/lib/repull/models/airbnb_review.rb +23 -1
  48. data/lib/repull/models/airbnb_review_list_response.rb +13 -4
  49. data/lib/repull/models/airbnb_safety_disclosure.rb +202 -0
  50. data/lib/repull/models/airbnb_safety_disclosures_response.rb +162 -0
  51. data/lib/repull/models/airbnb_safety_disclosures_write_request.rb +176 -0
  52. data/lib/repull/models/airbnb_thread.rb +23 -1
  53. data/lib/repull/models/airbnb_thread_list_response.rb +13 -4
  54. data/lib/repull/models/airbnb_transaction.rb +23 -1
  55. data/lib/repull/models/booking_availability_update.rb +4 -20
  56. data/lib/repull/models/booking_availability_update_date_range.rb +193 -0
  57. data/lib/repull/models/booking_availability_update_request.rb +14 -3
  58. data/lib/repull/models/booking_pricing_rate_update.rb +32 -4
  59. data/lib/repull/models/booking_pricing_rate_update_date_range.rb +3 -0
  60. data/lib/repull/models/booking_pricing_rate_update_restrictions.rb +10 -10
  61. data/lib/repull/models/booking_pricing_response.rb +16 -4
  62. data/lib/repull/models/booking_pricing_update_response.rb +82 -18
  63. data/lib/repull/models/booking_property.rb +107 -36
  64. data/lib/repull/models/booking_property_listings_inner.rb +244 -0
  65. data/lib/repull/models/booking_rate_write_occupancy.rb +187 -0
  66. data/lib/repull/models/booking_rate_write_price_half.rb +188 -0
  67. data/lib/repull/models/booking_rate_write_restriction_half.rb +212 -0
  68. data/lib/repull/models/booking_rate_write_verification.rb +200 -0
  69. data/lib/repull/models/booking_rate_write_verification_row.rb +196 -0
  70. data/lib/repull/models/booking_restriction_request_row.rb +199 -0
  71. data/lib/repull/models/booking_restriction_verification.rb +208 -0
  72. data/lib/repull/models/booking_restriction_verification_row.rb +203 -0
  73. data/lib/repull/models/booking_restriction_verification_row_booking_value.rb +105 -0
  74. data/lib/repull/models/booking_restriction_verification_row_expected.rb +105 -0
  75. data/lib/repull/models/booking_rooms_rates_response.rb +41 -7
  76. data/lib/repull/models/booking_rooms_rates_response_rooms_inner.rb +12 -1
  77. data/lib/repull/models/booking_rooms_rates_response_rooms_inner_rates_inner.rb +1 -0
  78. data/lib/repull/models/booking_upstream_failure.rb +204 -0
  79. data/lib/repull/models/calendar_updated_event.rb +95 -31
  80. data/lib/repull/models/conversation_message_attachment.rb +28 -1
  81. data/lib/repull/models/create_airbnb_listing_room_request.rb +315 -0
  82. data/lib/repull/models/create_airbnb_offer_request.rb +93 -8
  83. data/lib/repull/models/create_airbnb_offer_request_guest_details.rb +279 -0
  84. data/lib/repull/models/create_conversation_special_offer201_response.rb +293 -0
  85. data/lib/repull/models/create_conversation_special_offer201_response_guests.rb +189 -0
  86. data/lib/repull/models/create_conversation_special_offer_request.rb +263 -0
  87. data/lib/repull/models/create_conversation_special_offer_request_guests.rb +263 -0
  88. data/lib/repull/models/decline_reservation_request_request.rb +234 -0
  89. data/lib/repull/models/delete_airbnb_listing_photo200_response.rb +14 -4
  90. data/lib/repull/models/delete_airbnb_listing_room200_response.rb +157 -0
  91. data/lib/repull/models/error_error.rb +31 -1
  92. data/lib/repull/models/get_airbnb_booking_settings200_response.rb +190 -0
  93. data/lib/repull/models/get_airbnb_booking_settings200_response_data.rb +246 -0
  94. data/lib/repull/models/get_airbnb_booking_settings200_response_data_advance_notice.rb +172 -0
  95. data/lib/repull/models/get_airbnb_booking_settings200_response_data_booking_window.rb +160 -0
  96. data/lib/repull/models/get_airbnb_booking_settings200_response_data_cancellation.rb +203 -0
  97. data/lib/repull/models/get_airbnb_booking_settings200_response_data_cancellation_non_refundable.rb +218 -0
  98. data/lib/repull/models/get_airbnb_booking_settings200_response_data_check_in.rb +159 -0
  99. data/lib/repull/models/get_airbnb_booking_settings200_response_data_check_in_start.rb +104 -0
  100. data/lib/repull/models/get_airbnb_booking_settings200_response_data_check_out.rb +172 -0
  101. data/lib/repull/models/get_airbnb_booking_settings200_response_data_instant_book.rb +206 -0
  102. data/lib/repull/models/get_airbnb_booking_settings200_response_data_preparation_time.rb +173 -0
  103. data/lib/repull/models/get_airbnb_listing_details200_response.rb +192 -0
  104. data/lib/repull/models/get_airbnb_offer200_response.rb +289 -0
  105. data/lib/repull/models/get_usage_summary200_response.rb +10 -1
  106. data/lib/repull/models/get_usage_summary200_response_limits.rb +11 -1
  107. data/lib/repull/models/get_usage_summary200_response_remaining.rb +11 -1
  108. data/lib/repull/models/get_usage_summary200_response_used.rb +10 -1
  109. data/lib/repull/models/get_usage_tier200_response.rb +10 -1
  110. data/lib/repull/models/get_usage_tier200_response_limits.rb +11 -1
  111. data/lib/repull/models/get_usage_tier200_response_remaining.rb +11 -1
  112. data/lib/repull/models/get_usage_tier200_response_used.rb +10 -1
  113. data/lib/repull/models/inquiry_created_event.rb +281 -0
  114. data/lib/repull/models/inquiry_created_payload.rb +185 -0
  115. data/lib/repull/models/inquiry_updated_event.rb +281 -0
  116. data/lib/repull/models/inquiry_updated_payload.rb +213 -0
  117. data/lib/repull/models/inquiry_webhook_object.rb +323 -0
  118. data/lib/repull/models/inquiry_webhook_object_expected_payout.rb +158 -0
  119. data/lib/repull/models/inquiry_webhook_object_guests.rb +188 -0
  120. data/lib/repull/models/list_airbnb_listing_permits200_response.rb +190 -0
  121. data/lib/repull/models/list_airbnb_listing_safety_disclosures200_response.rb +190 -0
  122. data/lib/repull/models/list_airbnb_thread_messages200_response.rb +170 -0
  123. data/lib/repull/models/list_airbnb_thread_messages200_response_data_inner.rb +274 -0
  124. data/lib/repull/models/list_airbnb_thread_messages200_response_pagination.rb +158 -0
  125. data/lib/repull/models/list_inquiries200_response.rb +192 -0
  126. data/lib/repull/models/list_inquiries200_response_data_inner.rb +418 -0
  127. data/lib/repull/models/list_inquiries200_response_data_inner_expected_payout.rb +159 -0
  128. data/lib/repull/models/list_inquiries200_response_data_inner_guests.rb +188 -0
  129. data/lib/repull/models/listing.rb +2 -1
  130. data/lib/repull/models/listing_content.rb +13 -2
  131. data/lib/repull/models/listing_content_update_request.rb +21 -2
  132. data/lib/repull/models/listing_content_update_request_details.rb +206 -0
  133. data/lib/repull/models/listing_content_update_request_policies.rb +95 -5
  134. data/lib/repull/models/listing_content_update_response.rb +1 -1
  135. data/lib/repull/models/listing_created_event.rb +95 -31
  136. data/lib/repull/models/listing_deleted_event.rb +95 -31
  137. data/lib/repull/models/listing_deleted_payload.rb +55 -21
  138. data/lib/repull/models/listing_publish_airbnb_response.rb +165 -0
  139. data/lib/repull/models/listing_pull_airbnb_request.rb +149 -0
  140. data/lib/repull/models/listing_pull_response.rb +231 -0
  141. data/lib/repull/models/listing_reactivated_event.rb +281 -0
  142. data/lib/repull/models/listing_suspended_event.rb +281 -0
  143. data/lib/repull/models/listing_suspension_payload.rb +202 -0
  144. data/lib/repull/models/listing_updated_event.rb +95 -31
  145. data/lib/repull/models/listing_updated_payload.rb +50 -22
  146. data/lib/repull/models/listing_webhook_object.rb +291 -0
  147. data/lib/repull/models/listing_webhook_object_address.rb +168 -0
  148. data/lib/repull/models/listing_webhook_object_channels_inner.rb +184 -0
  149. data/lib/repull/models/message.rb +1 -0
  150. data/lib/repull/models/payment_completed_event.rb +95 -31
  151. data/lib/repull/models/payment_completed_payload.rb +46 -44
  152. data/lib/repull/models/payment_refunded_event.rb +95 -31
  153. data/lib/repull/models/payment_refunded_payload.rb +46 -44
  154. data/lib/repull/models/payment_webhook_object.rb +351 -0
  155. data/lib/repull/models/preapprove_conversation201_response.rb +253 -0
  156. data/lib/repull/models/preapprove_conversation_request.rb +150 -0
  157. data/lib/repull/models/publish_section_error.rb +232 -0
  158. data/lib/repull/models/reorder_airbnb_listing_photos200_response.rb +191 -0
  159. data/lib/repull/models/reorder_airbnb_listing_photos200_response_data.rb +172 -0
  160. data/lib/repull/models/reorder_airbnb_listing_photos_request.rb +185 -0
  161. data/lib/repull/models/replay_webhook_delivery_request.rb +150 -0
  162. data/lib/repull/models/repull_ping_event.rb +95 -31
  163. data/lib/repull/models/reservation.rb +44 -2
  164. data/lib/repull/models/reservation_alteration_created_event.rb +95 -31
  165. data/lib/repull/models/reservation_alteration_responded_event.rb +95 -31
  166. data/lib/repull/models/reservation_cancelled_event.rb +95 -31
  167. data/lib/repull/models/reservation_created_event.rb +95 -32
  168. data/lib/repull/models/reservation_message_received_event.rb +95 -31
  169. data/lib/repull/models/reservation_message_received_payload.rb +17 -4
  170. data/lib/repull/models/reservation_request_created_event.rb +281 -0
  171. data/lib/repull/models/reservation_request_created_payload.rb +224 -0
  172. data/lib/repull/models/reservation_request_updated_event.rb +281 -0
  173. data/lib/repull/models/reservation_request_updated_payload.rb +251 -0
  174. data/lib/repull/models/reservation_updated_event.rb +95 -31
  175. data/lib/repull/models/reservation_webhook_object.rb +38 -5
  176. data/lib/repull/models/review_created_event.rb +95 -31
  177. data/lib/repull/models/review_responded_event.rb +95 -31
  178. data/lib/repull/models/send_airbnb_message201_response.rb +104 -0
  179. data/lib/repull/models/send_airbnb_message_request.rb +4 -20
  180. data/lib/repull/models/send_message_attachment.rb +225 -0
  181. data/lib/repull/models/send_message_part.rb +201 -0
  182. data/lib/repull/models/send_message_request.rb +44 -19
  183. data/lib/repull/models/send_message_response.rb +29 -5
  184. data/lib/repull/models/sent_attachment.rb +196 -0
  185. data/lib/repull/models/set_airbnb_listing_cover_photo200_response.rb +191 -0
  186. data/lib/repull/models/set_airbnb_listing_cover_photo200_response_data.rb +171 -0
  187. data/lib/repull/models/set_airbnb_listing_cover_photo_request.rb +165 -0
  188. data/lib/repull/models/update_airbnb_booking_settings200_response.rb +164 -0
  189. data/lib/repull/models/update_airbnb_booking_settings200_response_data.rb +205 -0
  190. data/lib/repull/models/update_airbnb_booking_settings_request.rb +202 -0
  191. data/lib/repull/models/update_airbnb_booking_settings_request_advance_notice.rb +183 -0
  192. data/lib/repull/models/update_airbnb_booking_settings_request_booking_window.rb +183 -0
  193. data/lib/repull/models/update_airbnb_booking_settings_request_cancellation.rb +201 -0
  194. data/lib/repull/models/update_airbnb_booking_settings_request_cancellation_non_refundable.rb +183 -0
  195. data/lib/repull/models/update_airbnb_booking_settings_request_check_in.rb +159 -0
  196. data/lib/repull/models/update_airbnb_booking_settings_request_check_out.rb +182 -0
  197. data/lib/repull/models/update_airbnb_booking_settings_request_instant_book.rb +203 -0
  198. data/lib/repull/models/update_airbnb_booking_settings_request_preparation_time.rb +182 -0
  199. data/lib/repull/models/update_airbnb_listing_amenities200_response.rb +191 -0
  200. data/lib/repull/models/update_airbnb_listing_amenities200_response_data.rb +158 -0
  201. data/lib/repull/models/update_airbnb_listing_amenities_request.rb +199 -0
  202. data/lib/repull/models/update_airbnb_listing_amenities_request_accessibility_amenities_inner.rb +246 -0
  203. data/lib/repull/models/update_airbnb_listing_amenities_request_amenities_inner.rb +218 -0
  204. data/lib/repull/models/update_airbnb_listing_permits200_response.rb +168 -0
  205. data/lib/repull/models/update_airbnb_listing_photo200_response.rb +194 -0
  206. data/lib/repull/models/update_airbnb_listing_photo_request.rb +242 -0
  207. data/lib/repull/models/update_airbnb_listing_room200_response.rb +194 -0
  208. data/lib/repull/models/update_airbnb_listing_room_request.rb +293 -0
  209. data/lib/repull/models/update_airbnb_listing_room_request_beds_inner.rb +209 -0
  210. data/lib/repull/models/update_airbnb_listing_room_request_room_amenities_inner.rb +182 -0
  211. data/lib/repull/models/update_airbnb_listing_room_request_room_amenities_inner_value.rb +105 -0
  212. data/lib/repull/models/update_airbnb_listing_safety_disclosures200_response.rb +180 -0
  213. data/lib/repull/models/upload_airbnb_listing_photos_request.rb +184 -0
  214. data/lib/repull/models/upload_airbnb_listing_photos_request_photos_inner.rb +305 -0
  215. data/lib/repull/models/upload_airbnb_listing_photos_request_photos_inner_listing_id.rb +105 -0
  216. data/lib/repull/models/usage_quota_warning_event.rb +281 -0
  217. data/lib/repull/models/usage_quota_warning_payload.rb +224 -0
  218. data/lib/repull/models/usage_quota_warning_payload_top_operation.rb +167 -0
  219. data/lib/repull/models/webhook_event.rb +17 -3
  220. data/lib/repull/models/webhook_event_account.rb +171 -0
  221. data/lib/repull/models/webhook_event_type.rb +8 -1
  222. data/lib/repull/models/withdraw_conversation_special_offer200_response.rb +240 -0
  223. data/lib/repull/version.rb +1 -1
  224. data/lib/repull.rb +138 -1
  225. data/openapi/v1.json +19578 -10662
  226. data/scripts/regen.sh +1 -1
  227. metadata +140 -3
@@ -564,16 +564,16 @@ module Repull
564
564
  end
565
565
 
566
566
  # List listings
567
- # Cursor-paginated list of listings owned by the authenticated workspace. Use `pagination.nextCursor` from one response as the `cursor` query param of the next request to walk the full set. `?offset=` is also accepted as a first-class alias for shallow paging (0..10000) — see the `offset` parameter below. Mutually exclusive with `cursor`. Filters: `q` (substring on name/street/city), `status`, `channel`. **Optional expansions:** Pass `?include=content` to enrich each row with the rich content slab (summary, description, space, house rules, etc. — sourced from `listings_descriptions` for the `en` locale). Pass `?include=details` for the structural slab (bedrooms, bathrooms, person capacity, check-in window, wifi, house manual, etc.). Both default to `null` per row when the underlying `listings_descriptions` / `listings_details` row is missing — distinct from the field being absent (which signals the expansion was not requested). Combine comma-separated, e.g. `?include=content,details`. The default response stays lean; consumers must opt in. **Inactive listings:** by default only active listings are returned. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated, so when `status` asks for inactive ones they carry only `id`, `name`, `status` and `channels` — enough to choose what to activate with `PATCH /v1/listings/{id}`. `?include=` expansions are not applied to them.
567
+ # Cursor-paginated list of listings owned by the authenticated workspace. Use `pagination.nextCursor` from one response as the `cursor` query param of the next request to walk the full set. `?offset=` is also accepted as a first-class alias for shallow paging (0..10000) — see the `offset` parameter below. Mutually exclusive with `cursor`. Filters: `q` (substring on name/street/city), `status`, `channel`. **Optional expansions:** Pass `?include=content` to enrich each row with the rich content slab (summary, description, space, house rules, etc. — sourced from `listings_descriptions` for the `en` locale). Pass `?include=details` for the structural slab (bedrooms, bathrooms, person capacity, check-in window, wifi, house manual, etc.). Both default to `null` per row when the underlying `listings_descriptions` / `listings_details` row is missing — distinct from the field being absent (which signals the expansion was not requested). Pass `?include=thumbnail` to guarantee `thumbnailUrl` on every returned row — including the reduced inactive ones. Combine comma-separated, e.g. `?include=content,thumbnail`. The default response stays lean; consumers must opt in. **Inactive listings:** by default only active listings are returned. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated, so when `status` asks for inactive ones they carry only `id`, `name`, `status` and `channels` — enough to choose what to activate with `PATCH /v1/listings/{id}`. The `content` and `details` expansions are not applied to them. `?include=thumbnail` is the one exception: it adds `thumbnailUrl` to an inactive row so a single request can render an active/inactive selection screen with pictures, instead of one follow-up call per listing (which an inactive listing would answer with `403 listing_inactive` anyway).
568
568
  # @param [Hash] opts the optional parameters
569
569
  # @option opts [String] :x_schema Apply a custom or built-in schema to transform the response. Built-in: `native` (default), `calry`, `calry-v1`. Custom: any schema name created via `POST /v1/schema/custom`. Unknown / inactive schema names fall back to `native`.
570
570
  # @option opts [String] :cursor Opaque cursor returned in the previous response's `pagination.nextCursor`. Omit to fetch the first page.
571
571
  # @option opts [Integer] :offset First-class alias for cursor-based pagination. Mutually exclusive with `cursor` — passing both returns 422. Accepts integers in `[0, 10000]`; deeper walks must use `cursor` (constant per-page cost). The response always includes `pagination.nextCursor` so consumers can switch from offset → cursor mid-walk for deep pagination without re-keying. (default to 0)
572
572
  # @option opts [Integer] :limit Max items per page. Hard cap is 100. (default to 20)
573
573
  # @option opts [String] :q Case-insensitive substring search on name, street, or city.
574
- # @option opts [String] :status Filter by listing status. Defaults to `active`. Pass `inactive` to list the listings you can activate, `archived` for archived ones, or `all` for every status. Inactive listings are returned with identity fields only — `id`, `name`, `status` and `channels` — and never with `address`, `thumbnailUrl`, `content` or `details`; activate one to see the rest. (default to 'active')
574
+ # @option opts [String] :status Filter by listing status. Defaults to `active`. Pass `inactive` to list the listings you can activate, `archived` for archived ones, or `all` for every status. Inactive listings are returned with identity fields only — `id`, `name`, `status` and `channels` — and never with `address`, `content` or `details`; activate one to see the rest. The only field you can add to an inactive row is `thumbnailUrl`, via `?include=thumbnail`. (default to 'active')
575
575
  # @option opts [String] :channel Restrict to listings published on the given channel (`airbnb`, `booking`, `vrbo`, etc.). Joins through `listing_platform_links` and matches active links only.
576
- # @option opts [String] :include Comma-separated optional expansions. Currently supported: `content`, `details`. Unknown values return 422 with a `valid_values` envelope. (Note: `amenities` is not yet supported on the list endpoint — use the detail endpoint to fetch amenity rows for a single listing.)
576
+ # @option opts [String] :include Comma-separated optional expansions. Currently supported: `content`, `details`, `thumbnail`. `thumbnail` guarantees `thumbnailUrl` on every row and is the only expansion that applies to inactive listings. Unknown values return 422 with a `valid_values` envelope. (Note: `amenities` is not yet supported on the list endpoint — use the detail endpoint to fetch amenity rows for a single listing.)
577
577
  # @return [ListingListResponse]
578
578
  def list_listings(opts = {})
579
579
  data, _status_code, _headers = list_listings_with_http_info(opts)
@@ -581,16 +581,16 @@ module Repull
581
581
  end
582
582
 
583
583
  # List listings
584
- # Cursor-paginated list of listings owned by the authenticated workspace. Use `pagination.nextCursor` from one response as the `cursor` query param of the next request to walk the full set. `?offset=` is also accepted as a first-class alias for shallow paging (0..10000) — see the `offset` parameter below. Mutually exclusive with `cursor`. Filters: `q` (substring on name/street/city), `status`, `channel`. **Optional expansions:** Pass `?include=content` to enrich each row with the rich content slab (summary, description, space, house rules, etc. — sourced from `listings_descriptions` for the `en` locale). Pass `?include=details` for the structural slab (bedrooms, bathrooms, person capacity, check-in window, wifi, house manual, etc.). Both default to `null` per row when the underlying `listings_descriptions` / `listings_details` row is missing — distinct from the field being absent (which signals the expansion was not requested). Combine comma-separated, e.g. `?include=content,details`. The default response stays lean; consumers must opt in. **Inactive listings:** by default only active listings are returned. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated, so when `status` asks for inactive ones they carry only `id`, `name`, `status` and `channels` — enough to choose what to activate with `PATCH /v1/listings/{id}`. `?include=` expansions are not applied to them.
584
+ # Cursor-paginated list of listings owned by the authenticated workspace. Use `pagination.nextCursor` from one response as the `cursor` query param of the next request to walk the full set. `?offset=` is also accepted as a first-class alias for shallow paging (0..10000) — see the `offset` parameter below. Mutually exclusive with `cursor`. Filters: `q` (substring on name/street/city), `status`, `channel`. **Optional expansions:** Pass `?include=content` to enrich each row with the rich content slab (summary, description, space, house rules, etc. — sourced from `listings_descriptions` for the `en` locale). Pass `?include=details` for the structural slab (bedrooms, bathrooms, person capacity, check-in window, wifi, house manual, etc.). Both default to `null` per row when the underlying `listings_descriptions` / `listings_details` row is missing — distinct from the field being absent (which signals the expansion was not requested). Pass `?include=thumbnail` to guarantee `thumbnailUrl` on every returned row — including the reduced inactive ones. Combine comma-separated, e.g. `?include=content,thumbnail`. The default response stays lean; consumers must opt in. **Inactive listings:** by default only active listings are returned. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated, so when `status` asks for inactive ones they carry only `id`, `name`, `status` and `channels` — enough to choose what to activate with `PATCH /v1/listings/{id}`. The `content` and `details` expansions are not applied to them. `?include=thumbnail` is the one exception: it adds `thumbnailUrl` to an inactive row so a single request can render an active/inactive selection screen with pictures, instead of one follow-up call per listing (which an inactive listing would answer with `403 listing_inactive` anyway).
585
585
  # @param [Hash] opts the optional parameters
586
586
  # @option opts [String] :x_schema Apply a custom or built-in schema to transform the response. Built-in: `native` (default), `calry`, `calry-v1`. Custom: any schema name created via `POST /v1/schema/custom`. Unknown / inactive schema names fall back to `native`.
587
587
  # @option opts [String] :cursor Opaque cursor returned in the previous response's `pagination.nextCursor`. Omit to fetch the first page.
588
588
  # @option opts [Integer] :offset First-class alias for cursor-based pagination. Mutually exclusive with `cursor` — passing both returns 422. Accepts integers in `[0, 10000]`; deeper walks must use `cursor` (constant per-page cost). The response always includes `pagination.nextCursor` so consumers can switch from offset → cursor mid-walk for deep pagination without re-keying. (default to 0)
589
589
  # @option opts [Integer] :limit Max items per page. Hard cap is 100. (default to 20)
590
590
  # @option opts [String] :q Case-insensitive substring search on name, street, or city.
591
- # @option opts [String] :status Filter by listing status. Defaults to `active`. Pass `inactive` to list the listings you can activate, `archived` for archived ones, or `all` for every status. Inactive listings are returned with identity fields only — `id`, `name`, `status` and `channels` — and never with `address`, `thumbnailUrl`, `content` or `details`; activate one to see the rest. (default to 'active')
591
+ # @option opts [String] :status Filter by listing status. Defaults to `active`. Pass `inactive` to list the listings you can activate, `archived` for archived ones, or `all` for every status. Inactive listings are returned with identity fields only — `id`, `name`, `status` and `channels` — and never with `address`, `content` or `details`; activate one to see the rest. The only field you can add to an inactive row is `thumbnailUrl`, via `?include=thumbnail`. (default to 'active')
592
592
  # @option opts [String] :channel Restrict to listings published on the given channel (`airbnb`, `booking`, `vrbo`, etc.). Joins through `listing_platform_links` and matches active links only.
593
- # @option opts [String] :include Comma-separated optional expansions. Currently supported: `content`, `details`. Unknown values return 422 with a `valid_values` envelope. (Note: `amenities` is not yet supported on the list endpoint — use the detail endpoint to fetch amenity rows for a single listing.)
593
+ # @option opts [String] :include Comma-separated optional expansions. Currently supported: `content`, `details`, `thumbnail`. `thumbnail` guarantees `thumbnailUrl` on every row and is the only expansion that applies to inactive listings. Unknown values return 422 with a `valid_values` envelope. (Note: `amenities` is not yet supported on the list endpoint — use the detail endpoint to fetch amenity rows for a single listing.)
594
594
  # @return [Array<(ListingListResponse, Integer, Hash)>] ListingListResponse data, response status code and response headers
595
595
  def list_listings_with_http_info(opts = {})
596
596
  if @api_client.config.debugging
@@ -665,22 +665,24 @@ module Repull
665
665
  end
666
666
 
667
667
  # Publish a listing to Airbnb
668
- # Push a Repull listing to Airbnb. Pass `airbnbConnectionId` to update an already-mapped Airbnb listing, or `hostId` to create a brand-new Airbnb listing under that host. 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.
668
+ # Push a Repull listing's canonical content to Airbnb. Pass `airbnbConnectionId` to update an already-mapped Airbnb listing, or `hostId` to create a brand-new Airbnb listing under that host. **A publish is not one call to Airbnb.** It is up to eight independent ones — details, description, amenities, rooms, policies, photos, pricing, checkout_tasks — and each can fail on its own. `result.published` is true only when every attempted section landed; `result.sections` lists the ones that did and `result.errors[]` carries Airbnb's own reason, per section, for the ones that did not. **A partial publish is normal and is not rolled back**: what succeeded stays applied. Publish again once you have fixed the failing sections — a re-publish of an unchanged section is harmless. `result.lockedFields` names the fields Airbnb will not let this listing change at all. They are not retryable by anyone: Airbnb answers 200 and applies nothing. `GET /v1/channels/airbnb/listings/{id}` reports the same list up front. **Which fields this pushes** — title, description sections and house rules (English/primary locale), amenities, rooms and beds, photos, nightly price and fees, cancellation policy and guest controls, check-in/out times, quiet hours, property and room type, checkout tasks. **Not pushed by this endpoint:** non-primary locales (`PUT /v1/channels/airbnb/listings/{id}/descriptions`), guest-safety disclosures (`PUT …/safety-disclosures`), check-in method (`PUT …/details`), permits (`PUT …/permits`), and the calendar (`PUT …/availability`). `force: true` re-pushes every section, ignoring dirty-field tracking. Without it only the sections changed since the last successful publish are sent. Send `Idempotency-Key` to make a retry safe: a timeout on a publish otherwise leaves you unable to tell whether it ran. 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.
669
669
  # @param id [Integer]
670
670
  # @param [Hash] opts the optional parameters
671
+ # @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged &#x60;Idempotency-Status: cached&#x60; — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → &#x60;409 idempotency_key_in_use&#x60;. - Same key with a DIFFERENT payload → &#x60;422 idempotency_key_reused&#x60;. Generate a new key per distinct request; reuse one only when retrying that exact request. - Retryable outcomes are deliberately not stored, so a retry with the same key runs for real: any status &gt;&#x3D; 500, &#x60;408&#x60;, &#x60;425&#x60; and &#x60;429&#x60;, and the refusals that happen before anything is done and tell you to fix something outside the request first — &#x60;connection_reauth_required&#x60;, &#x60;listing_inactive&#x60;, and the rate/daily limits. Every other answer, including a final refusal such as &#x60;422 airbnb_rejected&#x60;, is stored and replayed.
671
672
  # @option opts [ListingPublishAirbnbRequest] :listing_publish_airbnb_request
672
- # @return [ListingPublishResponse]
673
+ # @return [ListingPublishAirbnbResponse]
673
674
  def publish_listing_to_airbnb(id, opts = {})
674
675
  data, _status_code, _headers = publish_listing_to_airbnb_with_http_info(id, opts)
675
676
  data
676
677
  end
677
678
 
678
679
  # Publish a listing to Airbnb
679
- # Push a Repull listing to Airbnb. Pass &#x60;airbnbConnectionId&#x60; to update an already-mapped Airbnb listing, or &#x60;hostId&#x60; to create a brand-new Airbnb listing under that host. Returns &#x60;403 listing_inactive&#x60; when the listing is inactive. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated.
680
+ # Push a Repull listing&#39;s canonical content to Airbnb. Pass &#x60;airbnbConnectionId&#x60; to update an already-mapped Airbnb listing, or &#x60;hostId&#x60; to create a brand-new Airbnb listing under that host. **A publish is not one call to Airbnb.** It is up to eight independent ones — details, description, amenities, rooms, policies, photos, pricing, checkout_tasks — and each can fail on its own. &#x60;result.published&#x60; is true only when every attempted section landed; &#x60;result.sections&#x60; lists the ones that did and &#x60;result.errors[]&#x60; carries Airbnb&#39;s own reason, per section, for the ones that did not. **A partial publish is normal and is not rolled back**: what succeeded stays applied. Publish again once you have fixed the failing sections — a re-publish of an unchanged section is harmless. &#x60;result.lockedFields&#x60; names the fields Airbnb will not let this listing change at all. They are not retryable by anyone: Airbnb answers 200 and applies nothing. &#x60;GET /v1/channels/airbnb/listings/{id}&#x60; reports the same list up front. **Which fields this pushes** — title, description sections and house rules (English/primary locale), amenities, rooms and beds, photos, nightly price and fees, cancellation policy and guest controls, check-in/out times, quiet hours, property and room type, checkout tasks. **Not pushed by this endpoint:** non-primary locales (&#x60;PUT /v1/channels/airbnb/listings/{id}/descriptions&#x60;), guest-safety disclosures (&#x60;PUT …/safety-disclosures&#x60;), check-in method (&#x60;PUT …/details&#x60;), permits (&#x60;PUT …/permits&#x60;), and the calendar (&#x60;PUT …/availability&#x60;). &#x60;force: true&#x60; re-pushes every section, ignoring dirty-field tracking. Without it only the sections changed since the last successful publish are sent. Send &#x60;Idempotency-Key&#x60; to make a retry safe: a timeout on a publish otherwise leaves you unable to tell whether it ran. Returns &#x60;403 listing_inactive&#x60; when the listing is inactive. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated.
680
681
  # @param id [Integer]
681
682
  # @param [Hash] opts the optional parameters
683
+ # @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged &#x60;Idempotency-Status: cached&#x60; — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → &#x60;409 idempotency_key_in_use&#x60;. - Same key with a DIFFERENT payload → &#x60;422 idempotency_key_reused&#x60;. Generate a new key per distinct request; reuse one only when retrying that exact request. - Retryable outcomes are deliberately not stored, so a retry with the same key runs for real: any status &gt;&#x3D; 500, &#x60;408&#x60;, &#x60;425&#x60; and &#x60;429&#x60;, and the refusals that happen before anything is done and tell you to fix something outside the request first — &#x60;connection_reauth_required&#x60;, &#x60;listing_inactive&#x60;, and the rate/daily limits. Every other answer, including a final refusal such as &#x60;422 airbnb_rejected&#x60;, is stored and replayed.
682
684
  # @option opts [ListingPublishAirbnbRequest] :listing_publish_airbnb_request
683
- # @return [Array<(ListingPublishResponse, Integer, Hash)>] ListingPublishResponse data, response status code and response headers
685
+ # @return [Array<(ListingPublishAirbnbResponse, Integer, Hash)>] ListingPublishAirbnbResponse data, response status code and response headers
684
686
  def publish_listing_to_airbnb_with_http_info(id, opts = {})
685
687
  if @api_client.config.debugging
686
688
  @api_client.config.logger.debug 'Calling API: ListingsApi.publish_listing_to_airbnb ...'
@@ -689,6 +691,10 @@ module Repull
689
691
  if @api_client.config.client_side_validation && id.nil?
690
692
  fail ArgumentError, "Missing the required parameter 'id' when calling ListingsApi.publish_listing_to_airbnb"
691
693
  end
694
+ if @api_client.config.client_side_validation && !opts[:'idempotency_key'].nil? && opts[:'idempotency_key'].to_s.length > 255
695
+ fail ArgumentError, 'invalid value for "opts[:"idempotency_key"]" when calling ListingsApi.publish_listing_to_airbnb, the character length must be smaller than or equal to 255.'
696
+ end
697
+
692
698
  # resource path
693
699
  local_var_path = '/v1/listings/{id}/publish/airbnb'.sub('{id}', CGI.escape(id.to_s))
694
700
 
@@ -704,6 +710,7 @@ module Repull
704
710
  if !content_type.nil?
705
711
  header_params['Content-Type'] = content_type
706
712
  end
713
+ header_params[:'Idempotency-Key'] = opts[:'idempotency_key'] if !opts[:'idempotency_key'].nil?
707
714
 
708
715
  # form parameters
709
716
  form_params = opts[:form_params] || {}
@@ -712,7 +719,7 @@ module Repull
712
719
  post_body = opts[:debug_body] || @api_client.object_to_http_body(opts[:'listing_publish_airbnb_request'])
713
720
 
714
721
  # return_type
715
- return_type = opts[:debug_return_type] || 'ListingPublishResponse'
722
+ return_type = opts[:debug_return_type] || 'ListingPublishAirbnbResponse'
716
723
 
717
724
  # auth_names
718
725
  auth_names = opts[:debug_auth_names] || ['bearerAuth']
@@ -797,6 +804,76 @@ module Repull
797
804
  return data, status_code, headers
798
805
  end
799
806
 
807
+ # Refresh a listing from Airbnb
808
+ # Re-read this listing from Airbnb and update your stored copy, then report what was refreshed and when. The mirror image of `POST /v1/listings/{id}/publish/airbnb`. Every other Airbnb read on this API is served from our database. This endpoint is the one that goes and asks Airbnb — use it after a push, to see the values Airbnb actually kept, or when a host has changed something in the Airbnb app. **What it refreshes:** basic listing facts (property type, bedrooms, beds, bathrooms, capacity), descriptions, photos, rooms and beds, amenities, booking settings (check-in/check-out windows, guest controls, cancellation policy), stay rules (min/max nights, advance-booking window, turnover buffer), pricing settings and standard fees, permits, checkout tasks and the check-in guide. After it returns, those values are what `GET /v1/listings/{id}?include=content,details` and the `/v1/channels/airbnb/**` routes serve. **What it does NOT refresh:** the calendar (nightly rates and availability — see `GET /v1/channels/airbnb/listings/{id}/availability`), reservations, messages, reviews or payouts. Those arrive continuously through the channel's own sync and never need a manual pull. **Runs synchronously** — the response is the result, not a job id. Expect several seconds. **One pull per listing per 15 minutes.** A pull is roughly a dozen Airbnb calls; a second call inside the window returns `429 rate_limit_exceeded` with `Retry-After` and `nextPullAvailableAt`, and makes no Airbnb calls. Two simultaneous calls cannot both run. 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.
809
+ # @param id [Integer]
810
+ # @param [Hash] opts the optional parameters
811
+ # @option opts [ListingPullAirbnbRequest] :listing_pull_airbnb_request
812
+ # @return [ListingPullResponse]
813
+ def pull_listing_from_airbnb(id, opts = {})
814
+ data, _status_code, _headers = pull_listing_from_airbnb_with_http_info(id, opts)
815
+ data
816
+ end
817
+
818
+ # Refresh a listing from Airbnb
819
+ # Re-read this listing from Airbnb and update your stored copy, then report what was refreshed and when. The mirror image of &#x60;POST /v1/listings/{id}/publish/airbnb&#x60;. Every other Airbnb read on this API is served from our database. This endpoint is the one that goes and asks Airbnb — use it after a push, to see the values Airbnb actually kept, or when a host has changed something in the Airbnb app. **What it refreshes:** basic listing facts (property type, bedrooms, beds, bathrooms, capacity), descriptions, photos, rooms and beds, amenities, booking settings (check-in/check-out windows, guest controls, cancellation policy), stay rules (min/max nights, advance-booking window, turnover buffer), pricing settings and standard fees, permits, checkout tasks and the check-in guide. After it returns, those values are what &#x60;GET /v1/listings/{id}?include&#x3D;content,details&#x60; and the &#x60;/v1/channels/airbnb/**&#x60; routes serve. **What it does NOT refresh:** the calendar (nightly rates and availability — see &#x60;GET /v1/channels/airbnb/listings/{id}/availability&#x60;), reservations, messages, reviews or payouts. Those arrive continuously through the channel&#39;s own sync and never need a manual pull. **Runs synchronously** — the response is the result, not a job id. Expect several seconds. **One pull per listing per 15 minutes.** A pull is roughly a dozen Airbnb calls; a second call inside the window returns &#x60;429 rate_limit_exceeded&#x60; with &#x60;Retry-After&#x60; and &#x60;nextPullAvailableAt&#x60;, and makes no Airbnb calls. Two simultaneous calls cannot both run. Returns &#x60;403 listing_inactive&#x60; when the listing is inactive. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated.
820
+ # @param id [Integer]
821
+ # @param [Hash] opts the optional parameters
822
+ # @option opts [ListingPullAirbnbRequest] :listing_pull_airbnb_request
823
+ # @return [Array<(ListingPullResponse, Integer, Hash)>] ListingPullResponse data, response status code and response headers
824
+ def pull_listing_from_airbnb_with_http_info(id, opts = {})
825
+ if @api_client.config.debugging
826
+ @api_client.config.logger.debug 'Calling API: ListingsApi.pull_listing_from_airbnb ...'
827
+ end
828
+ # verify the required parameter 'id' is set
829
+ if @api_client.config.client_side_validation && id.nil?
830
+ fail ArgumentError, "Missing the required parameter 'id' when calling ListingsApi.pull_listing_from_airbnb"
831
+ end
832
+ # resource path
833
+ local_var_path = '/v1/listings/{id}/pull/airbnb'.sub('{id}', CGI.escape(id.to_s))
834
+
835
+ # query parameters
836
+ query_params = opts[:query_params] || {}
837
+
838
+ # header parameters
839
+ header_params = opts[:header_params] || {}
840
+ # HTTP header 'Accept' (if needed)
841
+ header_params['Accept'] = @api_client.select_header_accept(['application/json']) unless header_params['Accept']
842
+ # HTTP header 'Content-Type'
843
+ content_type = @api_client.select_header_content_type(['application/json'])
844
+ if !content_type.nil?
845
+ header_params['Content-Type'] = content_type
846
+ end
847
+
848
+ # form parameters
849
+ form_params = opts[:form_params] || {}
850
+
851
+ # http body (model)
852
+ post_body = opts[:debug_body] || @api_client.object_to_http_body(opts[:'listing_pull_airbnb_request'])
853
+
854
+ # return_type
855
+ return_type = opts[:debug_return_type] || 'ListingPullResponse'
856
+
857
+ # auth_names
858
+ auth_names = opts[:debug_auth_names] || ['bearerAuth']
859
+
860
+ new_options = opts.merge(
861
+ :operation => :"ListingsApi.pull_listing_from_airbnb",
862
+ :header_params => header_params,
863
+ :query_params => query_params,
864
+ :form_params => form_params,
865
+ :body => post_body,
866
+ :auth_names => auth_names,
867
+ :return_type => return_type
868
+ )
869
+
870
+ data, status_code, headers = @api_client.call_api(:POST, local_var_path, new_options)
871
+ if @api_client.config.debugging
872
+ @api_client.config.logger.debug "API called: ListingsApi#pull_listing_from_airbnb\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
873
+ end
874
+ return data, status_code, headers
875
+ end
876
+
800
877
  # Activate or deactivate listings in bulk
801
878
  # Sets up to 500 listings active or inactive in one call. Send `{ \"listingIds\": [\"4118\", \"4119\"], \"active\": false }` to deactivate them, or `\"active\": true` to activate them. An inactive listing is not counted toward your plan's listing limit or billed. It is NOT deleted and the upstream channel (Airbnb / Booking.com / your PMS) is never touched — its data keeps syncing, so it is complete the moment you activate it again. Until then it cannot be read, changed, or receive webhooks. **All or nothing.** Nothing changes unless the whole request can be applied: - If any id is not one of your listings, the call returns `404` naming those ids. - If activating would take you over your plan's listing limit, the call returns `402 listings_limit_exceeded`. Only listings that are currently inactive count toward the new total, so re-sending ids that are already active never trips the limit. Deactivating is always allowed, including when your account is already over its limit — it is how you get back under it. **Idempotent.** Ids already in the requested state are returned in `unchanged`; ids this call changed are returned in `updated`. For a single listing, `PATCH /v1/listings/{id}` does the same.
802
879
  # @param listing_status_batch_request [ListingStatusBatchRequest]
@@ -940,10 +1017,11 @@ module Repull
940
1017
  end
941
1018
 
942
1019
  # Update canonical listing content
943
- # Write your PMS's canonical listing content — title, description, amenities, address, occupancy, and policies — into a Repull listing, making it the source of truth. This is the flagship \"the PMS owns listing content, Repull distributes it\" enabler. **Partial update:** every field is optional. Only the fields you send are written; absent fields are left untouched. `amenities` is a FULL replacement of the amenity set (omit to leave untouched, send `[]` to clear). **Local write only — NOT a channel publish.** This mutates Repull's own copy of the content. It does NOT push to Airbnb / Booking.com; it marks the channels dirty so a later publish knows what changed. Distribution stays a separate explicit step. **Photos are deferred:** a provided `photos` array is echoed back in the `deferred` field and NOT persisted (media ingestion is a follow-up). Cross-tenant access (a listing that belongs to a different workspace) returns 404 — never 403. This endpoint is served even when the account is over the plan-listings cap, since editing content on a listing you already own never grows the portfolio. 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.
1020
+ # Write your PMS's canonical listing content — title, description, amenities, address, occupancy, and policies — into a Repull listing, making it the source of truth. This is the flagship \"the PMS owns listing content, Repull distributes it\" enabler. **Partial update:** every field is optional. Only the fields you send are written; absent fields are left untouched. `amenities` is a FULL replacement of the amenity set (omit to leave untouched, send `[]` to clear). **Multilingual:** send `locale` to say which language this copy is in (`it`, `pt-BR`, …). Canonical content is stored per locale, so each language keeps its own row instead of overwriting the English one. Omit it for English. **Local write only — NOT a channel publish.** This mutates Repull's own copy of the content. It does NOT push to Airbnb / Booking.com; it marks the channels dirty so a later publish knows what changed. Distribution stays a separate explicit step. **Photos are deferred:** a provided `photos` array is echoed back in the `deferred` field and NOT persisted (media ingestion is a follow-up). Cross-tenant access (a listing that belongs to a different workspace) returns 404 — never 403. This endpoint is served even when the account is over the plan-listings cap, since editing content on a listing you already own never grows the portfolio. 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.
944
1021
  # @param id [Integer] Repull listing id
945
1022
  # @param listing_content_update_request [ListingContentUpdateRequest]
946
1023
  # @param [Hash] opts the optional parameters
1024
+ # @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged &#x60;Idempotency-Status: cached&#x60; — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → &#x60;409 idempotency_key_in_use&#x60;. - Same key with a DIFFERENT payload → &#x60;422 idempotency_key_reused&#x60;. Generate a new key per distinct request; reuse one only when retrying that exact request. - Retryable outcomes are deliberately not stored, so a retry with the same key runs for real: any status &gt;&#x3D; 500, &#x60;408&#x60;, &#x60;425&#x60; and &#x60;429&#x60;, and the refusals that happen before anything is done and tell you to fix something outside the request first — &#x60;connection_reauth_required&#x60;, &#x60;listing_inactive&#x60;, and the rate/daily limits. Every other answer, including a final refusal such as &#x60;422 airbnb_rejected&#x60;, is stored and replayed.
947
1025
  # @return [ListingContentUpdateResponse]
948
1026
  def update_listing_content(id, listing_content_update_request, opts = {})
949
1027
  data, _status_code, _headers = update_listing_content_with_http_info(id, listing_content_update_request, opts)
@@ -951,10 +1029,11 @@ module Repull
951
1029
  end
952
1030
 
953
1031
  # Update canonical listing content
954
- # Write your PMS&#39;s canonical listing content — title, description, amenities, address, occupancy, and policies — into a Repull listing, making it the source of truth. This is the flagship \&quot;the PMS owns listing content, Repull distributes it\&quot; enabler. **Partial update:** every field is optional. Only the fields you send are written; absent fields are left untouched. &#x60;amenities&#x60; is a FULL replacement of the amenity set (omit to leave untouched, send &#x60;[]&#x60; to clear). **Local write only — NOT a channel publish.** This mutates Repull&#39;s own copy of the content. It does NOT push to Airbnb / Booking.com; it marks the channels dirty so a later publish knows what changed. Distribution stays a separate explicit step. **Photos are deferred:** a provided &#x60;photos&#x60; array is echoed back in the &#x60;deferred&#x60; field and NOT persisted (media ingestion is a follow-up). Cross-tenant access (a listing that belongs to a different workspace) returns 404 — never 403. This endpoint is served even when the account is over the plan-listings cap, since editing content on a listing you already own never grows the portfolio. Returns &#x60;403 listing_inactive&#x60; when the listing is inactive. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated.
1032
+ # Write your PMS&#39;s canonical listing content — title, description, amenities, address, occupancy, and policies — into a Repull listing, making it the source of truth. This is the flagship \&quot;the PMS owns listing content, Repull distributes it\&quot; enabler. **Partial update:** every field is optional. Only the fields you send are written; absent fields are left untouched. &#x60;amenities&#x60; is a FULL replacement of the amenity set (omit to leave untouched, send &#x60;[]&#x60; to clear). **Multilingual:** send &#x60;locale&#x60; to say which language this copy is in (&#x60;it&#x60;, &#x60;pt-BR&#x60;, …). Canonical content is stored per locale, so each language keeps its own row instead of overwriting the English one. Omit it for English. **Local write only — NOT a channel publish.** This mutates Repull&#39;s own copy of the content. It does NOT push to Airbnb / Booking.com; it marks the channels dirty so a later publish knows what changed. Distribution stays a separate explicit step. **Photos are deferred:** a provided &#x60;photos&#x60; array is echoed back in the &#x60;deferred&#x60; field and NOT persisted (media ingestion is a follow-up). Cross-tenant access (a listing that belongs to a different workspace) returns 404 — never 403. This endpoint is served even when the account is over the plan-listings cap, since editing content on a listing you already own never grows the portfolio. Returns &#x60;403 listing_inactive&#x60; when the listing is inactive. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated.
955
1033
  # @param id [Integer] Repull listing id
956
1034
  # @param listing_content_update_request [ListingContentUpdateRequest]
957
1035
  # @param [Hash] opts the optional parameters
1036
+ # @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged &#x60;Idempotency-Status: cached&#x60; — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → &#x60;409 idempotency_key_in_use&#x60;. - Same key with a DIFFERENT payload → &#x60;422 idempotency_key_reused&#x60;. Generate a new key per distinct request; reuse one only when retrying that exact request. - Retryable outcomes are deliberately not stored, so a retry with the same key runs for real: any status &gt;&#x3D; 500, &#x60;408&#x60;, &#x60;425&#x60; and &#x60;429&#x60;, and the refusals that happen before anything is done and tell you to fix something outside the request first — &#x60;connection_reauth_required&#x60;, &#x60;listing_inactive&#x60;, and the rate/daily limits. Every other answer, including a final refusal such as &#x60;422 airbnb_rejected&#x60;, is stored and replayed.
958
1037
  # @return [Array<(ListingContentUpdateResponse, Integer, Hash)>] ListingContentUpdateResponse data, response status code and response headers
959
1038
  def update_listing_content_with_http_info(id, listing_content_update_request, opts = {})
960
1039
  if @api_client.config.debugging
@@ -968,6 +1047,10 @@ module Repull
968
1047
  if @api_client.config.client_side_validation && listing_content_update_request.nil?
969
1048
  fail ArgumentError, "Missing the required parameter 'listing_content_update_request' when calling ListingsApi.update_listing_content"
970
1049
  end
1050
+ if @api_client.config.client_side_validation && !opts[:'idempotency_key'].nil? && opts[:'idempotency_key'].to_s.length > 255
1051
+ fail ArgumentError, 'invalid value for "opts[:"idempotency_key"]" when calling ListingsApi.update_listing_content, the character length must be smaller than or equal to 255.'
1052
+ end
1053
+
971
1054
  # resource path
972
1055
  local_var_path = '/v1/listings/{id}/content'.sub('{id}', CGI.escape(id.to_s))
973
1056
 
@@ -983,6 +1066,7 @@ module Repull
983
1066
  if !content_type.nil?
984
1067
  header_params['Content-Type'] = content_type
985
1068
  end
1069
+ header_params[:'Idempotency-Key'] = opts[:'idempotency_key'] if !opts[:'idempotency_key'].nil?
986
1070
 
987
1071
  # form parameters
988
1072
  form_params = opts[:form_params] || {}
@@ -19,11 +19,81 @@ module Repull
19
19
  def initialize(api_client = ApiClient.default)
20
20
  @api_client = api_client
21
21
  end
22
+ # Accept a booking request
23
+ # Accept a pending Airbnb booking request — a reservation with status `pending`, made on a listing without Instant Book. Find them with `GET /v1/reservations?status=pending`. Airbnb expires a request the host has not answered within 24 hours. Runs the same action as the Vanio dashboard’s Accept button. Airbnb confirms asynchronously: the reservation’s status moves to confirmed, and a `reservation.updated` webhook fires, when Airbnb’s notification lands (usually within seconds). The response reports what Airbnb was asked to do. **Airbnb only**, and only for listings connected to Airbnb directly: other channels have no request step (`422 channel_not_supported`). A reservation that is not pending is refused before Airbnb is contacted (`409 reservation_not_pending`); one Airbnb says already moved on is `409 request_no_longer_pending`. Neither is worth retrying. Takes no body. Send `Idempotency-Key`: a repeat with the same key replays the first response instead of acting twice (a `409 idempotency_key_in_use` while the first is still running). A 5xx, a `429 airbnb_rate_limited` or a `403 connection_reauth_required` is not stored — nothing was done — so retrying with the same key reaches Airbnb again.
24
+ # @param id [Integer] Repull reservation id (from &#x60;GET /v1/reservations?status&#x3D;pending&#x60;) — not the Airbnb confirmation code.
25
+ # @param [Hash] opts the optional parameters
26
+ # @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged &#x60;Idempotency-Status: cached&#x60; — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → &#x60;409 idempotency_key_in_use&#x60;. - Same key with a DIFFERENT payload → &#x60;422 idempotency_key_reused&#x60;. Generate a new key per distinct request; reuse one only when retrying that exact request. - Retryable outcomes are deliberately not stored, so a retry with the same key runs for real: any status &gt;&#x3D; 500, &#x60;408&#x60;, &#x60;425&#x60; and &#x60;429&#x60;, and the refusals that happen before anything is done and tell you to fix something outside the request first — &#x60;connection_reauth_required&#x60;, &#x60;listing_inactive&#x60;, and the rate/daily limits. Every other answer, including a final refusal such as &#x60;422 airbnb_rejected&#x60;, is stored and replayed.
27
+ # @return [AcceptReservationRequest200Response]
28
+ def accept_reservation_request(id, opts = {})
29
+ data, _status_code, _headers = accept_reservation_request_with_http_info(id, opts)
30
+ data
31
+ end
32
+
33
+ # Accept a booking request
34
+ # Accept a pending Airbnb booking request — a reservation with status &#x60;pending&#x60;, made on a listing without Instant Book. Find them with &#x60;GET /v1/reservations?status&#x3D;pending&#x60;. Airbnb expires a request the host has not answered within 24 hours. Runs the same action as the Vanio dashboard’s Accept button. Airbnb confirms asynchronously: the reservation’s status moves to confirmed, and a &#x60;reservation.updated&#x60; webhook fires, when Airbnb’s notification lands (usually within seconds). The response reports what Airbnb was asked to do. **Airbnb only**, and only for listings connected to Airbnb directly: other channels have no request step (&#x60;422 channel_not_supported&#x60;). A reservation that is not pending is refused before Airbnb is contacted (&#x60;409 reservation_not_pending&#x60;); one Airbnb says already moved on is &#x60;409 request_no_longer_pending&#x60;. Neither is worth retrying. Takes no body. Send &#x60;Idempotency-Key&#x60;: a repeat with the same key replays the first response instead of acting twice (a &#x60;409 idempotency_key_in_use&#x60; while the first is still running). A 5xx, a &#x60;429 airbnb_rate_limited&#x60; or a &#x60;403 connection_reauth_required&#x60; is not stored — nothing was done — so retrying with the same key reaches Airbnb again.
35
+ # @param id [Integer] Repull reservation id (from &#x60;GET /v1/reservations?status&#x3D;pending&#x60;) — not the Airbnb confirmation code.
36
+ # @param [Hash] opts the optional parameters
37
+ # @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged &#x60;Idempotency-Status: cached&#x60; — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → &#x60;409 idempotency_key_in_use&#x60;. - Same key with a DIFFERENT payload → &#x60;422 idempotency_key_reused&#x60;. Generate a new key per distinct request; reuse one only when retrying that exact request. - Retryable outcomes are deliberately not stored, so a retry with the same key runs for real: any status &gt;&#x3D; 500, &#x60;408&#x60;, &#x60;425&#x60; and &#x60;429&#x60;, and the refusals that happen before anything is done and tell you to fix something outside the request first — &#x60;connection_reauth_required&#x60;, &#x60;listing_inactive&#x60;, and the rate/daily limits. Every other answer, including a final refusal such as &#x60;422 airbnb_rejected&#x60;, is stored and replayed.
38
+ # @return [Array<(AcceptReservationRequest200Response, Integer, Hash)>] AcceptReservationRequest200Response data, response status code and response headers
39
+ def accept_reservation_request_with_http_info(id, opts = {})
40
+ if @api_client.config.debugging
41
+ @api_client.config.logger.debug 'Calling API: ReservationsApi.accept_reservation_request ...'
42
+ end
43
+ # verify the required parameter 'id' is set
44
+ if @api_client.config.client_side_validation && id.nil?
45
+ fail ArgumentError, "Missing the required parameter 'id' when calling ReservationsApi.accept_reservation_request"
46
+ end
47
+ if @api_client.config.client_side_validation && !opts[:'idempotency_key'].nil? && opts[:'idempotency_key'].to_s.length > 255
48
+ fail ArgumentError, 'invalid value for "opts[:"idempotency_key"]" when calling ReservationsApi.accept_reservation_request, the character length must be smaller than or equal to 255.'
49
+ end
50
+
51
+ # resource path
52
+ local_var_path = '/v1/reservations/{id}/accept'.sub('{id}', CGI.escape(id.to_s))
53
+
54
+ # query parameters
55
+ query_params = opts[:query_params] || {}
56
+
57
+ # header parameters
58
+ header_params = opts[:header_params] || {}
59
+ # HTTP header 'Accept' (if needed)
60
+ header_params['Accept'] = @api_client.select_header_accept(['application/json']) unless header_params['Accept']
61
+ header_params[:'Idempotency-Key'] = opts[:'idempotency_key'] if !opts[:'idempotency_key'].nil?
62
+
63
+ # form parameters
64
+ form_params = opts[:form_params] || {}
65
+
66
+ # http body (model)
67
+ post_body = opts[:debug_body]
68
+
69
+ # return_type
70
+ return_type = opts[:debug_return_type] || 'AcceptReservationRequest200Response'
71
+
72
+ # auth_names
73
+ auth_names = opts[:debug_auth_names] || ['bearerAuth']
74
+
75
+ new_options = opts.merge(
76
+ :operation => :"ReservationsApi.accept_reservation_request",
77
+ :header_params => header_params,
78
+ :query_params => query_params,
79
+ :form_params => form_params,
80
+ :body => post_body,
81
+ :auth_names => auth_names,
82
+ :return_type => return_type
83
+ )
84
+
85
+ data, status_code, headers = @api_client.call_api(:POST, local_var_path, new_options)
86
+ if @api_client.config.debugging
87
+ @api_client.config.logger.debug "API called: ReservationsApi#accept_reservation_request\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
88
+ end
89
+ return data, status_code, headers
90
+ end
91
+
22
92
  # Create a reservation
23
93
  # Creates a reservation and everything that hangs off one: the guest, the conversation thread, the dashboard item, the calendar block, and the `reservation.created` fan-out that issues the door code and starts the messaging automations. **Platform is restricted to `direct`, `website` and `owner`.** Reservations on Airbnb, Booking.com and Vrbo are owned by the channel and arrive through sync — creating one here would mint a local booking the channel has never heard of, which then fights the next sync. Create those on the channel. **Dates are validated** (`YYYY-MM-DD`, and `checkOut` must be after `checkIn`), and an unrecognised field is rejected by name rather than silently ignored. **This endpoint does not set the price.** There is no `totalPrice` field: the reservation pipeline derives the price breakdown from the property's own rates and overwrites anything supplied, so accepting a total would be taking a value and discarding it. A reservation created here is priced by that engine (`0` when the property has no rates for the range). `currency` IS honoured. Quote a stay with `GET /v1/quotes` before booking if you need the figure up front. **Availability is NOT checked.** This creates the reservation you asked for even if the dates overlap an existing booking. Call `GET /v1/availability/{propertyId}` first if that matters. Send `Idempotency-Key` — a network timeout here is exactly the case it exists for: without it, a retry books the guest twice. 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.
24
94
  # @param reservation_create_request [ReservationCreateRequest]
25
95
  # @param [Hash] opts the optional parameters
26
- # @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged &#x60;Idempotency-Status: cached&#x60; — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → &#x60;409 idempotency_key_in_use&#x60;. - Same key with a DIFFERENT payload → &#x60;422 idempotency_key_reused&#x60;. Generate a new key per distinct request; reuse one only when retrying that exact request. - Responses with status &gt;&#x3D; 500 are deliberately not stored, so a server error stays retryable.
96
+ # @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged &#x60;Idempotency-Status: cached&#x60; — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → &#x60;409 idempotency_key_in_use&#x60;. - Same key with a DIFFERENT payload → &#x60;422 idempotency_key_reused&#x60;. Generate a new key per distinct request; reuse one only when retrying that exact request. - Retryable outcomes are deliberately not stored, so a retry with the same key runs for real: any status &gt;&#x3D; 500, &#x60;408&#x60;, &#x60;425&#x60; and &#x60;429&#x60;, and the refusals that happen before anything is done and tell you to fix something outside the request first — &#x60;connection_reauth_required&#x60;, &#x60;listing_inactive&#x60;, and the rate/daily limits. Every other answer, including a final refusal such as &#x60;422 airbnb_rejected&#x60;, is stored and replayed.
27
97
  # @return [ReservationCreateResponse]
28
98
  def create_reservation(reservation_create_request, opts = {})
29
99
  data, _status_code, _headers = create_reservation_with_http_info(reservation_create_request, opts)
@@ -34,7 +104,7 @@ module Repull
34
104
  # Creates a reservation and everything that hangs off one: the guest, the conversation thread, the dashboard item, the calendar block, and the &#x60;reservation.created&#x60; fan-out that issues the door code and starts the messaging automations. **Platform is restricted to &#x60;direct&#x60;, &#x60;website&#x60; and &#x60;owner&#x60;.** Reservations on Airbnb, Booking.com and Vrbo are owned by the channel and arrive through sync — creating one here would mint a local booking the channel has never heard of, which then fights the next sync. Create those on the channel. **Dates are validated** (&#x60;YYYY-MM-DD&#x60;, and &#x60;checkOut&#x60; must be after &#x60;checkIn&#x60;), and an unrecognised field is rejected by name rather than silently ignored. **This endpoint does not set the price.** There is no &#x60;totalPrice&#x60; field: the reservation pipeline derives the price breakdown from the property&#39;s own rates and overwrites anything supplied, so accepting a total would be taking a value and discarding it. A reservation created here is priced by that engine (&#x60;0&#x60; when the property has no rates for the range). &#x60;currency&#x60; IS honoured. Quote a stay with &#x60;GET /v1/quotes&#x60; before booking if you need the figure up front. **Availability is NOT checked.** This creates the reservation you asked for even if the dates overlap an existing booking. Call &#x60;GET /v1/availability/{propertyId}&#x60; first if that matters. Send &#x60;Idempotency-Key&#x60; — a network timeout here is exactly the case it exists for: without it, a retry books the guest twice. Returns &#x60;403 listing_inactive&#x60; when the listing is inactive. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated.
35
105
  # @param reservation_create_request [ReservationCreateRequest]
36
106
  # @param [Hash] opts the optional parameters
37
- # @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged &#x60;Idempotency-Status: cached&#x60; — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → &#x60;409 idempotency_key_in_use&#x60;. - Same key with a DIFFERENT payload → &#x60;422 idempotency_key_reused&#x60;. Generate a new key per distinct request; reuse one only when retrying that exact request. - Responses with status &gt;&#x3D; 500 are deliberately not stored, so a server error stays retryable.
107
+ # @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged &#x60;Idempotency-Status: cached&#x60; — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → &#x60;409 idempotency_key_in_use&#x60;. - Same key with a DIFFERENT payload → &#x60;422 idempotency_key_reused&#x60;. Generate a new key per distinct request; reuse one only when retrying that exact request. - Retryable outcomes are deliberately not stored, so a retry with the same key runs for real: any status &gt;&#x3D; 500, &#x60;408&#x60;, &#x60;425&#x60; and &#x60;429&#x60;, and the refusals that happen before anything is done and tell you to fix something outside the request first — &#x60;connection_reauth_required&#x60;, &#x60;listing_inactive&#x60;, and the rate/daily limits. Every other answer, including a final refusal such as &#x60;422 airbnb_rejected&#x60;, is stored and replayed.
38
108
  # @return [Array<(ReservationCreateResponse, Integer, Hash)>] ReservationCreateResponse data, response status code and response headers
39
109
  def create_reservation_with_http_info(reservation_create_request, opts = {})
40
110
  if @api_client.config.debugging
@@ -94,6 +164,87 @@ module Repull
94
164
  return data, status_code, headers
95
165
  end
96
166
 
167
+ # Decline a booking request
168
+ # Decline a pending Airbnb booking request (a reservation with status `pending`; find them with `GET /v1/reservations?status=pending`). `reason` must be one of Airbnb’s own decline reasons. `message` is required: Airbnb sends it to the guest with the decline (at most 500 characters). It is not defaulted — a canned message would put words in your mouth. Runs the same action as the Vanio dashboard’s Decline button. Airbnb confirms asynchronously; the reservation’s status moves, and `reservation.updated` fires, when its notification lands. Same channel and status rules as `POST /v1/reservations/{id}/accept`. Send `Idempotency-Key`: a repeat with the same key replays the first response instead of acting twice (a `409 idempotency_key_in_use` while the first is still running). A 5xx, a `429 airbnb_rate_limited` or a `403 connection_reauth_required` is not stored — nothing was done — so retrying with the same key reaches Airbnb again.
169
+ # @param id [Integer] Repull reservation id (from &#x60;GET /v1/reservations?status&#x3D;pending&#x60;) — not the Airbnb confirmation code.
170
+ # @param decline_reservation_request_request [DeclineReservationRequestRequest]
171
+ # @param [Hash] opts the optional parameters
172
+ # @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged &#x60;Idempotency-Status: cached&#x60; — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → &#x60;409 idempotency_key_in_use&#x60;. - Same key with a DIFFERENT payload → &#x60;422 idempotency_key_reused&#x60;. Generate a new key per distinct request; reuse one only when retrying that exact request. - Retryable outcomes are deliberately not stored, so a retry with the same key runs for real: any status &gt;&#x3D; 500, &#x60;408&#x60;, &#x60;425&#x60; and &#x60;429&#x60;, and the refusals that happen before anything is done and tell you to fix something outside the request first — &#x60;connection_reauth_required&#x60;, &#x60;listing_inactive&#x60;, and the rate/daily limits. Every other answer, including a final refusal such as &#x60;422 airbnb_rejected&#x60;, is stored and replayed.
173
+ # @return [AcceptReservationRequest200Response]
174
+ def decline_reservation_request(id, decline_reservation_request_request, opts = {})
175
+ data, _status_code, _headers = decline_reservation_request_with_http_info(id, decline_reservation_request_request, opts)
176
+ data
177
+ end
178
+
179
+ # Decline a booking request
180
+ # Decline a pending Airbnb booking request (a reservation with status &#x60;pending&#x60;; find them with &#x60;GET /v1/reservations?status&#x3D;pending&#x60;). &#x60;reason&#x60; must be one of Airbnb’s own decline reasons. &#x60;message&#x60; is required: Airbnb sends it to the guest with the decline (at most 500 characters). It is not defaulted — a canned message would put words in your mouth. Runs the same action as the Vanio dashboard’s Decline button. Airbnb confirms asynchronously; the reservation’s status moves, and &#x60;reservation.updated&#x60; fires, when its notification lands. Same channel and status rules as &#x60;POST /v1/reservations/{id}/accept&#x60;. Send &#x60;Idempotency-Key&#x60;: a repeat with the same key replays the first response instead of acting twice (a &#x60;409 idempotency_key_in_use&#x60; while the first is still running). A 5xx, a &#x60;429 airbnb_rate_limited&#x60; or a &#x60;403 connection_reauth_required&#x60; is not stored — nothing was done — so retrying with the same key reaches Airbnb again.
181
+ # @param id [Integer] Repull reservation id (from &#x60;GET /v1/reservations?status&#x3D;pending&#x60;) — not the Airbnb confirmation code.
182
+ # @param decline_reservation_request_request [DeclineReservationRequestRequest]
183
+ # @param [Hash] opts the optional parameters
184
+ # @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged &#x60;Idempotency-Status: cached&#x60; — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → &#x60;409 idempotency_key_in_use&#x60;. - Same key with a DIFFERENT payload → &#x60;422 idempotency_key_reused&#x60;. Generate a new key per distinct request; reuse one only when retrying that exact request. - Retryable outcomes are deliberately not stored, so a retry with the same key runs for real: any status &gt;&#x3D; 500, &#x60;408&#x60;, &#x60;425&#x60; and &#x60;429&#x60;, and the refusals that happen before anything is done and tell you to fix something outside the request first — &#x60;connection_reauth_required&#x60;, &#x60;listing_inactive&#x60;, and the rate/daily limits. Every other answer, including a final refusal such as &#x60;422 airbnb_rejected&#x60;, is stored and replayed.
185
+ # @return [Array<(AcceptReservationRequest200Response, Integer, Hash)>] AcceptReservationRequest200Response data, response status code and response headers
186
+ def decline_reservation_request_with_http_info(id, decline_reservation_request_request, opts = {})
187
+ if @api_client.config.debugging
188
+ @api_client.config.logger.debug 'Calling API: ReservationsApi.decline_reservation_request ...'
189
+ end
190
+ # verify the required parameter 'id' is set
191
+ if @api_client.config.client_side_validation && id.nil?
192
+ fail ArgumentError, "Missing the required parameter 'id' when calling ReservationsApi.decline_reservation_request"
193
+ end
194
+ # verify the required parameter 'decline_reservation_request_request' is set
195
+ if @api_client.config.client_side_validation && decline_reservation_request_request.nil?
196
+ fail ArgumentError, "Missing the required parameter 'decline_reservation_request_request' when calling ReservationsApi.decline_reservation_request"
197
+ end
198
+ if @api_client.config.client_side_validation && !opts[:'idempotency_key'].nil? && opts[:'idempotency_key'].to_s.length > 255
199
+ fail ArgumentError, 'invalid value for "opts[:"idempotency_key"]" when calling ReservationsApi.decline_reservation_request, the character length must be smaller than or equal to 255.'
200
+ end
201
+
202
+ # resource path
203
+ local_var_path = '/v1/reservations/{id}/decline'.sub('{id}', CGI.escape(id.to_s))
204
+
205
+ # query parameters
206
+ query_params = opts[:query_params] || {}
207
+
208
+ # header parameters
209
+ header_params = opts[:header_params] || {}
210
+ # HTTP header 'Accept' (if needed)
211
+ header_params['Accept'] = @api_client.select_header_accept(['application/json']) unless header_params['Accept']
212
+ # HTTP header 'Content-Type'
213
+ content_type = @api_client.select_header_content_type(['application/json'])
214
+ if !content_type.nil?
215
+ header_params['Content-Type'] = content_type
216
+ end
217
+ header_params[:'Idempotency-Key'] = opts[:'idempotency_key'] if !opts[:'idempotency_key'].nil?
218
+
219
+ # form parameters
220
+ form_params = opts[:form_params] || {}
221
+
222
+ # http body (model)
223
+ post_body = opts[:debug_body] || @api_client.object_to_http_body(decline_reservation_request_request)
224
+
225
+ # return_type
226
+ return_type = opts[:debug_return_type] || 'AcceptReservationRequest200Response'
227
+
228
+ # auth_names
229
+ auth_names = opts[:debug_auth_names] || ['bearerAuth']
230
+
231
+ new_options = opts.merge(
232
+ :operation => :"ReservationsApi.decline_reservation_request",
233
+ :header_params => header_params,
234
+ :query_params => query_params,
235
+ :form_params => form_params,
236
+ :body => post_body,
237
+ :auth_names => auth_names,
238
+ :return_type => return_type
239
+ )
240
+
241
+ data, status_code, headers = @api_client.call_api(:POST, local_var_path, new_options)
242
+ if @api_client.config.debugging
243
+ @api_client.config.logger.debug "API called: ReservationsApi#decline_reservation_request\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
244
+ end
245
+ return data, status_code, headers
246
+ end
247
+
97
248
  # Get reservation details
98
249
  # Returns the full record for a single reservation, scoped to the authenticated workspace. Response shape is identical to a single row in `GET /v1/reservations` so SDK consumers can use the same type for both. Returns **404** if the id does not exist OR belongs to a different workspace — the API never differentiates the two so caller can't enumerate other workspaces' ids. Returns `403 listing_inactive` when the listing this resolves to is inactive. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated.
99
250
  # @param id [Integer] Internal Repull reservation ID.
@@ -168,7 +319,7 @@ module Repull
168
319
  # @option opts [String] :cursor Opaque cursor returned in the previous response&#39;s &#x60;pagination.nextCursor&#x60;. Omit to fetch the first page.
169
320
  # @option opts [Integer] :offset First-class alias for cursor-based pagination. Mutually exclusive with &#x60;cursor&#x60; — passing both returns 422. Accepts integers in &#x60;[0, 10000]&#x60;; deeper walks must use &#x60;cursor&#x60; (constant per-page cost). The response always includes &#x60;pagination.nextCursor&#x60; so consumers can switch from offset → cursor mid-walk for deep pagination without re-keying. (default to 0)
170
321
  # @option opts [String] :platform Filter by booking platform
171
- # @option opts [String] :status Filter by lifecycle status. **Case-insensitive** — &#x60;confirmed&#x60;, &#x60;Confirmed&#x60;, and &#x60;CONFIRMED&#x60; all match. Each public value expands to the full set of internal sub-states server-side: &#x60;confirmed&#x60; matches &#x60;accept&#x60;/&#x60;confirmed&#x60;/&#x60;modified&#x60;, &#x60;cancelled&#x60; matches every cancellation sub-state (&#x60;cancelled_by_host&#x60;, &#x60;declined&#x60;, &#x60;expired&#x60;, etc.), &#x60;pending&#x60; includes &#x60;inquiry&#x60;/&#x60;awaiting_payment&#x60;. &#x60;completed&#x60; is a derived state — combine &#x60;status&#x3D;confirmed&#x60; with &#x60;check_out_before&#x3D;&lt;today&gt;&#x60; to filter for past stays.
322
+ # @option opts [String] :status Filter by lifecycle status. **Case-insensitive** — &#x60;confirmed&#x60;, &#x60;Confirmed&#x60;, and &#x60;CONFIRMED&#x60; all match. Each public value expands to the full set of internal sub-states server-side: &#x60;confirmed&#x60; matches &#x60;accept&#x60;/&#x60;confirmed&#x60;/&#x60;modified&#x60;, &#x60;cancelled&#x60; matches every cancellation sub-state (&#x60;cancelled_by_host&#x60;, &#x60;declined&#x60;, &#x60;expired&#x60;, etc.), &#x60;pending&#x60; includes &#x60;inquiry&#x60;/&#x60;awaiting_payment&#x60;. &#x60;completed&#x60; is a derived state — combine &#x60;status&#x3D;confirmed&#x60; with &#x60;check_out_before&#x3D;&lt;today&gt;&#x60; to filter for past stays. &#x60;pending&#x60; is how an Airbnb booking **request** awaiting the host appears — answer it with &#x60;POST /v1/reservations/{id}/accept&#x60; or &#x60;/decline&#x60; before its &#x60;respondBy&#x60;. &#x60;pending&#x60; lists only requests that can still be answered: one the channel already let lapse (Airbnb expires a request 24 hours after the guest asks; no request survives its check-in date) is left out and appears under &#x60;cancelled&#x60; with &#x60;statusDetail: \&quot;request_expired\&quot;&#x60; instead. The stored record is not changed — this is derived when you read it. Airbnb **inquiries** (questions before booking) are not reservations: list them with &#x60;GET /v1/inquiries&#x60;.
172
323
  # @option opts [Integer] :listing_id Filter to a single listing
173
324
  # @option opts [Date] :check_in_after Check-in date &gt;&#x3D; this value
174
325
  # @option opts [Date] :check_in_before Check-in date &lt;&#x3D; this value
@@ -196,7 +347,7 @@ module Repull
196
347
  # @option opts [String] :cursor Opaque cursor returned in the previous response&#39;s &#x60;pagination.nextCursor&#x60;. Omit to fetch the first page.
197
348
  # @option opts [Integer] :offset First-class alias for cursor-based pagination. Mutually exclusive with &#x60;cursor&#x60; — passing both returns 422. Accepts integers in &#x60;[0, 10000]&#x60;; deeper walks must use &#x60;cursor&#x60; (constant per-page cost). The response always includes &#x60;pagination.nextCursor&#x60; so consumers can switch from offset → cursor mid-walk for deep pagination without re-keying. (default to 0)
198
349
  # @option opts [String] :platform Filter by booking platform
199
- # @option opts [String] :status Filter by lifecycle status. **Case-insensitive** — &#x60;confirmed&#x60;, &#x60;Confirmed&#x60;, and &#x60;CONFIRMED&#x60; all match. Each public value expands to the full set of internal sub-states server-side: &#x60;confirmed&#x60; matches &#x60;accept&#x60;/&#x60;confirmed&#x60;/&#x60;modified&#x60;, &#x60;cancelled&#x60; matches every cancellation sub-state (&#x60;cancelled_by_host&#x60;, &#x60;declined&#x60;, &#x60;expired&#x60;, etc.), &#x60;pending&#x60; includes &#x60;inquiry&#x60;/&#x60;awaiting_payment&#x60;. &#x60;completed&#x60; is a derived state — combine &#x60;status&#x3D;confirmed&#x60; with &#x60;check_out_before&#x3D;&lt;today&gt;&#x60; to filter for past stays.
350
+ # @option opts [String] :status Filter by lifecycle status. **Case-insensitive** — &#x60;confirmed&#x60;, &#x60;Confirmed&#x60;, and &#x60;CONFIRMED&#x60; all match. Each public value expands to the full set of internal sub-states server-side: &#x60;confirmed&#x60; matches &#x60;accept&#x60;/&#x60;confirmed&#x60;/&#x60;modified&#x60;, &#x60;cancelled&#x60; matches every cancellation sub-state (&#x60;cancelled_by_host&#x60;, &#x60;declined&#x60;, &#x60;expired&#x60;, etc.), &#x60;pending&#x60; includes &#x60;inquiry&#x60;/&#x60;awaiting_payment&#x60;. &#x60;completed&#x60; is a derived state — combine &#x60;status&#x3D;confirmed&#x60; with &#x60;check_out_before&#x3D;&lt;today&gt;&#x60; to filter for past stays. &#x60;pending&#x60; is how an Airbnb booking **request** awaiting the host appears — answer it with &#x60;POST /v1/reservations/{id}/accept&#x60; or &#x60;/decline&#x60; before its &#x60;respondBy&#x60;. &#x60;pending&#x60; lists only requests that can still be answered: one the channel already let lapse (Airbnb expires a request 24 hours after the guest asks; no request survives its check-in date) is left out and appears under &#x60;cancelled&#x60; with &#x60;statusDetail: \&quot;request_expired\&quot;&#x60; instead. The stored record is not changed — this is derived when you read it. Airbnb **inquiries** (questions before booking) are not reservations: list them with &#x60;GET /v1/inquiries&#x60;.
200
351
  # @option opts [Integer] :listing_id Filter to a single listing
201
352
  # @option opts [Date] :check_in_after Check-in date &gt;&#x3D; this value
202
353
  # @option opts [Date] :check_in_before Check-in date &lt;&#x3D; this value
@@ -299,7 +450,7 @@ module Repull
299
450
  # @param id [Integer] Internal Repull reservation ID.
300
451
  # @param reservation_update_request [ReservationUpdateRequest]
301
452
  # @param [Hash] opts the optional parameters
302
- # @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged &#x60;Idempotency-Status: cached&#x60; — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → &#x60;409 idempotency_key_in_use&#x60;. - Same key with a DIFFERENT payload → &#x60;422 idempotency_key_reused&#x60;. Generate a new key per distinct request; reuse one only when retrying that exact request. - Responses with status &gt;&#x3D; 500 are deliberately not stored, so a server error stays retryable.
453
+ # @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged &#x60;Idempotency-Status: cached&#x60; — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → &#x60;409 idempotency_key_in_use&#x60;. - Same key with a DIFFERENT payload → &#x60;422 idempotency_key_reused&#x60;. Generate a new key per distinct request; reuse one only when retrying that exact request. - Retryable outcomes are deliberately not stored, so a retry with the same key runs for real: any status &gt;&#x3D; 500, &#x60;408&#x60;, &#x60;425&#x60; and &#x60;429&#x60;, and the refusals that happen before anything is done and tell you to fix something outside the request first — &#x60;connection_reauth_required&#x60;, &#x60;listing_inactive&#x60;, and the rate/daily limits. Every other answer, including a final refusal such as &#x60;422 airbnb_rejected&#x60;, is stored and replayed.
303
454
  # @return [ReservationUpdateResponse]
304
455
  def update_reservation(id, reservation_update_request, opts = {})
305
456
  data, _status_code, _headers = update_reservation_with_http_info(id, reservation_update_request, opts)
@@ -311,7 +462,7 @@ module Repull
311
462
  # @param id [Integer] Internal Repull reservation ID.
312
463
  # @param reservation_update_request [ReservationUpdateRequest]
313
464
  # @param [Hash] opts the optional parameters
314
- # @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged &#x60;Idempotency-Status: cached&#x60; — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → &#x60;409 idempotency_key_in_use&#x60;. - Same key with a DIFFERENT payload → &#x60;422 idempotency_key_reused&#x60;. Generate a new key per distinct request; reuse one only when retrying that exact request. - Responses with status &gt;&#x3D; 500 are deliberately not stored, so a server error stays retryable.
465
+ # @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged &#x60;Idempotency-Status: cached&#x60; — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → &#x60;409 idempotency_key_in_use&#x60;. - Same key with a DIFFERENT payload → &#x60;422 idempotency_key_reused&#x60;. Generate a new key per distinct request; reuse one only when retrying that exact request. - Retryable outcomes are deliberately not stored, so a retry with the same key runs for real: any status &gt;&#x3D; 500, &#x60;408&#x60;, &#x60;425&#x60; and &#x60;429&#x60;, and the refusals that happen before anything is done and tell you to fix something outside the request first — &#x60;connection_reauth_required&#x60;, &#x60;listing_inactive&#x60;, and the rate/daily limits. Every other answer, including a final refusal such as &#x60;422 airbnb_rejected&#x60;, is stored and replayed.
315
466
  # @return [Array<(ReservationUpdateResponse, Integer, Hash)>] ReservationUpdateResponse data, response status code and response headers
316
467
  def update_reservation_with_http_info(id, reservation_update_request, opts = {})
317
468
  if @api_client.config.debugging
@@ -547,10 +547,11 @@ module Repull
547
547
  end
548
548
 
549
549
  # Replay webhook delivery
550
- # Re-sends the original payload (same eventId, fresh deliveryId, attempt + 1). A delivery about a listing that is inactive now is not re-sent and answers `403 listing_inactive`; activate the listing first.
550
+ # Re-sends the original payload (same eventId, fresh deliveryId, attempt + 1). A delivery may be replayed at most **3 times per rolling 60 minutes**; the 4th inside that window answers `409 replay_limit_reached` and names the time the next one is allowed. The limit is charged to the original delivery, so replaying the delivery a replay produced draws on the same budget. It is not a lifetime cap — a delivery that has not been replayed for an hour starts fresh. A delivery your endpoint already accepted is not re-sent (it would be a duplicate) and answers `409 delivery_already_succeeded`; send `{\"force\": true}` to replay it anyway, which still counts against the limit. A delivery about a listing that is inactive now is not re-sent and answers `403 listing_inactive`; activate the listing first.
551
551
  # @param id [String]
552
552
  # @param delivery_id [String]
553
553
  # @param [Hash] opts the optional parameters
554
+ # @option opts [ReplayWebhookDeliveryRequest] :replay_webhook_delivery_request
554
555
  # @return [nil]
555
556
  def replay_webhook_delivery(id, delivery_id, opts = {})
556
557
  replay_webhook_delivery_with_http_info(id, delivery_id, opts)
@@ -558,10 +559,11 @@ module Repull
558
559
  end
559
560
 
560
561
  # Replay webhook delivery
561
- # Re-sends the original payload (same eventId, fresh deliveryId, attempt + 1). A delivery about a listing that is inactive now is not re-sent and answers &#x60;403 listing_inactive&#x60;; activate the listing first.
562
+ # Re-sends the original payload (same eventId, fresh deliveryId, attempt + 1). A delivery may be replayed at most **3 times per rolling 60 minutes**; the 4th inside that window answers &#x60;409 replay_limit_reached&#x60; and names the time the next one is allowed. The limit is charged to the original delivery, so replaying the delivery a replay produced draws on the same budget. It is not a lifetime cap — a delivery that has not been replayed for an hour starts fresh. A delivery your endpoint already accepted is not re-sent (it would be a duplicate) and answers &#x60;409 delivery_already_succeeded&#x60;; send &#x60;{\&quot;force\&quot;: true}&#x60; to replay it anyway, which still counts against the limit. A delivery about a listing that is inactive now is not re-sent and answers &#x60;403 listing_inactive&#x60;; activate the listing first.
562
563
  # @param id [String]
563
564
  # @param delivery_id [String]
564
565
  # @param [Hash] opts the optional parameters
566
+ # @option opts [ReplayWebhookDeliveryRequest] :replay_webhook_delivery_request
565
567
  # @return [Array<(nil, Integer, Hash)>] nil, response status code and response headers
566
568
  def replay_webhook_delivery_with_http_info(id, delivery_id, opts = {})
567
569
  if @api_client.config.debugging
@@ -585,12 +587,17 @@ module Repull
585
587
  header_params = opts[:header_params] || {}
586
588
  # HTTP header 'Accept' (if needed)
587
589
  header_params['Accept'] = @api_client.select_header_accept(['application/json']) unless header_params['Accept']
590
+ # HTTP header 'Content-Type'
591
+ content_type = @api_client.select_header_content_type(['application/json'])
592
+ if !content_type.nil?
593
+ header_params['Content-Type'] = content_type
594
+ end
588
595
 
589
596
  # form parameters
590
597
  form_params = opts[:form_params] || {}
591
598
 
592
599
  # http body (model)
593
- post_body = opts[:debug_body]
600
+ post_body = opts[:debug_body] || @api_client.object_to_http_body(opts[:'replay_webhook_delivery_request'])
594
601
 
595
602
  # return_type
596
603
  return_type = opts[:debug_return_type]