repull 0.2.34 → 0.2.36

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/lib/repull/api/connect_api.rb +6 -6
  3. data/lib/repull/api/health_api.rb +3 -3
  4. data/lib/repull/api/listings_api.rb +8 -8
  5. data/lib/repull/api/migrate_api.rb +68 -0
  6. data/lib/repull/models/{calendar_updated_event.rb → booking_unacknowledged_event.rb} +4 -4
  7. data/lib/repull/models/booking_unacknowledged_payload.rb +229 -0
  8. data/lib/repull/models/channel_degraded_event.rb +279 -0
  9. data/lib/repull/models/channel_degraded_payload.rb +174 -0
  10. data/lib/repull/models/channel_degraded_payload_object.rb +262 -0
  11. data/lib/repull/models/channel_sync_failed_event.rb +280 -0
  12. data/lib/repull/models/channel_sync_failure_payload.rb +214 -0
  13. data/lib/repull/models/channel_sync_failure_payload_failures_inner.rb +213 -0
  14. data/lib/repull/models/channel_sync_failure_payload_object.rb +289 -0
  15. data/lib/repull/models/charge_per.rb +42 -0
  16. data/lib/repull/models/connect_session_completed_payload.rb +1 -1
  17. data/lib/repull/models/connect_status_accounts_inner.rb +12 -1
  18. data/lib/repull/models/create_connect_session_request.rb +26 -2
  19. data/lib/repull/models/create_connection_request.rb +3 -23
  20. data/lib/repull/models/{plumguide_listing_list_response.rb → import_from_channex200_response.rb} +8 -19
  21. data/lib/repull/models/import_from_channex200_response_data.rb +324 -0
  22. data/lib/repull/models/import_from_channex200_response_data_channels_inner.rb +263 -0
  23. data/lib/repull/models/import_from_channex200_response_data_properties_inner.rb +222 -0
  24. data/lib/repull/models/import_from_channex200_response_data_summary.rb +201 -0
  25. data/lib/repull/models/import_from_channex200_response_data_summary_bookings.rb +165 -0
  26. data/lib/repull/models/import_from_channex200_response_data_summary_properties.rb +165 -0
  27. data/lib/repull/models/import_from_channex_request.rb +223 -0
  28. data/lib/repull/models/list_connection_units200_response.rb +12 -1
  29. data/lib/repull/models/list_connection_units200_response_units_inner.rb +1 -0
  30. data/lib/repull/models/listing.rb +82 -1
  31. data/lib/repull/models/listing_address.rb +62 -5
  32. data/lib/repull/models/listing_content_photo.rb +206 -0
  33. data/lib/repull/models/listing_fee.rb +229 -0
  34. data/lib/repull/models/listing_policies.rb +257 -0
  35. data/lib/repull/models/{calendar_updated_payload.rb → listing_policies_check_in.rb} +33 -38
  36. data/lib/repull/models/listing_policies_check_out.rb +148 -0
  37. data/lib/repull/models/{calendar_updated_payload_range.rb → listing_policies_quiet_hours.rb} +5 -5
  38. data/lib/repull/models/listing_pricing_settings.rb +233 -0
  39. data/lib/repull/models/listing_room.rb +190 -0
  40. data/lib/repull/models/{plumguide_listing.rb → listing_room_beds_inner.rb} +16 -27
  41. data/lib/repull/models/listing_rules.rb +212 -0
  42. data/lib/repull/models/listing_tax.rb +241 -0
  43. data/lib/repull/models/message.rb +24 -1
  44. data/lib/repull/models/postal_address.rb +216 -0
  45. data/lib/repull/models/property.rb +12 -2
  46. data/lib/repull/models/reservation_thread_assigned_event.rb +279 -0
  47. data/lib/repull/models/reservation_thread_assigned_payload.rb +174 -0
  48. data/lib/repull/models/reservation_thread_assigned_payload_object.rb +249 -0
  49. data/lib/repull/models/webhook_event.rb +8 -2
  50. data/lib/repull/models/webhook_event_type.rb +5 -2
  51. data/lib/repull/version.rb +1 -1
  52. data/lib/repull.rb +33 -6
  53. data/openapi/v1.json +1712 -352
  54. metadata +35 -10
  55. data/lib/repull/api/plumguide_api.rb +0 -552
  56. data/spec/api/plumguide_api_spec.rb +0 -85
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a248ac037a338371cfaa5c3460bc42fd061099795538f7a81aa66b4d21272be
4
- data.tar.gz: 3a664de3e52c9602b1dd8d2513c3e401b6948a8bf069af0664c3bc27961546b7
3
+ metadata.gz: 751997bcb46f19e528ab83ca056a1155ac4fe845ee599add4bfda29eb26714c8
4
+ data.tar.gz: 4a279c4160c27f0e51d9c04b53aef5e726de72160a4a4f8f1b4543eec1be6824
5
5
  SHA512:
6
- metadata.gz: 8c81c265d78915514dfa9e52b3e90e626c74682806bd8e2d820486a01dbedd5f50a2c466542272bb89da2a646a6cf4005574970628c793d9637d52b197e24c75
7
- data.tar.gz: fd89562f25b577ee6716952ae8379c00cd3cad4e6a01ca1055b7e2d2311b82b4459ab098f6d31fda0a59a33269eba7d5aaa6041546709dc3ae5ab1a58a705347
6
+ metadata.gz: ac7602f28a982e29082158feba621f3f6b684f7258bb1f2aa14fbebc01ef1cb116ebc7eb2891cf338720579abc4666e2450071adc1d6b83b9dbafbdffb7d0fee
7
+ data.tar.gz: 5c93798f05f33c0638ea2158d3a33d9523565488a12dcfd46e2f2d76bbc23a7e6e9772942609f22c128dc8bbcf91651bddceea296299cb6c1009f33352e8e5be
@@ -156,7 +156,7 @@ module Repull
156
156
  end
157
157
 
158
158
  # Connect to PMS/OTA provider
159
- # Establish a connection to a PMS or OTA platform. Credentials vary by provider — see docs for each provider. Airbnb-specific: pass `redirectUrl` (where to send the user after consent) and optionally `accessType`. Three tiers: `read_only` grants read-only scopes; `messaging` grants read scopes plus message read/send but NOT property management, so it can coexist with another app (e.g. an existing PMS) that already holds property management on the same Airbnb account; `full_access` — the default — grants full host scopes including the exclusive property management (only one app per Airbnb account can hold it). The response returns a hosted `url` to redirect the user to. Booking.com: pass `redirectUrl` (no `accessType`). The response returns a hosted `url` — send the user there to designate FantasticStay in their Booking.com Extranet and paste their Hotel ID. Same response shape as Airbnb (`url`, `sessionId`, `expiresAt`). Plumguide passes `clientId`/`clientSecret`. PMS providers are not connected by this call: send their credentials to `POST /v1/connect/{provider}/credentials`, or start a hosted session with `POST /v1/connect`.
159
+ # Establish a connection to a PMS or OTA platform. Credentials vary by provider — see docs for each provider. Airbnb-specific: pass `redirectUrl` (where to send the user after consent) and optionally `accessType`. Three tiers: `read_only` grants read-only scopes; `messaging` (shown to hosts as \"Messaging & reviews\") grants read scopes plus message read/send and review writes (reply to guest reviews, submit host reviews — Airbnb's `reviews_write`) but NOT property management, so it can coexist with another app (e.g. an existing PMS) that already holds property management on the same Airbnb account; `full_access` — the default — grants full host scopes including the exclusive property management (only one app per Airbnb account can hold it). The response returns a hosted `url` to redirect the user to. Booking.com: pass `redirectUrl` (no `accessType`). The response returns a hosted `url` — send the user there to select our connectivity provider in their Booking.com Extranet and paste their Hotel ID. Same response shape as Airbnb (`url`, `sessionId`, `expiresAt`). PMS providers are not connected by this call: send their credentials to `POST /v1/connect/{provider}/credentials`, or start a hosted session with `POST /v1/connect`.
160
160
  # @param provider [String] PMS provider slug (e.g., hostaway, guesty, ownerrez)
161
161
  # @param [Hash] opts the optional parameters
