repull 0.2.6 → 0.2.8

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 (283) hide show
  1. checksums.yaml +4 -4
  2. data/lib/repull/api/ai_api.rb +1 -1
  3. data/lib/repull/api/airbnb_api.rb +5 -5
  4. data/lib/repull/api/atlas_api.rb +1 -1
  5. data/lib/repull/api/availability_api.rb +1 -1
  6. data/lib/repull/api/billing_api.rb +1 -1
  7. data/lib/repull/api/booking_com_api.rb +1 -1
  8. data/lib/repull/api/connect_api.rb +1 -1
  9. data/lib/repull/api/conversations_api.rb +1 -1
  10. data/lib/repull/api/guests_api.rb +1 -1
  11. data/lib/repull/api/kv_api.rb +1 -1
  12. data/lib/repull/api/listings_api.rb +138 -1
  13. data/lib/repull/api/markets_api.rb +1 -1
  14. data/lib/repull/api/plumguide_api.rb +1 -1
  15. data/lib/repull/api/pricing_api.rb +1 -1
  16. data/lib/repull/api/properties_api.rb +1 -1
  17. data/lib/repull/api/reservations_api.rb +1 -1
  18. data/lib/repull/api/reviews_api.rb +1 -1
  19. data/lib/repull/api/schema_api.rb +1 -1
  20. data/lib/repull/api/studio_api.rb +1 -1
  21. data/lib/repull/api/system_api.rb +1 -1
  22. data/lib/repull/api/vrbo_api.rb +1 -1
  23. data/lib/repull/api/webhooks_api.rb +1 -1
  24. data/lib/repull/api_client.rb +1 -1
  25. data/lib/repull/api_error.rb +1 -1
  26. data/lib/repull/api_model_base.rb +1 -1
  27. data/lib/repull/configuration.rb +1 -1
  28. data/lib/repull/models/account_created_event.rb +1 -1
  29. data/lib/repull/models/account_created_payload.rb +1 -1
  30. data/lib/repull/models/account_disconnected_event.rb +1 -1
  31. data/lib/repull/models/account_disconnected_payload.rb +1 -1
  32. data/lib/repull/models/ai_operation.rb +1 -1
  33. data/lib/repull/models/ai_operation_completed_event.rb +1 -1
  34. data/lib/repull/models/ai_operation_completed_payload.rb +1 -1
  35. data/lib/repull/models/ai_operation_failed_event.rb +1 -1
  36. data/lib/repull/models/ai_operation_failed_payload.rb +1 -1
  37. data/lib/repull/models/ai_operation_failed_payload_error.rb +1 -1
  38. data/lib/repull/models/airbnb_connection.rb +1 -1
  39. data/lib/repull/models/airbnb_connection_accessibility_amenities_inner.rb +1 -1
  40. data/lib/repull/models/airbnb_connection_amenities_inner.rb +1 -1
  41. data/lib/repull/models/airbnb_connection_host.rb +1 -1
  42. data/lib/repull/models/airbnb_connection_response.rb +1 -1
  43. data/lib/repull/models/airbnb_connection_summary.rb +1 -1
  44. data/lib/repull/models/airbnb_data_freshness.rb +1 -1
  45. data/lib/repull/models/airbnb_listing.rb +1 -1
  46. data/lib/repull/models/airbnb_listing_list_response.rb +1 -1
  47. data/lib/repull/models/airbnb_reservation.rb +1 -1
  48. data/lib/repull/models/airbnb_reservation_list_response.rb +1 -1
  49. data/lib/repull/models/airbnb_review.rb +1 -1
  50. data/lib/repull/models/airbnb_review_list_response.rb +1 -1
  51. data/lib/repull/models/airbnb_thread.rb +1 -1
  52. data/lib/repull/models/airbnb_thread_list_response.rb +1 -1
  53. data/lib/repull/models/booking_connect_listing_option.rb +1 -1
  54. data/lib/repull/models/booking_connect_room.rb +1 -1
  55. data/lib/repull/models/booking_connect_rooms_response.rb +1 -1
  56. data/lib/repull/models/booking_conversation.rb +1 -1
  57. data/lib/repull/models/booking_conversation_list_response.rb +1 -1
  58. data/lib/repull/models/booking_pricing_rate_update.rb +1 -1
  59. data/lib/repull/models/booking_pricing_rate_update_date_range.rb +1 -1
  60. data/lib/repull/models/booking_pricing_rate_update_restrictions.rb +1 -1
  61. data/lib/repull/models/booking_pricing_response.rb +1 -1
  62. data/lib/repull/models/booking_pricing_update_request.rb +1 -1
  63. data/lib/repull/models/booking_pricing_update_response.rb +1 -1
  64. data/lib/repull/models/booking_property.rb +1 -1
  65. data/lib/repull/models/booking_property_list_response.rb +1 -1
  66. data/lib/repull/models/booking_room_mapping.rb +1 -1
  67. data/lib/repull/models/booking_verify_hotel_request.rb +1 -1
  68. data/lib/repull/models/booking_verify_hotel_response.rb +1 -1
  69. data/lib/repull/models/bulk_pricing_failure.rb +1 -1
  70. data/lib/repull/models/bulk_pricing_item.rb +1 -1
  71. data/lib/repull/models/bulk_pricing_request.rb +1 -1
  72. data/lib/repull/models/bulk_pricing_response.rb +1 -1
  73. data/lib/repull/models/calendar_day.rb +1 -1
  74. data/lib/repull/models/calendar_response.rb +1 -1
  75. data/lib/repull/models/calendar_updated_event.rb +1 -1
  76. data/lib/repull/models/calendar_updated_payload.rb +1 -1
  77. data/lib/repull/models/calendar_updated_payload_range.rb +1 -1
  78. data/lib/repull/models/clear_kv200_response.rb +1 -1
  79. data/lib/repull/models/connect_host.rb +1 -1
  80. data/lib/repull/models/connect_provider.rb +1 -1
  81. data/lib/repull/models/connect_provider_list_response.rb +1 -1
  82. data/lib/repull/models/connect_session.rb +1 -1
  83. data/lib/repull/models/connect_status.rb +1 -1
  84. data/lib/repull/models/connection.rb +1 -1
  85. data/lib/repull/models/connection_list_response.rb +1 -1
  86. data/lib/repull/models/conversation.rb +1 -1
  87. data/lib/repull/models/conversation_detail.rb +1 -1
  88. data/lib/repull/models/conversation_guest.rb +1 -1
  89. data/lib/repull/models/conversation_guest_contact.rb +1 -1
  90. data/lib/repull/models/conversation_host.rb +1 -1
  91. data/lib/repull/models/conversation_list_response.rb +1 -1
  92. data/lib/repull/models/conversation_message_attachment.rb +1 -1
  93. data/lib/repull/models/create_ai_operation200_response.rb +1 -1
  94. data/lib/repull/models/create_billing_checkout_request.rb +1 -1
  95. data/lib/repull/models/create_connect_session_request.rb +17 -6
  96. data/lib/repull/models/create_connection_request.rb +16 -5
  97. data/lib/repull/models/create_reservation_request.rb +1 -1
  98. data/lib/repull/models/create_studio_deployment201_response.rb +1 -1
  99. data/lib/repull/models/create_studio_deployment201_response_data.rb +1 -1
  100. data/lib/repull/models/create_studio_deployment_request.rb +1 -1
  101. data/lib/repull/models/create_studio_project201_response.rb +1 -1
  102. data/lib/repull/models/create_studio_project201_response_data.rb +1 -1
  103. data/lib/repull/models/create_studio_project_generation201_response.rb +1 -1
  104. data/lib/repull/models/create_studio_project_generation201_response_data.rb +1 -1
  105. data/lib/repull/models/create_studio_project_generation_request.rb +1 -1
  106. data/lib/repull/models/create_studio_project_request.rb +1 -1
  107. data/lib/repull/models/create_webhook_request.rb +1 -1
  108. data/lib/repull/models/custom_schema.rb +1 -1
  109. data/lib/repull/models/custom_schema_create.rb +1 -1
  110. data/lib/repull/models/custom_schema_create_response.rb +1 -1
  111. data/lib/repull/models/custom_schema_delete_response.rb +1 -1
  112. data/lib/repull/models/custom_schema_list_response.rb +1 -1
  113. data/lib/repull/models/custom_schema_summary.rb +1 -1
  114. data/lib/repull/models/custom_schema_update.rb +1 -1
  115. data/lib/repull/models/delete_kv200_response.rb +1 -1
  116. data/lib/repull/models/delete_studio_deployment200_response.rb +1 -1
  117. data/lib/repull/models/delete_studio_deployment200_response_data.rb +1 -1
  118. data/lib/repull/models/delete_studio_project200_response.rb +1 -1
  119. data/lib/repull/models/delete_studio_project200_response_data.rb +1 -1
  120. data/lib/repull/models/delete_studio_project_file200_response.rb +1 -1
  121. data/lib/repull/models/delete_studio_project_file200_response_data.rb +1 -1
  122. data/lib/repull/models/error.rb +1 -1
  123. data/lib/repull/models/error_error.rb +1 -1
  124. data/lib/repull/models/error_error_support.rb +1 -1
  125. data/lib/repull/models/generate_studio_completion200_response.rb +1 -1
  126. data/lib/repull/models/generate_studio_completion200_response_data.rb +1 -1
  127. data/lib/repull/models/generate_studio_completion_request.rb +1 -1
  128. data/lib/repull/models/generate_studio_completion_request_project_id.rb +1 -1
  129. data/lib/repull/models/get_health200_response.rb +1 -1
  130. data/lib/repull/models/get_studio_deployment200_response.rb +1 -1
  131. data/lib/repull/models/get_studio_project200_response.rb +1 -1
  132. data/lib/repull/models/guest.rb +1 -1
  133. data/lib/repull/models/guest_contact.rb +1 -1
  134. data/lib/repull/models/guest_flag.rb +1 -1
  135. data/lib/repull/models/guest_list_response.rb +1 -1
  136. data/lib/repull/models/guest_note.rb +1 -1
  137. data/lib/repull/models/guest_profile.rb +1 -1
  138. data/lib/repull/models/guest_reservations_summary.rb +1 -1
  139. data/lib/repull/models/list_kv200_response.rb +1 -1
  140. data/lib/repull/models/list_kv200_response_data_inner.rb +1 -1
  141. data/lib/repull/models/list_kv200_response_pagination.rb +1 -1
  142. data/lib/repull/models/list_studio_deployments200_response.rb +1 -1
  143. data/lib/repull/models/list_studio_project_files200_response.rb +1 -1
  144. data/lib/repull/models/list_studio_projects200_response.rb +1 -1
  145. data/lib/repull/models/listing.rb +1 -1
  146. data/lib/repull/models/listing_active_request.rb +165 -0
  147. data/lib/repull/models/listing_active_response.rb +158 -0
  148. data/lib/repull/models/listing_address.rb +1 -1
  149. data/lib/repull/models/listing_amenity.rb +1 -1
  150. data/lib/repull/models/listing_channel.rb +1 -1
  151. data/lib/repull/models/listing_comp.rb +1 -1
  152. data/lib/repull/models/listing_comp_nightly.rb +1 -1
  153. data/lib/repull/models/listing_comp_ratings.rb +1 -1
  154. data/lib/repull/models/listing_comps_response.rb +1 -1
  155. data/lib/repull/models/listing_content.rb +1 -1
  156. data/lib/repull/models/listing_create_request.rb +1 -1
  157. data/lib/repull/models/listing_create_response.rb +1 -1
  158. data/lib/repull/models/listing_created_event.rb +1 -1
  159. data/lib/repull/models/listing_created_payload.rb +1 -1
  160. data/lib/repull/models/listing_created_payload_address.rb +1 -1
  161. data/lib/repull/models/listing_deleted_event.rb +1 -1
  162. data/lib/repull/models/listing_deleted_payload.rb +1 -1
  163. data/lib/repull/models/listing_details.rb +1 -1
  164. data/lib/repull/models/listing_generate_content_request.rb +1 -1
  165. data/lib/repull/models/listing_generate_content_response.rb +1 -1
  166. data/lib/repull/models/listing_list_response.rb +1 -1
  167. data/lib/repull/models/listing_pricing_apply_request.rb +1 -1
  168. data/lib/repull/models/listing_pricing_apply_response.rb +1 -1
  169. data/lib/repull/models/listing_pricing_history_entry.rb +1 -1
  170. data/lib/repull/models/listing_pricing_history_response.rb +1 -1
  171. data/lib/repull/models/listing_pricing_recommendation.rb +1 -1
  172. data/lib/repull/models/listing_pricing_response.rb +1 -1
  173. data/lib/repull/models/listing_pricing_response_comp_summary.rb +1 -1
  174. data/lib/repull/models/listing_pricing_response_date_range.rb +1 -1
  175. data/lib/repull/models/listing_pricing_response_listing.rb +1 -1
  176. data/lib/repull/models/listing_pricing_strategy.rb +1 -1
  177. data/lib/repull/models/listing_pricing_strategy_input.rb +1 -1
  178. data/lib/repull/models/listing_publish_airbnb_request.rb +1 -1
  179. data/lib/repull/models/listing_publish_response.rb +1 -1
  180. data/lib/repull/models/listing_publish_status_channel.rb +1 -1
  181. data/lib/repull/models/listing_publish_status_connection.rb +1 -1
  182. data/lib/repull/models/listing_publish_status_response.rb +1 -1
  183. data/lib/repull/models/listing_quality_tier.rb +1 -1
  184. data/lib/repull/models/listing_segment.rb +1 -1
  185. data/lib/repull/models/listing_segment_recommendation.rb +1 -1
  186. data/lib/repull/models/listing_segments_response.rb +1 -1
  187. data/lib/repull/models/listing_segments_response_scope.rb +1 -1
  188. data/lib/repull/models/listing_updated_event.rb +1 -1
  189. data/lib/repull/models/listing_updated_payload.rb +1 -1
  190. data/lib/repull/models/map_connect_booking_rooms_request.rb +1 -1
  191. data/lib/repull/models/map_connect_booking_rooms_response.rb +1 -1
  192. data/lib/repull/models/market_browse_category.rb +1 -1
  193. data/lib/repull/models/market_browse_entry.rb +1 -1
  194. data/lib/repull/models/market_browse_featured.rb +1 -1
  195. data/lib/repull/models/market_browse_response.rb +1 -1
  196. data/lib/repull/models/market_calendar_day.rb +1 -1
  197. data/lib/repull/models/market_calendar_day_events_inner.rb +1 -1
  198. data/lib/repull/models/market_calendar_response.rb +1 -1
  199. data/lib/repull/models/market_detail_response.rb +1 -1
  200. data/lib/repull/models/market_detail_response_price_distribution_inner.rb +1 -1
  201. data/lib/repull/models/market_detail_response_property_type_mix_inner.rb +1 -1
  202. data/lib/repull/models/market_detail_response_supply_trend_inner.rb +1 -1
  203. data/lib/repull/models/market_detail_response_top_comps.rb +1 -1
  204. data/lib/repull/models/market_event.rb +1 -1
  205. data/lib/repull/models/market_my_listing.rb +1 -1
  206. data/lib/repull/models/market_summary.rb +1 -1
  207. data/lib/repull/models/market_top_comp.rb +1 -1
  208. data/lib/repull/models/markets_overview_response.rb +1 -1
  209. data/lib/repull/models/markets_overview_response_browse.rb +1 -1
  210. data/lib/repull/models/markets_overview_response_subscriptions.rb +1 -1
  211. data/lib/repull/models/markets_overview_response_totals.rb +1 -1
  212. data/lib/repull/models/message.rb +1 -1
  213. data/lib/repull/models/message_list_response.rb +1 -1
  214. data/lib/repull/models/pagination.rb +1 -1
  215. data/lib/repull/models/payment_completed_event.rb +1 -1
  216. data/lib/repull/models/payment_completed_payload.rb +1 -1
  217. data/lib/repull/models/payment_refunded_event.rb +1 -1
  218. data/lib/repull/models/payment_refunded_payload.rb +1 -1
  219. data/lib/repull/models/plumguide_listing.rb +1 -1
  220. data/lib/repull/models/plumguide_listing_list_response.rb +1 -1
  221. data/lib/repull/models/property.rb +1 -1
  222. data/lib/repull/models/property_list_response.rb +1 -1
  223. data/lib/repull/models/reply_booking_review200_response.rb +1 -1
  224. data/lib/repull/models/reply_booking_review_request.rb +1 -1
  225. data/lib/repull/models/repull_ping_event.rb +1 -1
  226. data/lib/repull/models/repull_ping_payload.rb +1 -1
  227. data/lib/repull/models/reservation.rb +1 -1
  228. data/lib/repull/models/reservation_cancelled_event.rb +1 -1
  229. data/lib/repull/models/reservation_cancelled_payload.rb +1 -1
  230. data/lib/repull/models/reservation_created_event.rb +1 -1
  231. data/lib/repull/models/reservation_created_payload.rb +1 -1
  232. data/lib/repull/models/reservation_financials.rb +1 -1
  233. data/lib/repull/models/reservation_list_response.rb +1 -1
  234. data/lib/repull/models/reservation_message_received_event.rb +1 -1
  235. data/lib/repull/models/reservation_message_received_payload.rb +1 -1
  236. data/lib/repull/models/reservation_message_received_payload_from.rb +1 -1
  237. data/lib/repull/models/reservation_occupancy.rb +1 -1
  238. data/lib/repull/models/reservation_primary_guest.rb +1 -1
  239. data/lib/repull/models/reservation_updated_event.rb +1 -1
  240. data/lib/repull/models/reservation_updated_payload.rb +1 -1
  241. data/lib/repull/models/reservation_webhook_object.rb +1 -1
  242. data/lib/repull/models/respond_airbnb_review_request.rb +1 -1
  243. data/lib/repull/models/review.rb +1 -1
  244. data/lib/repull/models/review_category.rb +1 -1
  245. data/lib/repull/models/review_list_response.rb +1 -1
  246. data/lib/repull/models/review_response.rb +1 -1
  247. data/lib/repull/models/rotate_webhook_secret200_response.rb +1 -1
  248. data/lib/repull/models/select_connect_provider_request.rb +1 -1
  249. data/lib/repull/models/select_provider_response.rb +1 -1
  250. data/lib/repull/models/set_kv_request.rb +1 -1
  251. data/lib/repull/models/studio_deployment.rb +1 -1
  252. data/lib/repull/models/studio_error.rb +1 -1
  253. data/lib/repull/models/studio_error_error.rb +1 -1
  254. data/lib/repull/models/studio_file.rb +1 -1
  255. data/lib/repull/models/studio_generation.rb +1 -1
  256. data/lib/repull/models/studio_project.rb +1 -1
  257. data/lib/repull/models/test_webhook_request.rb +1 -1
  258. data/lib/repull/models/update_availability_request.rb +1 -1
  259. data/lib/repull/models/update_listing_pricing_strategy200_response.rb +1 -1
  260. data/lib/repull/models/update_reservation_request.rb +1 -1
  261. data/lib/repull/models/update_studio_project_request.rb +1 -1
  262. data/lib/repull/models/update_webhook_request.rb +1 -1
  263. data/lib/repull/models/upsert_studio_project_file200_response.rb +1 -1
  264. data/lib/repull/models/upsert_studio_project_file200_response_data.rb +1 -1
  265. data/lib/repull/models/upsert_studio_project_file_request.rb +1 -1
  266. data/lib/repull/models/vrbo_listing.rb +1 -1
  267. data/lib/repull/models/vrbo_listing_list_response.rb +1 -1
  268. data/lib/repull/models/vrbo_reservation.rb +1 -1
  269. data/lib/repull/models/vrbo_reservation_list_response.rb +1 -1
  270. data/lib/repull/models/webhook_delivery.rb +1 -1
  271. data/lib/repull/models/webhook_delivery_detail.rb +1 -1
  272. data/lib/repull/models/webhook_delivery_list_response.rb +1 -1
  273. data/lib/repull/models/webhook_event.rb +1 -1
  274. data/lib/repull/models/webhook_event_catalog.rb +1 -1
  275. data/lib/repull/models/webhook_event_catalog_domains_inner.rb +1 -1
  276. data/lib/repull/models/webhook_event_catalog_entry.rb +1 -1
  277. data/lib/repull/models/webhook_event_type.rb +1 -1
  278. data/lib/repull/models/webhook_list_response.rb +1 -1
  279. data/lib/repull/models/webhook_subscription.rb +1 -1
  280. data/lib/repull/version.rb +2 -2
  281. data/lib/repull.rb +3 -1
  282. data/openapi/v1.json +141 -8
  283. metadata +4 -2
