repull 0.2.9 → 0.2.14

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 (376) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/lib/repull/api/airbnb_api.rb +1703 -196
  4. data/lib/repull/api/atlas_api.rb +5 -5
  5. data/lib/repull/api/availability_api.rb +241 -0
  6. data/lib/repull/api/billing_api.rb +227 -1
  7. data/lib/repull/api/booking_com_api.rb +777 -31
  8. data/lib/repull/api/connect_api.rb +761 -8
  9. data/lib/repull/api/conversations_api.rb +92 -11
  10. data/lib/repull/api/guests_api.rb +82 -7
  11. data/lib/repull/api/health_api.rb +318 -0
  12. data/lib/repull/api/kv_api.rb +1 -1
  13. data/lib/repull/api/listings_api.rb +303 -24
  14. data/lib/repull/api/markets_api.rb +3 -3
  15. data/lib/repull/api/plumguide_api.rb +262 -9
  16. data/lib/repull/api/pricing_api.rb +15 -15
  17. data/lib/repull/api/properties_api.rb +12 -9
  18. data/lib/repull/api/quotes_api.rb +109 -0
  19. data/lib/repull/api/reservations_api.rb +166 -7
  20. data/lib/repull/api/reviews_api.rb +81 -7
  21. data/lib/repull/api/schema_api.rb +1 -1
  22. data/lib/repull/api/system_api.rb +1 -1
  23. data/lib/repull/api/vrbo_api.rb +10 -10
  24. data/lib/repull/api/webhooks_api.rb +11 -9
  25. data/lib/repull/api_client.rb +1 -1
  26. data/lib/repull/api_error.rb +1 -1
  27. data/lib/repull/api_model_base.rb +1 -1
  28. data/lib/repull/configuration.rb +1 -1
  29. data/lib/repull/models/account_created_event.rb +1 -1
  30. data/lib/repull/models/account_created_payload.rb +1 -1
  31. data/lib/repull/models/account_disconnected_event.rb +1 -1
  32. data/lib/repull/models/account_disconnected_payload.rb +1 -1
  33. data/lib/repull/models/acknowledge_booking_reservations_request.rb +176 -0
  34. data/lib/repull/models/ai_operation.rb +1 -1
  35. data/lib/repull/models/ai_operation_completed_event.rb +1 -1
  36. data/lib/repull/models/ai_operation_completed_payload.rb +1 -1
  37. data/lib/repull/models/ai_operation_failed_event.rb +1 -1
  38. data/lib/repull/models/ai_operation_failed_payload.rb +1 -1
  39. data/lib/repull/models/ai_operation_failed_payload_error.rb +1 -1
  40. data/lib/repull/models/airbnb_alteration.rb +335 -0
  41. data/lib/repull/models/airbnb_amenity.rb +171 -0
  42. data/lib/repull/models/airbnb_availability_write_request.rb +20 -1
  43. data/lib/repull/models/airbnb_calendar_operation.rb +97 -8
  44. data/lib/repull/models/airbnb_connection.rb +4 -4
  45. data/lib/repull/models/airbnb_connection_accessibility_amenities_inner.rb +1 -1
  46. data/lib/repull/models/airbnb_connection_amenities_inner.rb +1 -1
  47. data/lib/repull/models/airbnb_connection_host.rb +1 -1
  48. data/lib/repull/models/airbnb_connection_response.rb +1 -1
  49. data/lib/repull/models/airbnb_connection_summary.rb +1 -1
  50. data/lib/repull/models/airbnb_data_freshness.rb +3 -3
  51. data/lib/repull/models/airbnb_listing.rb +2 -2
  52. data/lib/repull/models/airbnb_listing_action_request.rb +1 -1
  53. data/lib/repull/models/airbnb_listing_list_response.rb +2 -2
  54. data/lib/repull/models/airbnb_pricing_write_request.rb +54 -3
  55. data/lib/repull/models/airbnb_pricing_write_request_records_inner.rb +236 -0
  56. data/lib/repull/models/airbnb_reservation.rb +1 -1
  57. data/lib/repull/models/airbnb_reservation_list_response.rb +2 -2
  58. data/lib/repull/models/airbnb_review.rb +1 -1
  59. data/lib/repull/models/airbnb_review_list_response.rb +1 -1
  60. data/lib/repull/models/airbnb_thread.rb +1 -1
  61. data/lib/repull/models/airbnb_thread_list_response.rb +1 -1
  62. data/lib/repull/models/airbnb_transaction.rb +502 -0
  63. data/lib/repull/models/airbnb_transaction_guest_breakdown.rb +171 -0
  64. data/lib/repull/models/airbnb_transaction_host_breakdown.rb +246 -0
  65. data/lib/repull/models/airbnb_transaction_payout.rb +175 -0
  66. data/lib/repull/models/alteration_change.rb +161 -0
  67. data/lib/repull/models/alteration_webhook_object.rb +296 -0
  68. data/lib/repull/models/availability_batch_write_request.rb +296 -0
  69. data/lib/repull/models/availability_write_request.rb +259 -0
  70. data/lib/repull/models/availability_write_result.rb +178 -0
  71. data/lib/repull/models/availability_write_result_synced.rb +176 -0
  72. data/lib/repull/models/availability_write_settings.rb +215 -0
  73. data/lib/repull/models/booking_availability_state_response.rb +149 -0
  74. data/lib/repull/models/booking_availability_update.rb +1 -1
  75. data/lib/repull/models/booking_availability_update_request.rb +1 -1
  76. data/lib/repull/models/booking_availability_update_request_property_id.rb +1 -1
  77. data/lib/repull/models/booking_availability_update_request_updates_inner.rb +1 -1
  78. data/lib/repull/models/booking_connect_listing_option.rb +1 -1
  79. data/lib/repull/models/booking_connect_room.rb +1 -1
  80. data/lib/repull/models/booking_connect_rooms_response.rb +39 -5
  81. data/lib/repull/models/booking_conversation.rb +1 -1
  82. data/lib/repull/models/booking_pricing_rate_update.rb +1 -1
  83. data/lib/repull/models/booking_pricing_rate_update_date_range.rb +1 -1
  84. data/lib/repull/models/booking_pricing_rate_update_restrictions.rb +1 -1
  85. data/lib/repull/models/booking_pricing_response.rb +1 -1
  86. data/lib/repull/models/booking_pricing_update_request.rb +1 -1
  87. data/lib/repull/models/booking_pricing_update_response.rb +1 -1
  88. data/lib/repull/models/booking_property.rb +1 -1
  89. data/lib/repull/models/booking_reservation.rb +277 -0
  90. data/lib/repull/models/booking_reservation_room.rb +271 -0
  91. data/lib/repull/models/booking_room_mapping.rb +18 -8
  92. data/lib/repull/models/booking_rooms_rates_response.rb +170 -0
  93. data/lib/repull/models/booking_rooms_rates_response_rooms_inner.rb +170 -0
  94. data/lib/repull/models/booking_rooms_rates_response_rooms_inner_rates_inner.rb +212 -0
  95. data/lib/repull/models/booking_setup_request.rb +220 -0
  96. data/lib/repull/models/booking_verify_hotel_request.rb +1 -1
  97. data/lib/repull/models/booking_verify_hotel_response.rb +40 -6
  98. data/lib/repull/models/bulk_pricing_failure.rb +1 -1
  99. data/lib/repull/models/bulk_pricing_item.rb +1 -1
  100. data/lib/repull/models/bulk_pricing_request.rb +1 -1
  101. data/lib/repull/models/bulk_pricing_response.rb +1 -1
  102. data/lib/repull/models/calendar_day.rb +1 -1
  103. data/lib/repull/models/calendar_response.rb +1 -1
  104. data/lib/repull/models/calendar_updated_event.rb +1 -1
  105. data/lib/repull/models/calendar_updated_payload.rb +1 -1
  106. data/lib/repull/models/calendar_updated_payload_range.rb +1 -1
  107. data/lib/repull/models/clear_kv200_response.rb +1 -1
  108. data/lib/repull/models/connect_host.rb +1 -1
  109. data/lib/repull/models/connect_provider.rb +1 -1
  110. data/lib/repull/models/connect_provider_list_response.rb +1 -1
  111. data/lib/repull/models/connect_session.rb +1 -1
  112. data/lib/repull/models/connect_status.rb +18 -6
  113. data/lib/repull/models/connect_status_accounts_inner.rb +188 -0
  114. data/lib/repull/models/connection.rb +1 -1
  115. data/lib/repull/models/connection_list_response.rb +1 -1
  116. data/lib/repull/models/conversation.rb +13 -2
  117. data/lib/repull/models/conversation_detail.rb +13 -2
  118. data/lib/repull/models/conversation_guest.rb +1 -1
  119. data/lib/repull/models/conversation_guest_contact.rb +1 -1
  120. data/lib/repull/models/conversation_host.rb +1 -1
  121. data/lib/repull/models/conversation_list_response.rb +1 -1
  122. data/lib/repull/models/conversation_message_attachment.rb +1 -1
  123. data/lib/repull/models/create_airbnb_alteration_request.rb +195 -0
  124. data/lib/repull/models/create_airbnb_offer_request.rb +211 -0
  125. data/lib/repull/models/create_billing_checkout_request.rb +1 -1
  126. data/lib/repull/models/create_booking_webhook_request.rb +192 -0
  127. data/lib/repull/models/create_connect_session_request.rb +1 -1
  128. data/lib/repull/models/create_connection_request.rb +2 -2
  129. data/lib/repull/models/create_webhook_request.rb +1 -1
  130. data/lib/repull/models/custom_schema.rb +1 -1
  131. data/lib/repull/models/custom_schema_create.rb +1 -1
  132. data/lib/repull/models/custom_schema_create_response.rb +1 -1
  133. data/lib/repull/models/custom_schema_delete_response.rb +1 -1
  134. data/lib/repull/models/custom_schema_list_response.rb +1 -1
  135. data/lib/repull/models/custom_schema_summary.rb +1 -1
  136. data/lib/repull/models/custom_schema_update.rb +1 -1
  137. data/lib/repull/models/{studio_error.rb → delete_airbnb_listing_photo200_response.rb} +11 -12
  138. data/lib/repull/models/delete_connection200_response.rb +234 -0
  139. data/lib/repull/models/delete_kv200_response.rb +1 -1
  140. data/lib/repull/models/error.rb +1 -1
  141. data/lib/repull/models/error_error.rb +14 -2
  142. data/lib/repull/models/error_error_support.rb +1 -1
  143. data/lib/repull/models/get_airbnb_alteration200_response.rb +190 -0
  144. data/lib/repull/models/get_airbnb_checkin_guide200_response.rb +192 -0
  145. data/lib/repull/models/get_airbnb_listing_quality200_response.rb +177 -0
  146. data/lib/repull/models/get_airbnb_listing_settings200_response.rb +177 -0
  147. data/lib/repull/models/{sandbox_fixture_ref.rb → get_airbnb_thread200_response.rb} +35 -38
  148. data/lib/repull/models/get_health200_response.rb +1 -1
  149. data/lib/repull/models/{vrbo_listing_list_response.rb → get_usage_logs200_response.rb} +18 -9
  150. data/lib/repull/models/get_usage_logs200_response_data_inner.rb +264 -0
  151. data/lib/repull/models/get_usage_logs200_response_pagination.rb +166 -0
  152. data/lib/repull/models/get_usage_summary200_response.rb +232 -0
  153. data/lib/repull/models/get_usage_summary200_response_breakdown_inner.rb +183 -0
  154. data/lib/repull/models/get_usage_summary200_response_limits.rb +158 -0
  155. data/lib/repull/models/get_usage_summary200_response_remaining.rb +158 -0
  156. data/lib/repull/models/get_usage_summary200_response_status_distribution.rb +174 -0
  157. data/lib/repull/models/get_usage_summary200_response_timeline_inner.rb +165 -0
  158. data/lib/repull/models/get_usage_summary200_response_totals.rb +165 -0
  159. data/lib/repull/models/get_usage_summary200_response_used.rb +156 -0
  160. data/lib/repull/models/get_usage_tier200_response.rb +183 -0
  161. data/lib/repull/models/get_usage_tier200_response_limits.rb +168 -0
  162. data/lib/repull/models/get_usage_tier200_response_remaining.rb +168 -0
  163. data/lib/repull/models/get_usage_tier200_response_used.rb +165 -0
  164. data/lib/repull/models/guest.rb +1 -1
  165. data/lib/repull/models/guest_contact.rb +1 -1
  166. data/lib/repull/models/guest_create_request.rb +250 -0
  167. data/lib/repull/models/guest_create_response.rb +227 -0
  168. data/lib/repull/models/guest_create_response_contacts_inner.rb +199 -0
  169. data/lib/repull/models/guest_flag.rb +1 -1
  170. data/lib/repull/models/guest_list_response.rb +1 -1
  171. data/lib/repull/models/guest_note.rb +1 -1
  172. data/lib/repull/models/guest_profile.rb +1 -1
  173. data/lib/repull/models/guest_reservations_summary.rb +1 -1
  174. data/lib/repull/models/list_airbnb_alterations200_response.rb +192 -0
  175. data/lib/repull/models/list_airbnb_listing_amenities200_response.rb +190 -0
  176. data/lib/repull/models/list_airbnb_listing_amenities200_response_data.rb +160 -0
  177. data/lib/repull/models/list_airbnb_transactions200_response.rb +192 -0
  178. data/lib/repull/models/list_booking_reservations200_response.rb +104 -0
  179. data/lib/repull/models/list_kv200_response.rb +1 -1
  180. data/lib/repull/models/list_kv200_response_data_inner.rb +1 -1
  181. data/lib/repull/models/list_kv200_response_pagination.rb +2 -2
  182. data/lib/repull/models/listing.rb +2 -2
  183. data/lib/repull/models/listing_active_request.rb +2 -2
  184. data/lib/repull/models/listing_active_response.rb +1 -1
  185. data/lib/repull/models/listing_address.rb +1 -1
  186. data/lib/repull/models/listing_amenity.rb +1 -1
  187. data/lib/repull/models/listing_channel.rb +1 -1
  188. data/lib/repull/models/listing_comp.rb +1 -1
  189. data/lib/repull/models/listing_comp_nightly.rb +1 -1
  190. data/lib/repull/models/listing_comp_ratings.rb +1 -1
  191. data/lib/repull/models/listing_comps_response.rb +1 -1
  192. data/lib/repull/models/listing_content.rb +1 -1
  193. data/lib/repull/models/listing_content_update_request.rb +1 -1
  194. data/lib/repull/models/listing_content_update_request_address.rb +1 -1
  195. data/lib/repull/models/listing_content_update_request_amenities.rb +1 -1
  196. data/lib/repull/models/listing_content_update_request_amenities_one_of_inner.rb +1 -1
  197. data/lib/repull/models/listing_content_update_request_occupancy.rb +1 -1
  198. data/lib/repull/models/listing_content_update_request_photos_inner.rb +1 -1
  199. data/lib/repull/models/listing_content_update_request_photos_inner_one_of.rb +1 -1
  200. data/lib/repull/models/listing_content_update_request_policies.rb +1 -1
  201. data/lib/repull/models/listing_content_update_response.rb +1 -1
  202. data/lib/repull/models/listing_create_request.rb +1 -1
  203. data/lib/repull/models/listing_create_response.rb +1 -1
  204. data/lib/repull/models/listing_created_event.rb +1 -1
  205. data/lib/repull/models/listing_created_payload.rb +1 -1
  206. data/lib/repull/models/listing_created_payload_address.rb +1 -1
  207. data/lib/repull/models/listing_deleted_event.rb +1 -1
  208. data/lib/repull/models/listing_deleted_payload.rb +1 -1
  209. data/lib/repull/models/listing_details.rb +1 -1
  210. data/lib/repull/models/listing_generate_content_request.rb +1 -1
  211. data/lib/repull/models/listing_generate_content_response.rb +1 -1
  212. data/lib/repull/models/listing_list_response.rb +1 -1
  213. data/lib/repull/models/{studio_file.rb → listing_photo.rb} +23 -34
  214. data/lib/repull/models/listing_photo_delete_request.rb +165 -0
  215. data/lib/repull/models/listing_photo_delete_response.rb +156 -0
  216. data/lib/repull/models/listing_photo_upload_url_request.rb +203 -0
  217. data/lib/repull/models/listing_photo_upload_url_response.rb +198 -0
  218. data/lib/repull/models/{booking_property_list_response.rb → listing_photos_response.rb} +19 -19
  219. data/lib/repull/models/listing_pricing_apply_request.rb +1 -1
  220. data/lib/repull/models/listing_pricing_apply_response.rb +1 -1
  221. data/lib/repull/models/listing_pricing_history_entry.rb +2 -2
  222. data/lib/repull/models/listing_pricing_history_response.rb +1 -1
  223. data/lib/repull/models/listing_pricing_recommendation.rb +1 -1
  224. data/lib/repull/models/listing_pricing_response.rb +1 -1
  225. data/lib/repull/models/listing_pricing_response_comp_summary.rb +1 -1
  226. data/lib/repull/models/listing_pricing_response_date_range.rb +1 -1
  227. data/lib/repull/models/listing_pricing_response_listing.rb +1 -1
  228. data/lib/repull/models/listing_pricing_strategy.rb +1 -1
  229. data/lib/repull/models/listing_pricing_strategy_input.rb +1 -1
  230. data/lib/repull/models/listing_publish_airbnb_request.rb +1 -1
  231. data/lib/repull/models/listing_publish_response.rb +1 -1
  232. data/lib/repull/models/listing_publish_status_channel.rb +1 -1
  233. data/lib/repull/models/listing_publish_status_connection.rb +1 -1
  234. data/lib/repull/models/listing_publish_status_response.rb +1 -1
  235. data/lib/repull/models/listing_quality_tier.rb +1 -1
  236. data/lib/repull/models/listing_segment.rb +1 -1
  237. data/lib/repull/models/listing_segment_recommendation.rb +1 -1
  238. data/lib/repull/models/listing_segments_response.rb +1 -1
  239. data/lib/repull/models/listing_segments_response_scope.rb +1 -1
  240. data/lib/repull/models/listing_status_batch_request.rb +212 -0
  241. data/lib/repull/models/listing_status_batch_response.rb +223 -0
  242. data/lib/repull/models/listing_updated_event.rb +1 -1
  243. data/lib/repull/models/listing_updated_payload.rb +1 -1
  244. data/lib/repull/models/map_airbnb_listing_request.rb +1 -1
  245. data/lib/repull/models/map_airbnb_listing_response.rb +1 -1
  246. data/lib/repull/models/map_connect_booking_rooms_request.rb +1 -1
  247. data/lib/repull/models/map_connect_booking_rooms_response.rb +16 -5
  248. data/lib/repull/models/market_browse_category.rb +1 -1
  249. data/lib/repull/models/market_browse_entry.rb +1 -1
  250. data/lib/repull/models/market_browse_featured.rb +1 -1
  251. data/lib/repull/models/market_browse_response.rb +1 -1
  252. data/lib/repull/models/market_calendar_day.rb +1 -1
  253. data/lib/repull/models/market_calendar_day_events_inner.rb +1 -1
  254. data/lib/repull/models/market_calendar_response.rb +1 -1
  255. data/lib/repull/models/market_detail_response.rb +1 -1
  256. data/lib/repull/models/market_detail_response_price_distribution_inner.rb +1 -1
  257. data/lib/repull/models/market_detail_response_property_type_mix_inner.rb +1 -1
  258. data/lib/repull/models/market_detail_response_supply_trend_inner.rb +1 -1
  259. data/lib/repull/models/market_detail_response_top_comps.rb +1 -1
  260. data/lib/repull/models/market_event.rb +1 -1
  261. data/lib/repull/models/market_my_listing.rb +1 -1
  262. data/lib/repull/models/market_summary.rb +1 -1
  263. data/lib/repull/models/market_top_comp.rb +1 -1
  264. data/lib/repull/models/markets_overview_response.rb +1 -1
  265. data/lib/repull/models/markets_overview_response_browse.rb +1 -1
  266. data/lib/repull/models/markets_overview_response_subscriptions.rb +1 -1
  267. data/lib/repull/models/markets_overview_response_totals.rb +1 -1
  268. data/lib/repull/models/message.rb +1 -1
  269. data/lib/repull/models/message_list_response.rb +1 -1
  270. data/lib/repull/models/pagination.rb +1 -1
  271. data/lib/repull/models/payment_completed_event.rb +1 -1
  272. data/lib/repull/models/payment_completed_payload.rb +1 -1
  273. data/lib/repull/models/payment_refunded_event.rb +1 -1
  274. data/lib/repull/models/payment_refunded_payload.rb +1 -1
  275. data/lib/repull/models/plumguide_listing.rb +1 -1
  276. data/lib/repull/models/plumguide_listing_list_response.rb +1 -1
  277. data/lib/repull/models/property.rb +17 -7
  278. data/lib/repull/models/property_availability.rb +248 -0
  279. data/lib/repull/models/property_availability_coverage.rb +222 -0
  280. data/lib/repull/models/property_availability_day.rb +247 -0
  281. data/lib/repull/models/property_list_response.rb +1 -1
  282. data/lib/repull/models/quote.rb +240 -0
  283. data/lib/repull/models/quote_pricing.rb +218 -0
  284. data/lib/repull/models/reply_booking_review200_response.rb +1 -1
  285. data/lib/repull/models/reply_booking_review_request.rb +1 -1
  286. data/lib/repull/models/reply_to_review201_response.rb +165 -0
  287. data/lib/repull/models/reply_to_review_request.rb +165 -0
  288. data/lib/repull/models/repull_ping_event.rb +1 -1
  289. data/lib/repull/models/repull_ping_payload.rb +1 -1
  290. data/lib/repull/models/reservation.rb +1 -1
  291. data/lib/repull/models/{studio_deployment.rb → reservation_alteration_created_event.rb} +67 -57
  292. data/lib/repull/models/reservation_alteration_created_payload.rb +177 -0
  293. data/lib/repull/models/reservation_alteration_responded_event.rb +217 -0
  294. data/lib/repull/models/reservation_alteration_responded_payload.rb +175 -0
  295. data/lib/repull/models/reservation_cancelled_event.rb +1 -1
  296. data/lib/repull/models/reservation_cancelled_payload.rb +1 -1
  297. data/lib/repull/models/reservation_create_request.rb +403 -0
  298. data/lib/repull/models/reservation_create_response.rb +233 -0
  299. data/lib/repull/models/reservation_created_event.rb +1 -1
  300. data/lib/repull/models/reservation_created_payload.rb +1 -1
  301. data/lib/repull/models/reservation_financials.rb +36 -8
  302. data/lib/repull/models/reservation_guest_financials.rb +173 -0
  303. data/lib/repull/models/reservation_guest_input.rb +193 -0
  304. data/lib/repull/models/reservation_host_financials.rb +207 -0
  305. data/lib/repull/models/reservation_list_response.rb +1 -1
  306. data/lib/repull/models/reservation_message_received_event.rb +1 -1
  307. data/lib/repull/models/reservation_message_received_payload.rb +1 -1
  308. data/lib/repull/models/reservation_message_received_payload_from.rb +1 -1
  309. data/lib/repull/models/reservation_money_line.rb +216 -0
  310. data/lib/repull/models/reservation_occupancy.rb +1 -1
  311. data/lib/repull/models/reservation_primary_guest.rb +1 -1
  312. data/lib/repull/models/reservation_update_request.rb +255 -0
  313. data/lib/repull/models/reservation_update_response.rb +240 -0
  314. data/lib/repull/models/reservation_updated_event.rb +1 -1
  315. data/lib/repull/models/reservation_updated_payload.rb +1 -1
  316. data/lib/repull/models/reservation_webhook_object.rb +1 -1
  317. data/lib/repull/models/respond_airbnb_review_request.rb +1 -1
  318. data/lib/repull/models/review.rb +14 -3
  319. data/lib/repull/models/review_category.rb +1 -1
  320. data/lib/repull/models/{sandbox_reset_result.rb → review_created_event.rb} +59 -59
  321. data/lib/repull/models/review_created_payload.rb +165 -0
  322. data/lib/repull/models/review_list_response.rb +1 -1
  323. data/lib/repull/models/review_responded_event.rb +217 -0
  324. data/lib/repull/models/review_responded_payload.rb +175 -0
  325. data/lib/repull/models/review_response.rb +1 -1
  326. data/lib/repull/models/review_webhook_object.rb +277 -0
  327. data/lib/repull/models/rotate_webhook_secret200_response.rb +1 -1
  328. data/lib/repull/models/select_connect_provider_request.rb +1 -1
  329. data/lib/repull/models/select_provider_response.rb +1 -1
  330. data/lib/repull/models/send_airbnb_message_request.rb +187 -0
  331. data/lib/repull/models/{sandbox_reset_result_deleted.rb → send_booking_message_request.rb} +53 -50
  332. data/lib/repull/models/{studio_error_error.rb → send_message_request.rb} +31 -50
  333. data/lib/repull/models/send_message_response.rb +241 -0
  334. data/lib/repull/models/set_kv_request.rb +1 -1
  335. data/lib/repull/models/{booking_conversation_list_response.rb → submit_beds24_credentials200_response.rb} +19 -19
  336. data/lib/repull/models/submit_beds24_credentials_request.rb +177 -0
  337. data/lib/repull/models/submit_bookingsync_credentials_request.rb +177 -0
  338. data/lib/repull/models/submit_guesty_credentials_request.rb +177 -0
  339. data/lib/repull/models/submit_hospitable_credentials_request.rb +177 -0
  340. data/lib/repull/models/submit_hostaway_credentials_request.rb +177 -0
  341. data/lib/repull/models/submit_igms_credentials_request.rb +177 -0
  342. data/lib/repull/models/submit_lodgify_credentials_request.rb +177 -0
  343. data/lib/repull/models/submit_ownerrez_credentials_request.rb +177 -0
  344. data/lib/repull/models/submit_smoobu_credentials_request.rb +177 -0
  345. data/lib/repull/models/submit_vrbo_credentials_request.rb +177 -0
  346. data/lib/repull/models/sync_airbnb_transactions200_response.rb +191 -0
  347. data/lib/repull/models/sync_airbnb_transactions_request.rb +201 -0
  348. data/lib/repull/models/test_webhook_request.rb +1 -1
  349. data/lib/repull/models/update_airbnb_message_request.rb +209 -0
  350. data/lib/repull/models/update_booking_charges_request.rb +194 -0
  351. data/lib/repull/models/update_listing_pricing_strategy200_response.rb +1 -1
  352. data/lib/repull/models/update_webhook_request.rb +1 -1
  353. data/lib/repull/models/vrbo_listing.rb +1 -1
  354. data/lib/repull/models/vrbo_reservation.rb +1 -1
  355. data/lib/repull/models/vrbo_reservation_list_response.rb +1 -1
  356. data/lib/repull/models/webhook_delivery.rb +1 -1
  357. data/lib/repull/models/webhook_delivery_detail.rb +1 -1
  358. data/lib/repull/models/webhook_delivery_list_response.rb +1 -1
  359. data/lib/repull/models/webhook_event.rb +12 -4
  360. data/lib/repull/models/webhook_event_catalog.rb +1 -1
  361. data/lib/repull/models/webhook_event_catalog_domains_inner.rb +1 -1
  362. data/lib/repull/models/webhook_event_catalog_entry.rb +1 -1
  363. data/lib/repull/models/webhook_event_type.rb +6 -2
  364. data/lib/repull/models/webhook_list_response.rb +1 -1
  365. data/lib/repull/models/webhook_subscription.rb +1 -1
  366. data/lib/repull/version.rb +2 -2
  367. data/lib/repull.rb +111 -15
  368. data/openapi/v1.json +9877 -3482
  369. data/scripts/check-spec-freshness.py +399 -0
  370. data/scripts/regen.sh +32 -3
  371. metadata +113 -18
  372. data/lib/repull/api/sandbox_api.rb +0 -136
  373. data/lib/repull/models/sandbox_seed_result.rb +0 -278
  374. data/lib/repull/models/studio_generation.rb +0 -215
  375. data/lib/repull/models/studio_project.rb +0 -241
  376. data/spec/api/ai_api_spec.rb +0 -47