162
162
  # @option opts [CreateConnectionRequest] :create_connection_request
@@ -167,7 +167,7 @@ module Repull
167
167
  end
168
168
 
169
169
  # Connect to PMS/OTA provider
170
- # Establish a connection to a PMS or OTA platform. Credentials vary by provider — see docs for each provider. Airbnb-specific: pass `redirectUrl` (where to send the user after consent) and optionally `accessType`. Three tiers: `read_only` grants read-only scopes; `messaging` grants read scopes plus message read/send but NOT property management, so it can coexist with another app (e.g. an existing PMS) that already holds property management on the same Airbnb account; `full_access` — the default — grants full host scopes including the exclusive property management (only one app per Airbnb account can hold it). The response returns a hosted `url` to redirect the user to. Booking.com: pass `redirectUrl` (no `accessType`). The response returns a hosted `url` — send the user there to designate FantasticStay in their Booking.com Extranet and paste their Hotel ID. Same response shape as Airbnb (`url`, `sessionId`, `expiresAt`). Plumguide passes `clientId`/`clientSecret`. PMS providers are not connected by this call: send their credentials to `POST /v1/connect/{provider}/credentials`, or start a hosted session with `POST /v1/connect`.
170
+ # Establish a connection to a PMS or OTA platform. Credentials vary by provider — see docs for each provider. Airbnb-specific: pass `redirectUrl` (where to send the user after consent) and optionally `accessType`. Three tiers: `read_only` grants read-only scopes; `messaging` (shown to hosts as \"Messaging & reviews\") grants read scopes plus message read/send and review writes (reply to guest reviews, submit host reviews — Airbnb's `reviews_write`) but NOT property management, so it can coexist with another app (e.g. an existing PMS) that already holds property management on the same Airbnb account; `full_access` — the default — grants full host scopes including the exclusive property management (only one app per Airbnb account can hold it). The response returns a hosted `url` to redirect the user to. Booking.com: pass `redirectUrl` (no `accessType`). The response returns a hosted `url` — send the user there to select our connectivity provider in their Booking.com Extranet and paste their Hotel ID. Same response shape as Airbnb (`url`, `sessionId`, `expiresAt`). PMS providers are not connected by this call: send their credentials to `POST /v1/connect/{provider}/credentials`, or start a hosted session with `POST /v1/connect`.
171
171
  # @param provider [String] PMS provider slug (e.g., hostaway, guesty, ownerrez)
172
172
  # @param [Hash] opts the optional parameters
173
173
  # @option opts [CreateConnectionRequest] :create_connection_request
@@ -226,7 +226,7 @@ module Repull
226
226
  end
227
227
 
228
228
  # Disconnect provider
229
- # Disconnect ONE connected account of a provider from this workspace. Supported for `airbnb` and `booking`. **Which account.** Pass `accountId` — for Airbnb the host id (`accounts[].externalAccountId` from `GET /v1/connect/airbnb`), for Booking.com the hotel id. It is optional only when the workspace has exactly one account for the provider. With several and no `accountId`, the call returns `422` with the account ids in `valid_values` instead of guessing. An `accountId` that is not connected to this workspace returns `404`. Disconnecting one account leaves the others connected. **What happens.** The account's stored authorization is removed and it stops syncing. Its listings are **deactivated**, not deleted: they stop counting toward your plan's listing limit, their data is kept, and they are returned in `listingsDeactivated`. A listing that is still connected through another account or channel stays active. Reconnect the account, then activate the listings with `POST /v1/listings/status`. The change is all or nothing. For Airbnb, the host can also revoke access on Airbnb's side (Account → Privacy & sharing → Connected apps); that alone does not update this workspace, so call this endpoint as well. Other providers return `501 not_implemented` with instructions for disconnecting on the provider's side. That answer depends only on the provider, not on your workspace: an unsupported provider returns `501` whether or not you have a connection to it. `404 not_found` on a supported provider means this workspace has no connection to it (or, with `accountId`, that the account is not connected here).
229
+ # Disconnect ONE connected account of a provider from this workspace. Supported for `airbnb`, `booking` and `vrbo-login`. **Which account.** Pass `accountId` — for Airbnb the host id (`accounts[].externalAccountId` from `GET /v1/connect/airbnb`), for Booking.com the hotel id, for `vrbo-login` the sign-in's `accounts[].externalAccountId` from `GET /v1/connect/vrbo-login`. It is optional only when the workspace has exactly one account for the provider. With several and no `accountId`, the call returns `422` with the account ids in `valid_values` instead of guessing. An `accountId` that is not connected to this workspace returns `404`. Disconnecting one account leaves the others connected. **What happens.** The account's stored authorization is removed and it stops syncing. Its listings are **deactivated**, not deleted: they stop counting toward your plan's listing limit, their data is kept, and they are returned in `listingsDeactivated`. A listing that is still connected through another account or channel stays active. Reconnect the account, then activate the listings with `POST /v1/listings/status`. The change is all or nothing. For Airbnb, the host can also revoke access on Airbnb's side (Account → Privacy & sharing → Connected apps); that alone does not update this workspace, so call this endpoint as well. Other providers return `501 not_implemented` with instructions for disconnecting on the provider's side. That answer depends only on the provider, not on your workspace: an unsupported provider returns `501` whether or not you have a connection to it. `404 not_found` on a supported provider means this workspace has no connection to it (or, with `accountId`, that the account is not connected here).
230
230
  # @param provider [String] PMS provider slug (e.g., hostaway, guesty, ownerrez)
231
231
  # @param [Hash] opts the optional parameters
232
232
  # @option opts [String] :account_id The account to disconnect: the Airbnb host id (`accounts[].externalAccountId` on `GET /v1/connect/airbnb`) or the Booking.com hotel id. Required when the workspace has more than one connected account for the provider. Not the same as the `X-Account-Id` header.
@@ -237,7 +237,7 @@ module Repull
237
237
  end
238
238
 
239
239
  # Disconnect provider
240
- # Disconnect ONE connected account of a provider from this workspace. Supported for `airbnb` and `booking`. **Which account.** Pass `accountId` — for Airbnb the host id (`accounts[].externalAccountId` from `GET /v1/connect/airbnb`), for Booking.com the hotel id. It is optional only when the workspace has exactly one account for the provider. With several and no `accountId`, the call returns `422` with the account ids in `valid_values` instead of guessing. An `accountId` that is not connected to this workspace returns `404`. Disconnecting one account leaves the others connected. **What happens.** The account's stored authorization is removed and it stops syncing. Its listings are **deactivated**, not deleted: they stop counting toward your plan's listing limit, their data is kept, and they are returned in `listingsDeactivated`. A listing that is still connected through another account or channel stays active. Reconnect the account, then activate the listings with `POST /v1/listings/status`. The change is all or nothing. For Airbnb, the host can also revoke access on Airbnb's side (Account → Privacy & sharing → Connected apps); that alone does not update this workspace, so call this endpoint as well. Other providers return `501 not_implemented` with instructions for disconnecting on the provider's side. That answer depends only on the provider, not on your workspace: an unsupported provider returns `501` whether or not you have a connection to it. `404 not_found` on a supported provider means this workspace has no connection to it (or, with `accountId`, that the account is not connected here).
240
+ # Disconnect ONE connected account of a provider from this workspace. Supported for `airbnb`, `booking` and `vrbo-login`. **Which account.** Pass `accountId` — for Airbnb the host id (`accounts[].externalAccountId` from `GET /v1/connect/airbnb`), for Booking.com the hotel id, for `vrbo-login` the sign-in's `accounts[].externalAccountId` from `GET /v1/connect/vrbo-login`. It is optional only when the workspace has exactly one account for the provider. With several and no `accountId`, the call returns `422` with the account ids in `valid_values` instead of guessing. An `accountId` that is not connected to this workspace returns `404`. Disconnecting one account leaves the others connected. **What happens.** The account's stored authorization is removed and it stops syncing. Its listings are **deactivated**, not deleted: they stop counting toward your plan's listing limit, their data is kept, and they are returned in `listingsDeactivated`. A listing that is still connected through another account or channel stays active. Reconnect the account, then activate the listings with `POST /v1/listings/status`. The change is all or nothing. For Airbnb, the host can also revoke access on Airbnb's side (Account → Privacy & sharing → Connected apps); that alone does not update this workspace, so call this endpoint as well. Other providers return `501 not_implemented` with instructions for disconnecting on the provider's side. That answer depends only on the provider, not on your workspace: an unsupported provider returns `501` whether or not you have a connection to it. `404 not_found` on a supported provider means this workspace has no connection to it (or, with `accountId`, that the account is not connected here).
241
241
  # @param provider [String] PMS provider slug (e.g., hostaway, guesty, ownerrez)
