repull 0.2.8 → 0.2.10

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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/lib/repull/api/airbnb_api.rb +1443 -182
  3. data/lib/repull/api/availability_api.rb +24 -92
  4. data/lib/repull/api/billing_api.rb +186 -15
  5. data/lib/repull/api/booking_com_api.rb +532 -41
  6. data/lib/repull/api/listings_api.rb +74 -0
  7. data/lib/repull/api/plumguide_api.rb +245 -0
  8. data/lib/repull/api/reservations_api.rb +0 -197
  9. data/lib/repull/api/sandbox_api.rb +136 -0
  10. data/lib/repull/api/vrbo_api.rb +0 -126
  11. data/lib/repull/models/acknowledge_booking_reservations_request.rb +176 -0
  12. data/lib/repull/models/{create_studio_project201_response_data.rb → airbnb_alteration.rb} +44 -52
  13. data/lib/repull/models/airbnb_amenity.rb +171 -0
  14. data/lib/repull/models/{get_studio_deployment200_response.rb → airbnb_availability_write_request.rb} +52 -10
  15. data/lib/repull/models/airbnb_calendar_operation.rb +250 -0
  16. data/lib/repull/models/airbnb_listing_action_request.rb +198 -0
  17. data/lib/repull/models/{update_availability_request.rb → airbnb_pricing_write_request.rb} +100 -11
  18. data/lib/repull/models/booking_availability_update.rb +276 -0
  19. data/lib/repull/models/booking_availability_update_request.rb +230 -0
  20. data/lib/repull/models/{generate_studio_completion_request_project_id.rb → booking_availability_update_request_property_id.rb} +2 -2
  21. data/lib/repull/models/booking_availability_update_request_updates_inner.rb +104 -0
  22. data/lib/repull/models/booking_pricing_rate_update.rb +1 -0
  23. data/lib/repull/models/booking_pricing_rate_update_restrictions.rb +65 -6
  24. data/lib/repull/models/booking_setup_request.rb +220 -0
  25. data/lib/repull/models/create_airbnb_alteration_request.rb +195 -0
  26. data/lib/repull/models/{create_studio_deployment201_response_data.rb → create_airbnb_offer_request.rb} +42 -30
  27. data/lib/repull/models/{create_studio_project_request.rb → create_booking_webhook_request.rb} +36 -47
  28. data/lib/repull/models/{generate_studio_completion200_response.rb → delete_airbnb_listing_photo200_response.rb} +10 -10
  29. data/lib/repull/models/{delete_studio_project200_response.rb → get_airbnb_alteration200_response.rb} +50 -7
  30. data/lib/repull/models/{delete_studio_project_file200_response.rb → get_airbnb_listing_quality200_response.rb} +37 -7
  31. data/lib/repull/models/{create_studio_project_generation201_response.rb → get_airbnb_listing_settings200_response.rb} +37 -7
  32. data/lib/repull/models/{delete_studio_deployment200_response.rb → get_airbnb_thread200_response.rb} +50 -7
  33. data/lib/repull/models/{list_studio_deployments200_response.rb → get_usage_logs200_response.rb} +17 -8
  34. data/lib/repull/models/get_usage_logs200_response_data_inner.rb +264 -0
  35. data/lib/repull/models/{create_studio_deployment201_response.rb → get_usage_logs200_response_pagination.rb} +29 -10
  36. data/lib/repull/models/get_usage_summary200_response.rb +232 -0
  37. data/lib/repull/models/get_usage_summary200_response_breakdown_inner.rb +183 -0
  38. data/lib/repull/models/{delete_studio_deployment200_response_data.rb → get_usage_summary200_response_limits.rb} +18 -16
  39. data/lib/repull/models/{delete_studio_project200_response_data.rb → get_usage_summary200_response_remaining.rb} +18 -16
  40. data/lib/repull/models/{create_studio_project_generation201_response_data.rb → get_usage_summary200_response_status_distribution.rb} +31 -22
  41. data/lib/repull/models/{upsert_studio_project_file_request.rb → get_usage_summary200_response_timeline_inner.rb} +28 -28
  42. data/lib/repull/models/{create_studio_project_generation_request.rb → get_usage_summary200_response_totals.rb} +28 -28
  43. data/lib/repull/models/{create_studio_project201_response.rb → get_usage_summary200_response_used.rb} +19 -10
  44. data/lib/repull/models/get_usage_tier200_response.rb +183 -0
  45. data/lib/repull/models/{list_studio_projects200_response.rb → get_usage_tier200_response_limits.rb} +31 -12
  46. data/lib/repull/models/{update_reservation_request.rb → get_usage_tier200_response_remaining.rb} +25 -31
  47. data/lib/repull/models/{get_studio_project200_response.rb → get_usage_tier200_response_used.rb} +28 -10
  48. data/lib/repull/models/list_airbnb_alterations200_response.rb +192 -0
  49. data/lib/repull/models/list_airbnb_listing_amenities200_response.rb +190 -0
  50. data/lib/repull/models/{create_studio_deployment_request.rb → list_airbnb_listing_amenities200_response_data.rb} +23 -28
  51. data/lib/repull/models/{list_studio_project_files200_response.rb → list_airbnb_transactions200_response.rb} +50 -7
  52. data/lib/repull/models/listing_content_update_request.rb +243 -0
  53. data/lib/repull/models/{upsert_studio_project_file200_response.rb → listing_content_update_request_address.rb} +53 -10
  54. data/lib/repull/models/listing_content_update_request_amenities.rb +105 -0
  55. data/lib/repull/models/listing_content_update_request_amenities_one_of_inner.rb +196 -0
  56. data/lib/repull/models/listing_content_update_request_occupancy.rb +179 -0
  57. data/lib/repull/{api/ai_api.rb → models/listing_content_update_request_photos_inner.rb} +77 -59
  58. data/lib/repull/models/{generate_studio_completion200_response_data.rb → listing_content_update_request_photos_inner_one_of.rb} +81 -66
  59. data/lib/repull/models/listing_content_update_request_policies.rb +253 -0
  60. data/lib/repull/models/{create_ai_operation200_response.rb → listing_content_update_response.rb} +32 -16
  61. data/lib/repull/models/map_airbnb_listing_request.rb +215 -0
  62. data/lib/repull/models/{create_reservation_request.rb → map_airbnb_listing_response.rb} +137 -116
  63. data/lib/repull/models/property.rb +42 -69
  64. data/lib/repull/models/property_availability.rb +222 -0
  65. data/lib/repull/models/property_availability_day.rb +247 -0
  66. data/lib/repull/models/reservation.rb +28 -1
  67. data/lib/repull/models/sandbox_fixture_ref.rb +193 -0
  68. data/lib/repull/models/{delete_studio_project_file200_response_data.rb → sandbox_reset_result.rb} +72 -11
  69. data/lib/repull/models/sandbox_reset_result_deleted.rb +216 -0
  70. data/lib/repull/models/sandbox_seed_result.rb +278 -0
  71. data/lib/repull/models/{update_studio_project_request.rb → update_airbnb_message_request.rb} +43 -24
  72. data/lib/repull/models/update_booking_charges_request.rb +194 -0
  73. data/lib/repull/version.rb +1 -1
  74. data/lib/repull.rb +59 -34
  75. data/openapi/v1.json +3956 -2522
  76. metadata +61 -36
  77. data/lib/repull/api/studio_api.rb +0 -1094
  78. data/lib/repull/models/generate_studio_completion_request.rb +0 -305
  79. data/lib/repull/models/upsert_studio_project_file200_response_data.rb +0 -147