@@ -1,7 +1,7 @@
1
1
  =begin
2
2
  #Repull API
3
3
 
4
- #The unified API for vacation rental tech. Connect to 50+ PMS platforms and 4 OTA channels through one REST API. Built-in AI operations for guest communication, pricing, and listing optimization. ## Designed for AI agents Every error response on this API includes machine-parseable fields so an LLM (Claude in MCP, Cursor, Cline, GPT, etc.) can self-recover without escalating to a human: - `error.code` — stable string identifier (e.g. `invalid_params`, `rate_limit_exceeded`) - `error.message` — human-readable cause - `error.fix` — exact recovery steps (e.g. \"Pass `check_in_after` as ISO 8601: `?check_in_after=2026-01-15`\") - `error.docs_url` — link to the canonical write-up at `https://repull.dev/docs/errors/{code}` - `error.request_id` — id to correlate with server-side logs - `error.field` / `error.value_received` / `error.valid_values` / `error.did_you_mean` — when the error is parameter-specific - `error.retry_after` — seconds to wait before retrying (rate-limit + transient upstream) `Access-Control-Expose-Headers` lists `x-request-id` and the `X-RateLimit-*` family so browsers can read them on cross-origin responses. ## Quick Start 1. Get an API key at https://repull.dev/dashboard 2. Connect a PMS: `POST /v1/connect/{provider}` 3. List properties: `GET /v1/properties` 4. Get reservations: `GET /v1/reservations` ## Authentication All requests require a Bearer token: ``` Authorization: Bearer sk_test_YOUR_API_KEY ``` Sandbox keys start with `sk_test_`, production with `sk_live_`. ## Request Correlation (X-Request-ID) Every response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports — we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id. You may set the header on the inbound request to forward your own trace id; we will echo it back instead of generating a new one. Accepted format: `^[\\\\w.-]{1,128}$`. The id is also embedded in error envelopes as `request_id` so server-side log diffs work even when the response headers are stripped by an intermediate proxy. ## Rate Limits The public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas. **Default policy:** 600 requests per 60 seconds, per API key. Sliding window — there is no fixed-minute boundary you can burst across. Every response includes: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests permitted in the current window. | | `X-RateLimit-Remaining` | Requests left in the current window after this call. | | `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. | | `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. | | `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** | **On 429 (rate_limit_exceeded):** the response body matches the standard error envelope with `code: \"rate_limit_exceeded\"`, plus `limit`, `window_seconds`, `retry_after`, and `request_id` fields. SDKs MUST honor `Retry-After` and use exponential backoff with jitter on subsequent retries — never a tight loop. Recommended backoff: ``` sleep_ms = (Retry-After * 1000) + random(0..250) ``` Monthly + daily-AI tier quotas (`free`, `starter`, `custom`) are enforced separately and also surface as 429s; they include `tier`, `scope`, and `resets_at` fields. ## Plan Limits (402 — `listings_limit_exceeded`) The Repull API also enforces a per-tier cap on **active listings**: | Tier | Active listings cap | |---|---| | `free` | 3 | | `starter` | 50 | | `custom` | unlimited | When a customer's active-listing count is above their tier cap, the API returns **`402 Payment Required`** with `error.code = \"listings_limit_exceeded\"` on every route EXCEPT: - `/v1/health` — uptime probes are never gated. - `/v1/usage/*` — so dashboards can render the over-cap state. - Any `DELETE` — so the customer can trim listings to get back under the cap without paying. Unlike 429, 402 is NOT a \"wait and retry\" condition — `Retry-After` is not set. The only paths back to 200 are: 1. `DELETE` enough listings to come back under the cap, or 2. Upgrade at `https://repull.dev/dashboard/billing`. The server-side usage cache is 60s, so the first 200 after an upgrade may take up to a minute. The envelope mirrors `rate_limit_exceeded` for SDK ergonomics: `tier`, `limit`, `active_listings`, `upgrade_url`, plus the standard `code` / `message` / `fix` / `docs_url` / `request_id`.
4
+ #The unified API for vacation rental tech. Connect to 50+ PMS platforms and 4 OTA channels through one REST API. Built-in AI operations for guest communication, pricing, and listing optimization. ## Designed for AI agents Every error response on this API includes machine-parseable fields so an LLM (Claude in MCP, Cursor, Cline, GPT, etc.) can self-recover without escalating to a human: - `error.code` — stable string identifier (e.g. `invalid_params`, `rate_limit_exceeded`) - `error.message` — human-readable cause - `error.fix` — exact recovery steps (e.g. \"Pass `check_in_after` as ISO 8601: `?check_in_after=2026-01-15`\") - `error.docs_url` — link to the canonical write-up at `https://repull.dev/docs/errors/{code}` - `error.request_id` — id to correlate with server-side logs - `error.field` / `error.value_received` / `error.valid_values` / `error.did_you_mean` — when the error is parameter-specific - `error.retry_after` — seconds to wait before retrying (rate-limit + transient upstream) `Access-Control-Expose-Headers` lists `x-request-id` and the `X-RateLimit-*` family so browsers can read them on cross-origin responses. ## Quick Start 1. Get an API key at https://repull.dev/dashboard 2. Connect a PMS: `POST /v1/connect/{provider}` 3. List properties: `GET /v1/properties` 4. Get reservations: `GET /v1/reservations` ## Authentication All requests require a Bearer token: ``` Authorization: Bearer sk_live_YOUR_API_KEY ``` ## Request Correlation (X-Request-ID) Every response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports — we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id. You may set the header on the inbound request to forward your own trace id; we will echo it back instead of generating a new one. Accepted format: `^[\\\\w.-]{1,128}$`. The id is also embedded in error envelopes as `request_id` so server-side log diffs work even when the response headers are stripped by an intermediate proxy. ## Rate Limits The public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas. **Default policy:** 600 requests per 60 seconds, per API key. Sliding window — there is no fixed-minute boundary you can burst across. Every response includes: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests permitted in the current window. | | `X-RateLimit-Remaining` | Requests left in the current window after this call. | | `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. | | `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. | | `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** | **On 429 (rate_limit_exceeded):** the response body matches the standard error envelope with `code: \"rate_limit_exceeded\"`, plus `limit`, `window_seconds`, `retry_after`, and `request_id` fields. SDKs MUST honor `Retry-After` and use exponential backoff with jitter on subsequent retries — never a tight loop. Recommended backoff: ``` sleep_ms = (Retry-After * 1000) + random(0..250) ``` Monthly + daily-AI tier quotas (`free`, `starter`, `custom`) are enforced separately and also surface as 429s; they include `tier`, `scope`, and `resetsAt` fields. ## Plan Limits (402 — `listings_limit_exceeded`) The Repull API also enforces a per-tier cap on **active listings**: | Tier | Active listings cap | |---|---| | `free` | 3 | | `starter` | 50 | | `custom` | unlimited | When a customer's active-listing count is above their tier cap, the API returns **`402 Payment Required`** with `error.code = \"listings_limit_exceeded\"` on every route EXCEPT: - `/v1/health` — uptime probes are never gated. - `/v1/usage/*` — so dashboards can render the over-cap state. - Any `DELETE` — so the customer can trim listings to get back under the cap without paying. Unlike 429, 402 is NOT a \"wait and retry\" condition — `Retry-After` is not set. The only paths back to 200 are: 1. `DELETE` enough listings to come back under the cap, or 2. Upgrade at `https://repull.dev/dashboard/billing`. The server-side usage cache is 60s, so the first 200 after an upgrade may take up to a minute. The envelope mirrors `rate_limit_exceeded` for SDK ergonomics: `tier`, `limit`, `active_listings`, `upgrade_url`, plus the standard `code` / `message` / `fix` / `docs_url` / `request_id`.
5
5
 