242
242
  # @param [Hash] opts the optional parameters
243
243
  # @option opts [String] :account_id The account to disconnect: the Airbnb host id (`accounts[].externalAccountId` on `GET /v1/connect/airbnb`) or the Booking.com hotel id. Required when the workspace has more than one connected account for the provider. Not the same as the `X-Account-Id` header.
@@ -2311,7 +2311,7 @@ module Repull
2311
2311
  end
2312
2312
 
2313
2313
  # Verify a Booking.com hotel ID for a Connect session
2314
- # Manual-paste fallback that closes the Booking.com claim flow. Call this after the customer completes Stage 1 designation in their Booking Extranet (ticking FantasticStay/Repull as their connectivity provider) and pastes their Hotel ID into the hosted picker. Validates the hotel against Booking's property API, persists the `pms_connections` row, kicks off the room import, and transitions the Connect session to `awaiting_room_mapping`. No API key required — the `sessionId` is the capability token. Sessions in any terminal state are rejected.
2314
+ # Manual-paste fallback that closes the Booking.com claim flow. Call this after the customer completes Stage 1 designation in their Booking Extranet (selecting our connectivity provider, named on the hosted Connect page) and pastes their Hotel ID into the hosted picker. Validates the hotel against Booking's property API, persists the `pms_connections` row, kicks off the room import, and transitions the Connect session to `awaiting_room_mapping`. No API key required — the `sessionId` is the capability token. Sessions in any terminal state are rejected.
2315
2315
  # @param booking_verify_hotel_request [BookingVerifyHotelRequest]
2316
2316
  # @param [Hash] opts the optional parameters
2317
2317
  # @return [BookingVerifyHotelResponse]
@@ -2321,7 +2321,7 @@ module Repull
2321
2321
  end
2322
2322
 
2323
2323
  # Verify a Booking.com hotel ID for a Connect session
2324
- # Manual-paste fallback that closes the Booking.com claim flow. Call this after the customer completes Stage 1 designation in their Booking Extranet (ticking FantasticStay/Repull as their connectivity provider) and pastes their Hotel ID into the hosted picker. Validates the hotel against Booking's property API, persists the `pms_connections` row, kicks off the room import, and transitions the Connect session to `awaiting_room_mapping`. No API key required — the `sessionId` is the capability token. Sessions in any terminal state are rejected.
2324
+ # Manual-paste fallback that closes the Booking.com claim flow. Call this after the customer completes Stage 1 designation in their Booking Extranet (selecting our connectivity provider, named on the hosted Connect page) and pastes their Hotel ID into the hosted picker. Validates the hotel against Booking's property API, persists the `pms_connections` row, kicks off the room import, and transitions the Connect session to `awaiting_room_mapping`. No API key required — the `sessionId` is the capability token. Sessions in any terminal state are rejected.
2325
2325
  # @param booking_verify_hotel_request [BookingVerifyHotelRequest]
2326
2326
  # @param [Hash] opts the optional parameters
2327
2327
  # @return [Array<(BookingVerifyHotelResponse, Integer, Hash)>] BookingVerifyHotelResponse data, response status code and response headers
@@ -77,7 +77,7 @@ module Repull
77
77
  end
78
78
 
79
79
  # Per-channel connectivity health
80
- # Reports reachability and auth state for one channel (`airbnb`, `booking`, `vrbo`, `plumguide`). Use it to tell \"the channel is down\" apart from \"this workspace's connection expired\". `200` when `status` is `ok`, `503` when `degraded` or `down` (the body's `status` and `message` say which and why). **`vrbo`** reports the connector's own signals in a `vrbo` block: connected accounts, accounts VRBO signed out (their bookings, messages and calendar stop until reconnected — `down`), accounts whose inbox sync is late (`degraded`), and the calendar push queue backlog and its oldest wait (`degraded` past 3 hours). Its rate is calendar pushes VRBO refused over finished ones in the last 3 hours; failures inside Repull's own connector are reported apart as `vrbo.connector_errors` and do not count (`vrbo.window_hours`; `refresh_attempts_24h` / `refresh_rejections_24h` count that window for VRBO), judged only once at least 50 pushes finished and at least 5 failed — VRBO pushes run in bursts, so a day-long window would keep reporting a problem already fixed.
80
+ # Reports reachability and auth state for one channel (`airbnb`, `booking`, `vrbo`). Use it to tell \"the channel is down\" apart from \"this workspace's connection expired\". `200` when `status` is `ok`, `503` when `degraded` or `down` (the body's `status` and `message` say which and why). **`vrbo`** reports the connector's own signals in a `vrbo` block: connected accounts, accounts VRBO signed out (their bookings, messages and calendar stop until reconnected — `down`), accounts whose inbox sync is late (`degraded`), and the calendar push queue backlog and its oldest wait (`degraded` past 3 hours). Its rate is calendar pushes VRBO refused over finished ones in the last 3 hours; failures inside Repull's own connector are reported apart as `vrbo.connector_errors` and do not count (`vrbo.window_hours`; `refresh_attempts_24h` / `refresh_rejections_24h` count that window for VRBO), judged only once at least 50 pushes finished and at least 5 failed — VRBO pushes run in bursts, so a day-long window would keep reporting a problem already fixed.
81
81
  # @param channel [String]
82
82
  # @param [Hash] opts the optional parameters
83
83
  # @return [GetChannelHealth200Response]
@@ -87,7 +87,7 @@ module Repull
87
87
  end
88
88
 
89
89
  # Per-channel connectivity health
90
- # Reports reachability and auth state for one channel (&#x60;airbnb&#x60;, &#x60;booking&#x60;, &#x60;vrbo&#x60;, &#x60;plumguide&#x60;). Use it to tell \&quot;the channel is down\&quot; apart from \&quot;this workspace&#39;s connection expired\&quot;. &#x60;200&#x60; when &#x60;status&#x60; is &#x60;ok&#x60;, &#x60;503&#x60; when &#x60;degraded&#x60; or &#x60;down&#x60; (the body&#39;s &#x60;status&#x60; and &#x60;message&#x60; say which and why). **&#x60;vrbo&#x60;** reports the connector&#39;s own signals in a &#x60;vrbo&#x60; block: connected accounts, accounts VRBO signed out (their bookings, messages and calendar stop until reconnected — &#x60;down&#x60;), accounts whose inbox sync is late (&#x60;degraded&#x60;), and the calendar push queue backlog and its oldest wait (&#x60;degraded&#x60; past 3 hours). Its rate is calendar pushes VRBO refused over finished ones in the last 3 hours; failures inside Repull&#39;s own connector are reported apart as &#x60;vrbo.connector_errors&#x60; and do not count (&#x60;vrbo.window_hours&#x60;; &#x60;refresh_attempts_24h&#x60; / &#x60;refresh_rejections_24h&#x60; count that window for VRBO), judged only once at least 50 pushes finished and at least 5 failed — VRBO pushes run in bursts, so a day-long window would keep reporting a problem already fixed.
90
+ # Reports reachability and auth state for one channel (&#x60;airbnb&#x60;, &#x60;booking&#x60;, &#x60;vrbo&#x60;). Use it to tell \&quot;the channel is down\&quot; apart from \&quot;this workspace&#39;s connection expired\&quot;. &#x60;200&#x60; when &#x60;status&#x60; is &#x60;ok&#x60;, &#x60;503&#x60; when &#x60;degraded&#x60; or &#x60;down&#x60; (the body&#39;s &#x60;status&#x60; and &#x60;message&#x60; say which and why). **&#x60;vrbo&#x60;** reports the connector&#39;s own signals in a &#x60;vrbo&#x60; block: connected accounts, accounts VRBO signed out (their bookings, messages and calendar stop until reconnected — &#x60;down&#x60;), accounts whose inbox sync is late (&#x60;degraded&#x60;), and the calendar push queue backlog and its oldest wait (&#x60;degraded&#x60; past 3 hours). Its rate is calendar pushes VRBO refused over finished ones in the last 3 hours; failures inside Repull&#39;s own connector are reported apart as &#x60;vrbo.connector_errors&#x60; and do not count (&#x60;vrbo.window_hours&#x60;; &#x60;refresh_attempts_24h&#x60; / &#x60;refresh_rejections_24h&#x60; count that window for VRBO), judged only once at least 50 pushes finished and at least 5 failed — VRBO pushes run in bursts, so a day-long window would keep reporting a problem already fixed.
91
91
  # @param channel [String]