data/openapi/v1.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "info": {
4
4
  "title": "Repull API",
5
5
  "version": "1.0.0",
6
- "description": "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.\n\n## Designed for AI agents\nEvery 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:\n- `error.code` \u2014 stable string identifier (e.g. `invalid_params`, `rate_limit_exceeded`)\n- `error.message` \u2014 human-readable cause\n- `error.fix` \u2014 exact recovery steps (e.g. \"Pass `check_in_after` as ISO 8601: `?check_in_after=2026-01-15`\")\n- `error.docs_url` \u2014 link to the canonical write-up at `https://repull.dev/docs/errors/{code}`\n- `error.request_id` \u2014 id to correlate with server-side logs\n- `error.field` / `error.value_received` / `error.valid_values` / `error.did_you_mean` \u2014 when the error is parameter-specific\n- `error.retry_after` \u2014 seconds to wait before retrying (rate-limit + transient upstream)\n\n`Access-Control-Expose-Headers` lists `x-request-id` and the `X-RateLimit-*` family so browsers can read them on cross-origin responses.\n\n## Quick Start\n1. Get an API key at https://repull.dev/dashboard\n2. Connect a PMS: `POST /v1/connect/{provider}`\n3. List properties: `GET /v1/properties`\n4. Get reservations: `GET /v1/reservations`\n\n## Authentication\nAll requests require a Bearer token:\n```\nAuthorization: Bearer sk_test_YOUR_API_KEY\n```\n\nSandbox keys start with `sk_test_`, production with `sk_live_`.\n\n## Request Correlation (X-Request-ID)\nEvery response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports \u2014 we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id.\n\nYou 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}$`.\n\nThe 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.\n\n## Rate Limits\nThe public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas.\n\n**Default policy:** 600 requests per 60 seconds, per API key. Sliding window \u2014 there is no fixed-minute boundary you can burst across.\n\nEvery response includes:\n\n| Header | Meaning |\n|---|---|\n| `X-RateLimit-Limit` | Requests permitted in the current window. |\n| `X-RateLimit-Remaining` | Requests left in the current window after this call. |\n| `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. |\n| `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. |\n| `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** |\n\n**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 \u2014 never a tight loop.\n\nRecommended backoff:\n```\nsleep_ms = (Retry-After * 1000) + random(0..250)\n```\n\nMonthly + daily-AI tier quotas (`free`, `starter`, `custom`) are enforced separately and also surface as 429s; they include `tier`, `scope`, and `resets_at` fields.\n\n## Plan Limits (402 \u2014 `listings_limit_exceeded`)\nThe Repull API also enforces a per-tier cap on **active listings**:\n\n| Tier | Active listings cap |\n|---|---|\n| `free` | 5 |\n| `starter` | 50 |\n| `custom` | unlimited |\n\nWhen 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:\n\n- `/v1/health` \u2014 uptime probes are never gated.\n- `/v1/usage/*` \u2014 so dashboards can render the over-cap state.\n- Any `DELETE` \u2014 so the customer can trim listings to get back under the cap without paying.\n\nUnlike 429, 402 is NOT a \"wait and retry\" condition \u2014 `Retry-After` is not set. The only paths back to 200 are:\n 1. `DELETE` enough listings to come back under the cap, or\n 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.\n\nThe envelope mirrors `rate_limit_exceeded` for SDK ergonomics: `tier`, `limit`, `active_listings`, `upgrade_url`, plus the standard `code` / `message` / `fix` / `docs_url` / `request_id`.",
6
+ "description": "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.\n\n## Designed for AI agents\nEvery 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:\n- `error.code` \u2014 stable string identifier (e.g. `invalid_params`, `rate_limit_exceeded`)\n- `error.message` \u2014 human-readable cause\n- `error.fix` \u2014 exact recovery steps (e.g. \"Pass `check_in_after` as ISO 8601: `?check_in_after=2026-01-15`\")\n- `error.docs_url` \u2014 link to the canonical write-up at `https://repull.dev/docs/errors/{code}`\n- `error.request_id` \u2014 id to correlate with server-side logs\n- `error.field` / `error.value_received` / `error.valid_values` / `error.did_you_mean` \u2014 when the error is parameter-specific\n- `error.retry_after` \u2014 seconds to wait before retrying (rate-limit + transient upstream)\n\n`Access-Control-Expose-Headers` lists `x-request-id` and the `X-RateLimit-*` family so browsers can read them on cross-origin responses.\n\n## Quick Start\n1. Get an API key at https://repull.dev/dashboard\n2. Connect a PMS: `POST /v1/connect/{provider}`\n3. List properties: `GET /v1/properties`\n4. Get reservations: `GET /v1/reservations`\n\n## Authentication\nAll requests require a Bearer token:\n```\nAuthorization: Bearer sk_test_YOUR_API_KEY\n```\n\nSandbox keys start with `sk_test_`, production with `sk_live_`.\n\n## Request Correlation (X-Request-ID)\nEvery response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports \u2014 we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id.\n\nYou 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}$`.\n\nThe 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.\n\n## Rate Limits\nThe public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas.\n\n**Default policy:** 600 requests per 60 seconds, per API key. Sliding window \u2014 there is no fixed-minute boundary you can burst across.\n\nEvery response includes:\n\n| Header | Meaning |\n|---|---|\n| `X-RateLimit-Limit` | Requests permitted in the current window. |\n| `X-RateLimit-Remaining` | Requests left in the current window after this call. |\n| `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. |\n| `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. |\n| `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** |\n\n**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 \u2014 never a tight loop.\n\nRecommended backoff:\n```\nsleep_ms = (Retry-After * 1000) + random(0..250)\n```\n\nMonthly + daily-AI tier quotas (`free`, `starter`, `custom`) are enforced separately and also surface as 429s; they include `tier`, `scope`, and `resets_at` fields.\n\n## Plan Limits (402 \u2014 `listings_limit_exceeded`)\nThe Repull API also enforces a per-tier cap on **active listings**:\n\n| Tier | Active listings cap |\n|---|---|\n| `free` | 3 |\n| `starter` | 50 |\n| `custom` | unlimited |\n\nWhen 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:\n\n- `/v1/health` \u2014 uptime probes are never gated.\n- `/v1/usage/*` \u2014 so dashboards can render the over-cap state.\n- Any `DELETE` \u2014 so the customer can trim listings to get back under the cap without paying.\n\nUnlike 429, 402 is NOT a \"wait and retry\" condition \u2014 `Retry-After` is not set. The only paths back to 200 are:\n 1. `DELETE` enough listings to come back under the cap, or\n 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.\n\nThe envelope mirrors `rate_limit_exceeded` for SDK ergonomics: `tier`, `limit`, `active_listings`, `upgrade_url`, plus the standard `code` / `message` / `fix` / `docs_url` / `request_id`.",
7
7
  "contact": {
8
8
  "email": "ivan@vanio.ai",
9
9
  "url": "https://repull.dev"
@@ -3688,6 +3688,31 @@
3688
3688
  }
3689
3689
  }