@@ -0,0 +1,230 @@
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_test_YOUR_API_KEY ``` Sandbox keys start with `sk_test_`, production with `sk_live_`. ## Request Correlation (X-Request-ID) Every response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports — we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id. You may set the header on the inbound request to forward your own trace id; we will echo it back instead of generating a new one. Accepted format: `^[\\\\w.-]{1,128}$`. The id is also embedded in error envelopes as `request_id` so server-side log diffs work even when the response headers are stripped by an intermediate proxy. ## Rate Limits The public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas. **Default policy:** 600 requests per 60 seconds, per API key. Sliding window — there is no fixed-minute boundary you can burst across. Every response includes: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests permitted in the current window. | | `X-RateLimit-Remaining` | Requests left in the current window after this call. | | `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. | | `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. | | `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** | **On 429 (rate_limit_exceeded):** the response body matches the standard error envelope with `code: \"rate_limit_exceeded\"`, plus `limit`, `window_seconds`, `retry_after`, and `request_id` fields. SDKs MUST honor `Retry-After` and use exponential backoff with jitter on subsequent retries — never a tight loop. Recommended backoff: ``` sleep_ms = (Retry-After * 1000) + random(0..250) ``` Monthly + daily-AI tier quotas (`free`, `starter`, `custom`) are enforced separately and also surface as 429s; they include `tier`, `scope`, and `resets_at` fields. ## Plan Limits (402 — `listings_limit_exceeded`) The Repull API also enforces a per-tier cap on **active listings**: | Tier | Active listings cap | |---|---| | `free` | 3 | | `starter` | 50 | | `custom` | unlimited | When a customer's active-listing count is above their tier cap, the API returns **`402 Payment Required`** with `error.code = \"listings_limit_exceeded\"` on every route EXCEPT: - `/v1/health` — uptime probes are never gated. - `/v1/usage/*` — so dashboards can render the over-cap state. - Any `DELETE` — so the customer can trim listings to get back under the cap without paying. Unlike 429, 402 is NOT a \"wait and retry\" condition — `Retry-After` is not set. The only paths back to 200 are: 1. `DELETE` enough listings to come back under the cap, or 2. Upgrade at `https://repull.dev/dashboard/billing`. The server-side usage cache is 60s, so the first 200 after an upgrade may take up to a minute. The envelope mirrors `rate_limit_exceeded` for SDK ergonomics: `tier`, `limit`, `active_listings`, `upgrade_url`, plus the standard `code` / `message` / `fix` / `docs_url` / `request_id`.
5
+
6
+ The version of the OpenAPI document: 1.0.0
7
+ Contact: ivan@vanio.ai
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.22.0
10
+
11
+ =end
12
+
13
+ require 'date'
14
+ require 'time'
15
+
16
+ module Repull
17
+ # Body for `PUT /v1/channels/booking/availability`. Selects one of Booking's three ARI write paths via `type` and forwards `updates` verbatim to the connector.
18
+ class BookingAvailabilityUpdateRequest < ApiModelBase
19
+ # `rates` → price + restrictions (`updateRates`); `availability` → inventory + stop-sell + restrictions (`updateAvailability`); `derived-pricing` → occupancy-derived pricing rules (`updateDerivedPricing`).
20
+ attr_accessor :type
21
+
22
+ attr_accessor :property_id
23
+
24
+ # For `type: \"rates\"` each item is a `BookingPricingRateUpdate`; for `type: \"availability\"` a `BookingAvailabilityUpdate`; for `type: \"derived-pricing\"` a derived-price rule set.
25
+ attr_accessor :updates
26
+
27
+ # Attribute mapping from ruby-style variable name to JSON key.
28
+ def self.attribute_map
29
+ {
30
+ :'type' => :'type',
31
+ :'property_id' => :'property_id',
32
+ :'updates' => :'updates'
33
+ }
34
+ end
35
+
36
+ # Returns attribute mapping this model knows about
37
+ def self.acceptable_attribute_map
38
+ attribute_map
39
+ end
40
+
41
+ # Returns all the JSON keys this model knows about
42
+ def self.acceptable_attributes
43
+ acceptable_attribute_map.values
44
+ end
45
+
46
+ # Attribute type mapping.
47
+ def self.openapi_types
48
+ {
49
+ :'type' => :'String',
50
+ :'property_id' => :'BookingAvailabilityUpdateRequestPropertyId',
51
+ :'updates' => :'Array<BookingAvailabilityUpdateRequestUpdatesInner>'
52
+ }
53
+ end
54
+
55
+ # List of attributes with nullable: true
56
+ def self.openapi_nullable
57
+ Set.new([
58
+ ])
59
+ end
60
+
61
+ # Initializes the object
62
+ # @param [Hash] attributes Model attributes in the form of hash
63
+ def initialize(attributes = {})
64
+ if (!attributes.is_a?(Hash))
65
+ fail ArgumentError, "The input argument (attributes) must be a hash in `Repull::BookingAvailabilityUpdateRequest` initialize method"
66
+ end
67
+
68
+ # check to see if the attribute exists and convert string to symbol for hash key
69
+ acceptable_attribute_map = self.class.acceptable_attribute_map
70
+ attributes = attributes.each_with_object({}) { |(k, v), h|
71
+ if (!acceptable_attribute_map.key?(k.to_sym))
72
+ fail ArgumentError, "`#{k}` is not a valid attribute in `Repull::BookingAvailabilityUpdateRequest`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
73
+ end
74
+ h[k.to_sym] = v
75
+ }
76
+
77
+ if attributes.key?(:'type')
78
+ self.type = attributes[:'type']
79
+ else
80
+ self.type = nil
81
+ end
82
+
83
+ if attributes.key?(:'property_id')
84
+ self.property_id = attributes[:'property_id']
85
+ else
86
+ self.property_id = nil
87
+ end
88
+
89
+ if attributes.key?(:'updates')
90
+ if (value = attributes[:'updates']).is_a?(Array)
91
+ self.updates = value
92
+ end
93
+ else
94
+ self.updates = nil
95
+ end
96
+ end
97
+
98
+ # Show invalid properties with the reasons. Usually used together with valid?
99
+ # @return Array for valid properties with the reasons
100
+ def list_invalid_properties
101
+ warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
102
+ invalid_properties = Array.new
103
+ if @type.nil?
104
+ invalid_properties.push('invalid value for "type", type cannot be nil.')
105
+ end
106
+
107
+ if @property_id.nil?
108
+ invalid_properties.push('invalid value for "property_id", property_id cannot be nil.')
109
+ end
110
+
111
+ if @updates.nil?
112
+ invalid_properties.push('invalid value for "updates", updates cannot be nil.')
113
+ end
114
+
115
+ if @updates.length < 1
116
+ invalid_properties.push('invalid value for "updates", number of items must be greater than or equal to 1.')
117
+ end
118
+
119
+ invalid_properties
120
+ end
121
+
122
+ # Check to see if the all the properties in the model are valid
123
+ # @return true if the model is valid
124
+ def valid?
125
+ warn '[DEPRECATED] the `valid?` method is obsolete'
126
+ return false if @type.nil?
127
+ return false if @property_id.nil?
128
+ return false if @updates.nil?
129
+ return false if @updates.length < 1
130
+ true
131
+ end
132
+
133
+ # Custom attribute writer method with validation
134
+ # @param [Object] type Value to be assigned
135
+ def type=(type)
136
+ if type.nil?
137
+ fail ArgumentError, 'type cannot be nil'
138
+ end
139
+
140
+ @type = type
141
+ end
142
+
143
+ # Custom attribute writer method with validation
144
+ # @param [Object] property_id Value to be assigned
145
+ def property_id=(property_id)
146
+ if property_id.nil?
147
+ fail ArgumentError, 'property_id cannot be nil'
148
+ end
149
+
150
+ @property_id = property_id
151
+ end
152
+
153
+ # Custom attribute writer method with validation
154
+ # @param [Object] updates Value to be assigned
155
+ def updates=(updates)
156
+ if updates.nil?
157
+ fail ArgumentError, 'updates cannot be nil'
158
+ end
159
+
160
+ if updates.length < 1
161
+ fail ArgumentError, 'invalid value for "updates", number of items must be greater than or equal to 1.'
162
+ end
163
+
164
+ @updates = updates
165
+ end
166
+
167
+ # Checks equality by comparing each attribute.
168
+ # @param [Object] Object to be compared
169
+ def ==(o)
170
+ return true if self.equal?(o)
171
+ self.class == o.class &&
172
+ type == o.type &&
173
+ property_id == o.property_id &&
174
+ updates == o.updates
175
+ end
176
+
177
+ # @see the `==` method
178
+ # @param [Object] Object to be compared
179
+ def eql?(o)
180
+ self == o
181
+ end
182
+
183
+ # Calculates hash code according to all attributes.
184
+ # @return [Integer] Hash code
185
+ def hash
186
+ [type, property_id, updates].hash
187
+ end
188
+
189
+ # Builds the object from hash
190
+ # @param [Hash] attributes Model attributes in the form of hash
191
+ # @return [Object] Returns the model itself
192
+ def self.build_from_hash(attributes)
193
+ return nil unless attributes.is_a?(Hash)
194
+ attributes = attributes.transform_keys(&:to_sym)
195
+ transformed_hash = {}
196
+ openapi_types.each_pair do |key, type|
197
+ if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
198
+ transformed_hash["#{key}"] = nil
199
+ elsif type =~ /\AArray<(.*)>/i
200
+ # check to ensure the input is an array given that the attribute
201
+ # is documented as an array but the input is not
202
+ if attributes[attribute_map[key]].is_a?(Array)
203
+ transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
204
+ end
205
+ elsif !attributes[attribute_map[key]].nil?
206
+ transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
207
+ end
208
+ end
209
+ new(transformed_hash)
210
+ end
211
+
212
+ # Returns the object in the form of hash
213
+ # @return [Hash] Returns the object in the form of hash
214
+ def to_hash
215
+ hash = {}
216
+ self.class.attribute_map.each_pair do |attr, param|
217
+ value = self.send(attr)
218
+ if value.nil?
219
+ is_nullable = self.class.openapi_nullable.include?(attr)
220
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
221
+ end
222
+
223
+ hash[param] = _to_hash(value)
224
+ end
225
+ hash
226
+ end
227
+
228
+ end
229
+
230
+ end
@@ -14,8 +14,8 @@ require 'date'
14
14
  require 'time'