92
92
  # @param [Hash] opts the optional parameters
93
93
  # @return [Array<(GetChannelHealth200Response, Integer, Hash)>] GetChannelHealth200Response data, response status code and response headers
@@ -100,7 +100,7 @@ module Repull
100
100
  fail ArgumentError, "Missing the required parameter 'channel' when calling HealthApi.get_channel_health"
101
101
  end
102
102
  # verify enum value
103
- allowable_values = ["airbnb", "booking", "vrbo", "plumguide"]
103
+ allowable_values = ["airbnb", "booking", "vrbo"]
104
104
  if @api_client.config.client_side_validation && !allowable_values.include?(channel)
105
105
  fail ArgumentError, "invalid value for \"channel\", must be one of #{allowable_values}"
106
106
  end
@@ -369,11 +369,11 @@ module Repull
369
369
  end
370
370
 
371
371
  # Get a listing
372
- # Fetch a single listing by id. Returns the same shape as one element of the `GET /v1/listings` response, so you can bind the result to the same model. Cross-tenant access (a listing that belongs to a different workspace) returns 404 — never 403, never reveals the listing's existence. **Optional expansions:** Pass `?include=amenities` to enrich the response with the listing's amenity rows (`[]` when the listing has none). Pass `?include=content` for the rich content slab (summary, description, space, house rules, etc. — sourced from `listings_descriptions` for the `en` locale; `null` when no row is stored). Pass `?include=details` for the structural slab (bedrooms, bathrooms, person capacity, check-in window, wifi, house manual, etc.; `null` when no row is stored). Combine comma-separated, e.g. `?include=amenities,content,details`. 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.
372
+ # Fetch a single listing by id. Returns the same shape as one element of the `GET /v1/listings` response, so you can bind the result to the same model. Cross-tenant access (a listing that belongs to a different workspace) returns 404 — never 403, never reveals the listing's existence. **Optional expansions:** Pass `?include=amenities` to enrich the response with the listing's amenity rows (`[]` when the listing has none). Pass `?include=content` for the rich content slab (summary, description, space, house rules, etc. — sourced from `listings_descriptions` for the `en` locale; `null` when no row is stored). Pass `?include=details` for the structural slab (bedrooms, bathrooms, person capacity, check-in window, wifi, house manual, etc.; `null` when no row is stored). Pass `?include=rooms` for rooms and beds, `policies` for cancellation, house rules, check-in/out and guest rules, `rules` for stay rules (min/max nights, booking window, notice, preparation time), `pricing` for standing prices and discounts, `fees` and `taxes` for every fee and tax in one shape whatever channel or PMS the listing comes from, and `photos`. Combine comma-separated, e.g. `?include=content,details,rooms,policies,pricing,fees,taxes`. 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.
373
373
  # @param id [Integer] Repull listing id
374
374
  # @param [Hash] opts the optional parameters
375
375
  # @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;.
376
- # @option opts [String] :include Comma-separated optional expansions. Currently supported: &#x60;amenities&#x60;, &#x60;content&#x60;, &#x60;details&#x60;. Unknown values return 422 with a &#x60;valid_values&#x60; envelope.
376
+ # @option opts [String] :include Comma-separated optional expansions. Currently supported: &#x60;amenities&#x60;, &#x60;content&#x60;, &#x60;details&#x60;, &#x60;rooms&#x60;, &#x60;policies&#x60;, &#x60;rules&#x60;, &#x60;pricing&#x60;, &#x60;fees&#x60;, &#x60;taxes&#x60;, &#x60;photos&#x60;. Unknown values return 422 with a &#x60;valid_values&#x60; envelope.
377
377
  # @return [Listing]
378
378
  def get_listing(id, opts = {})
379
379
  data, _status_code, _headers = get_listing_with_http_info(id, opts)
@@ -381,11 +381,11 @@ module Repull
381
381
  end
382
382
 
383
383
  # Get a listing
384
- # Fetch a single listing by id. Returns the same shape as one element of the &#x60;GET /v1/listings&#x60; response, so you can bind the result to the same model. Cross-tenant access (a listing that belongs to a different workspace) returns 404 — never 403, never reveals the listing&#39;s existence. **Optional expansions:** Pass &#x60;?include&#x3D;amenities&#x60; to enrich the response with the listing&#39;s amenity rows (&#x60;[]&#x60; when the listing has none). Pass &#x60;?include&#x3D;content&#x60; for the rich content slab (summary, description, space, house rules, etc. — sourced from &#x60;listings_descriptions&#x60; for the &#x60;en&#x60; locale; &#x60;null&#x60; when no row is stored). Pass &#x60;?include&#x3D;details&#x60; for the structural slab (bedrooms, bathrooms, person capacity, check-in window, wifi, house manual, etc.; &#x60;null&#x60; when no row is stored). Combine comma-separated, e.g. &#x60;?include&#x3D;amenities,content,details&#x60;. The default response stays lean; consumers must opt in. 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.
384
+ # Fetch a single listing by id. Returns the same shape as one element of the &#x60;GET /v1/listings&#x60; response, so you can bind the result to the same model. Cross-tenant access (a listing that belongs to a different workspace) returns 404 — never 403, never reveals the listing&#39;s existence. **Optional expansions:** Pass &#x60;?include&#x3D;amenities&#x60; to enrich the response with the listing&#39;s amenity rows (&#x60;[]&#x60; when the listing has none). Pass &#x60;?include&#x3D;content&#x60; for the rich content slab (summary, description, space, house rules, etc. — sourced from &#x60;listings_descriptions&#x60; for the &#x60;en&#x60; locale; &#x60;null&#x60; when no row is stored). Pass &#x60;?include&#x3D;details&#x60; for the structural slab (bedrooms, bathrooms, person capacity, check-in window, wifi, house manual, etc.; &#x60;null&#x60; when no row is stored). Pass &#x60;?include&#x3D;rooms&#x60; for rooms and beds, &#x60;policies&#x60; for cancellation, house rules, check-in/out and guest rules, &#x60;rules&#x60; for stay rules (min/max nights, booking window, notice, preparation time), &#x60;pricing&#x60; for standing prices and discounts, &#x60;fees&#x60; and &#x60;taxes&#x60; for every fee and tax in one shape whatever channel or PMS the listing comes from, and &#x60;photos&#x60;. Combine comma-separated, e.g. &#x60;?include&#x3D;content,details,rooms,policies,pricing,fees,taxes&#x60;. The default response stays lean; consumers must opt in. 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.
385
385
  # @param id [Integer] Repull listing id
386
386
  # @param [Hash] opts the optional parameters
387
387
  # @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;.
388
- # @option opts [String] :include Comma-separated optional expansions. Currently supported: &#x60;amenities&#x60;, &#x60;content&#x60;, &#x60;details&#x60;. Unknown values return 422 with a &#x60;valid_values&#x60; envelope.
388
+ # @option opts [String] :include Comma-separated optional expansions. Currently supported: &#x60;amenities&#x60;, &#x60;content&#x60;, &#x60;details&#x60;, &#x60;rooms&#x60;, &#x60;policies&#x60;, &#x60;rules&#x60;, &#x60;pricing&#x60;, &#x60;fees&#x60;, &#x60;taxes&#x60;, &#x60;photos&#x60;. Unknown values return 422 with a &#x60;valid_values&#x60; envelope.
389
389
  # @return [Array<(Listing, Integer, Hash)>] Listing data, response status code and response headers