6
6
  The version of the OpenAPI document: 1.0.0
7
7
  Contact: ivan@vanio.ai
@@ -20,7 +20,7 @@ module Repull
20
20
  @api_client = api_client
21
21
  end
22
22
  # Get property details
23
- # Fetch a single property by Repull id. Property ids are workspace-scoped — an id from one workspace is not valid in another. 404 means the id does not exist OR belongs to a different workspace. **Optional expansions:** Pass `?include=amenities` to enrich the response with the property's amenities (sourced from the unified `listings_amenities` table). Returns `[]` when the property has no amenity rows. The default response stays lean; consumers must opt in.
23
+ # Fetch a single property by Repull id. Property ids are workspace-scoped — an id from one workspace is not valid in another. 404 means the id does not exist OR belongs to a different workspace. **Optional expansions:** Pass `?include=amenities` to enrich the response with the property's amenities (sourced from the unified `listings_amenities` table). Returns `[]` when the property has no amenity rows. The default response stays lean; consumers must opt in. 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
24
  # @param id [Integer]
25
25
  # @param [Hash] opts the optional parameters
26
26
  # @option opts [String] :include Comma-separated optional expansions. Currently supported: `amenities`. Unknown values return 422.
@@ -31,7 +31,7 @@ module Repull
31
31
  end
