repull 0.2.15 → 0.2.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/repull/api/airbnb_api.rb +147 -52
- data/lib/repull/api/billing_api.rb +4 -4
- data/lib/repull/api/booking_com_api.rb +36 -27
- data/lib/repull/api/conversations_api.rb +398 -4
- data/lib/repull/api/guests_api.rb +2 -2
- data/lib/repull/api/listings_api.rb +4 -4
- data/lib/repull/api/reservations_api.rb +157 -6
- data/lib/repull/api/webhooks_api.rb +10 -3
- data/lib/repull/models/accept_reservation_request200_response.rb +321 -0
- data/lib/repull/models/account_created_event.rb +95 -31
- data/lib/repull/models/account_disconnected_event.rb +95 -31
- data/lib/repull/models/ai_operation_completed_event.rb +95 -31
- data/lib/repull/models/ai_operation_failed_event.rb +95 -31
- data/lib/repull/models/airbnb_reservation_action200_response.rb +157 -0
- data/lib/repull/models/airbnb_reservation_action_request.rb +248 -0
- data/lib/repull/models/booking_availability_update.rb +4 -20
- data/lib/repull/models/booking_availability_update_date_range.rb +193 -0
- data/lib/repull/models/booking_availability_update_request.rb +14 -3
- data/lib/repull/models/booking_pricing_rate_update.rb +32 -4
- data/lib/repull/models/booking_pricing_rate_update_date_range.rb +3 -0
- data/lib/repull/models/booking_pricing_rate_update_restrictions.rb +10 -10
- data/lib/repull/models/booking_pricing_response.rb +16 -4
- data/lib/repull/models/booking_pricing_update_response.rb +82 -18
- data/lib/repull/models/booking_property.rb +107 -36
- data/lib/repull/models/booking_property_listings_inner.rb +244 -0
- data/lib/repull/models/booking_rate_write_occupancy.rb +187 -0
- data/lib/repull/models/booking_rate_write_price_half.rb +188 -0
- data/lib/repull/models/booking_rate_write_restriction_half.rb +212 -0
- data/lib/repull/models/booking_rate_write_verification.rb +200 -0
- data/lib/repull/models/booking_rate_write_verification_row.rb +196 -0
- data/lib/repull/models/booking_restriction_request_row.rb +199 -0
- data/lib/repull/models/booking_restriction_verification.rb +208 -0
- data/lib/repull/models/booking_restriction_verification_row.rb +203 -0
- data/lib/repull/models/booking_restriction_verification_row_booking_value.rb +105 -0
- data/lib/repull/models/booking_restriction_verification_row_expected.rb +105 -0
- data/lib/repull/models/booking_rooms_rates_response.rb +41 -7
- data/lib/repull/models/booking_rooms_rates_response_rooms_inner.rb +12 -1
- data/lib/repull/models/booking_rooms_rates_response_rooms_inner_rates_inner.rb +1 -0
- data/lib/repull/models/booking_upstream_failure.rb +204 -0
- data/lib/repull/models/calendar_updated_event.rb +95 -31
- data/lib/repull/models/conversation_message_attachment.rb +28 -1
- data/lib/repull/models/create_airbnb_offer_request.rb +93 -8
- data/lib/repull/models/create_airbnb_offer_request_guest_details.rb +279 -0
- data/lib/repull/models/create_conversation_special_offer201_response.rb +293 -0
- data/lib/repull/models/create_conversation_special_offer201_response_guests.rb +189 -0
- data/lib/repull/models/create_conversation_special_offer_request.rb +263 -0
- data/lib/repull/models/create_conversation_special_offer_request_guests.rb +263 -0
- data/lib/repull/models/decline_reservation_request_request.rb +234 -0
- data/lib/repull/models/get_airbnb_offer200_response.rb +289 -0
- data/lib/repull/models/get_usage_summary200_response.rb +10 -1
- data/lib/repull/models/get_usage_summary200_response_limits.rb +11 -1
- data/lib/repull/models/get_usage_summary200_response_remaining.rb +11 -1
- data/lib/repull/models/get_usage_summary200_response_used.rb +10 -1
- data/lib/repull/models/get_usage_tier200_response.rb +10 -1
- data/lib/repull/models/get_usage_tier200_response_limits.rb +11 -1
- data/lib/repull/models/get_usage_tier200_response_remaining.rb +11 -1
- data/lib/repull/models/get_usage_tier200_response_used.rb +10 -1
- data/lib/repull/models/inquiry_created_event.rb +281 -0
- data/lib/repull/models/inquiry_created_payload.rb +185 -0
- data/lib/repull/models/inquiry_updated_event.rb +281 -0
- data/lib/repull/models/inquiry_updated_payload.rb +213 -0
- data/lib/repull/models/inquiry_webhook_object.rb +323 -0
- data/lib/repull/models/inquiry_webhook_object_expected_payout.rb +158 -0
- data/lib/repull/models/inquiry_webhook_object_guests.rb +188 -0
- data/lib/repull/models/list_airbnb_thread_messages200_response.rb +170 -0
- data/lib/repull/models/list_airbnb_thread_messages200_response_data_inner.rb +274 -0
- data/lib/repull/models/list_airbnb_thread_messages200_response_pagination.rb +158 -0
- data/lib/repull/models/list_inquiries200_response.rb +192 -0
- data/lib/repull/models/list_inquiries200_response_data_inner.rb +418 -0
- data/lib/repull/models/list_inquiries200_response_data_inner_expected_payout.rb +159 -0
- data/lib/repull/models/list_inquiries200_response_data_inner_guests.rb +188 -0
- data/lib/repull/models/listing_created_event.rb +95 -31
- data/lib/repull/models/listing_deleted_event.rb +95 -31
- data/lib/repull/models/listing_deleted_payload.rb +55 -21
- data/lib/repull/models/listing_reactivated_event.rb +281 -0
- data/lib/repull/models/listing_suspended_event.rb +281 -0
- data/lib/repull/models/listing_suspension_payload.rb +202 -0
- data/lib/repull/models/listing_updated_event.rb +95 -31
- data/lib/repull/models/listing_updated_payload.rb +50 -22
- data/lib/repull/models/listing_webhook_object.rb +291 -0
- data/lib/repull/models/listing_webhook_object_address.rb +168 -0
- data/lib/repull/models/listing_webhook_object_channels_inner.rb +184 -0
- data/lib/repull/models/message.rb +1 -0
- data/lib/repull/models/payment_completed_event.rb +95 -31
- data/lib/repull/models/payment_completed_payload.rb +46 -44
- data/lib/repull/models/payment_refunded_event.rb +95 -31
- data/lib/repull/models/payment_refunded_payload.rb +46 -44
- data/lib/repull/models/payment_webhook_object.rb +351 -0
- data/lib/repull/models/preapprove_conversation201_response.rb +253 -0
- data/lib/repull/models/preapprove_conversation_request.rb +150 -0
- data/lib/repull/models/replay_webhook_delivery_request.rb +150 -0
- data/lib/repull/models/repull_ping_event.rb +95 -31
- data/lib/repull/models/reservation.rb +22 -2
- data/lib/repull/models/reservation_alteration_created_event.rb +95 -31
- data/lib/repull/models/reservation_alteration_responded_event.rb +95 -31
- data/lib/repull/models/reservation_cancelled_event.rb +95 -31
- data/lib/repull/models/reservation_created_event.rb +95 -32
- data/lib/repull/models/reservation_message_received_event.rb +95 -31
- data/lib/repull/models/reservation_message_received_payload.rb +17 -4
- data/lib/repull/models/reservation_request_created_event.rb +281 -0
- data/lib/repull/models/reservation_request_created_payload.rb +224 -0
- data/lib/repull/models/reservation_request_updated_event.rb +281 -0
- data/lib/repull/models/reservation_request_updated_payload.rb +251 -0
- data/lib/repull/models/reservation_updated_event.rb +95 -31
- data/lib/repull/models/review_created_event.rb +95 -31
- data/lib/repull/models/review_responded_event.rb +95 -31
- data/lib/repull/models/send_airbnb_message201_response.rb +104 -0
- data/lib/repull/models/send_airbnb_message_request.rb +4 -20
- data/lib/repull/models/send_message_attachment.rb +225 -0
- data/lib/repull/models/send_message_part.rb +201 -0
- data/lib/repull/models/send_message_request.rb +44 -19
- data/lib/repull/models/send_message_response.rb +29 -5
- data/lib/repull/models/sent_attachment.rb +196 -0
- data/lib/repull/models/usage_quota_warning_event.rb +281 -0
- data/lib/repull/models/usage_quota_warning_payload.rb +224 -0
- data/lib/repull/models/usage_quota_warning_payload_top_operation.rb +167 -0
- data/lib/repull/models/webhook_event.rb +17 -3
- data/lib/repull/models/webhook_event_account.rb +171 -0
- data/lib/repull/models/webhook_event_type.rb +8 -1
- data/lib/repull/models/withdraw_conversation_special_offer200_response.rb +240 -0
- data/lib/repull/version.rb +1 -1
- data/lib/repull.rb +60 -0
- data/openapi/v1.json +19295 -13620
- data/scripts/regen.sh +1 -1
- metadata +62 -2
|
@@ -19,11 +19,81 @@ module Repull
|
|
|
19
19
|
def initialize(api_client = ApiClient.default)
|
|
20
20
|
@api_client = api_client
|
|
21
21
|
end
|
|
22
|
+
# Accept a booking request
|
|
23
|
+
# Accept a pending Airbnb booking request — a reservation with status `pending`, made on a listing without Instant Book. Find them with `GET /v1/reservations?status=pending`. Airbnb expires a request the host has not answered within 24 hours. Runs the same action as the Vanio dashboard’s Accept button. Airbnb confirms asynchronously: the reservation’s status moves to confirmed, and a `reservation.updated` webhook fires, when Airbnb’s notification lands (usually within seconds). The response reports what Airbnb was asked to do. **Airbnb only**, and only for listings connected to Airbnb directly: other channels have no request step (`422 channel_not_supported`). A reservation that is not pending is refused before Airbnb is contacted (`409 reservation_not_pending`); one Airbnb says already moved on is `409 request_no_longer_pending`. Neither is worth retrying. Takes no body. Send `Idempotency-Key`: a repeat with the same key replays the first response instead of acting twice (a `409 idempotency_key_in_use` while the first is still running). A 5xx, a `429 airbnb_rate_limited` or a `403 connection_reauth_required` is not stored — nothing was done — so retrying with the same key reaches Airbnb again.
|
|
24
|
+
# @param id [Integer] Repull reservation id (from `GET /v1/reservations?status=pending`) — not the Airbnb confirmation code.
|
|
25
|
+
# @param [Hash] opts the optional parameters
|
|
26
|
+
# @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged `Idempotency-Status: cached` — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → `409 idempotency_key_in_use`. - Same key with a DIFFERENT payload → `422 idempotency_key_reused`. Generate a new key per distinct request; reuse one only when retrying that exact request. - Retryable outcomes are deliberately not stored, so a retry with the same key runs for real: any status >= 500, `408`, `425` and `429`, and the refusals that happen before anything is done and tell you to fix something outside the request first — `connection_reauth_required`, `listing_inactive`, and the rate/daily limits. Every other answer, including a final refusal such as `422 airbnb_rejected`, is stored and replayed.
|
|
27
|
+
# @return [AcceptReservationRequest200Response]
|
|
28
|
+
def accept_reservation_request(id, opts = {})
|
|
29
|
+
data, _status_code, _headers = accept_reservation_request_with_http_info(id, opts)
|
|
30
|
+
data
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Accept a booking request
|
|
34
|
+
# Accept a pending Airbnb booking request — a reservation with status `pending`, made on a listing without Instant Book. Find them with `GET /v1/reservations?status=pending`. Airbnb expires a request the host has not answered within 24 hours. Runs the same action as the Vanio dashboard’s Accept button. Airbnb confirms asynchronously: the reservation’s status moves to confirmed, and a `reservation.updated` webhook fires, when Airbnb’s notification lands (usually within seconds). The response reports what Airbnb was asked to do. **Airbnb only**, and only for listings connected to Airbnb directly: other channels have no request step (`422 channel_not_supported`). A reservation that is not pending is refused before Airbnb is contacted (`409 reservation_not_pending`); one Airbnb says already moved on is `409 request_no_longer_pending`. Neither is worth retrying. Takes no body. Send `Idempotency-Key`: a repeat with the same key replays the first response instead of acting twice (a `409 idempotency_key_in_use` while the first is still running). A 5xx, a `429 airbnb_rate_limited` or a `403 connection_reauth_required` is not stored — nothing was done — so retrying with the same key reaches Airbnb again.
|
|
35
|
+
# @param id [Integer] Repull reservation id (from `GET /v1/reservations?status=pending`) — not the Airbnb confirmation code.
|
|
36
|
+
# @param [Hash] opts the optional parameters
|
|
37
|
+
# @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged `Idempotency-Status: cached` — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → `409 idempotency_key_in_use`. - Same key with a DIFFERENT payload → `422 idempotency_key_reused`. Generate a new key per distinct request; reuse one only when retrying that exact request. - Retryable outcomes are deliberately not stored, so a retry with the same key runs for real: any status >= 500, `408`, `425` and `429`, and the refusals that happen before anything is done and tell you to fix something outside the request first — `connection_reauth_required`, `listing_inactive`, and the rate/daily limits. Every other answer, including a final refusal such as `422 airbnb_rejected`, is stored and replayed.
|
|
38
|
+
# @return [Array<(AcceptReservationRequest200Response, Integer, Hash)>] AcceptReservationRequest200Response data, response status code and response headers
|
|
39
|
+
def accept_reservation_request_with_http_info(id, opts = {})
|
|
40
|
+
if @api_client.config.debugging
|
|
41
|
+
@api_client.config.logger.debug 'Calling API: ReservationsApi.accept_reservation_request ...'
|
|
42
|
+
end
|
|
43
|
+
# verify the required parameter 'id' is set
|
|
44
|
+
if @api_client.config.client_side_validation && id.nil?
|
|
45
|
+
fail ArgumentError, "Missing the required parameter 'id' when calling ReservationsApi.accept_reservation_request"
|
|
46
|
+
end
|
|
47
|
+
if @api_client.config.client_side_validation && !opts[:'idempotency_key'].nil? && opts[:'idempotency_key'].to_s.length > 255
|
|
48
|
+
fail ArgumentError, 'invalid value for "opts[:"idempotency_key"]" when calling ReservationsApi.accept_reservation_request, the character length must be smaller than or equal to 255.'
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# resource path
|
|
52
|
+
local_var_path = '/v1/reservations/{id}/accept'.sub('{id}', CGI.escape(id.to_s))
|
|
53
|
+
|
|
54
|
+
# query parameters
|
|
55
|
+
query_params = opts[:query_params] || {}
|
|
56
|
+
|
|
57
|
+
# header parameters
|
|
58
|
+
header_params = opts[:header_params] || {}
|
|
59
|
+
# HTTP header 'Accept' (if needed)
|
|
60
|
+
header_params['Accept'] = @api_client.select_header_accept(['application/json']) unless header_params['Accept']
|
|
61
|
+
header_params[:'Idempotency-Key'] = opts[:'idempotency_key'] if !opts[:'idempotency_key'].nil?
|
|
62
|
+
|
|
63
|
+
# form parameters
|
|
64
|
+
form_params = opts[:form_params] || {}
|
|
65
|
+
|
|
66
|
+
# http body (model)
|
|
67
|
+
post_body = opts[:debug_body]
|
|
68
|
+
|
|
69
|
+
# return_type
|
|
70
|
+
return_type = opts[:debug_return_type] || 'AcceptReservationRequest200Response'
|
|
71
|
+
|
|
72
|
+
# auth_names
|
|
73
|
+
auth_names = opts[:debug_auth_names] || ['bearerAuth']
|
|
74
|
+
|
|
75
|
+
new_options = opts.merge(
|
|
76
|
+
:operation => :"ReservationsApi.accept_reservation_request",
|
|
77
|
+
:header_params => header_params,
|
|
78
|
+
:query_params => query_params,
|
|
79
|
+
:form_params => form_params,
|
|
80
|
+
:body => post_body,
|
|
81
|
+
:auth_names => auth_names,
|
|
82
|
+
:return_type => return_type
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
data, status_code, headers = @api_client.call_api(:POST, local_var_path, new_options)
|
|
86
|
+
if @api_client.config.debugging
|
|
87
|
+
@api_client.config.logger.debug "API called: ReservationsApi#accept_reservation_request\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
|
|
88
|
+
end
|
|
89
|
+
return data, status_code, headers
|
|
90
|
+
end
|
|
91
|
+
|
|
22
92
|
# Create a reservation
|
|
23
93
|
# Creates a reservation and everything that hangs off one: the guest, the conversation thread, the dashboard item, the calendar block, and the `reservation.created` fan-out that issues the door code and starts the messaging automations. **Platform is restricted to `direct`, `website` and `owner`.** Reservations on Airbnb, Booking.com and Vrbo are owned by the channel and arrive through sync — creating one here would mint a local booking the channel has never heard of, which then fights the next sync. Create those on the channel. **Dates are validated** (`YYYY-MM-DD`, and `checkOut` must be after `checkIn`), and an unrecognised field is rejected by name rather than silently ignored. **This endpoint does not set the price.** There is no `totalPrice` field: the reservation pipeline derives the price breakdown from the property's own rates and overwrites anything supplied, so accepting a total would be taking a value and discarding it. A reservation created here is priced by that engine (`0` when the property has no rates for the range). `currency` IS honoured. Quote a stay with `GET /v1/quotes` before booking if you need the figure up front. **Availability is NOT checked.** This creates the reservation you asked for even if the dates overlap an existing booking. Call `GET /v1/availability/{propertyId}` first if that matters. Send `Idempotency-Key` — a network timeout here is exactly the case it exists for: without it, a retry books the guest twice. Returns `403 listing_inactive` when the listing is inactive. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated.
|
|
24
94
|
# @param reservation_create_request [ReservationCreateRequest]
|
|
25
95
|
# @param [Hash] opts the optional parameters
|
|
26
|
-
# @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged `Idempotency-Status: cached` — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → `409 idempotency_key_in_use`. - Same key with a DIFFERENT payload → `422 idempotency_key_reused`. Generate a new key per distinct request; reuse one only when retrying that exact request. -
|
|
96
|
+
# @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged `Idempotency-Status: cached` — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → `409 idempotency_key_in_use`. - Same key with a DIFFERENT payload → `422 idempotency_key_reused`. Generate a new key per distinct request; reuse one only when retrying that exact request. - Retryable outcomes are deliberately not stored, so a retry with the same key runs for real: any status >= 500, `408`, `425` and `429`, and the refusals that happen before anything is done and tell you to fix something outside the request first — `connection_reauth_required`, `listing_inactive`, and the rate/daily limits. Every other answer, including a final refusal such as `422 airbnb_rejected`, is stored and replayed.
|
|
27
97
|
# @return [ReservationCreateResponse]
|
|
28
98
|
def create_reservation(reservation_create_request, opts = {})
|
|
29
99
|
data, _status_code, _headers = create_reservation_with_http_info(reservation_create_request, opts)
|
|
@@ -34,7 +104,7 @@ module Repull
|
|
|
34
104
|
# Creates a reservation and everything that hangs off one: the guest, the conversation thread, the dashboard item, the calendar block, and the `reservation.created` fan-out that issues the door code and starts the messaging automations. **Platform is restricted to `direct`, `website` and `owner`.** Reservations on Airbnb, Booking.com and Vrbo are owned by the channel and arrive through sync — creating one here would mint a local booking the channel has never heard of, which then fights the next sync. Create those on the channel. **Dates are validated** (`YYYY-MM-DD`, and `checkOut` must be after `checkIn`), and an unrecognised field is rejected by name rather than silently ignored. **This endpoint does not set the price.** There is no `totalPrice` field: the reservation pipeline derives the price breakdown from the property's own rates and overwrites anything supplied, so accepting a total would be taking a value and discarding it. A reservation created here is priced by that engine (`0` when the property has no rates for the range). `currency` IS honoured. Quote a stay with `GET /v1/quotes` before booking if you need the figure up front. **Availability is NOT checked.** This creates the reservation you asked for even if the dates overlap an existing booking. Call `GET /v1/availability/{propertyId}` first if that matters. Send `Idempotency-Key` — a network timeout here is exactly the case it exists for: without it, a retry books the guest twice. Returns `403 listing_inactive` when the listing is inactive. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated.
|
|
35
105
|
# @param reservation_create_request [ReservationCreateRequest]
|
|
36
106
|
# @param [Hash] opts the optional parameters
|
|
37
|
-
# @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged `Idempotency-Status: cached` — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → `409 idempotency_key_in_use`. - Same key with a DIFFERENT payload → `422 idempotency_key_reused`. Generate a new key per distinct request; reuse one only when retrying that exact request. -
|
|
107
|
+
# @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged `Idempotency-Status: cached` — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → `409 idempotency_key_in_use`. - Same key with a DIFFERENT payload → `422 idempotency_key_reused`. Generate a new key per distinct request; reuse one only when retrying that exact request. - Retryable outcomes are deliberately not stored, so a retry with the same key runs for real: any status >= 500, `408`, `425` and `429`, and the refusals that happen before anything is done and tell you to fix something outside the request first — `connection_reauth_required`, `listing_inactive`, and the rate/daily limits. Every other answer, including a final refusal such as `422 airbnb_rejected`, is stored and replayed.
|
|
38
108
|
# @return [Array<(ReservationCreateResponse, Integer, Hash)>] ReservationCreateResponse data, response status code and response headers
|
|
39
109
|
def create_reservation_with_http_info(reservation_create_request, opts = {})
|
|
40
110
|
if @api_client.config.debugging
|
|
@@ -94,6 +164,87 @@ module Repull
|
|
|
94
164
|
return data, status_code, headers
|
|
95
165
|
end
|
|
96
166
|
|
|
167
|
+
# Decline a booking request
|
|
168
|
+
# Decline a pending Airbnb booking request (a reservation with status `pending`; find them with `GET /v1/reservations?status=pending`). `reason` must be one of Airbnb’s own decline reasons. `message` is required: Airbnb sends it to the guest with the decline (at most 500 characters). It is not defaulted — a canned message would put words in your mouth. Runs the same action as the Vanio dashboard’s Decline button. Airbnb confirms asynchronously; the reservation’s status moves, and `reservation.updated` fires, when its notification lands. Same channel and status rules as `POST /v1/reservations/{id}/accept`. Send `Idempotency-Key`: a repeat with the same key replays the first response instead of acting twice (a `409 idempotency_key_in_use` while the first is still running). A 5xx, a `429 airbnb_rate_limited` or a `403 connection_reauth_required` is not stored — nothing was done — so retrying with the same key reaches Airbnb again.
|
|
169
|
+
# @param id [Integer] Repull reservation id (from `GET /v1/reservations?status=pending`) — not the Airbnb confirmation code.
|
|
170
|
+
# @param decline_reservation_request_request [DeclineReservationRequestRequest]
|
|
171
|
+
# @param [Hash] opts the optional parameters
|
|
172
|
+
# @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged `Idempotency-Status: cached` — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → `409 idempotency_key_in_use`. - Same key with a DIFFERENT payload → `422 idempotency_key_reused`. Generate a new key per distinct request; reuse one only when retrying that exact request. - Retryable outcomes are deliberately not stored, so a retry with the same key runs for real: any status >= 500, `408`, `425` and `429`, and the refusals that happen before anything is done and tell you to fix something outside the request first — `connection_reauth_required`, `listing_inactive`, and the rate/daily limits. Every other answer, including a final refusal such as `422 airbnb_rejected`, is stored and replayed.
|
|
173
|
+
# @return [AcceptReservationRequest200Response]
|
|
174
|
+
def decline_reservation_request(id, decline_reservation_request_request, opts = {})
|
|
175
|
+
data, _status_code, _headers = decline_reservation_request_with_http_info(id, decline_reservation_request_request, opts)
|
|
176
|
+
data
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Decline a booking request
|
|
180
|
+
# Decline a pending Airbnb booking request (a reservation with status `pending`; find them with `GET /v1/reservations?status=pending`). `reason` must be one of Airbnb’s own decline reasons. `message` is required: Airbnb sends it to the guest with the decline (at most 500 characters). It is not defaulted — a canned message would put words in your mouth. Runs the same action as the Vanio dashboard’s Decline button. Airbnb confirms asynchronously; the reservation’s status moves, and `reservation.updated` fires, when its notification lands. Same channel and status rules as `POST /v1/reservations/{id}/accept`. Send `Idempotency-Key`: a repeat with the same key replays the first response instead of acting twice (a `409 idempotency_key_in_use` while the first is still running). A 5xx, a `429 airbnb_rate_limited` or a `403 connection_reauth_required` is not stored — nothing was done — so retrying with the same key reaches Airbnb again.
|
|
181
|
+
# @param id [Integer] Repull reservation id (from `GET /v1/reservations?status=pending`) — not the Airbnb confirmation code.
|
|
182
|
+
# @param decline_reservation_request_request [DeclineReservationRequestRequest]
|
|
183
|
+
# @param [Hash] opts the optional parameters
|
|
184
|
+
# @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged `Idempotency-Status: cached` — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → `409 idempotency_key_in_use`. - Same key with a DIFFERENT payload → `422 idempotency_key_reused`. Generate a new key per distinct request; reuse one only when retrying that exact request. - Retryable outcomes are deliberately not stored, so a retry with the same key runs for real: any status >= 500, `408`, `425` and `429`, and the refusals that happen before anything is done and tell you to fix something outside the request first — `connection_reauth_required`, `listing_inactive`, and the rate/daily limits. Every other answer, including a final refusal such as `422 airbnb_rejected`, is stored and replayed.
|
|
185
|
+
# @return [Array<(AcceptReservationRequest200Response, Integer, Hash)>] AcceptReservationRequest200Response data, response status code and response headers
|
|
186
|
+
def decline_reservation_request_with_http_info(id, decline_reservation_request_request, opts = {})
|
|
187
|
+
if @api_client.config.debugging
|
|
188
|
+
@api_client.config.logger.debug 'Calling API: ReservationsApi.decline_reservation_request ...'
|
|
189
|
+
end
|
|
190
|
+
# verify the required parameter 'id' is set
|
|
191
|
+
if @api_client.config.client_side_validation && id.nil?
|
|
192
|
+
fail ArgumentError, "Missing the required parameter 'id' when calling ReservationsApi.decline_reservation_request"
|
|
193
|
+
end
|
|
194
|
+
# verify the required parameter 'decline_reservation_request_request' is set
|
|
195
|
+
if @api_client.config.client_side_validation && decline_reservation_request_request.nil?
|
|
196
|
+
fail ArgumentError, "Missing the required parameter 'decline_reservation_request_request' when calling ReservationsApi.decline_reservation_request"
|
|
197
|
+
end
|
|
198
|
+
if @api_client.config.client_side_validation && !opts[:'idempotency_key'].nil? && opts[:'idempotency_key'].to_s.length > 255
|
|
199
|
+
fail ArgumentError, 'invalid value for "opts[:"idempotency_key"]" when calling ReservationsApi.decline_reservation_request, the character length must be smaller than or equal to 255.'
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# resource path
|
|
203
|
+
local_var_path = '/v1/reservations/{id}/decline'.sub('{id}', CGI.escape(id.to_s))
|
|
204
|
+
|
|
205
|
+
# query parameters
|
|
206
|
+
query_params = opts[:query_params] || {}
|
|
207
|
+
|
|
208
|
+
# header parameters
|
|
209
|
+
header_params = opts[:header_params] || {}
|
|
210
|
+
# HTTP header 'Accept' (if needed)
|
|
211
|
+
header_params['Accept'] = @api_client.select_header_accept(['application/json']) unless header_params['Accept']
|
|
212
|
+
# HTTP header 'Content-Type'
|
|
213
|
+
content_type = @api_client.select_header_content_type(['application/json'])
|
|
214
|
+
if !content_type.nil?
|
|
215
|
+
header_params['Content-Type'] = content_type
|
|
216
|
+
end
|
|
217
|
+
header_params[:'Idempotency-Key'] = opts[:'idempotency_key'] if !opts[:'idempotency_key'].nil?
|
|
218
|
+
|
|
219
|
+
# form parameters
|
|
220
|
+
form_params = opts[:form_params] || {}
|
|
221
|
+
|
|
222
|
+
# http body (model)
|
|
223
|
+
post_body = opts[:debug_body] || @api_client.object_to_http_body(decline_reservation_request_request)
|
|
224
|
+
|
|
225
|
+
# return_type
|
|
226
|
+
return_type = opts[:debug_return_type] || 'AcceptReservationRequest200Response'
|
|
227
|
+
|
|
228
|
+
# auth_names
|
|
229
|
+
auth_names = opts[:debug_auth_names] || ['bearerAuth']
|
|
230
|
+
|
|
231
|
+
new_options = opts.merge(
|
|
232
|
+
:operation => :"ReservationsApi.decline_reservation_request",
|
|
233
|
+
:header_params => header_params,
|
|
234
|
+
:query_params => query_params,
|
|
235
|
+
:form_params => form_params,
|
|
236
|
+
:body => post_body,
|
|
237
|
+
:auth_names => auth_names,
|
|
238
|
+
:return_type => return_type
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
data, status_code, headers = @api_client.call_api(:POST, local_var_path, new_options)
|
|
242
|
+
if @api_client.config.debugging
|
|
243
|
+
@api_client.config.logger.debug "API called: ReservationsApi#decline_reservation_request\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
|
|
244
|
+
end
|
|
245
|
+
return data, status_code, headers
|
|
246
|
+
end
|
|
247
|
+
|
|
97
248
|
# Get reservation details
|
|
98
249
|
# Returns the full record for a single reservation, scoped to the authenticated workspace. Response shape is identical to a single row in `GET /v1/reservations` so SDK consumers can use the same type for both. Returns **404** if the id does not exist OR belongs to a different workspace — the API never differentiates the two so caller can't enumerate other workspaces' ids. Returns `403 listing_inactive` when the listing this resolves to is inactive. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated.
|
|
99
250
|
# @param id [Integer] Internal Repull reservation ID.
|
|
@@ -168,7 +319,7 @@ module Repull
|
|
|
168
319
|
# @option opts [String] :cursor Opaque cursor returned in the previous response's `pagination.nextCursor`. Omit to fetch the first page.
|
|
169
320
|
# @option opts [Integer] :offset First-class alias for cursor-based pagination. Mutually exclusive with `cursor` — passing both returns 422. Accepts integers in `[0, 10000]`; deeper walks must use `cursor` (constant per-page cost). The response always includes `pagination.nextCursor` so consumers can switch from offset → cursor mid-walk for deep pagination without re-keying. (default to 0)
|
|
170
321
|
# @option opts [String] :platform Filter by booking platform
|
|
171
|
-
# @option opts [String] :status Filter by lifecycle status. **Case-insensitive** — `confirmed`, `Confirmed`, and `CONFIRMED` all match. Each public value expands to the full set of internal sub-states server-side: `confirmed` matches `accept`/`confirmed`/`modified`, `cancelled` matches every cancellation sub-state (`cancelled_by_host`, `declined`, `expired`, etc.), `pending` includes `inquiry`/`awaiting_payment`. `completed` is a derived state — combine `status=confirmed` with `check_out_before=<today>` to filter for past stays.
|
|
322
|
+
# @option opts [String] :status Filter by lifecycle status. **Case-insensitive** — `confirmed`, `Confirmed`, and `CONFIRMED` all match. Each public value expands to the full set of internal sub-states server-side: `confirmed` matches `accept`/`confirmed`/`modified`, `cancelled` matches every cancellation sub-state (`cancelled_by_host`, `declined`, `expired`, etc.), `pending` includes `inquiry`/`awaiting_payment`. `completed` is a derived state — combine `status=confirmed` with `check_out_before=<today>` to filter for past stays. `pending` is how an Airbnb booking **request** awaiting the host appears — answer it with `POST /v1/reservations/{id}/accept` or `/decline` before its `respondBy`. `pending` lists only requests that can still be answered: one the channel already let lapse (Airbnb expires a request 24 hours after the guest asks; no request survives its check-in date) is left out and appears under `cancelled` with `statusDetail: \"request_expired\"` instead. The stored record is not changed — this is derived when you read it. Airbnb **inquiries** (questions before booking) are not reservations: list them with `GET /v1/inquiries`.
|
|
172
323
|
# @option opts [Integer] :listing_id Filter to a single listing
|
|
173
324
|
# @option opts [Date] :check_in_after Check-in date >= this value
|
|
174
325
|
# @option opts [Date] :check_in_before Check-in date <= this value
|
|
@@ -196,7 +347,7 @@ module Repull
|
|
|
196
347
|
# @option opts [String] :cursor Opaque cursor returned in the previous response's `pagination.nextCursor`. Omit to fetch the first page.
|
|
197
348
|
# @option opts [Integer] :offset First-class alias for cursor-based pagination. Mutually exclusive with `cursor` — passing both returns 422. Accepts integers in `[0, 10000]`; deeper walks must use `cursor` (constant per-page cost). The response always includes `pagination.nextCursor` so consumers can switch from offset → cursor mid-walk for deep pagination without re-keying. (default to 0)
|
|
198
349
|
# @option opts [String] :platform Filter by booking platform
|
|
199
|
-
# @option opts [String] :status Filter by lifecycle status. **Case-insensitive** — `confirmed`, `Confirmed`, and `CONFIRMED` all match. Each public value expands to the full set of internal sub-states server-side: `confirmed` matches `accept`/`confirmed`/`modified`, `cancelled` matches every cancellation sub-state (`cancelled_by_host`, `declined`, `expired`, etc.), `pending` includes `inquiry`/`awaiting_payment`. `completed` is a derived state — combine `status=confirmed` with `check_out_before=<today>` to filter for past stays.
|
|
350
|
+
# @option opts [String] :status Filter by lifecycle status. **Case-insensitive** — `confirmed`, `Confirmed`, and `CONFIRMED` all match. Each public value expands to the full set of internal sub-states server-side: `confirmed` matches `accept`/`confirmed`/`modified`, `cancelled` matches every cancellation sub-state (`cancelled_by_host`, `declined`, `expired`, etc.), `pending` includes `inquiry`/`awaiting_payment`. `completed` is a derived state — combine `status=confirmed` with `check_out_before=<today>` to filter for past stays. `pending` is how an Airbnb booking **request** awaiting the host appears — answer it with `POST /v1/reservations/{id}/accept` or `/decline` before its `respondBy`. `pending` lists only requests that can still be answered: one the channel already let lapse (Airbnb expires a request 24 hours after the guest asks; no request survives its check-in date) is left out and appears under `cancelled` with `statusDetail: \"request_expired\"` instead. The stored record is not changed — this is derived when you read it. Airbnb **inquiries** (questions before booking) are not reservations: list them with `GET /v1/inquiries`.
|
|
200
351
|
# @option opts [Integer] :listing_id Filter to a single listing
|
|
201
352
|
# @option opts [Date] :check_in_after Check-in date >= this value
|
|
202
353
|
# @option opts [Date] :check_in_before Check-in date <= this value
|
|
@@ -299,7 +450,7 @@ module Repull
|
|
|
299
450
|
# @param id [Integer] Internal Repull reservation ID.
|
|
300
451
|
# @param reservation_update_request [ReservationUpdateRequest]
|
|
301
452
|
# @param [Hash] opts the optional parameters
|
|
302
|
-
# @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged `Idempotency-Status: cached` — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → `409 idempotency_key_in_use`. - Same key with a DIFFERENT payload → `422 idempotency_key_reused`. Generate a new key per distinct request; reuse one only when retrying that exact request. -
|
|
453
|
+
# @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged `Idempotency-Status: cached` — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → `409 idempotency_key_in_use`. - Same key with a DIFFERENT payload → `422 idempotency_key_reused`. Generate a new key per distinct request; reuse one only when retrying that exact request. - Retryable outcomes are deliberately not stored, so a retry with the same key runs for real: any status >= 500, `408`, `425` and `429`, and the refusals that happen before anything is done and tell you to fix something outside the request first — `connection_reauth_required`, `listing_inactive`, and the rate/daily limits. Every other answer, including a final refusal such as `422 airbnb_rejected`, is stored and replayed.
|
|
303
454
|
# @return [ReservationUpdateResponse]
|
|
304
455
|
def update_reservation(id, reservation_update_request, opts = {})
|
|
305
456
|
data, _status_code, _headers = update_reservation_with_http_info(id, reservation_update_request, opts)
|
|
@@ -311,7 +462,7 @@ module Repull
|
|
|
311
462
|
# @param id [Integer] Internal Repull reservation ID.
|
|
312
463
|
# @param reservation_update_request [ReservationUpdateRequest]
|
|
313
464
|
# @param [Hash] opts the optional parameters
|
|
314
|
-
# @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged `Idempotency-Status: cached` — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → `409 idempotency_key_in_use`. - Same key with a DIFFERENT payload → `422 idempotency_key_reused`. Generate a new key per distinct request; reuse one only when retrying that exact request. -
|
|
465
|
+
# @option opts [String] :idempotency_key Makes a retry of this request safe. Send a unique string (a UUID generated at the point you build the request) and the response is stored for 24 hours: a repeat with the SAME key replays that stored response — tagged `Idempotency-Status: cached` — without running the operation again, so no duplicate reservation, guest or guest message is created. - Same key while the first request is still in flight → `409 idempotency_key_in_use`. - Same key with a DIFFERENT payload → `422 idempotency_key_reused`. Generate a new key per distinct request; reuse one only when retrying that exact request. - Retryable outcomes are deliberately not stored, so a retry with the same key runs for real: any status >= 500, `408`, `425` and `429`, and the refusals that happen before anything is done and tell you to fix something outside the request first — `connection_reauth_required`, `listing_inactive`, and the rate/daily limits. Every other answer, including a final refusal such as `422 airbnb_rejected`, is stored and replayed.
|
|
315
466
|
# @return [Array<(ReservationUpdateResponse, Integer, Hash)>] ReservationUpdateResponse data, response status code and response headers
|
|
316
467
|
def update_reservation_with_http_info(id, reservation_update_request, opts = {})
|
|
317
468
|
if @api_client.config.debugging
|
|
@@ -547,10 +547,11 @@ module Repull
|
|
|
547
547
|
end
|
|
548
548
|
|
|
549
549
|
# Replay webhook delivery
|
|
550
|
-
# Re-sends the original payload (same eventId, fresh deliveryId, attempt + 1). A delivery about a listing that is inactive now is not re-sent and answers `403 listing_inactive`; activate the listing first.
|
|
550
|
+
# Re-sends the original payload (same eventId, fresh deliveryId, attempt + 1). A delivery may be replayed at most **3 times per rolling 60 minutes**; the 4th inside that window answers `409 replay_limit_reached` and names the time the next one is allowed. The limit is charged to the original delivery, so replaying the delivery a replay produced draws on the same budget. It is not a lifetime cap — a delivery that has not been replayed for an hour starts fresh. A delivery your endpoint already accepted is not re-sent (it would be a duplicate) and answers `409 delivery_already_succeeded`; send `{\"force\": true}` to replay it anyway, which still counts against the limit. A delivery about a listing that is inactive now is not re-sent and answers `403 listing_inactive`; activate the listing first.
|
|
551
551
|
# @param id [String]
|
|
552
552
|
# @param delivery_id [String]
|
|
553
553
|
# @param [Hash] opts the optional parameters
|
|
554
|
+
# @option opts [ReplayWebhookDeliveryRequest] :replay_webhook_delivery_request
|
|
554
555
|
# @return [nil]
|
|
555
556
|
def replay_webhook_delivery(id, delivery_id, opts = {})
|
|
556
557
|
replay_webhook_delivery_with_http_info(id, delivery_id, opts)
|
|
@@ -558,10 +559,11 @@ module Repull
|
|
|
558
559
|
end
|
|
559
560
|
|
|
560
561
|
# Replay webhook delivery
|
|
561
|
-
# Re-sends the original payload (same eventId, fresh deliveryId, attempt + 1). A delivery about a listing that is inactive now is not re-sent and answers `403 listing_inactive`; activate the listing first.
|
|
562
|
+
# Re-sends the original payload (same eventId, fresh deliveryId, attempt + 1). A delivery may be replayed at most **3 times per rolling 60 minutes**; the 4th inside that window answers `409 replay_limit_reached` and names the time the next one is allowed. The limit is charged to the original delivery, so replaying the delivery a replay produced draws on the same budget. It is not a lifetime cap — a delivery that has not been replayed for an hour starts fresh. A delivery your endpoint already accepted is not re-sent (it would be a duplicate) and answers `409 delivery_already_succeeded`; send `{\"force\": true}` to replay it anyway, which still counts against the limit. A delivery about a listing that is inactive now is not re-sent and answers `403 listing_inactive`; activate the listing first.
|
|
562
563
|
# @param id [String]
|
|
563
564
|
# @param delivery_id [String]
|
|
564
565
|
# @param [Hash] opts the optional parameters
|
|
566
|
+
# @option opts [ReplayWebhookDeliveryRequest] :replay_webhook_delivery_request
|
|
565
567
|
# @return [Array<(nil, Integer, Hash)>] nil, response status code and response headers
|
|
566
568
|
def replay_webhook_delivery_with_http_info(id, delivery_id, opts = {})
|
|
567
569
|
if @api_client.config.debugging
|
|
@@ -585,12 +587,17 @@ module Repull
|
|
|
585
587
|
header_params = opts[:header_params] || {}
|
|
586
588
|
# HTTP header 'Accept' (if needed)
|
|
587
589
|
header_params['Accept'] = @api_client.select_header_accept(['application/json']) unless header_params['Accept']
|
|
590
|
+
# HTTP header 'Content-Type'
|
|
591
|
+
content_type = @api_client.select_header_content_type(['application/json'])
|
|
592
|
+
if !content_type.nil?
|
|
593
|
+
header_params['Content-Type'] = content_type
|
|
594
|
+
end
|
|
588
595
|
|
|
589
596
|
# form parameters
|
|
590
597
|
form_params = opts[:form_params] || {}
|
|
591
598
|
|
|
592
599
|
# http body (model)
|
|
593
|
-
post_body = opts[:debug_body]
|
|
600
|
+
post_body = opts[:debug_body] || @api_client.object_to_http_body(opts[:'replay_webhook_delivery_request'])
|
|
594
601
|
|
|
595
602
|
# return_type
|
|
596
603
|
return_type = opts[:debug_return_type]
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
#Repull API
|
|
3
|
+
|
|
4
|
+
#The unified API for vacation rental tech. Connect to 50+ PMS platforms and 4 OTA channels through one REST API. Built-in AI operations for guest communication, pricing, and listing optimization. ## Designed for AI agents Every error response on this API includes machine-parseable fields so an LLM (Claude in MCP, Cursor, Cline, GPT, etc.) can self-recover without escalating to a human: - `error.code` — stable string identifier (e.g. `invalid_params`, `rate_limit_exceeded`) - `error.message` — human-readable cause - `error.fix` — exact recovery steps (e.g. \"Pass `check_in_after` as ISO 8601: `?check_in_after=2026-01-15`\") - `error.docs_url` — link to the canonical write-up at `https://repull.dev/docs/errors/{code}` - `error.request_id` — id to correlate with server-side logs - `error.field` / `error.value_received` / `error.valid_values` / `error.did_you_mean` — when the error is parameter-specific - `error.retry_after` — seconds to wait before retrying (rate-limit + transient upstream) `Access-Control-Expose-Headers` lists `x-request-id` and the `X-RateLimit-*` family so browsers can read them on cross-origin responses. ## Quick Start 1. Get an API key at https://repull.dev/dashboard 2. Connect a PMS: `POST /v1/connect/{provider}` 3. List properties: `GET /v1/properties` 4. Get reservations: `GET /v1/reservations` ## Authentication All requests require a Bearer token: ``` Authorization: Bearer sk_live_YOUR_API_KEY ``` ## Request Correlation (X-Request-ID) Every response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports — we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id. You may set the header on the inbound request to forward your own trace id; we will echo it back instead of generating a new one. Accepted format: `^[\\\\w.-]{1,128}$`. The id is also embedded in error envelopes as `request_id` so server-side log diffs work even when the response headers are stripped by an intermediate proxy. ## Rate Limits The public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas. **Default policy:** 600 requests per 60 seconds, per API key. Sliding window — there is no fixed-minute boundary you can burst across. Every response includes: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests permitted in the current window. | | `X-RateLimit-Remaining` | Requests left in the current window after this call. | | `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. | | `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. | | `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** | **On 429 (rate_limit_exceeded):** the response body matches the standard error envelope with `code: \"rate_limit_exceeded\"`, plus `limit`, `window_seconds`, `retry_after`, and `request_id` fields. SDKs MUST honor `Retry-After` and use exponential backoff with jitter on subsequent retries — never a tight loop. Recommended backoff: ``` sleep_ms = (Retry-After * 1000) + random(0..250) ``` Monthly + daily-AI tier quotas (`free`, `starter`, `custom`) are enforced separately and also surface as 429s; they include `tier`, `scope`, and `resetsAt` fields. ## Plan Limits (402 — `listings_limit_exceeded`) The Repull API also enforces a per-tier cap on **active listings**: | Tier | Active listings cap | |---|---| | `free` | 3 | | `starter` | 50 | | `custom` | unlimited | When a customer's active-listing count is above their tier cap, the API returns **`402 Payment Required`** with `error.code = \"listings_limit_exceeded\"` on every route EXCEPT: - `/v1/health` — uptime probes are never gated. - `/v1/usage/*` — so dashboards can render the over-cap state. - Any `DELETE` — so the customer can trim listings to get back under the cap without paying. Unlike 429, 402 is NOT a \"wait and retry\" condition — `Retry-After` is not set. The only paths back to 200 are: 1. `DELETE` enough listings to come back under the cap, or 2. Upgrade at `https://repull.dev/dashboard/billing`. The server-side usage cache is 60s, so the first 200 after an upgrade may take up to a minute. The envelope mirrors `rate_limit_exceeded` for SDK ergonomics: `tier`, `limit`, `active_listings`, `upgrade_url`, plus the standard `code` / `message` / `fix` / `docs_url` / `request_id`.
|
|
5
|
+
|
|
6
|
+
The version of the OpenAPI document: 1.0.0
|
|
7
|
+
Contact: ivan@vanio.ai
|
|
8
|
+
Generated by: https://openapi-generator.tech
|
|
9
|
+
Generator version: 7.22.0
|
|
10
|
+
|
|
11
|
+
=end
|
|
12
|
+
|
|
13
|
+
require 'date'
|
|
14
|
+
require 'time'
|
|
15
|
+
|
|
16
|
+
module Repull
|
|
17
|
+
class AcceptReservationRequest200Response < ApiModelBase
|
|
18
|
+
attr_accessor :reservation_id
|
|
19
|
+
|
|
20
|
+
attr_accessor :confirmation_code
|
|
21
|
+
|
|
22
|
+
attr_accessor :channel
|
|
23
|
+
|
|
24
|
+
attr_accessor :action
|
|
25
|
+
|
|
26
|
+
# What Airbnb was asked to do and did not refuse. The reservation itself moves when Airbnb’s own notification lands, usually within seconds — that is when `reservation.request.updated` fires (`requestStatus` `accepted` or `declined`), plus `reservation.created` for an accepted request.
|
|
27
|
+
attr_accessor :status
|
|
28
|
+
|
|
29
|
+
attr_accessor :decline_reason
|
|
30
|
+
|
|
31
|
+
class EnumAttributeValidator
|
|
32
|
+
attr_reader :datatype
|
|
33
|
+
attr_reader :allowable_values
|
|
34
|
+
|
|
35
|
+
def initialize(datatype, allowable_values)
|
|
36
|
+
@allowable_values = allowable_values.map do |value|
|
|
37
|
+
case datatype.to_s
|
|
38
|
+
when /Integer/i
|
|
39
|
+
value.to_i
|
|
40
|
+
when /Float/i
|
|
41
|
+
value.to_f
|
|
42
|
+
else
|
|
43
|
+
value
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def valid?(value)
|
|
49
|
+
!value || allowable_values.include?(value)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Attribute mapping from ruby-style variable name to JSON key.
|
|
54
|
+
def self.attribute_map
|
|
55
|
+
{
|
|
56
|
+
:'reservation_id' => :'reservationId',
|
|
57
|
+
:'confirmation_code' => :'confirmationCode',
|
|
58
|
+
:'channel' => :'channel',
|
|
59
|
+
:'action' => :'action',
|
|
60
|
+
:'status' => :'status',
|
|
61
|
+
:'decline_reason' => :'declineReason'
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Returns attribute mapping this model knows about
|
|
66
|
+
def self.acceptable_attribute_map
|
|
67
|
+
attribute_map
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Returns all the JSON keys this model knows about
|
|
71
|
+
def self.acceptable_attributes
|
|
72
|
+
acceptable_attribute_map.values
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Attribute type mapping.
|
|
76
|
+
def self.openapi_types
|
|
77
|
+
{
|
|
78
|
+
:'reservation_id' => :'String',
|
|
79
|
+
:'confirmation_code' => :'String',
|
|
80
|
+
:'channel' => :'String',
|
|
81
|
+
:'action' => :'String',
|
|
82
|
+
:'status' => :'String',
|
|
83
|
+
:'decline_reason' => :'String'
|
|
84
|
+
}
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# List of attributes with nullable: true
|
|
88
|
+
def self.openapi_nullable
|
|
89
|
+
Set.new([
|
|
90
|
+
:'decline_reason'
|
|
91
|
+
])
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Initializes the object
|
|
95
|
+
# @param [Hash] attributes Model attributes in the form of hash
|
|
96
|
+
def initialize(attributes = {})
|
|
97
|
+
if (!attributes.is_a?(Hash))
|
|
98
|
+
fail ArgumentError, "The input argument (attributes) must be a hash in `Repull::AcceptReservationRequest200Response` initialize method"
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# check to see if the attribute exists and convert string to symbol for hash key
|
|
102
|
+
acceptable_attribute_map = self.class.acceptable_attribute_map
|
|
103
|
+
attributes = attributes.each_with_object({}) { |(k, v), h|
|
|
104
|
+
if (!acceptable_attribute_map.key?(k.to_sym))
|
|
105
|
+
fail ArgumentError, "`#{k}` is not a valid attribute in `Repull::AcceptReservationRequest200Response`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
|
|
106
|
+
end
|
|
107
|
+
h[k.to_sym] = v
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if attributes.key?(:'reservation_id')
|
|
111
|
+
self.reservation_id = attributes[:'reservation_id']
|
|
112
|
+
else
|
|
113
|
+
self.reservation_id = nil
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
if attributes.key?(:'confirmation_code')
|
|
117
|
+
self.confirmation_code = attributes[:'confirmation_code']
|
|
118
|
+
else
|
|
119
|
+
self.confirmation_code = nil
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
if attributes.key?(:'channel')
|
|
123
|
+
self.channel = attributes[:'channel']
|
|
124
|
+
else
|
|
125
|
+
self.channel = nil
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
if attributes.key?(:'action')
|
|
129
|
+
self.action = attributes[:'action']
|
|
130
|
+
else
|
|
131
|
+
self.action = nil
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
if attributes.key?(:'status')
|
|
135
|
+
self.status = attributes[:'status']
|
|
136
|
+
else
|
|
137
|
+
self.status = nil
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
if attributes.key?(:'decline_reason')
|
|
141
|
+
self.decline_reason = attributes[:'decline_reason']
|
|
142
|
+
else
|
|
143
|
+
self.decline_reason = nil
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Show invalid properties with the reasons. Usually used together with valid?
|
|
148
|
+
# @return Array for valid properties with the reasons
|
|
149
|
+
def list_invalid_properties
|
|
150
|
+
warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
|
|
151
|
+
invalid_properties = Array.new
|
|
152
|
+
if @reservation_id.nil?
|
|
153
|
+
invalid_properties.push('invalid value for "reservation_id", reservation_id cannot be nil.')
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
if @confirmation_code.nil?
|
|
157
|
+
invalid_properties.push('invalid value for "confirmation_code", confirmation_code cannot be nil.')
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
if @channel.nil?
|
|
161
|
+
invalid_properties.push('invalid value for "channel", channel cannot be nil.')
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
if @action.nil?
|
|
165
|
+
invalid_properties.push('invalid value for "action", action cannot be nil.')
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
if @status.nil?
|
|
169
|
+
invalid_properties.push('invalid value for "status", status cannot be nil.')
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
invalid_properties
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Check to see if the all the properties in the model are valid
|
|
176
|
+
# @return true if the model is valid
|
|
177
|
+
def valid?
|
|
178
|
+
warn '[DEPRECATED] the `valid?` method is obsolete'
|
|
179
|
+
return false if @reservation_id.nil?
|
|
180
|
+
return false if @confirmation_code.nil?
|
|
181
|
+
return false if @channel.nil?
|
|
182
|
+
channel_validator = EnumAttributeValidator.new('String', ["airbnb"])
|
|
183
|
+
return false unless channel_validator.valid?(@channel)
|
|
184
|
+
return false if @action.nil?
|
|
185
|
+
action_validator = EnumAttributeValidator.new('String', ["accept", "decline"])
|
|
186
|
+
return false unless action_validator.valid?(@action)
|
|
187
|
+
return false if @status.nil?
|
|
188
|
+
status_validator = EnumAttributeValidator.new('String', ["accepted", "declined"])
|
|
189
|
+
return false unless status_validator.valid?(@status)
|
|
190
|
+
decline_reason_validator = EnumAttributeValidator.new('String', ["dates_not_available", "not_comfortable", "listing_not_ready", "different_dates_needed", "spam", "other"])
|
|
191
|
+
return false unless decline_reason_validator.valid?(@decline_reason)
|
|
192
|
+
true
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# Custom attribute writer method with validation
|
|
196
|
+
# @param [Object] reservation_id Value to be assigned
|
|
197
|
+
def reservation_id=(reservation_id)
|
|
198
|
+
if reservation_id.nil?
|
|
199
|
+
fail ArgumentError, 'reservation_id cannot be nil'
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
@reservation_id = reservation_id
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Custom attribute writer method with validation
|
|
206
|
+
# @param [Object] confirmation_code Value to be assigned
|
|
207
|
+
def confirmation_code=(confirmation_code)
|
|
208
|
+
if confirmation_code.nil?
|
|
209
|
+
fail ArgumentError, 'confirmation_code cannot be nil'
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
@confirmation_code = confirmation_code
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# Custom attribute writer method checking allowed values (enum).
|
|
216
|
+
# @param [Object] channel Object to be assigned
|
|
217
|
+
def channel=(channel)
|
|
218
|
+
validator = EnumAttributeValidator.new('String', ["airbnb"])
|
|
219
|
+
unless validator.valid?(channel)
|
|
220
|
+
fail ArgumentError, "invalid value for \"channel\", must be one of #{validator.allowable_values}."
|
|
221
|
+
end
|
|
222
|
+
@channel = channel
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Custom attribute writer method checking allowed values (enum).
|
|
226
|
+
# @param [Object] action Object to be assigned
|
|
227
|
+
def action=(action)
|
|
228
|
+
validator = EnumAttributeValidator.new('String', ["accept", "decline"])
|
|
229
|
+
unless validator.valid?(action)
|
|
230
|
+
fail ArgumentError, "invalid value for \"action\", must be one of #{validator.allowable_values}."
|
|
231
|
+
end
|
|
232
|
+
@action = action
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Custom attribute writer method checking allowed values (enum).
|
|
236
|
+
# @param [Object] status Object to be assigned
|
|
237
|
+
def status=(status)
|
|
238
|
+
validator = EnumAttributeValidator.new('String', ["accepted", "declined"])
|
|
239
|
+
unless validator.valid?(status)
|
|
240
|
+
fail ArgumentError, "invalid value for \"status\", must be one of #{validator.allowable_values}."
|
|
241
|
+
end
|
|
242
|
+
@status = status
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# Custom attribute writer method checking allowed values (enum).
|
|
246
|
+
# @param [Object] decline_reason Object to be assigned
|
|
247
|
+
def decline_reason=(decline_reason)
|
|
248
|
+
validator = EnumAttributeValidator.new('String', ["dates_not_available", "not_comfortable", "listing_not_ready", "different_dates_needed", "spam", "other"])
|
|
249
|
+
unless validator.valid?(decline_reason)
|
|
250
|
+
fail ArgumentError, "invalid value for \"decline_reason\", must be one of #{validator.allowable_values}."
|
|
251
|
+
end
|
|
252
|
+
@decline_reason = decline_reason
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# Checks equality by comparing each attribute.
|
|
256
|
+
# @param [Object] Object to be compared
|
|
257
|
+
def ==(o)
|
|
258
|
+
return true if self.equal?(o)
|
|
259
|
+
self.class == o.class &&
|
|
260
|
+
reservation_id == o.reservation_id &&
|
|
261
|
+
confirmation_code == o.confirmation_code &&
|
|
262
|
+
channel == o.channel &&
|
|
263
|
+
action == o.action &&
|
|
264
|
+
status == o.status &&
|
|
265
|
+
decline_reason == o.decline_reason
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# @see the `==` method
|
|
269
|
+
# @param [Object] Object to be compared
|
|
270
|
+
def eql?(o)
|
|
271
|
+
self == o
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# Calculates hash code according to all attributes.
|
|
275
|
+
# @return [Integer] Hash code
|
|
276
|
+
def hash
|
|
277
|
+
[reservation_id, confirmation_code, channel, action, status, decline_reason].hash
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
# Builds the object from hash
|
|
281
|
+
# @param [Hash] attributes Model attributes in the form of hash
|
|
282
|
+
# @return [Object] Returns the model itself
|
|
283
|
+
def self.build_from_hash(attributes)
|
|
284
|
+
return nil unless attributes.is_a?(Hash)
|
|
285
|
+
attributes = attributes.transform_keys(&:to_sym)
|
|
286
|
+
transformed_hash = {}
|
|
287
|
+
openapi_types.each_pair do |key, type|
|
|
288
|
+
if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
|
|
289
|
+
transformed_hash["#{key}"] = nil
|
|
290
|
+
elsif type =~ /\AArray<(.*)>/i
|
|
291
|
+
# check to ensure the input is an array given that the attribute
|
|
292
|
+
# is documented as an array but the input is not
|
|
293
|
+
if attributes[attribute_map[key]].is_a?(Array)
|
|
294
|
+
transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
|
|
295
|
+
end
|
|
296
|
+
elsif !attributes[attribute_map[key]].nil?
|
|
297
|
+
transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
new(transformed_hash)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# Returns the object in the form of hash
|
|
304
|
+
# @return [Hash] Returns the object in the form of hash
|
|
305
|
+
def to_hash
|
|
306
|
+
hash = {}
|
|
307
|
+
self.class.attribute_map.each_pair do |attr, param|
|
|
308
|
+
value = self.send(attr)
|
|
309
|
+
if value.nil?
|
|
310
|
+
is_nullable = self.class.openapi_nullable.include?(attr)
|
|
311
|
+
next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
hash[param] = _to_hash(value)
|
|
315
|
+
end
|
|
316
|
+
hash
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
end
|