390
390
  def get_listing_with_http_info(id, opts = {})
391
391
  if @api_client.config.debugging
@@ -753,7 +753,7 @@ module Repull
753
753
  end
754
754
 
755
755
  # List listings
756
- # Cursor-paginated list of listings owned by the authenticated workspace. Use `pagination.nextCursor` from one response as the `cursor` query param of the next request to walk the full set. `?offset=` is also accepted as a first-class alias for shallow paging (0..10000) — see the `offset` parameter below. Mutually exclusive with `cursor`. Filters: `q` (substring on name/street/city), `status`, `channel`. **Optional expansions:** Pass `?include=content` to enrich each row with the rich content slab (summary, description, space, house rules, etc. — sourced from `listings_descriptions` for the `en` locale). Pass `?include=details` for the structural slab (bedrooms, bathrooms, person capacity, check-in window, wifi, house manual, etc.). Both default to `null` per row when the underlying `listings_descriptions` / `listings_details` row is missing — distinct from the field being absent (which signals the expansion was not requested). Pass `?include=thumbnail` to guarantee `thumbnailUrl` on every returned row — including the reduced inactive ones. Combine comma-separated, e.g. `?include=content,thumbnail`. The default response stays lean; consumers must opt in. **Inactive listings:** by default only active listings are returned. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated, so when `status` asks for inactive ones they carry only `id`, `name`, `status` and `channels` — enough to choose what to activate with `PATCH /v1/listings/{id}`. The `content` and `details` expansions are not applied to them. `?include=thumbnail` is the one exception: it adds `thumbnailUrl` to an inactive row so a single request can render an active/inactive selection screen with pictures, instead of one follow-up call per listing (which an inactive listing would answer with `403 listing_inactive` anyway).
756
+ # Cursor-paginated list of listings owned by the authenticated workspace. Use `pagination.nextCursor` from one response as the `cursor` query param of the next request to walk the full set. `?offset=` is also accepted as a first-class alias for shallow paging (0..10000) — see the `offset` parameter below. Mutually exclusive with `cursor`. Filters: `q` (substring on name/street/city), `status`, `channel`. **Optional expansions:** Pass `?include=content` to enrich each row with the rich content slab (summary, description, space, house rules, etc. — sourced from `listings_descriptions` for the `en` locale). Pass `?include=details` for the structural slab (bedrooms, bathrooms, person capacity, check-in window, wifi, house manual, etc.). Both default to `null` per row when the underlying `listings_descriptions` / `listings_details` row is missing — distinct from the field being absent (which signals the expansion was not requested). Pass `?include=thumbnail` to guarantee `thumbnailUrl` on every returned row — including the reduced inactive ones. Pass `rooms`, `policies`, `rules`, `pricing`, `fees`, `taxes` or `photos` for the same sections as `GET /v1/listings/{id}`, loaded for the whole page in one go. Combine comma-separated, e.g. `?include=content,thumbnail`. The default response stays lean; consumers must opt in. **Inactive listings:** by default only active listings are returned. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated, so when `status` asks for inactive ones they carry only `id`, `name`, `status` and `channels` — enough to choose what to activate with `PATCH /v1/listings/{id}`. The `content` and `details` expansions are not applied to them. `?include=thumbnail` is the one exception: it adds `thumbnailUrl` to an inactive row so a single request can render an active/inactive selection screen with pictures, instead of one follow-up call per listing (which an inactive listing would answer with `403 listing_inactive` anyway).
757
757
  # @param [Hash] opts the optional parameters
758
758
  # @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;.
759
759
  # @option opts [String] :cursor Opaque cursor returned in the previous response&#39;s &#x60;pagination.nextCursor&#x60;. Omit to fetch the first page.
@@ -762,7 +762,7 @@ module Repull
762
762
  # @option opts [String] :q Case-insensitive substring search on name, street, or city.
763
763
  # @option opts [String] :status Filter by listing status. Defaults to &#x60;active&#x60;. Pass &#x60;inactive&#x60; to list the listings you can activate, &#x60;archived&#x60; for archived ones, or &#x60;all&#x60; for every status. Inactive listings are returned with identity fields only — &#x60;id&#x60;, &#x60;name&#x60;, &#x60;status&#x60;, &#x60;inactiveReason&#x60; (&#x60;plan_limit&#x60;, &#x60;unlisted_on_airbnb&#x60; or &#x60;deactivated&#x60;), &#x60;address.city&#x60; and &#x60;channels&#x60; — and never with the street, &#x60;content&#x60; or &#x60;details&#x60;; activate one to see the rest. The only field you can add to an inactive row is &#x60;thumbnailUrl&#x60;, via &#x60;?include&#x3D;thumbnail&#x60;. (default to 'active')
764
764
  # @option opts [String] :channel Restrict to listings published on the given channel (&#x60;airbnb&#x60;, &#x60;booking&#x60;, &#x60;vrbo&#x60;, etc.). Joins through &#x60;listing_platform_links&#x60; and matches active links only.
765
- # @option opts [String] :include Comma-separated optional expansions. Currently supported: &#x60;content&#x60;, &#x60;details&#x60;, &#x60;thumbnail&#x60;. &#x60;thumbnail&#x60; guarantees &#x60;thumbnailUrl&#x60; on every row and is the only expansion that applies to inactive listings. Unknown values return 422 with a &#x60;valid_values&#x60; envelope. (Note: &#x60;amenities&#x60; is not yet supported on the list endpoint — use the detail endpoint to fetch amenity rows for a single listing.)
765
+ # @option opts [String] :include Comma-separated optional expansions. Currently supported: &#x60;content&#x60;, &#x60;details&#x60;, &#x60;thumbnail&#x60;, &#x60;rooms&#x60;, &#x60;policies&#x60;, &#x60;rules&#x60;, &#x60;pricing&#x60;, &#x60;fees&#x60;, &#x60;taxes&#x60;, &#x60;photos&#x60; (the last seven are described on &#x60;GET /v1/listings/{id}&#x60;; read for the whole page at once). &#x60;thumbnail&#x60; guarantees &#x60;thumbnailUrl&#x60; on every row and is the only expansion that applies to inactive listings. Unknown values return 422 with a &#x60;valid_values&#x60; envelope. (Note: &#x60;amenities&#x60; is not yet supported on the list endpoint — use the detail endpoint to fetch amenity rows for a single listing.)
766
766
  # @return [ListingListResponse]
767
767
  def list_listings(opts = {})
768
768
  data, _status_code, _headers = list_listings_with_http_info(opts)
@@ -770,7 +770,7 @@ module Repull
770
770
  end
771
771
 
772
772
  # List listings