3690
3690
  },
3691
+ "ListingActiveRequest": {
3692
+ "type": "object",
3693
+ "required": [
3694
+ "active"
3695
+ ],
3696
+ "properties": {
3697
+ "active": {
3698
+ "type": "boolean",
3699
+ "description": "Target active state. `false` deactivates (excludes) the listing; `true` reactivates it (subject to the plan-listings cap)."
3700
+ }
3701
+ }
3702
+ },
3703
+ "ListingActiveResponse": {
3704
+ "type": "object",
3705
+ "properties": {
3706
+ "id": {
3707
+ "type": "string",
3708
+ "description": "The listing id (id fields are serialized as strings to preserve precision)."
3709
+ },
3710
+ "active": {
3711
+ "type": "boolean",
3712
+ "description": "The resulting active state after the toggle."
3713
+ }
3714
+ }
3715
+ },
3691
3716
  "ListingGenerateContentRequest": {
3692
3717
  "type": "object",
3693
3718
  "properties": {
@@ -6286,7 +6311,7 @@
6286
6311
  }
6287
6312
  },
6288
6313
  "PaymentRequired": {
6289
- "description": "Plan-listings cap exceeded. The customer's active listing count is above the cap of their resolved Repull tier (`free` = 5, `starter` = 50, `custom` = unlimited). Returned on every route except `/v1/health`, `/v1/usage/*`, and any `DELETE` \u2014 these stay served so the customer can read their state, render the over-cap UI, or trim listings to get back under the cap.\n\nDistinct from 429 / `rate_limit_exceeded` \u2014 this is NOT a \"wait and retry\" condition. The only paths back to a 200 are:\n 1. `DELETE` enough listings via `DELETE /v1/listings/{id}` (or the channel-specific listings DELETE) until `active_listings <= limit`.\n 2. Upgrade to a tier with a higher cap at `https://repull.dev/dashboard/billing`. The very next request after the upgrade lands will see the new cap (server-side usage cache is 60s, so allow up to 1 minute for propagation).\n\nNo `Retry-After` header \u2014 backoff doesn't fix this.",
6314
+ "description": "Plan-listings cap exceeded. The customer's active listing count is above the cap of their resolved Repull tier (`free` = 3, `starter` = 50, `custom` = unlimited). Returned on every route except `/v1/health`, `/v1/usage/*`, and any `DELETE` \u2014 these stay served so the customer can read their state, render the over-cap UI, or trim listings to get back under the cap.\n\nDistinct from 429 / `rate_limit_exceeded` \u2014 this is NOT a \"wait and retry\" condition. The only paths back to a 200 are:\n 1. `DELETE` enough listings via `DELETE /v1/listings/{id}` (or the channel-specific listings DELETE) until `active_listings <= limit`.\n 2. Upgrade to a tier with a higher cap at `https://repull.dev/dashboard/billing`. The very next request after the upgrade lands will see the new cap (server-side usage cache is 60s, so allow up to 1 minute for propagation).\n\nNo `Retry-After` header \u2014 backoff doesn't fix this.",
6290
6315
  "content": {
6291
6316
  "application/json": {
6292
6317
  "schema": {
@@ -6294,16 +6319,16 @@
6294
6319
  },
6295
6320
  "examples": {
6296
6321
  "freeTierOverCap": {
6297
- "summary": "Free tier customer over the 5-listings cap",
6322
+ "summary": "Free tier customer over the 3-listings cap",
6298
6323
  "value": {
6299
6324
  "error": {
6300
6325
  "code": "listings_limit_exceeded",
6301
- "message": "Your account has 24 active listings but the 'free' tier is capped at 5. The Repull API only serves accounts whose listing count is within their plan.",
6302
- "fix": "Either reduce your active listings to 5 or fewer (via DELETE endpoints \u2014 these are still served), or upgrade your plan at https://repull.dev/dashboard/billing to lift the cap immediately.",
6326
+ "message": "Your account has 24 active listings but the 'free' tier is capped at 3. The Repull API only serves accounts whose listing count is within their plan.",
6327
+ "fix": "Either reduce your active listings to 3 or fewer (via DELETE endpoints \u2014 these are still served), or upgrade your plan at https://repull.dev/dashboard/billing to lift the cap immediately.",
6303
6328
  "docs_url": "https://repull.dev/docs/errors/listings_limit_exceeded",
6304
6329
  "request_id": "req_01J5X7Y8Z9ABCDEF12345678",
6305
6330
  "tier": "free",
6306
- "limit": 5,
6331
+ "limit": 3,
6307
6332
  "active_listings": 24,
6308
6333
  "upgrade_url": "https://repull.dev/dashboard/billing"
6309
6334
  }
@@ -7632,6 +7657,12 @@
7632
7657
  },
7633
7658
  "nullable": true,
7634
7659
  "description": "Optional whitelist of provider IDs the picker should expose. Omit to show every channel in the registry."
7660
+ },
7661
+ "locale": {
7662
+ "type": "string",
7663
+ "nullable": true,
7664
+ "description": "Optional UI language for the hosted Connect pages. Accepts any supported locale code (currently `en`, `fr`). When set it pins the language for the whole flow, overriding the workspace `default_language`. Unknown codes are ignored and the page falls back to the workspace default, then `Accept-Language`, then `en`. The end user can still override per-visit with a `?locale=` query param on the hosted page.",
7665
+ "example": "fr"
7635
7666
  }
7636
7667
  }
7637
7668
  }
@@ -7800,6 +7831,12 @@
7800
7831
  "clientSecret": {
7801
7832
  "type": "string",
7802
7833
  "description": "Plumguide \u2014 client secret."
7834
+ },
7835
+ "locale": {
7836
+ "type": "string",
7837
+ "nullable": true,
7838
+ "description": "Airbnb only \u2014 optional UI language for the hosted Connect pages. Accepts any supported locale code (currently `en`, `fr`); unknown codes are ignored and resolution falls back to the workspace `default_language`, then `Accept-Language`, then `en`.",
7839
+ "example": "fr"
7803
7840
  }
7804
7841
  }
7805
7842
  }