15
15
 
16
16
  module Repull
17
- # Project the generation belongs to (used for billing + rate limits).
18
- module GenerateStudioCompletionRequestProjectId
17
+ # Booking.com hotel/property id (numeric; accepted as int or numeric string).
18
+ module BookingAvailabilityUpdateRequestPropertyId
19
19
  class << self
20
20
  # List of class defined in oneOf (OpenAPI v3)
21
21
  def openapi_one_of
@@ -0,0 +1,104 @@
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_test_YOUR_API_KEY ``` Sandbox keys start with `sk_test_`, production with `sk_live_`. ## Request Correlation (X-Request-ID) Every response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports — we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id. You may set the header on the inbound request to forward your own trace id; we will echo it back instead of generating a new one. Accepted format: `^[\\\\w.-]{1,128}$`. The id is also embedded in error envelopes as `request_id` so server-side log diffs work even when the response headers are stripped by an intermediate proxy. ## Rate Limits The public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas. **Default policy:** 600 requests per 60 seconds, per API key. Sliding window — there is no fixed-minute boundary you can burst across. Every response includes: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests permitted in the current window. | | `X-RateLimit-Remaining` | Requests left in the current window after this call. | | `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. | | `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. | | `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** | **On 429 (rate_limit_exceeded):** the response body matches the standard error envelope with `code: \"rate_limit_exceeded\"`, plus `limit`, `window_seconds`, `retry_after`, and `request_id` fields. SDKs MUST honor `Retry-After` and use exponential backoff with jitter on subsequent retries — never a tight loop. Recommended backoff: ``` sleep_ms = (Retry-After * 1000) + random(0..250) ``` Monthly + daily-AI tier quotas (`free`, `starter`, `custom`) are enforced separately and also surface as 429s; they include `tier`, `scope`, and `resets_at` fields. ## Plan Limits (402 — `listings_limit_exceeded`) The Repull API also enforces a per-tier cap on **active listings**: | Tier | Active listings cap | |---|---| | `free` | 3 | | `starter` | 50 | | `custom` | unlimited | When a customer's active-listing count is above their tier cap, the API returns **`402 Payment Required`** with `error.code = \"listings_limit_exceeded\"` on every route EXCEPT: - `/v1/health` — uptime probes are never gated. - `/v1/usage/*` — so dashboards can render the over-cap state. - Any `DELETE` — so the customer can trim listings to get back under the cap without paying. Unlike 429, 402 is NOT a \"wait and retry\" condition — `Retry-After` is not set. The only paths back to 200 are: 1. `DELETE` enough listings to come back under the cap, or 2. Upgrade at `https://repull.dev/dashboard/billing`. The server-side usage cache is 60s, so the first 200 after an upgrade may take up to a minute. The envelope mirrors `rate_limit_exceeded` for SDK ergonomics: `tier`, `limit`, `active_listings`, `upgrade_url`, plus the standard `code` / `message` / `fix` / `docs_url` / `request_id`.
5
+
6
+ The version of the OpenAPI document: 1.0.0
7
+ Contact: ivan@vanio.ai
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.22.0
10
+
11
+ =end
12
+
13
+ require 'date'
14
+ require 'time'
15
+
16
+ module Repull
17
+ module BookingAvailabilityUpdateRequestUpdatesInner
18
+ class << self
19
+ # List of class defined in oneOf (OpenAPI v3)
20
+ def openapi_one_of
21
+ [
22
+ :'BookingAvailabilityUpdate',
23
+ :'BookingPricingRateUpdate'
24
+ ]
25
+ end
26
+
27
+ # Builds the object
28
+ # @param [Mixed] Data to be matched against the list of oneOf items
29
+ # @return [Object] Returns the model or the data itself
30
+ def build(data)
31
+ # Go through the list of oneOf items and attempt to identify the appropriate one.
32
+ # Note:
33
+ # - We do not attempt to check whether exactly one item matches.
34
+ # - No advanced validation of types in some cases (e.g. "x: { type: string }" will happily match { x: 123 })
35
+ # due to the way the deserialization is made in the base_object template (it just casts without verifying).
36
+ # - TODO: scalar values are de facto behaving as if they were nullable.
37
+ # - TODO: logging when debugging is set.
38
+ openapi_one_of.each do |klass|
39
+ begin
40
+ next if klass == :AnyType # "nullable: true"
41
+ return find_and_cast_into_type(klass, data)
42
+ rescue # rescue all errors so we keep iterating even if the current item lookup raises
43
+ end
44
+ end
45
+
46
+ openapi_one_of.include?(:AnyType) ? data : nil
47
+ end
48
+
49
+ private
50
+
51
+ SchemaMismatchError = Class.new(StandardError)
52
+
53
+ # Note: 'File' is missing here because in the regular case we get the data _after_ a call to JSON.parse.
54
+ def find_and_cast_into_type(klass, data)
55
+ return if data.nil?
56
+
57
+ case klass.to_s
58
+ when 'Boolean'
59
+ return data if data.instance_of?(TrueClass) || data.instance_of?(FalseClass)
60
+ when 'Float'
61
+ return data if data.instance_of?(Float)
62
+ when 'Integer'
63
+ return data if data.instance_of?(Integer)
64
+ when 'Time'
65
+ return Time.parse(data)
66
+ when 'Date'
67
+ return Date.iso8601(data)
68
+ when 'String'
69
+ return data if data.instance_of?(String)
70
+ when 'Object' # "type: object"
71
+ return data if data.instance_of?(Hash)
72
+ when /\AArray<(?<sub_type>.+)>\z/ # "type: array"
73
+ if data.instance_of?(Array)
74
+ sub_type = Regexp.last_match[:sub_type]
75
+ return data.map { |item| find_and_cast_into_type(sub_type, item) }
76
+ end
77
+ when /\AHash<String, (?<sub_type>.+)>\z/ # "type: object" with "additionalProperties: { ... }"
78
+ if data.instance_of?(Hash) && data.keys.all? { |k| k.instance_of?(Symbol) || k.instance_of?(String) }
79
+ sub_type = Regexp.last_match[:sub_type]
80
+ return data.each_with_object({}) { |(k, v), hsh| hsh[k] = find_and_cast_into_type(sub_type, v) }
81
+ end
82
+ else # model
83
+ const = Repull.const_get(klass)
84
+ if const
85
+ if const.respond_to?(:openapi_one_of) # nested oneOf model
86
+ model = const.build(data)
87
+ return model if model
88
+ else
89
+ # raise if data contains keys that are not known to the model
90
+ raise if const.respond_to?(:acceptable_attributes) && !(data.keys - const.acceptable_attributes).empty?
91
+ model = const.build_from_hash(data)
92
+ return model if model
93
+ end
94
+ end
95
+ end
96
+
97
+ raise # if no match by now, raise
98
+ rescue
99
+ raise SchemaMismatchError, "#{data} doesn't match the #{klass} type"
100
+ end
101
+ end
102
+ end
103
+
104
+ end
@@ -32,6 +32,7 @@ module Repull
32
32
 