773
- # Cursor-paginated list of listings owned by the authenticated workspace. Use &#x60;pagination.nextCursor&#x60; from one response as the &#x60;cursor&#x60; query param of the next request to walk the full set. &#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;, &#x60;channel&#x60;. **Optional expansions:** Pass &#x60;?include&#x3D;content&#x60; to enrich each row with the rich content slab (summary, description, space, house rules, etc. — sourced from &#x60;listings_descriptions&#x60; for the &#x60;en&#x60; locale). Pass &#x60;?include&#x3D;details&#x60; for the structural slab (bedrooms, bathrooms, person capacity, check-in window, wifi, house manual, etc.). Both default to &#x60;null&#x60; per row when the underlying &#x60;listings_descriptions&#x60; / &#x60;listings_details&#x60; row is missing — distinct from the field being absent (which signals the expansion was not requested). Pass &#x60;?include&#x3D;thumbnail&#x60; to guarantee &#x60;thumbnailUrl&#x60; on every returned row — including the reduced inactive ones. Combine comma-separated, e.g. &#x60;?include&#x3D;content,thumbnail&#x60;. The default response stays lean; consumers must opt in. **Inactive listings:** by default only active listings are returned. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated, so when &#x60;status&#x60; asks for inactive ones they carry only &#x60;id&#x60;, &#x60;name&#x60;, &#x60;status&#x60; and &#x60;channels&#x60; — enough to choose what to activate with &#x60;PATCH /v1/listings/{id}&#x60;. The &#x60;content&#x60; and &#x60;details&#x60; expansions are not applied to them. &#x60;?include&#x3D;thumbnail&#x60; is the one exception: it adds &#x60;thumbnailUrl&#x60; to an inactive row so a single request can render an active/inactive selection screen with pictures, instead of one follow-up call per listing (which an inactive listing would answer with &#x60;403 listing_inactive&#x60; anyway).
773
+ # Cursor-paginated list of listings owned by the authenticated workspace. Use &#x60;pagination.nextCursor&#x60; from one response as the &#x60;cursor&#x60; query param of the next request to walk the full set. &#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;, &#x60;channel&#x60;. **Optional expansions:** Pass &#x60;?include&#x3D;content&#x60; to enrich each row with the rich content slab (summary, description, space, house rules, etc. — sourced from &#x60;listings_descriptions&#x60; for the &#x60;en&#x60; locale). Pass &#x60;?include&#x3D;details&#x60; for the structural slab (bedrooms, bathrooms, person capacity, check-in window, wifi, house manual, etc.). Both default to &#x60;null&#x60; per row when the underlying &#x60;listings_descriptions&#x60; / &#x60;listings_details&#x60; row is missing — distinct from the field being absent (which signals the expansion was not requested). Pass &#x60;?include&#x3D;thumbnail&#x60; to guarantee &#x60;thumbnailUrl&#x60; on every returned row — including the reduced inactive ones. Pass &#x60;rooms&#x60;, &#x60;policies&#x60;, &#x60;rules&#x60;, &#x60;pricing&#x60;, &#x60;fees&#x60;, &#x60;taxes&#x60; or &#x60;photos&#x60; for the same sections as &#x60;GET /v1/listings/{id}&#x60;, loaded for the whole page in one go. Combine comma-separated, e.g. &#x60;?include&#x3D;content,thumbnail&#x60;. The default response stays lean; consumers must opt in. **Inactive listings:** by default only active listings are returned. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated, so when &#x60;status&#x60; asks for inactive ones they carry only &#x60;id&#x60;, &#x60;name&#x60;, &#x60;status&#x60; and &#x60;channels&#x60; — enough to choose what to activate with &#x60;PATCH /v1/listings/{id}&#x60;. The &#x60;content&#x60; and &#x60;details&#x60; expansions are not applied to them. &#x60;?include&#x3D;thumbnail&#x60; is the one exception: it adds &#x60;thumbnailUrl&#x60; to an inactive row so a single request can render an active/inactive selection screen with pictures, instead of one follow-up call per listing (which an inactive listing would answer with &#x60;403 listing_inactive&#x60; anyway).
774
774
  # @param [Hash] opts the optional parameters
775
775
  # @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;.
776
776
  # @option opts [String] :cursor Opaque cursor returned in the previous response&#39;s &#x60;pagination.nextCursor&#x60;. Omit to fetch the first page.
@@ -779,7 +779,7 @@ module Repull
779
779
  # @option opts [String] :q Case-insensitive substring search on name, street, or city.
780
780
  # @option opts [String] :status Filter by listing status. Defaults to &#x60;active&#x60;. Pass &#x60;inactive&#x60; to list the listings you can activate, &#x60;archived&#x60; for archived ones, or &#x60;all&#x60; for every status. Inactive listings are returned with identity fields only — &#x60;id&#x60;, &#x60;name&#x60;, &#x60;status&#x60;, &#x60;inactiveReason&#x60; (&#x60;plan_limit&#x60;, &#x60;unlisted_on_airbnb&#x60; or &#x60;deactivated&#x60;), &#x60;address.city&#x60; and &#x60;channels&#x60; — and never with the street, &#x60;content&#x60; or &#x60;details&#x60;; activate one to see the rest. The only field you can add to an inactive row is &#x60;thumbnailUrl&#x60;, via &#x60;?include&#x3D;thumbnail&#x60;. (default to 'active')
781
781
  # @option opts [String] :channel Restrict to listings published on the given channel (&#x60;airbnb&#x60;, &#x60;booking&#x60;, &#x60;vrbo&#x60;, etc.). Joins through &#x60;listing_platform_links&#x60; and matches active links only.
782
- # @option opts [String] :include Comma-separated optional expansions. Currently supported: &#x60;content&#x60;, &#x60;details&#x60;, &#x60;thumbnail&#x60;. &#x60;thumbnail&#x60; guarantees &#x60;thumbnailUrl&#x60; on every row and is the only expansion that applies to inactive listings. Unknown values return 422 with a &#x60;valid_values&#x60; envelope. (Note: &#x60;amenities&#x60; is not yet supported on the list endpoint — use the detail endpoint to fetch amenity rows for a single listing.)
782
+ # @option opts [String] :include Comma-separated optional expansions. Currently supported: &#x60;content&#x60;, &#x60;details&#x60;, &#x60;thumbnail&#x60;, &#x60;rooms&#x60;, &#x60;policies&#x60;, &#x60;rules&#x60;, &#x60;pricing&#x60;, &#x60;fees&#x60;, &#x60;taxes&#x60;, &#x60;photos&#x60; (the last seven are described on &#x60;GET /v1/listings/{id}&#x60;; read for the whole page at once). &#x60;thumbnail&#x60; guarantees &#x60;thumbnailUrl&#x60; on every row and is the only expansion that applies to inactive listings. Unknown values return 422 with a &#x60;valid_values&#x60; envelope. (Note: &#x60;amenities&#x60; is not yet supported on the list endpoint — use the detail endpoint to fetch amenity rows for a single listing.)
783
783
  # @return [Array<(ListingListResponse, Integer, Hash)>] ListingListResponse data, response status code and response headers
784
784
  def list_listings_with_http_info(opts = {})
785
785
  if @api_client.config.debugging
@@ -408,6 +408,74 @@ module Repull
408
408
  return data, status_code, headers
409
409
  end
410
410
 