32
32
 
33
33
  # Get property details
34
- # Fetch a single property by Repull id. Property ids are workspace-scoped — an id from one workspace is not valid in another. 404 means the id does not exist OR belongs to a different workspace. **Optional expansions:** Pass `?include=amenities` to enrich the response with the property's amenities (sourced from the unified `listings_amenities` table). Returns `[]` when the property has no amenity rows. The default response stays lean; consumers must opt in.
34
+ # Fetch a single property by Repull id. Property ids are workspace-scoped — an id from one workspace is not valid in another. 404 means the id does not exist OR belongs to a different workspace. **Optional expansions:** Pass `?include=amenities` to enrich the response with the property's amenities (sourced from the unified `listings_amenities` table). Returns `[]` when the property has no amenity rows. The default response stays lean; consumers must opt in. 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.
35
35
  # @param id [Integer]
36
36
  # @param [Hash] opts the optional parameters
37
37
  # @option opts [String] :include Comma-separated optional expansions. Currently supported: `amenities`. Unknown values return 422.
@@ -90,15 +90,16 @@ module Repull
90
90
  end
91
91
 
92
92
  # List properties
93
- # Cursor-paginated list of properties for the authenticated workspace. Walk pages with `?cursor=<pagination.nextCursor>`; stop when `pagination.hasMore` is `false`. Cursor is opaque base64 — do not parse it. `?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` (active|inactive|all), `lifecycle_status` (exact match on the listing's lifecycle state). Other unknown params (e.g. `?search=` or `?propertyId=`) are rejected with 422 — no silent unfiltered results.
93
+ # Cursor-paginated list of properties for the authenticated workspace. Walk pages with `?cursor=<pagination.nextCursor>`; stop when `pagination.hasMore` is `false`. Cursor is opaque base64 — do not parse it. `?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` (active|inactive|all), `lifecycle_status` (exact match on the listing's lifecycle state). Other unknown params (e.g. `?search=` or `?propertyId=`) are rejected with 422 — no silent unfiltered results. **Incremental sync (only changes since last poll):** pass `?updated_since=<ISO8601>` to receive only properties changed at or after that instant. Each property carries `updatedAt` — the last row of the final page is your next watermark. `updated_since` changes the page ordering to `updatedAt ASC, id ASC` (and the cursor with it); see the parameter description. `GET /v1/listings` does NOT yet accept `updated_since` — use this endpoint for property-side incremental sync. **Inactive properties:** an inactive property keeps syncing, but cannot be read or changed through the API until it is activated. They are only listed when `status` asks for them, and then with `id`, `name`, `status`, `lifecycleStatus`, `channels` and `updatedAt` only — enough to choose what to activate with `PATCH /v1/listings/{id}`.
94
94
  # @param [Hash] opts the optional parameters
95
95
  # @option opts [Integer] :limit Page size (max 100). Requests over the cap return 422. (default to 50)
96
96
  # @option opts [String] :cursor Opaque cursor returned in the previous response&#39;s &#x60;pagination.nextCursor&#x60;. Omit to fetch the first page.
97
- # @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.next_cursor&#x60; so consumers can switch from offset → cursor mid-walk for deep pagination without re-keying. (default to 0)
97
+ # @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)
98
98
  # @option opts [String] :q Case-insensitive substring search on name, street, or city.
99
- # @option opts [String] :status Filter by status. Default returns active only; pass &#x60;inactive&#x60; to invert or &#x60;all&#x60; to include both. (default to 'active')
99
+ # @option opts [String] :status Filter by status. Default returns active only; pass &#x60;inactive&#x60; to invert or &#x60;all&#x60; to include both. Inactive properties carry identity fields only — &#x60;id&#x60;, &#x60;name&#x60;, &#x60;status&#x60;, &#x60;lifecycleStatus&#x60;, &#x60;channels&#x60; and &#x60;updatedAt&#x60; — never &#x60;address&#x60;, &#x60;city&#x60; or &#x60;currency&#x60;. (default to 'active')
100
100
  # @option opts [String] :lifecycle_status Filter by lifecycle status (e.g. &#x60;live&#x60;, &#x60;draft&#x60;, &#x60;archived&#x60;). Pass &#x60;all&#x60; to disable the filter.
101
101
  # @option opts [String] :channel Filter to properties with an active link on the given OTA/channel (airbnb, booking, vrbo). Omit to include every channel. Each property also returns a &#x60;channels&#x60; array listing the OTAs it is published on.
102
+ # @option opts [Time] :updated_since Incremental sync: return only records whose &#x60;updatedAt&#x60; is at or after this instant. This is the only filter on record **mutation** time — every &#x60;check_*&#x60; filter targets guest **stay** dates. **Accepted formats.** ISO 8601, with &#x60;Z&#x60; or a numeric offset — both work: - &#x60;2026-08-01T00:00:00Z&#x60; - &#x60;2026-08-01T00:00:00.123Z&#x60; - &#x60;2026-08-01T00:00:00+00:00&#x60; - &#x60;2026-08-01T02:30:00-07:00&#x60; (offset colon optional: &#x60;-0700&#x60;) - &#x60;2026-08-01T00:00&#x60; (seconds optional) - &#x60;2026-08-01T00:00:00&#x60; — no zone designator, interpreted as **UTC** - &#x60;2026-08-01&#x60; — date only, means midnight UTC Anything else returns 422 &#x60;invalid_params&#x60; naming the field; the value is never silently ignored. **Ordering changes when you pass this.** Results are ordered &#x60;updatedAt ASC, id ASC&#x60; (instead of the endpoint default) and the cursor keys on the same pair. That is required for correctness: under the default ordering a record amended mid-walk can move behind the cursor and never be emitted — which is exactly the event you are polling for. Ascending mutation time is monotonic with the cursor, so anything touched during a walk resurfaces later in it or on the next poll. **Cursors are not interchangeable between the two orderings.** Keep &#x60;updated_since&#x60; on every page of an incremental walk; replaying a cursor from the other ordering returns 422 rather than a page that silently skips rows. **Watermark.** The bound is inclusive (&#x60;updatedAt &gt;&#x3D; value&#x60;), so the last row of the final page is the watermark for the next poll — re-polling with it re-emits that row. Delivery is at-least-once; upsert by &#x60;id&#x60;.
102
103
  # @option opts [Boolean] :include_total When &#x60;true&#x60; (default), the response&#39;s &#x60;pagination.total&#x60; carries the count of rows matching the current filter, across all pages. Pass &#x60;false&#x60; to skip the count for very large workspaces where the per-page COUNT(*) cost matters. (default to true)
103
104
  # @return [PropertyListResponse]
104
105
  def list_properties(opts = {})
@@ -107,15 +108,16 @@ module Repull
107
108
  end
108
109
 
109
110
  # List properties
110
- # Cursor-paginated list of properties for the authenticated workspace. Walk pages with &#x60;?cursor&#x3D;&lt;pagination.nextCursor&gt;&#x60;; stop when &#x60;pagination.hasMore&#x60; is &#x60;false&#x60;. Cursor is opaque base64 — do not parse it. &#x60;?offset&#x3D;&#x60; is also accepted as a first-class alias for shallow paging (0..10000) — see the &#x60;offset&#x60; parameter below. Mutually exclusive with &#x60;cursor&#x60;. Filters: &#x60;q&#x60; (substring on name/street/city), &#x60;status&#x60; (active|inactive|all), &#x60;lifecycle_status&#x60; (exact match on the listing&#39;s lifecycle state). Other unknown params (e.g. &#x60;?search&#x3D;&#x60; or &#x60;?propertyId&#x3D;&#x60;) are rejected with 422 — no silent unfiltered results.
111
+ # Cursor-paginated list of properties for the authenticated workspace. Walk pages with &#x60;?cursor&#x3D;&lt;pagination.nextCursor&gt;&#x60;; stop when &#x60;pagination.hasMore&#x60; is &#x60;false&#x60;. Cursor is opaque base64 — do not parse it. &#x60;?offset&#x3D;&#x60; is also accepted as a first-class alias for shallow paging (0..10000) — see the &#x60;offset&#x60; parameter below. Mutually exclusive with &#x60;cursor&#x60;. Filters: &#x60;q&#x60; (substring on name/street/city), &#x60;status&#x60; (active|inactive|all), &#x60;lifecycle_status&#x60; (exact match on the listing&#39;s lifecycle state). Other unknown params (e.g. &#x60;?search&#x3D;&#x60; or &#x60;?propertyId&#x3D;&#x60;) are rejected with 422 — no silent unfiltered results. **Incremental sync (only changes since last poll):** pass &#x60;?updated_since&#x3D;&lt;ISO8601&gt;&#x60; to receive only properties changed at or after that instant. Each property carries &#x60;updatedAt&#x60; — the last row of the final page is your next watermark. &#x60;updated_since&#x60; changes the page ordering to &#x60;updatedAt ASC, id ASC&#x60; (and the cursor with it); see the parameter description. &#x60;GET /v1/listings&#x60; does NOT yet accept &#x60;updated_since&#x60; — use this endpoint for property-side incremental sync. **Inactive properties:** an inactive property keeps syncing, but cannot be read or changed through the API until it is activated. They are only listed when &#x60;status&#x60; asks for them, and then with &#x60;id&#x60;, &#x60;name&#x60;, &#x60;status&#x60;, &#x60;lifecycleStatus&#x60;, &#x60;channels&#x60; and &#x60;updatedAt&#x60; only — enough to choose what to activate with &#x60;PATCH /v1/listings/{id}&#x60;.
111
112
  # @param [Hash] opts the optional parameters