@@ -8684,8 +8721,8 @@
8684
8721
  },
8685
8722
  "post": {
8686
8723
  "operationId": "airbnb_listing_action",
8687
- "summary": "Listing action (push/publish/unlist/delete)",
8688
- "description": "Apply a state action to an Airbnb listing \u2014 `push` (sync local changes upstream), `publish` (make publicly bookable), `unlist` (hide), or `delete` (permanent). Each action has different reversibility \u2014 see docs.",
8724
+ "summary": "Listing action (delete/push/publish/unlist)",
8725
+ "description": "Apply a state action to a listing by id.\n\n`delete` is implemented as a **deactivate of the Repull record only** \u2014 it sets the listing inactive and KEEPS the row; it does NOT touch the upstream Airbnb listing (Repull never deletes or deactivates on Airbnb's side). Use it to exclude a listing / trim back under the plan-listings cap; reactivate via `PATCH /v1/listings/{id}` with `{ \"active\": true }`. Idempotent.\n\n`push` (sync local changes upstream), `publish` (make publicly bookable), and `unlist` (hide) depend on the host-side sync orchestrator and currently return 501.",
8689
8726
  "tags": [
8690
8727
  "Airbnb"
8691
8728
  ],
@@ -9378,6 +9415,9 @@
9378
9415
  },