411
+ # Import from Channex
412
+ # Move a workspace off Channex without changing a single id on your side. Pass your Channex API key: Repull reads your Channex properties, room types, rate plans, webhooks, signing keys, channels and upcoming bookings through Channex's own API (read-only — nothing is written to Channex, and the key is not stored). Each Channex property is matched to your Repull listing or hotel (by Booking.com hotel/room and Airbnb/Vrbo listing ids, then by title and address) or created; every Channex id then resolves, and is returned, unchanged on the Channex-compatible API at `/channex/api/v1`. Webhooks are recreated inactive; activate them with `POST /channex/api/v1/migration/cutover`. Safe to re-run: a run that hits its time budget returns `complete: false` and the next run continues.
413
+ # @param import_from_channex_request [ImportFromChannexRequest]
414
+ # @param [Hash] opts the optional parameters
415
+ # @return [ImportFromChannex200Response]
416
+ def import_from_channex(import_from_channex_request, opts = {})
417
+ data, _status_code, _headers = import_from_channex_with_http_info(import_from_channex_request, opts)
418
+ data
419
+ end
420
+
421
+ # Import from Channex
422
+ # Move a workspace off Channex without changing a single id on your side. Pass your Channex API key: Repull reads your Channex properties, room types, rate plans, webhooks, signing keys, channels and upcoming bookings through Channex&#39;s own API (read-only — nothing is written to Channex, and the key is not stored). Each Channex property is matched to your Repull listing or hotel (by Booking.com hotel/room and Airbnb/Vrbo listing ids, then by title and address) or created; every Channex id then resolves, and is returned, unchanged on the Channex-compatible API at &#x60;/channex/api/v1&#x60;. Webhooks are recreated inactive; activate them with &#x60;POST /channex/api/v1/migration/cutover&#x60;. Safe to re-run: a run that hits its time budget returns &#x60;complete: false&#x60; and the next run continues.
423
+ # @param import_from_channex_request [ImportFromChannexRequest]
424
+ # @param [Hash] opts the optional parameters
425
+ # @return [Array<(ImportFromChannex200Response, Integer, Hash)>] ImportFromChannex200Response data, response status code and response headers
426
+ def import_from_channex_with_http_info(import_from_channex_request, opts = {})
427
+ if @api_client.config.debugging
428
+ @api_client.config.logger.debug 'Calling API: MigrateApi.import_from_channex ...'
429
+ end
430
+ # verify the required parameter 'import_from_channex_request' is set
431
+ if @api_client.config.client_side_validation && import_from_channex_request.nil?
432
+ fail ArgumentError, "Missing the required parameter 'import_from_channex_request' when calling MigrateApi.import_from_channex"
433
+ end
434
+ # resource path
435
+ local_var_path = '/v1/migrations/channex'
436
+
437
+ # query parameters
438
+ query_params = opts[:query_params] || {}
439
+
440
+ # header parameters
441
+ header_params = opts[:header_params] || {}
442
+ # HTTP header 'Accept' (if needed)
443
+ header_params['Accept'] = @api_client.select_header_accept(['application/json']) unless header_params['Accept']
444
+ # HTTP header 'Content-Type'
445
+ content_type = @api_client.select_header_content_type(['application/json'])
446
+ if !content_type.nil?
447
+ header_params['Content-Type'] = content_type
448
+ end
449
+
450
+ # form parameters
451
+ form_params = opts[:form_params] || {}
452
+
453
+ # http body (model)
454
+ post_body = opts[:debug_body] || @api_client.object_to_http_body(import_from_channex_request)
455
+
456
+ # return_type
457
+ return_type = opts[:debug_return_type] || 'ImportFromChannex200Response'
458
+
459
+ # auth_names
460
+ auth_names = opts[:debug_auth_names] || ['bearerAuth']
461
+
462
+ new_options = opts.merge(
463
+ :operation => :"MigrateApi.import_from_channex",
464
+ :header_params => header_params,
465
+ :query_params => query_params,
466
+ :form_params => form_params,
467
+ :body => post_body,
468
+ :auth_names => auth_names,
469
+ :return_type => return_type
470
+ )
471
+
472
+ data, status_code, headers = @api_client.call_api(:POST, local_var_path, new_options)
473
+ if @api_client.config.debugging
474
+ @api_client.config.logger.debug "API called: MigrateApi#import_from_channex\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
475
+ end
476
+ return data, status_code, headers
477
+ end
478
+
411
479
  # List migrations
412
480
  # Every property manager your workspace has moved through Repull Migrate, newest first, each with where it stands. Page with `pagination.nextCursor`.
413
481
  # @param [Hash] opts the optional parameters
@@ -14,7 +14,7 @@ require 'date'
14
14
  require 'time'
15
15
 
16
16
  module Repull
17
- class CalendarUpdatedEvent < ApiModelBase
17
+ class BookingUnacknowledgedEvent < ApiModelBase
18
18
  # The event name. This field is `event`, not `type`.
19
19
  attr_accessor :event
20
20
 
@@ -60,7 +60,7 @@ module Repull
60
60
  :'api_version' => :'String',
61
61
  :'timestamp' => :'Time',
62
62
  :'account' => :'WebhookEventAccount',
63
- :'data' => :'CalendarUpdatedPayload'
63
+ :'data' => :'BookingUnacknowledgedPayload'
64
64
  }
65
65
  end
66
66
 
@@ -75,14 +75,14 @@ module Repull
75
75
  # @param [Hash] attributes Model attributes in the form of hash
76
76
  def initialize(attributes = {})
77
77
  if (!attributes.is_a?(Hash))
78
- fail ArgumentError, "The input argument (attributes) must be a hash in `Repull::CalendarUpdatedEvent` initialize method"
78
+ fail ArgumentError, "The input argument (attributes) must be a hash in `Repull::BookingUnacknowledgedEvent` initialize method"
79
79
  end
80
80
 
81
81
  # check to see if the attribute exists and convert string to symbol for hash key
82
82
  acceptable_attribute_map = self.class.acceptable_attribute_map
83
83
  attributes = attributes.each_with_object({}) { |(k, v), h|
84
84
  if (!acceptable_attribute_map.key?(k.to_sym))
85
- fail ArgumentError, "`#{k}` is not a valid attribute in `Repull::CalendarUpdatedEvent`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
85
+ fail ArgumentError, "`#{k}` is not a valid attribute in `Repull::BookingUnacknowledgedEvent`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
86
86
  end
87
87
  h[k.to_sym] = v
88
88
  }