33
33
  attr_accessor :occupancy
34
34
 
35
+ # Rooms to sell for the date range. Set to `0` to stop-sell this room/rate on the rates endpoint (Booking's dedicated `<closed>` stop-sell flag lives on the availability endpoint — see `BookingAvailabilityUpdate.closed`).
35
36
  attr_accessor :rooms_to_sell
36
37
 
37
38
  attr_accessor :restrictions
@@ -14,23 +14,47 @@ require 'date'
14
14
  require 'time'
15
15
 
16
16
  module Repull
17
- # Optional length-of-stay / availability restrictions for one rate update.
17
+ # Optional length-of-stay / availability restrictions for one rate update. Every field here is forwarded verbatim into Booking.com's rates XML (`minimumstay`, `maximumstay`, `closedonarrival`, `closedondeparture`, …) — omit a field to leave that restriction untouched.
18
18
  class BookingPricingRateUpdateRestrictions < ApiModelBase
19
+ # Minimum length of stay (`minimumstay`).
19
20
  attr_accessor :min_stay
20
21
 
22
+ # Maximum length of stay (`maximumstay`).
21
23
  attr_accessor :max_stay
22
24
 
25
+ # Closed-to-arrival — guests may not check in on the affected dates (`closedonarrival`).
23
26
  attr_accessor :closed_to_arrival