112
113
  # @option opts [Integer] :limit Page size (max 100). Requests over the cap return 422. (default to 50)
113
114
  # @option opts [String] :cursor Opaque cursor returned in the previous response&#39;s &#x60;pagination.nextCursor&#x60;. Omit to fetch the first page.
114
- # @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.next_cursor&#x60; so consumers can switch from offset → cursor mid-walk for deep pagination without re-keying. (default to 0)
115
+ # @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)
115
116
  # @option opts [String] :q Case-insensitive substring search on name, street, or city.
116
- # @option opts [String] :status Filter by status. Default returns active only; pass &#x60;inactive&#x60; to invert or &#x60;all&#x60; to include both. (default to 'active')
117
+ # @option opts [String] :status Filter by status. Default returns active only; pass &#x60;inactive&#x60; to invert or &#x60;all&#x60; to include both. Inactive properties carry identity fields only — &#x60;id&#x60;, &#x60;name&#x60;, &#x60;status&#x60;, &#x60;lifecycleStatus&#x60;, &#x60;channels&#x60; and &#x60;updatedAt&#x60; — never &#x60;address&#x60;, &#x60;city&#x60; or &#x60;currency&#x60;. (default to 'active')
117
118
  # @option opts [String] :lifecycle_status Filter by lifecycle status (e.g. &#x60;live&#x60;, &#x60;draft&#x60;, &#x60;archived&#x60;). Pass &#x60;all&#x60; to disable the filter.
118
119
  # @option opts [String] :channel Filter to properties with an active link on the given OTA/channel (airbnb, booking, vrbo). Omit to include every channel. Each property also returns a &#x60;channels&#x60; array listing the OTAs it is published on.
120
+ # @option opts [Time] :updated_since Incremental sync: return only records whose &#x60;updatedAt&#x60; is at or after this instant. This is the only filter on record **mutation** time — every &#x60;check_*&#x60; filter targets guest **stay** dates. **Accepted formats.** ISO 8601, with &#x60;Z&#x60; or a numeric offset — both work: - &#x60;2026-08-01T00:00:00Z&#x60; - &#x60;2026-08-01T00:00:00.123Z&#x60; - &#x60;2026-08-01T00:00:00+00:00&#x60; - &#x60;2026-08-01T02:30:00-07:00&#x60; (offset colon optional: &#x60;-0700&#x60;) - &#x60;2026-08-01T00:00&#x60; (seconds optional) - &#x60;2026-08-01T00:00:00&#x60; — no zone designator, interpreted as **UTC** - &#x60;2026-08-01&#x60; — date only, means midnight UTC Anything else returns 422 &#x60;invalid_params&#x60; naming the field; the value is never silently ignored. **Ordering changes when you pass this.** Results are ordered &#x60;updatedAt ASC, id ASC&#x60; (instead of the endpoint default) and the cursor keys on the same pair. That is required for correctness: under the default ordering a record amended mid-walk can move behind the cursor and never be emitted — which is exactly the event you are polling for. Ascending mutation time is monotonic with the cursor, so anything touched during a walk resurfaces later in it or on the next poll. **Cursors are not interchangeable between the two orderings.** Keep &#x60;updated_since&#x60; on every page of an incremental walk; replaying a cursor from the other ordering returns 422 rather than a page that silently skips rows. **Watermark.** The bound is inclusive (&#x60;updatedAt &gt;&#x3D; value&#x60;), so the last row of the final page is the watermark for the next poll — re-polling with it re-emits that row. Delivery is at-least-once; upsert by &#x60;id&#x60;.
119
121
  # @option opts [Boolean] :include_total When &#x60;true&#x60; (default), the response&#39;s &#x60;pagination.total&#x60; carries the count of rows matching the current filter, across all pages. Pass &#x60;false&#x60; to skip the count for very large workspaces where the per-page COUNT(*) cost matters. (default to true)
120
122
  # @return [Array<(PropertyListResponse, Integer, Hash)>] PropertyListResponse data, response status code and response headers
121
123
  def list_properties_with_http_info(opts = {})
@@ -158,6 +160,7 @@ module Repull
158
160
  query_params[:'status'] = opts[:'status'] if !opts[:'status'].nil?
159
161
  query_params[:'lifecycle_status'] = opts[:'lifecycle_status'] if !opts[:'lifecycle_status'].nil?
160
162
  query_params[:'channel'] = opts[:'channel'] if !opts[:'channel'].nil?
163
+ query_params[:'updated_since'] = opts[:'updated_since'] if !opts[:'updated_since'].nil?
161
164
  query_params[:'include_total'] = opts[:'include_total'] if !opts[:'include_total'].nil?
162
165
 
163
166
  # header parameters
@@ -0,0 +1,109 @@
1
+ =begin
2
+ #Repull API
3
+
4
+ #The unified API for vacation rental tech. Connect to 50+ PMS platforms and 4 OTA channels through one REST API. Built-in AI operations for guest communication, pricing, and listing optimization. ## Designed for AI agents Every error response on this API includes machine-parseable fields so an LLM (Claude in MCP, Cursor, Cline, GPT, etc.) can self-recover without escalating to a human: - `error.code` — stable string identifier (e.g. `invalid_params`, `rate_limit_exceeded`) - `error.message` — human-readable cause - `error.fix` — exact recovery steps (e.g. \"Pass `check_in_after` as ISO 8601: `?check_in_after=2026-01-15`\") - `error.docs_url` — link to the canonical write-up at `https://repull.dev/docs/errors/{code}` - `error.request_id` — id to correlate with server-side logs - `error.field` / `error.value_received` / `error.valid_values` / `error.did_you_mean` — when the error is parameter-specific - `error.retry_after` — seconds to wait before retrying (rate-limit + transient upstream) `Access-Control-Expose-Headers` lists `x-request-id` and the `X-RateLimit-*` family so browsers can read them on cross-origin responses. ## Quick Start 1. Get an API key at https://repull.dev/dashboard 2. Connect a PMS: `POST /v1/connect/{provider}` 3. List properties: `GET /v1/properties` 4. Get reservations: `GET /v1/reservations` ## Authentication All requests require a Bearer token: ``` Authorization: Bearer sk_live_YOUR_API_KEY ``` ## Request Correlation (X-Request-ID) Every response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports — we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id. You may set the header on the inbound request to forward your own trace id; we will echo it back instead of generating a new one. Accepted format: `^[\\\\w.-]{1,128}$`. The id is also embedded in error envelopes as `request_id` so server-side log diffs work even when the response headers are stripped by an intermediate proxy. ## Rate Limits The public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas. **Default policy:** 600 requests per 60 seconds, per API key. Sliding window — there is no fixed-minute boundary you can burst across. Every response includes: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests permitted in the current window. | | `X-RateLimit-Remaining` | Requests left in the current window after this call. | | `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. | | `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. | | `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** | **On 429 (rate_limit_exceeded):** the response body matches the standard error envelope with `code: \"rate_limit_exceeded\"`, plus `limit`, `window_seconds`, `retry_after`, and `request_id` fields. SDKs MUST honor `Retry-After` and use exponential backoff with jitter on subsequent retries — never a tight loop. Recommended backoff: ``` sleep_ms = (Retry-After * 1000) + random(0..250) ``` Monthly + daily-AI tier quotas (`free`, `starter`, `custom`) are enforced separately and also surface as 429s; they include `tier`, `scope`, and `resetsAt` fields. ## Plan Limits (402 — `listings_limit_exceeded`) The Repull API also enforces a per-tier cap on **active listings**: | Tier | Active listings cap | |---|---| | `free` | 3 | | `starter` | 50 | | `custom` | unlimited | When a customer's active-listing count is above their tier cap, the API returns **`402 Payment Required`** with `error.code = \"listings_limit_exceeded\"` on every route EXCEPT: - `/v1/health` — uptime probes are never gated. - `/v1/usage/*` — so dashboards can render the over-cap state. - Any `DELETE` — so the customer can trim listings to get back under the cap without paying. Unlike 429, 402 is NOT a \"wait and retry\" condition — `Retry-After` is not set. The only paths back to 200 are: 1. `DELETE` enough listings to come back under the cap, or 2. Upgrade at `https://repull.dev/dashboard/billing`. The server-side usage cache is 60s, so the first 200 after an upgrade may take up to a minute. The envelope mirrors `rate_limit_exceeded` for SDK ergonomics: `tier`, `limit`, `active_listings`, `upgrade_url`, plus the standard `code` / `message` / `fix` / `docs_url` / `request_id`.
5
+
6
+ The version of the OpenAPI document: 1.0.0
7
+ Contact: ivan@vanio.ai
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.22.0
10
+
11
+ =end
12
+
13
+ require 'cgi'
14
+
15
+ module Repull
16
+ class QuotesApi
17
+ attr_accessor :api_client
18
+
19
+ def initialize(api_client = ApiClient.default)
20
+ @api_client = api_client
21
+ end
22
+ # Price a stay
23
+ # Returns the full price breakdown for a stay — nightly total, length-of-stay discount, cleaning fee, pet and other fees, taxes, and the total. A quote is priced against a booking website, because the markup, custom fees and tax overrides that decide what a guest is actually charged live there. A workspace with no booking site receives `422 quote_unavailable` rather than a number computed from different rules than the ones applied at checkout. 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
+ # @param property_id [Integer] Repull property id — discover via &#x60;GET /v1/properties&#x60;.
25
+ # @param check_in [Date]
26
+ # @param check_out [Date]
27
+ # @param [Hash] opts the optional parameters
28
+ # @option opts [Integer] :guests (default to 1)
29
+ # @option opts [Integer] :pets (default to 0)
30
+ # @option opts [Integer] :website_id Which booking site to price against. Defaults to the workspace&#39;s only site.
31
+ # @return [Quote]
32
+ def get_quote(property_id, check_in, check_out, opts = {})
33
+ data, _status_code, _headers = get_quote_with_http_info(property_id, check_in, check_out, opts)
34
+ data
35
+ end
36
+
37
+ # Price a stay
38
+ # Returns the full price breakdown for a stay — nightly total, length-of-stay discount, cleaning fee, pet and other fees, taxes, and the total. A quote is priced against a booking website, because the markup, custom fees and tax overrides that decide what a guest is actually charged live there. A workspace with no booking site receives &#x60;422 quote_unavailable&#x60; rather than a number computed from different rules than the ones applied at checkout. 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.
39
+ # @param property_id [Integer] Repull property id — discover via &#x60;GET /v1/properties&#x60;.
40
+ # @param check_in [Date]
41
+ # @param check_out [Date]
42
+ # @param [Hash] opts the optional parameters
43
+ # @option opts [Integer] :guests (default to 1)
44
+ # @option opts [Integer] :pets (default to 0)
45
+ # @option opts [Integer] :website_id Which booking site to price against. Defaults to the workspace&#39;s only site.
46
+ # @return [Array<(Quote, Integer, Hash)>] Quote data, response status code and response headers
47
+ def get_quote_with_http_info(property_id, check_in, check_out, opts = {})
48
+ if @api_client.config.debugging
49
+ @api_client.config.logger.debug 'Calling API: QuotesApi.get_quote ...'
50
+ end
51
+ # verify the required parameter 'property_id' is set
52
+ if @api_client.config.client_side_validation && property_id.nil?
53
+ fail ArgumentError, "Missing the required parameter 'property_id' when calling QuotesApi.get_quote"
54
+ end
55
+ # verify the required parameter 'check_in' is set
56
+ if @api_client.config.client_side_validation && check_in.nil?
57
+ fail ArgumentError, "Missing the required parameter 'check_in' when calling QuotesApi.get_quote"
58
+ end
59
+ # verify the required parameter 'check_out' is set
60
+ if @api_client.config.client_side_validation && check_out.nil?
61
+ fail ArgumentError, "Missing the required parameter 'check_out' when calling QuotesApi.get_quote"
62
+ end
63
+ # resource path
64
+ local_var_path = '/v1/quotes'
65
+
66
+ # query parameters
67
+ query_params = opts[:query_params] || {}
68
+ query_params[:'property_id'] = property_id
69
+ query_params[:'check_in'] = check_in
70
+ query_params[:'check_out'] = check_out
71
+ query_params[:'guests'] = opts[:'guests'] if !opts[:'guests'].nil?
72
+ query_params[:'pets'] = opts[:'pets'] if !opts[:'pets'].nil?
73
+ query_params[:'website_id'] = opts[:'website_id'] if !opts[:'website_id'].nil?
74
+
75
+ # header parameters
76
+ header_params = opts[:header_params] || {}
77
+ # HTTP header 'Accept' (if needed)
78
+ header_params['Accept'] = @api_client.select_header_accept(['application/json']) unless header_params['Accept']
79
+
80
+ # form parameters
81
+ form_params = opts[:form_params] || {}
82
+
83
+ # http body (model)
84
+ post_body = opts[:debug_body]
85
+
86
+ # return_type
87
+ return_type = opts[:debug_return_type] || 'Quote'
88
+
89
+ # auth_names
90
+ auth_names = opts[:debug_auth_names] || ['bearerAuth']
91
+
92
+ new_options = opts.merge(
93
+ :operation => :"QuotesApi.get_quote",
94
+ :header_params => header_params,
95
+ :query_params => query_params,
96
+ :form_params => form_params,
97
+ :body => post_body,
98
+ :auth_names => auth_names,
99
+ :return_type => return_type
100
+ )
101
+
102
+ data, status_code, headers = @api_client.call_api(:GET, local_var_path, new_options)
103
+ if @api_client.config.debugging
104
+ @api_client.config.logger.debug "API called: QuotesApi#get_quote\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
105
+ end
106
+ return data, status_code, headers
107
+ end
108
+ end
109
+ end
@@ -1,7 +1,7 @@
1
1
  =begin