@@ -0,0 +1,229 @@
1
+ =begin
2
+ #Repull API
3
+
4
+ #The unified API for vacation rental tech. Connect to 50+ PMS platforms and 4 OTA channels through one REST API. Built-in AI operations for guest communication, pricing, and listing optimization. ## Designed for AI agents Every error response on this API includes machine-parseable fields so an LLM (Claude in MCP, Cursor, Cline, GPT, etc.) can self-recover without escalating to a human: - `error.code` — stable string identifier (e.g. `invalid_params`, `rate_limit_exceeded`) - `error.message` — human-readable cause - `error.fix` — exact recovery steps (e.g. \"Pass `check_in_after` as ISO 8601: `?check_in_after=2026-01-15`\") - `error.docs_url` — link to the canonical write-up at `https://repull.dev/docs/errors/{code}` - `error.request_id` — id to correlate with server-side logs - `error.field` / `error.value_received` / `error.valid_values` / `error.did_you_mean` — when the error is parameter-specific - `error.retry_after` — seconds to wait before retrying (rate-limit + transient upstream) `Access-Control-Expose-Headers` lists `x-request-id` and the `X-RateLimit-*` family so browsers can read them on cross-origin responses. ## Quick Start 1. Get an API key at https://repull.dev/dashboard 2. Connect a PMS: `POST /v1/connect/{provider}` 3. List properties: `GET /v1/properties` 4. Get reservations: `GET /v1/reservations` ## Authentication All requests require a Bearer token: ``` Authorization: Bearer sk_live_YOUR_API_KEY ``` ## Request Correlation (X-Request-ID) Every response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports — we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id. You may set the header on the inbound request to forward your own trace id; we will echo it back instead of generating a new one. Accepted format: `^[\\\\w.-]{1,128}$`. The id is also embedded in error envelopes as `request_id` so server-side log diffs work even when the response headers are stripped by an intermediate proxy. ## Rate Limits The public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas. **Default policy:** 600 requests per 60 seconds, per API key. Sliding window — there is no fixed-minute boundary you can burst across. Every response includes: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests permitted in the current window. | | `X-RateLimit-Remaining` | Requests left in the current window after this call. | | `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. | | `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. | | `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** | **On 429 (rate_limit_exceeded):** the response body matches the standard error envelope with `code: \"rate_limit_exceeded\"`, plus `limit`, `window_seconds`, `retry_after`, and `request_id` fields. SDKs MUST honor `Retry-After` and use exponential backoff with jitter on subsequent retries — never a tight loop. Recommended backoff: ``` sleep_ms = (Retry-After * 1000) + random(0..250) ``` Monthly + daily-AI tier quotas (`free`, `starter`, `custom`) are enforced separately and also surface as 429s; they include `tier`, `scope`, and `resetsAt` fields. ## Plan Limits (402 — `listings_limit_exceeded`) The Repull API also enforces a per-tier cap on **active listings**: | Tier | Active listings cap | |---|---| | `free` | 3 | | `starter` | unlimited (10 included, then billed per listing) | | `custom` | unlimited | When a customer's active-listing count is above their tier cap, the API returns **`402 Payment Required`** with `error.code = \"listings_limit_exceeded\"` on every route EXCEPT: - `/v1/health` — uptime probes are never gated. - `/v1/usage/*` — so dashboards can render the over-cap state. - Any `DELETE` — so the customer can trim listings to get back under the cap without paying. Unlike 429, 402 is NOT a \"wait and retry\" condition — `Retry-After` is not set. The only paths back to 200 are: 1. `DELETE` enough listings to come back under the cap, or 2. Upgrade at `https://repull.dev/dashboard/billing`. The server-side usage cache is 60s, so the first 200 after an upgrade may take up to a minute. The envelope mirrors `rate_limit_exceeded` for SDK ergonomics: `tier`, `limit`, `active_listings`, `upgrade_url`, plus the standard `code` / `message` / `fix` / `docs_url` / `request_id`.
5
+
6
+ The version of the OpenAPI document: 1.0.0
7
+
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.22.0
10
+
11
+ =end
12
+
13
+ require 'date'
14
+ require 'time'
15
+
16
+ module Repull
17
+ # Payload for `booking.unacknowledged`. A booking changed and your system has not acknowledged the change through the revision feed. Sent once per outstanding revision — not once per check — so a booking that keeps waiting does not keep alerting. A booking that changes AGAIN mints a new revision and does alert again, because that is a new thing to acknowledge. Acknowledging the revision stops it.
18
+ class BookingUnacknowledgedPayload < ApiModelBase
19
+ attr_accessor :object
20
+
21
+ # The outstanding revision. Acknowledge this to stop the alert.
22
+ attr_accessor :revision_id
23
+
24
+ # When the booking actually changed — NOT when we noticed. Revisions are minted when you first poll the feed, so a mint timestamp would measure how recently you looked rather than how long the booking has waited.
25
+ attr_accessor :outstanding_since
26
+
27
+ # Whole hours since `outstandingSince`, for convenience.
28
+ attr_accessor :outstanding_hours
29
+
30
+ # Attribute mapping from ruby-style variable name to JSON key.
31
+ def self.attribute_map
32
+ {
33
+ :'object' => :'object',
34
+ :'revision_id' => :'revisionId',
35
+ :'outstanding_since' => :'outstandingSince',
36
+ :'outstanding_hours' => :'outstandingHours'
37
+ }
38
+ end
39
+
40
+ # Returns attribute mapping this model knows about
41
+ def self.acceptable_attribute_map
42
+ attribute_map
43
+ end
44
+
45
+ # Returns all the JSON keys this model knows about
46
+ def self.acceptable_attributes
47
+ acceptable_attribute_map.values
48
+ end
49
+
50
+ # Attribute type mapping.
51
+ def self.openapi_types
52
+ {
53
+ :'object' => :'ReservationWebhookObject',
54
+ :'revision_id' => :'String',
55
+ :'outstanding_since' => :'Time',
56
+ :'outstanding_hours' => :'Integer'
57
+ }
58
+ end
59
+
60
+ # List of attributes with nullable: true
61
+ def self.openapi_nullable
62
+ Set.new([
63
+ ])
64
+ end
65
+
66
+ # Initializes the object
67
+ # @param [Hash] attributes Model attributes in the form of hash
68
+ def initialize(attributes = {})
69
+ if (!attributes.is_a?(Hash))
70
+ fail ArgumentError, "The input argument (attributes) must be a hash in `Repull::BookingUnacknowledgedPayload` initialize method"
71
+ end
72
+
73
+ # check to see if the attribute exists and convert string to symbol for hash key
74
+ acceptable_attribute_map = self.class.acceptable_attribute_map
75
+ attributes = attributes.each_with_object({}) { |(k, v), h|
76
+ if (!acceptable_attribute_map.key?(k.to_sym))
77
+ fail ArgumentError, "`#{k}` is not a valid attribute in `Repull::BookingUnacknowledgedPayload`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
78
+ end
79
+ h[k.to_sym] = v
80
+ }
81
+
82
+ if attributes.key?(:'object')
83
+ self.object = attributes[:'object']
84
+ else
85
+ self.object = nil
86
+ end
87
+
88
+ if attributes.key?(:'revision_id')
89
+ self.revision_id = attributes[:'revision_id']
90
+ else
91
+ self.revision_id = nil
92
+ end
93
+
94
+ if attributes.key?(:'outstanding_since')
95
+ self.outstanding_since = attributes[:'outstanding_since']
96
+ else
97
+ self.outstanding_since = nil
98
+ end
99
+
100
+ if attributes.key?(:'outstanding_hours')
101
+ self.outstanding_hours = attributes[:'outstanding_hours']
102
+ end
103
+ end
104
+
105
+ # Show invalid properties with the reasons. Usually used together with valid?
106
+ # @return Array for valid properties with the reasons
107
+ def list_invalid_properties
108
+ warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
109
+ invalid_properties = Array.new
110
+ if @object.nil?
111
+ invalid_properties.push('invalid value for "object", object cannot be nil.')
112
+ end
113
+
114
+ if @revision_id.nil?
115
+ invalid_properties.push('invalid value for "revision_id", revision_id cannot be nil.')
116
+ end
117
+
118
+ if @outstanding_since.nil?
119
+ invalid_properties.push('invalid value for "outstanding_since", outstanding_since cannot be nil.')
120
+ end
121
+
122
+ invalid_properties
123
+ end
124
+
125
+ # Check to see if the all the properties in the model are valid
126
+ # @return true if the model is valid
127
+ def valid?
128
+ warn '[DEPRECATED] the `valid?` method is obsolete'
129
+ return false if @object.nil?
130
+ return false if @revision_id.nil?
131
+ return false if @outstanding_since.nil?
132
+ true
133
+ end
134
+
135
+ # Custom attribute writer method with validation
136
+ # @param [Object] object Value to be assigned
137
+ def object=(object)
138
+ if object.nil?
139
+ fail ArgumentError, 'object cannot be nil'
140
+ end
141
+
142
+ @object = object
143
+ end
144
+
145
+ # Custom attribute writer method with validation
146
+ # @param [Object] revision_id Value to be assigned
147
+ def revision_id=(revision_id)
148
+ if revision_id.nil?
149
+ fail ArgumentError, 'revision_id cannot be nil'
150
+ end
151
+
152
+ @revision_id = revision_id
153
+ end
154
+
155
+ # Custom attribute writer method with validation
156
+ # @param [Object] outstanding_since Value to be assigned
157
+ def outstanding_since=(outstanding_since)
158
+ if outstanding_since.nil?
159
+ fail ArgumentError, 'outstanding_since cannot be nil'
160
+ end
161
+
162
+ @outstanding_since = outstanding_since
163
+ end
164
+
165
+ # Checks equality by comparing each attribute.
166
+ # @param [Object] Object to be compared
167
+ def ==(o)
168
+ return true if self.equal?(o)
169
+ self.class == o.class &&
170
+ object == o.object &&
171
+ revision_id == o.revision_id &&
172
+ outstanding_since == o.outstanding_since &&
173
+ outstanding_hours == o.outstanding_hours
174
+ end
175
+
176
+ # @see the `==` method
177
+ # @param [Object] Object to be compared
178
+ def eql?(o)
179
+ self == o
180
+ end
181
+
182
+ # Calculates hash code according to all attributes.
183
+ # @return [Integer] Hash code
184
+ def hash
185
+ [object, revision_id, outstanding_since, outstanding_hours].hash
186
+ end
187
+
188
+ # Builds the object from hash
189
+ # @param [Hash] attributes Model attributes in the form of hash
190
+ # @return [Object] Returns the model itself
191
+ def self.build_from_hash(attributes)
192
+ return nil unless attributes.is_a?(Hash)
193
+ attributes = attributes.transform_keys(&:to_sym)
194
+ transformed_hash = {}
195
+ openapi_types.each_pair do |key, type|
196
+ if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
197
+ transformed_hash["#{key}"] = nil
198
+ elsif type =~ /\AArray<(.*)>/i
199
+ # check to ensure the input is an array given that the attribute
200
+ # is documented as an array but the input is not
201
+ if attributes[attribute_map[key]].is_a?(Array)
202
+ transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
203
+ end
204
+ elsif !attributes[attribute_map[key]].nil?
205
+ transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
206
+ end
207
+ end
208
+ new(transformed_hash)
209
+ end
210
+
211
+ # Returns the object in the form of hash
212
+ # @return [Hash] Returns the object in the form of hash
213
+ def to_hash
214
+ hash = {}
215
+ self.class.attribute_map.each_pair do |attr, param|
216
+ value = self.send(attr)
217
+ if value.nil?
218
+ is_nullable = self.class.openapi_nullable.include?(attr)
219
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
220
+ end
221
+
222
+ hash[param] = _to_hash(value)
223
+ end
224
+ hash
225
+ end
226
+
227
+ end
228
+
229
+ end