24
27
 
28
+ # Closed-to-departure — guests may not check out on the affected dates (`closedondeparture`).
25
29
  attr_accessor :closed_to_departure
26
30
 
31
+ # Arrival-based minimum length of stay (`minimumstay_arrival`).
32
+ attr_accessor :min_stay_arrival
33
+
34
+ # Arrival-based maximum length of stay (`maximumstay_arrival`).
35
+ attr_accessor :max_stay_arrival
36
+
37
+ # Arrival-based exact length of stay (`exactstay_arrival`).
38
+ attr_accessor :exact_stay_arrival
39
+
40
+ # Minimum advance-reservation window, format `XDY` (X days Y hours) — `min_advance_res`.
41
+ attr_accessor :min_advance_res
42
+
43
+ # Maximum advance-reservation window, format `XDY` (X days Y hours) — `max_advance_res`.
44
+ attr_accessor :max_advance_res
45
+
27
46
  # Attribute mapping from ruby-style variable name to JSON key.
28
47
  def self.attribute_map
29
48
  {
30
49
  :'min_stay' => :'minStay',
31
50
  :'max_stay' => :'maxStay',
32
51
  :'closed_to_arrival' => :'closedToArrival',
33
- :'closed_to_departure' => :'closedToDeparture'
52
+ :'closed_to_departure' => :'closedToDeparture',
53
+ :'min_stay_arrival' => :'minStayArrival',
54
+ :'max_stay_arrival' => :'maxStayArrival',
55
+ :'exact_stay_arrival' => :'exactStayArrival',
56
+ :'min_advance_res' => :'minAdvanceRes',
57
+ :'max_advance_res' => :'maxAdvanceRes'
34
58
  }