2
2
  #Repull API
3
3
 
4
- #The unified API for vacation rental tech. Connect to 50+ PMS platforms and 4 OTA channels through one REST API. Built-in AI operations for guest communication, pricing, and listing optimization. ## Designed for AI agents Every error response on this API includes machine-parseable fields so an LLM (Claude in MCP, Cursor, Cline, GPT, etc.) can self-recover without escalating to a human: - `error.code` — stable string identifier (e.g. `invalid_params`, `rate_limit_exceeded`) - `error.message` — human-readable cause - `error.fix` — exact recovery steps (e.g. \"Pass `check_in_after` as ISO 8601: `?check_in_after=2026-01-15`\") - `error.docs_url` — link to the canonical write-up at `https://repull.dev/docs/errors/{code}` - `error.request_id` — id to correlate with server-side logs - `error.field` / `error.value_received` / `error.valid_values` / `error.did_you_mean` — when the error is parameter-specific - `error.retry_after` — seconds to wait before retrying (rate-limit + transient upstream) `Access-Control-Expose-Headers` lists `x-request-id` and the `X-RateLimit-*` family so browsers can read them on cross-origin responses. ## Quick Start 1. Get an API key at https://repull.dev/dashboard 2. Connect a PMS: `POST /v1/connect/{provider}` 3. List properties: `GET /v1/properties` 4. Get reservations: `GET /v1/reservations` ## Authentication All requests require a Bearer token: ``` Authorization: Bearer sk_test_YOUR_API_KEY ``` Sandbox keys start with `sk_test_`, production with `sk_live_`. ## Request Correlation (X-Request-ID) Every response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports — we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id. You may set the header on the inbound request to forward your own trace id; we will echo it back instead of generating a new one. Accepted format: `^[\\\\w.-]{1,128}$`. The id is also embedded in error envelopes as `request_id` so server-side log diffs work even when the response headers are stripped by an intermediate proxy. ## Rate Limits The public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas. **Default policy:** 600 requests per 60 seconds, per API key. Sliding window — there is no fixed-minute boundary you can burst across. Every response includes: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests permitted in the current window. | | `X-RateLimit-Remaining` | Requests left in the current window after this call. | | `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. | | `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. | | `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** | **On 429 (rate_limit_exceeded):** the response body matches the standard error envelope with `code: \"rate_limit_exceeded\"`, plus `limit`, `window_seconds`, `retry_after`, and `request_id` fields. SDKs MUST honor `Retry-After` and use exponential backoff with jitter on subsequent retries — never a tight loop. Recommended backoff: ``` sleep_ms = (Retry-After * 1000) + random(0..250) ``` Monthly + daily-AI tier quotas (`free`, `starter`, `custom`) are enforced separately and also surface as 429s; they include `tier`, `scope`, and `resets_at` fields. ## Plan Limits (402 — `listings_limit_exceeded`) The Repull API also enforces a per-tier cap on **active listings**: | Tier | Active listings cap | |---|---| | `free` | 3 | | `starter` | 50 | | `custom` | unlimited | When a customer's active-listing count is above their tier cap, the API returns **`402 Payment Required`** with `error.code = \"listings_limit_exceeded\"` on every route EXCEPT: - `/v1/health` — uptime probes are never gated. - `/v1/usage/*` — so dashboards can render the over-cap state. - Any `DELETE` — so the customer can trim listings to get back under the cap without paying. Unlike 429, 402 is NOT a \"wait and retry\" condition — `Retry-After` is not set. The only paths back to 200 are: 1. `DELETE` enough listings to come back under the cap, or 2. Upgrade at `https://repull.dev/dashboard/billing`. The server-side usage cache is 60s, so the first 200 after an upgrade may take up to a minute. The envelope mirrors `rate_limit_exceeded` for SDK ergonomics: `tier`, `limit`, `active_listings`, `upgrade_url`, plus the standard `code` / `message` / `fix` / `docs_url` / `request_id`.
4
+ #The unified API for vacation rental tech. Connect to 50+ PMS platforms and 4 OTA channels through one REST API. Built-in AI operations for guest communication, pricing, and listing optimization. ## Designed for AI agents Every error response on this API includes machine-parseable fields so an LLM (Claude in MCP, Cursor, Cline, GPT, etc.) can self-recover without escalating to a human: - `error.code` — stable string identifier (e.g. `invalid_params`, `rate_limit_exceeded`) - `error.message` — human-readable cause - `error.fix` — exact recovery steps (e.g. \"Pass `check_in_after` as ISO 8601: `?check_in_after=2026-01-15`\") - `error.docs_url` — link to the canonical write-up at `https://repull.dev/docs/errors/{code}` - `error.request_id` — id to correlate with server-side logs - `error.field` / `error.value_received` / `error.valid_values` / `error.did_you_mean` — when the error is parameter-specific - `error.retry_after` — seconds to wait before retrying (rate-limit + transient upstream) `Access-Control-Expose-Headers` lists `x-request-id` and the `X-RateLimit-*` family so browsers can read them on cross-origin responses. ## Quick Start 1. Get an API key at https://repull.dev/dashboard 2. Connect a PMS: `POST /v1/connect/{provider}` 3. List properties: `GET /v1/properties` 4. Get reservations: `GET /v1/reservations` ## Authentication All requests require a Bearer token: ``` Authorization: Bearer sk_live_YOUR_API_KEY ``` ## Request Correlation (X-Request-ID) Every response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports — we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id. You may set the header on the inbound request to forward your own trace id; we will echo it back instead of generating a new one. Accepted format: `^[\\\\w.-]{1,128}$`. The id is also embedded in error envelopes as `request_id` so server-side log diffs work even when the response headers are stripped by an intermediate proxy. ## Rate Limits The public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas. **Default policy:** 600 requests per 60 seconds, per API key. Sliding window — there is no fixed-minute boundary you can burst across. Every response includes: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests permitted in the current window. | | `X-RateLimit-Remaining` | Requests left in the current window after this call. | | `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. | | `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. | | `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** | **On 429 (rate_limit_exceeded):** the response body matches the standard error envelope with `code: \"rate_limit_exceeded\"`, plus `limit`, `window_seconds`, `retry_after`, and `request_id` fields. SDKs MUST honor `Retry-After` and use exponential backoff with jitter on subsequent retries — never a tight loop. Recommended backoff: ``` sleep_ms = (Retry-After * 1000) + random(0..250) ``` Monthly + daily-AI tier quotas (`free`, `starter`, `custom`) are enforced separately and also surface as 429s; they include `tier`, `scope`, and `resetsAt` fields. ## Plan Limits (402 — `listings_limit_exceeded`) The Repull API also enforces a per-tier cap on **active listings**: | Tier | Active listings cap | |---|---| | `free` | 3 | | `starter` | 50 | | `custom` | unlimited | When a customer's active-listing count is above their tier cap, the API returns **`402 Payment Required`** with `error.code = \"listings_limit_exceeded\"` on every route EXCEPT: - `/v1/health` — uptime probes are never gated. - `/v1/usage/*` — so dashboards can render the over-cap state. - Any `DELETE` — so the customer can trim listings to get back under the cap without paying. Unlike 429, 402 is NOT a \"wait and retry\" condition — `Retry-After` is not set. The only paths back to 200 are: 1. `DELETE` enough listings to come back under the cap, or 2. Upgrade at `https://repull.dev/dashboard/billing`. The server-side usage cache is 60s, so the first 200 after an upgrade may take up to a minute. The envelope mirrors `rate_limit_exceeded` for SDK ergonomics: `tier`, `limit`, `active_listings`, `upgrade_url`, plus the standard `code` / `message` / `fix` / `docs_url` / `request_id`.
5
5
 
6
6
  The version of the OpenAPI document: 1.0.0
7
7
  Contact: ivan@vanio.ai
@@ -19,8 +19,83 @@ module Repull
19
19
  def initialize(api_client = ApiClient.default)
20
20
  @api_client = api_client
21
21
  end