9379
9416
  "400": {
9380
9417
  "$ref": "#/components/responses/BadRequest"
9418
+ },
9419
+ "402": {
9420
+ "$ref": "#/components/responses/PaymentRequired"
9381
9421
  }
9382
9422
  }
9383
9423
  }
@@ -9435,6 +9475,99 @@
9435
9475
  "$ref": "#/components/responses/UnprocessableEntity"
9436
9476
  }
9437
9477
  }
9478
+ },
9479
+ "patch": {
9480
+ "operationId": "updateListingActive",
9481
+ "summary": "Deactivate or reactivate a listing",
9482
+ "description": "Toggle a listing's active state. Send `{ \"active\": false }` to **deactivate** (exclude the listing from Repull) or `{ \"active\": true }` to **reactivate** it.\n\n\"Deactivate\" keeps the listing row \u2014 it is NOT a hard delete, and it NEVER touches the upstream channel (Airbnb / Hospitable / Booking.com). Repull only mutates its own copy of the inventory. Deactivating is the self-serve way to get back under the plan-listings cap without paying.\n\nReactivation respects the plan-listings cap: if activating this listing would push you over the cap for your tier, the call returns `402 listings_limit_exceeded` and the listing stays inactive. Deactivate another listing or upgrade first.\n\nIdempotent: setting a listing to the state it's already in returns 200.",
9483
+ "tags": [
9484
+ "Listings"
9485
+ ],
9486
+ "parameters": [
9487
+ {
9488
+ "name": "id",
9489
+ "in": "path",
9490
+ "required": true,
9491
+ "schema": {
9492
+ "type": "integer"
9493
+ },
9494
+ "description": "Repull listing id"
9495
+ }
9496
+ ],
9497
+ "requestBody": {
9498
+ "required": true,
9499
+ "content": {
9500
+ "application/json": {
9501
+ "schema": {
9502
+ "$ref": "#/components/schemas/ListingActiveRequest"
9503
+ }
9504
+ }
9505
+ }
9506
+ },
9507
+ "responses": {
9508
+ "200": {
9509
+ "description": "Updated active state",
9510
+ "content": {
9511
+ "application/json": {
9512
+ "schema": {
9513
+ "$ref": "#/components/schemas/ListingActiveResponse"
9514
+ }
9515
+ }
9516
+ }
9517
+ },
9518
+ "401": {
9519
+ "$ref": "#/components/responses/Unauthorized"
9520
+ },
9521
+ "402": {
9522
+ "$ref": "#/components/responses/PaymentRequired"
9523
+ },
9524
+ "404": {
9525
+ "$ref": "#/components/responses/NotFound"
9526
+ },
9527
+ "422": {
9528
+ "$ref": "#/components/responses/UnprocessableEntity"
9529
+ }
9530
+ }
9531
+ },
9532
+ "delete": {
9533
+ "operationId": "deactivateListing",
9534
+ "summary": "Deactivate (exclude) a listing",
9535
+ "description": "Deactivate a listing \u2014 sets it inactive and excludes it from Repull. This is a **soft** operation: the listing row is KEPT (never hard-deleted) and the upstream channel (Airbnb / Hospitable / Booking.com) is NEVER touched. Repull only mutates its own copy.\n\nEquivalent to `PATCH /v1/listings/{id}` with `{ \"active\": false }`. This is the primary self-serve way for a free-tier customer to trim back under the plan-listings cap \u2014 `DELETE` is served even when the account is over the cap (a 402-locked account can still call it). To bring a listing back, use `PATCH` with `{ \"active\": true }`.\n\nIdempotent: deactivating an already-inactive listing returns 200.",
9536
+ "tags": [
9537
+ "Listings"
9538
+ ],
9539
+ "parameters": [
9540
+ {
9541
+ "name": "id",
9542
+ "in": "path",
9543
+ "required": true,
9544
+ "schema": {
9545
+ "type": "integer"
9546
+ },
9547
+ "description": "Repull listing id"
9548
+ }
9549
+ ],
9550
+ "responses": {
9551
+ "200": {
9552
+ "description": "Listing deactivated",
9553
+ "content": {
9554
+ "application/json": {
9555
+ "schema": {
9556
+ "$ref": "#/components/schemas/ListingActiveResponse"
9557
+ }
9558
+ }
9559
+ }
9560
+ },
9561
+ "401": {
9562
+ "$ref": "#/components/responses/Unauthorized"
9563
+ },
9564
+ "404": {
9565
+ "$ref": "#/components/responses/NotFound"
9566
+ },
9567
+ "422": {
9568
+ "$ref": "#/components/responses/UnprocessableEntity"
9569
+ }
9570
+ }
9438
9571
  }
9439
9572
  },
9440
9573
  "/v1/listings/{id}/generate-content": {
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: repull
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.6
4
+ version: 0.2.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivan Nikolov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-06-25 00:00:00.000000000 Z
11
+ date: 2026-07-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: typhoeus
@@ -210,6 +210,8 @@ files:
210
210
  - lib/repull/models/list_studio_project_files200_response.rb
211
211
  - lib/repull/models/list_studio_projects200_response.rb
212
212
  - lib/repull/models/listing.rb
213
+ - lib/repull/models/listing_active_request.rb
214
+ - lib/repull/models/listing_active_response.rb
213
215
  - lib/repull/models/listing_address.rb
214
216
  - lib/repull/models/listing_amenity.rb
215
217
  - lib/repull/models/listing_channel.rb