35
59
  end
36
60
 
@@ -50,7 +74,12 @@ module Repull
50
74
  :'min_stay' => :'Integer',
51
75
  :'max_stay' => :'Integer',
52
76
  :'closed_to_arrival' => :'Boolean',
53
- :'closed_to_departure' => :'Boolean'
77
+ :'closed_to_departure' => :'Boolean',
78
+ :'min_stay_arrival' => :'Integer',
79
+ :'max_stay_arrival' => :'Integer',
80
+ :'exact_stay_arrival' => :'Integer',
81
+ :'min_advance_res' => :'String',
82
+ :'max_advance_res' => :'String'
54
83
  }
55
84
  end
56
85
 
@@ -60,7 +89,12 @@ module Repull
60
89
  :'min_stay',
61
90
  :'max_stay',
62
91
  :'closed_to_arrival',
63
- :'closed_to_departure'
92
+ :'closed_to_departure',
93
+ :'min_stay_arrival',
94
+ :'max_stay_arrival',
95
+ :'exact_stay_arrival',
96
+ :'min_advance_res',
97
+ :'max_advance_res'
64
98
  ])
65
99
  end
66
100
 
@@ -95,6 +129,26 @@ module Repull
95
129
  if attributes.key?(:'closed_to_departure')
96
130
  self.closed_to_departure = attributes[:'closed_to_departure']