22
+ # Create a reservation
23
+ # 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
+ # @param reservation_create_request [ReservationCreateRequest]
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. - Responses with status &gt;&#x3D; 500 are deliberately not stored, so a server error stays retryable.
27
+ # @return [ReservationCreateResponse]
28
+ def create_reservation(reservation_create_request, opts = {})
29
+ data, _status_code, _headers = create_reservation_with_http_info(reservation_create_request, opts)
30
+ data
31
+ end
32
+
33
+ # Create a reservation
34
+ # 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
+ # @param reservation_create_request [ReservationCreateRequest]
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. - Responses with status &gt;&#x3D; 500 are deliberately not stored, so a server error stays retryable.
38
+ # @return [Array<(ReservationCreateResponse, Integer, Hash)>] ReservationCreateResponse data, response status code and response headers
39
+ def create_reservation_with_http_info(reservation_create_request, opts = {})
40
+ if @api_client.config.debugging
41
+ @api_client.config.logger.debug 'Calling API: ReservationsApi.create_reservation ...'
42
+ end
43
+ # verify the required parameter 'reservation_create_request' is set
44
+ if @api_client.config.client_side_validation && reservation_create_request.nil?
45
+ fail ArgumentError, "Missing the required parameter 'reservation_create_request' when calling ReservationsApi.create_reservation"
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.create_reservation, the character length must be smaller than or equal to 255.'
49
+ end
50
+
51
+ # resource path
52
+ local_var_path = '/v1/reservations'
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
+ # HTTP header 'Content-Type'
62
+ content_type = @api_client.select_header_content_type(['application/json'])
63
+ if !content_type.nil?
64
+ header_params['Content-Type'] = content_type
65
+ end
66
+ header_params[:'Idempotency-Key'] = opts[:'idempotency_key'] if !opts[:'idempotency_key'].nil?
67
+
68
+ # form parameters
69
+ form_params = opts[:form_params] || {}
70
+
71
+ # http body (model)
72
+ post_body = opts[:debug_body] || @api_client.object_to_http_body(reservation_create_request)
73
+
74
+ # return_type
75
+ return_type = opts[:debug_return_type] || 'ReservationCreateResponse'
76
+
77
+ # auth_names
78
+ auth_names = opts[:debug_auth_names] || ['bearerAuth']
79
+
80
+ new_options = opts.merge(
81
+ :operation => :"ReservationsApi.create_reservation",
82
+ :header_params => header_params,
83
+ :query_params => query_params,
84
+ :form_params => form_params,
85
+ :body => post_body,
86
+ :auth_names => auth_names,
87
+ :return_type => return_type
88
+ )
89
+
90
+ data, status_code, headers = @api_client.call_api(:POST, local_var_path, new_options)
91
+ if @api_client.config.debugging
92
+ @api_client.config.logger.debug "API called: ReservationsApi#create_reservation\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
93
+ end
94
+ return data, status_code, headers
95
+ end
96
+
22
97
  # Get reservation details
23
- # 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.
98
+ # 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.
24
99
  # @param id [Integer] Internal Repull reservation ID.
25
100
  # @param [Hash] opts the optional parameters
26
101
  # @option opts [String] :x_schema Apply a custom or built-in schema to transform the response. Built-in: &#x60;native&#x60; (default), &#x60;calry&#x60;, &#x60;calry-v1&#x60;. Custom: any schema name created via &#x60;POST /v1/schema/custom&#x60;. Unknown / inactive schema names fall back to &#x60;native&#x60;.
@@ -31,7 +106,7 @@ module Repull
31
106
  end
32
107
 
33
108
  # Get reservation details
34
- # Returns the full record for a single reservation, scoped to the authenticated workspace. Response shape is identical to a single row in &#x60;GET /v1/reservations&#x60; 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&#39;t enumerate other workspaces&#39; ids.
109
+ # Returns the full record for a single reservation, scoped to the authenticated workspace. Response shape is identical to a single row in &#x60;GET /v1/reservations&#x60; 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&#39;t enumerate other workspaces&#39; ids. Returns &#x60;403 listing_inactive&#x60; 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.
35
110
  # @param id [Integer] Internal Repull reservation ID.
36
111
  # @param [Hash] opts the optional parameters
37
112
  # @option opts [String] :x_schema Apply a custom or built-in schema to transform the response. Built-in: &#x60;native&#x60; (default), &#x60;calry&#x60;, &#x60;calry-v1&#x60;. Custom: any schema name created via &#x60;POST /v1/schema/custom&#x60;. Unknown / inactive schema names fall back to &#x60;native&#x60;.
@@ -86,12 +161,12 @@ module Repull
86
161
  end
87
162
 
88
163
  # List reservations
89
- # Cursor-paginated list of reservations across all connected PMS platforms. Filter by platform, status, listing, or check-in date range. **Pagination:** Walk pages with `?cursor=` — pass `pagination.nextCursor` from one response back as `?cursor=` on the next request. Stop when `pagination.hasMore` is `false`. `limit` defaults to 50, max 100; requesting more returns 422 (no silent truncation). `?offset=` is also accepted as a first-class alias for shallow paging (0..10000) — see the `offset` parameter below. Mutually exclusive with `cursor`. For deep pagination cursor remains O(1) per page; offset > 10000 returns 422 with a docs link.
164
+ # Cursor-paginated list of reservations across all connected PMS platforms. Filter by platform, status, listing, or check-in date range. **Pagination:** Walk pages with `?cursor=` — pass `pagination.nextCursor` from one response back as `?cursor=` on the next request. Stop when `pagination.hasMore` is `false`. `limit` defaults to 50, max 100; requesting more returns 422 (no silent truncation). `?offset=` is also accepted as a first-class alias for shallow paging (0..10000) — see the `offset` parameter below. Mutually exclusive with `cursor`. For deep pagination cursor remains O(1) per page; offset > 10000 returns 422 with a docs link. **Incremental sync (only changes since last poll):** pass `?updated_since=<ISO8601>` to receive only reservations amended, cancelled, or created at or after that instant — no full re-walk. Each row carries `updatedAt`; the last row of the final page is your next watermark. Note that `updated_since` changes the page ordering to `updatedAt ASC, id ASC` (and the cursor with it) so mid-walk amendments cannot be skipped — see the parameter description for the full contract. Reservations on inactive listings are left out (counts and cursors included); they keep syncing and reappear once the listing is activated. Filtering by an inactive listing (`listing_id`) returns `403 listing_inactive`.
90
165
  # @param [Hash] opts the optional parameters
91
166
  # @option opts [String] :x_schema Apply a custom or built-in schema to transform the response. Built-in: &#x60;native&#x60; (default), &#x60;calry&#x60;, &#x60;calry-v1&#x60;. Custom: any schema name created via &#x60;POST /v1/schema/custom&#x60;. Unknown / inactive schema names fall back to &#x60;native&#x60;.
92
167
  # @option opts [Integer] :limit Page size (max 100). Requests over the cap return 422. (default to 50)
93
168
  # @option opts [String] :cursor Opaque cursor returned in the previous response&#39;s &#x60;pagination.nextCursor&#x60;. Omit to fetch the first page.
94
- # @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.next_cursor&#x60; so consumers can switch from offset → cursor mid-walk for deep pagination without re-keying. (default to 0)
169
+ # @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)
95
170
  # @option opts [String] :platform Filter by booking platform
96
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.
97
172
  # @option opts [Integer] :listing_id Filter to a single listing
@@ -105,6 +180,7 @@ module Repull
105
180
  # @option opts [Date] :check_in_before2 Use &#x60;check_in_before&#x60; (snake_case) instead.
106
181
  # @option opts [Date] :check_out_after2 Use &#x60;check_out_after&#x60; (snake_case) instead.
107
182
  # @option opts [Date] :check_out_before2 Use &#x60;check_out_before&#x60; (snake_case) instead.
183
+ # @option opts [Time] :updated_since Incremental sync: return only records whose &#x60;updatedAt&#x60; is at or after this instant. This is the only filter on record **mutation** time — every &#x60;check_*&#x60; filter targets guest **stay** dates. **Accepted formats.** ISO 8601, with &#x60;Z&#x60; or a numeric offset — both work: - &#x60;2026-08-01T00:00:00Z&#x60; - &#x60;2026-08-01T00:00:00.123Z&#x60; - &#x60;2026-08-01T00:00:00+00:00&#x60; - &#x60;2026-08-01T02:30:00-07:00&#x60; (offset colon optional: &#x60;-0700&#x60;) - &#x60;2026-08-01T00:00&#x60; (seconds optional) - &#x60;2026-08-01T00:00:00&#x60; — no zone designator, interpreted as **UTC** - &#x60;2026-08-01&#x60; — date only, means midnight UTC Anything else returns 422 &#x60;invalid_params&#x60; naming the field; the value is never silently ignored. **Ordering changes when you pass this.** Results are ordered &#x60;updatedAt ASC, id ASC&#x60; (instead of the endpoint default) and the cursor keys on the same pair. That is required for correctness: under the default ordering a record amended mid-walk can move behind the cursor and never be emitted — which is exactly the event you are polling for. Ascending mutation time is monotonic with the cursor, so anything touched during a walk resurfaces later in it or on the next poll. **Cursors are not interchangeable between the two orderings.** Keep &#x60;updated_since&#x60; on every page of an incremental walk; replaying a cursor from the other ordering returns 422 rather than a page that silently skips rows. **Watermark.** The bound is inclusive (&#x60;updatedAt &gt;&#x3D; value&#x60;), so the last row of the final page is the watermark for the next poll — re-polling with it re-emits that row. Delivery is at-least-once; upsert by &#x60;id&#x60;.
108
184
  # @option opts [Boolean] :include_total When &#x60;true&#x60; (default), the response&#39;s &#x60;pagination.total&#x60; carries the count of rows matching the current filter, across all pages. Pass &#x60;false&#x60; to skip the count for very large workspaces where the per-page COUNT(*) cost matters. (default to true)
109
185
  # @return [ReservationListResponse]
110
186
  def list_reservations(opts = {})
@@ -113,12 +189,12 @@ module Repull
113
189
  end
114
190
 
115
191
  # List reservations
116
- # Cursor-paginated list of reservations across all connected PMS platforms. Filter by platform, status, listing, or check-in date range. **Pagination:** Walk pages with &#x60;?cursor&#x3D;&#x60; — pass &#x60;pagination.nextCursor&#x60; from one response back as &#x60;?cursor&#x3D;&#x60; on the next request. Stop when &#x60;pagination.hasMore&#x60; is &#x60;false&#x60;. &#x60;limit&#x60; defaults to 50, max 100; requesting more returns 422 (no silent truncation). &#x60;?offset&#x3D;&#x60; is also accepted as a first-class alias for shallow paging (0..10000) — see the &#x60;offset&#x60; parameter below. Mutually exclusive with &#x60;cursor&#x60;. For deep pagination cursor remains O(1) per page; offset &gt; 10000 returns 422 with a docs link.
192
+ # Cursor-paginated list of reservations across all connected PMS platforms. Filter by platform, status, listing, or check-in date range. **Pagination:** Walk pages with &#x60;?cursor&#x3D;&#x60; — pass &#x60;pagination.nextCursor&#x60; from one response back as &#x60;?cursor&#x3D;&#x60; on the next request. Stop when &#x60;pagination.hasMore&#x60; is &#x60;false&#x60;. &#x60;limit&#x60; defaults to 50, max 100; requesting more returns 422 (no silent truncation). &#x60;?offset&#x3D;&#x60; is also accepted as a first-class alias for shallow paging (0..10000) — see the &#x60;offset&#x60; parameter below. Mutually exclusive with &#x60;cursor&#x60;. For deep pagination cursor remains O(1) per page; offset &gt; 10000 returns 422 with a docs link. **Incremental sync (only changes since last poll):** pass &#x60;?updated_since&#x3D;&lt;ISO8601&gt;&#x60; to receive only reservations amended, cancelled, or created at or after that instant — no full re-walk. Each row carries &#x60;updatedAt&#x60;; the last row of the final page is your next watermark. Note that &#x60;updated_since&#x60; changes the page ordering to &#x60;updatedAt ASC, id ASC&#x60; (and the cursor with it) so mid-walk amendments cannot be skipped — see the parameter description for the full contract. Reservations on inactive listings are left out (counts and cursors included); they keep syncing and reappear once the listing is activated. Filtering by an inactive listing (&#x60;listing_id&#x60;) returns &#x60;403 listing_inactive&#x60;.
117
193
  # @param [Hash] opts the optional parameters