97
131
  end
132
+
133
+ if attributes.key?(:'min_stay_arrival')
134
+ self.min_stay_arrival = attributes[:'min_stay_arrival']
135
+ end
136
+
137
+ if attributes.key?(:'max_stay_arrival')
138
+ self.max_stay_arrival = attributes[:'max_stay_arrival']
139
+ end
140
+
141
+ if attributes.key?(:'exact_stay_arrival')
142
+ self.exact_stay_arrival = attributes[:'exact_stay_arrival']
143
+ end
144
+
145
+ if attributes.key?(:'min_advance_res')
146
+ self.min_advance_res = attributes[:'min_advance_res']
147
+ end
148
+
149
+ if attributes.key?(:'max_advance_res')
150
+ self.max_advance_res = attributes[:'max_advance_res']
151
+ end
98
152
  end
99
153
 
100
154
  # Show invalid properties with the reasons. Usually used together with valid?
@@ -120,7 +174,12 @@ module Repull
120
174
  min_stay == o.min_stay &&
121
175
  max_stay == o.max_stay &&
122
176
  closed_to_arrival == o.closed_to_arrival &&
123
- closed_to_departure == o.closed_to_departure
177
+ closed_to_departure == o.closed_to_departure &&
178
+ min_stay_arrival == o.min_stay_arrival &&
179
+ max_stay_arrival == o.max_stay_arrival &&
180
+ exact_stay_arrival == o.exact_stay_arrival &&
181
+ min_advance_res == o.min_advance_res &&
182
+ max_advance_res == o.max_advance_res
124
183
  end
125
184
 
126
185
  # @see the `==` method
@@ -132,7 +191,7 @@ module Repull
132
191
  # Calculates hash code according to all attributes.
133
192
  # @return [Integer] Hash code
134
193
  def hash
135
- [min_stay, max_stay, closed_to_arrival, closed_to_departure].hash
194
+ [min_stay, max_stay, closed_to_arrival, closed_to_departure, min_stay_arrival, max_stay_arrival, exact_stay_arrival, min_advance_res, max_advance_res].hash
136
195
  end
137
196
 
138
197
  # Builds the object from hash