118
194
  # @option opts [String] :x_schema Apply a custom or built-in schema to transform the response. Built-in: &#x60;native&#x60; (default), &#x60;calry&#x60;, &#x60;calry-v1&#x60;. Custom: any schema name created via &#x60;POST /v1/schema/custom&#x60;. Unknown / inactive schema names fall back to &#x60;native&#x60;.
119
195
  # @option opts [Integer] :limit Page size (max 100). Requests over the cap return 422. (default to 50)
120
196
  # @option opts [String] :cursor Opaque cursor returned in the previous response&#39;s &#x60;pagination.nextCursor&#x60;. Omit to fetch the first page.
121
- # @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.next_cursor&#x60; so consumers can switch from offset → cursor mid-walk for deep pagination without re-keying. (default to 0)
197
+ # @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)
122
198
  # @option opts [String] :platform Filter by booking platform
123
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.
124
200
  # @option opts [Integer] :listing_id Filter to a single listing
@@ -132,6 +208,7 @@ module Repull
132
208
  # @option opts [Date] :check_in_before2 Use &#x60;check_in_before&#x60; (snake_case) instead.
133
209
  # @option opts [Date] :check_out_after2 Use &#x60;check_out_after&#x60; (snake_case) instead.
134
210
  # @option opts [Date] :check_out_before2 Use &#x60;check_out_before&#x60; (snake_case) instead.
211
+ # @option opts [Time] :updated_since Incremental sync: return only records whose &#x60;updatedAt&#x60; is at or after this instant. This is the only filter on record **mutation** time — every &#x60;check_*&#x60; filter targets guest **stay** dates. **Accepted formats.** ISO 8601, with &#x60;Z&#x60; or a numeric offset — both work: - &#x60;2026-08-01T00:00:00Z&#x60; - &#x60;2026-08-01T00:00:00.123Z&#x60; - &#x60;2026-08-01T00:00:00+00:00&#x60; - &#x60;2026-08-01T02:30:00-07:00&#x60; (offset colon optional: &#x60;-0700&#x60;) - &#x60;2026-08-01T00:00&#x60; (seconds optional) - &#x60;2026-08-01T00:00:00&#x60; — no zone designator, interpreted as **UTC** - &#x60;2026-08-01&#x60; — date only, means midnight UTC Anything else returns 422 &#x60;invalid_params&#x60; naming the field; the value is never silently ignored. **Ordering changes when you pass this.** Results are ordered &#x60;updatedAt ASC, id ASC&#x60; (instead of the endpoint default) and the cursor keys on the same pair. That is required for correctness: under the default ordering a record amended mid-walk can move behind the cursor and never be emitted — which is exactly the event you are polling for. Ascending mutation time is monotonic with the cursor, so anything touched during a walk resurfaces later in it or on the next poll. **Cursors are not interchangeable between the two orderings.** Keep &#x60;updated_since&#x60; on every page of an incremental walk; replaying a cursor from the other ordering returns 422 rather than a page that silently skips rows. **Watermark.** The bound is inclusive (&#x60;updatedAt &gt;&#x3D; value&#x60;), so the last row of the final page is the watermark for the next poll — re-polling with it re-emits that row. Delivery is at-least-once; upsert by &#x60;id&#x60;.
135
212
  # @option opts [Boolean] :include_total When &#x60;true&#x60; (default), the response&#39;s &#x60;pagination.total&#x60; carries the count of rows matching the current filter, across all pages. Pass &#x60;false&#x60; to skip the count for very large workspaces where the per-page COUNT(*) cost matters. (default to true)
136
213
  # @return [Array<(ReservationListResponse, Integer, Hash)>] ReservationListResponse data, response status code and response headers
137
214
  def list_reservations_with_http_info(opts = {})
@@ -179,6 +256,7 @@ module Repull
179
256
  query_params[:'checkInBefore'] = opts[:'check_in_before2'] if !opts[:'check_in_before2'].nil?
180
257
  query_params[:'checkOutAfter'] = opts[:'check_out_after2'] if !opts[:'check_out_after2'].nil?
181
258
  query_params[:'checkOutBefore'] = opts[:'check_out_before2'] if !opts[:'check_out_before2'].nil?
259
+ query_params[:'updated_since'] = opts[:'updated_since'] if !opts[:'updated_since'].nil?
182
260
  query_params[:'include_total'] = opts[:'include_total'] if !opts[:'include_total'].nil?
183
261
 
184
262
  # header parameters
@@ -215,5 +293,86 @@ module Repull
215
293
  end
216
294
  return data, status_code, headers
217
295
  end
296
+
297
+ # Update a reservation
298
+ # Changes the dates, the occupancy, or the unit. Drives the same command path the dashboard does, so the side effects come with it: the change audit is appended, bound task due dates re-sync, the old calendar dates unblock and the new ones block, the conversation's cached listing is invalidated, and `reservation.updated` fires — which is what revokes and re-issues the door code. Supply at least one field; an empty body returns 422 rather than a 200 that changed nothing. **Moving and re-dating in one call is one operation.** Send `listingId` together with `checkIn`/`checkOut` and it is applied as a single move, so the access code is re-issued once rather than twice. ### Fields this endpoint deliberately does NOT accept Each is rejected by name with the reason, never accepted and ignored: | Field | Why | |---|---| | `guest` / `guestDetails` | Guest name, email and phone live on the guest record. The underlying command has no branch for them, so accepting them would return a success that changed nothing. | | `pricing` / `totalPrice` / `currency` | Repricing writes the price breakdown, the pricing row and a pricing-history entry. It belongs to its own endpoint. | | `status` | Not a field. Cancelling, confirming and checking out are separate operations with materially different side effects — cancellation issues a credit refund and revokes access codes. | | `platform` | Immutable: it records where the booking actually originated. | | `notes` | `internal_notes` is an append-only audit trail the system writes on every change. | **Availability is NOT checked.** A date change that overlaps another booking will be written. Call `GET /v1/availability/{propertyId}` first if that matters. Returns `403 listing_inactive` when the reservation is on an inactive listing, or when a `listingId` move targets one; nothing is changed.
299
+ # @param id [Integer] Internal Repull reservation ID.
300
+ # @param reservation_update_request [ReservationUpdateRequest]
301
+ # @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.
303
+ # @return [ReservationUpdateResponse]
304
+ def update_reservation(id, reservation_update_request, opts = {})
305
+ data, _status_code, _headers = update_reservation_with_http_info(id, reservation_update_request, opts)
306
+ data
307
+ end
308
+
309
+ # Update a reservation
310
+ # Changes the dates, the occupancy, or the unit. Drives the same command path the dashboard does, so the side effects come with it: the change audit is appended, bound task due dates re-sync, the old calendar dates unblock and the new ones block, the conversation&#39;s cached listing is invalidated, and &#x60;reservation.updated&#x60; fires — which is what revokes and re-issues the door code. Supply at least one field; an empty body returns 422 rather than a 200 that changed nothing. **Moving and re-dating in one call is one operation.** Send &#x60;listingId&#x60; together with &#x60;checkIn&#x60;/&#x60;checkOut&#x60; and it is applied as a single move, so the access code is re-issued once rather than twice. ### Fields this endpoint deliberately does NOT accept Each is rejected by name with the reason, never accepted and ignored: | Field | Why | |---|---| | &#x60;guest&#x60; / &#x60;guestDetails&#x60; | Guest name, email and phone live on the guest record. The underlying command has no branch for them, so accepting them would return a success that changed nothing. | | &#x60;pricing&#x60; / &#x60;totalPrice&#x60; / &#x60;currency&#x60; | Repricing writes the price breakdown, the pricing row and a pricing-history entry. It belongs to its own endpoint. | | &#x60;status&#x60; | Not a field. Cancelling, confirming and checking out are separate operations with materially different side effects — cancellation issues a credit refund and revokes access codes. | | &#x60;platform&#x60; | Immutable: it records where the booking actually originated. | | &#x60;notes&#x60; | &#x60;internal_notes&#x60; is an append-only audit trail the system writes on every change. | **Availability is NOT checked.** A date change that overlaps another booking will be written. Call &#x60;GET /v1/availability/{propertyId}&#x60; first if that matters. Returns &#x60;403 listing_inactive&#x60; when the reservation is on an inactive listing, or when a &#x60;listingId&#x60; move targets one; nothing is changed.
311
+ # @param id [Integer] Internal Repull reservation ID.
312
+ # @param reservation_update_request [ReservationUpdateRequest]
313
+ # @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.
315
+ # @return [Array<(ReservationUpdateResponse, Integer, Hash)>] ReservationUpdateResponse data, response status code and response headers
316
+ def update_reservation_with_http_info(id, reservation_update_request, opts = {})
317
+ if @api_client.config.debugging
318
+ @api_client.config.logger.debug 'Calling API: ReservationsApi.update_reservation ...'
319
+ end
320
+ # verify the required parameter 'id' is set
321
+ if @api_client.config.client_side_validation && id.nil?
322
+ fail ArgumentError, "Missing the required parameter 'id' when calling ReservationsApi.update_reservation"
323
+ end
324
+ # verify the required parameter 'reservation_update_request' is set
325
+ if @api_client.config.client_side_validation && reservation_update_request.nil?
326
+ fail ArgumentError, "Missing the required parameter 'reservation_update_request' when calling ReservationsApi.update_reservation"
327
+ end
328
+ if @api_client.config.client_side_validation && !opts[:'idempotency_key'].nil? && opts[:'idempotency_key'].to_s.length > 255
329
+ fail ArgumentError, 'invalid value for "opts[:"idempotency_key"]" when calling ReservationsApi.update_reservation, the character length must be smaller than or equal to 255.'
330
+ end
331
+
332
+ # resource path
333
+ local_var_path = '/v1/reservations/{id}'.sub('{id}', CGI.escape(id.to_s))
334
+
335
+ # query parameters
336
+ query_params = opts[:query_params] || {}
337
+
338
+ # header parameters
339
+ header_params = opts[:header_params] || {}
340
+ # HTTP header 'Accept' (if needed)
341
+ header_params['Accept'] = @api_client.select_header_accept(['application/json']) unless header_params['Accept']
342
+ # HTTP header 'Content-Type'
343
+ content_type = @api_client.select_header_content_type(['application/json'])
344
+ if !content_type.nil?
345
+ header_params['Content-Type'] = content_type
346
+ end
347
+ header_params[:'Idempotency-Key'] = opts[:'idempotency_key'] if !opts[:'idempotency_key'].nil?
348
+
349
+ # form parameters
350
+ form_params = opts[:form_params] || {}
351
+
352
+ # http body (model)
353
+ post_body = opts[:debug_body] || @api_client.object_to_http_body(reservation_update_request)
354
+
355
+ # return_type
356
+ return_type = opts[:debug_return_type] || 'ReservationUpdateResponse'
357
+
358
+ # auth_names
359
+ auth_names = opts[:debug_auth_names] || ['bearerAuth']
360
+
361
+ new_options = opts.merge(
362
+ :operation => :"ReservationsApi.update_reservation",
363
+ :header_params => header_params,
364
+ :query_params => query_params,
365
+ :form_params => form_params,
366
+ :body => post_body,
367
+ :auth_names => auth_names,
368
+ :return_type => return_type
369
+ )
370
+
371
+ data, status_code, headers = @api_client.call_api(:PATCH, local_var_path, new_options)
372
+ if @api_client.config.debugging
373
+ @api_client.config.logger.debug "API called: ReservationsApi#update_reservation\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
374
+ end
375
+ return data, status_code, headers
376
+ end
218
377
  end
219
378
  end