repull 0.2.20 → 0.2.21
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/listings_api.rb +137 -0
- data/lib/repull/api/properties_api.rb +8 -8
- data/lib/repull/models/airbnb_connection.rb +1 -1
- data/lib/repull/models/booking_property.rb +1 -0
- data/lib/repull/models/get_listing_markups200_response.rb +170 -0
- data/lib/repull/models/get_listing_markups200_response_airbnb_inner.rb +159 -0
- data/lib/repull/models/get_listing_markups200_response_booking_inner.rb +171 -0
- data/lib/repull/models/set_listing_markup_request.rb +235 -0
- data/lib/repull/version.rb +1 -1
- data/lib/repull.rb +4 -0
- data/openapi/v1.json +316 -16
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9ae04570f4fcd2cdf1feb8fc95a1ff6700b136cd1732aab138f5997e9b2b5585
|
|
4
|
+
data.tar.gz: 80968fad4134b4b87d6b18b965dae6a29eff61e2f96e77f0d48c137c836d9f20
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 624fc79360d49dc82445c9d29e8db4297e9225f22a3de83e3c5ed7be6a120efa4538a2249a407b1f5e74c704d3de67668579dba605c8259401bd924afe53d63c
|
|
7
|
+
data.tar.gz: ff2676bc32a7982783d8b32eef11b92a120095f9dee811f86fe5106a15fd2a67a4e89efc808185d3a7e672eef98ffc43cbbee0c30c3192fd9c36ecf5e3a5babf
|
|
@@ -437,6 +437,69 @@ module Repull
|
|
|
437
437
|
return data, status_code, headers
|
|
438
438
|
end
|
|
439
439
|
|
|
440
|
+
# Get a listing's channel markups
|
|
441
|
+
# The markup each channel adds to this listing's price. A listing's price on a channel is its own nightly price plus the channel's markup: a $200 night with a 35% Airbnb markup is sent to Airbnb as $270. The calendar keeps the listing's own price (`GET /v1/availability/{propertyId}` returns it); the markup is added only when a price is sent to the channel. - **Airbnb** — one markup per listing. - **Booking.com** — one markup per **property**, shared by every listing priced through it (`listingIds` names them). Returns `404 not_found` for a listing that does not exist or is not in this workspace, and `403 listing_inactive` for an inactive one.
|
|
442
|
+
# @param id [String] Repull listing id.
|
|
443
|
+
# @param [Hash] opts the optional parameters
|
|
444
|
+
# @return [GetListingMarkups200Response]
|
|
445
|
+
def get_listing_markups(id, opts = {})
|
|
446
|
+
data, _status_code, _headers = get_listing_markups_with_http_info(id, opts)
|
|
447
|
+
data
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
# Get a listing's channel markups
|
|
451
|
+
# The markup each channel adds to this listing's price. A listing's price on a channel is its own nightly price plus the channel's markup: a $200 night with a 35% Airbnb markup is sent to Airbnb as $270. The calendar keeps the listing's own price (`GET /v1/availability/{propertyId}` returns it); the markup is added only when a price is sent to the channel. - **Airbnb** — one markup per listing. - **Booking.com** — one markup per **property**, shared by every listing priced through it (`listingIds` names them). Returns `404 not_found` for a listing that does not exist or is not in this workspace, and `403 listing_inactive` for an inactive one.
|
|
452
|
+
# @param id [String] Repull listing id.
|
|
453
|
+
# @param [Hash] opts the optional parameters
|
|
454
|
+
# @return [Array<(GetListingMarkups200Response, Integer, Hash)>] GetListingMarkups200Response data, response status code and response headers
|
|
455
|
+
def get_listing_markups_with_http_info(id, opts = {})
|
|
456
|
+
if @api_client.config.debugging
|
|
457
|
+
@api_client.config.logger.debug 'Calling API: ListingsApi.get_listing_markups ...'
|
|
458
|
+
end
|
|
459
|
+
# verify the required parameter 'id' is set
|
|
460
|
+
if @api_client.config.client_side_validation && id.nil?
|
|
461
|
+
fail ArgumentError, "Missing the required parameter 'id' when calling ListingsApi.get_listing_markups"
|
|
462
|
+
end
|
|
463
|
+
# resource path
|
|
464
|
+
local_var_path = '/v1/listings/{id}/markups'.sub('{id}', CGI.escape(id.to_s))
|
|
465
|
+
|
|
466
|
+
# query parameters
|
|
467
|
+
query_params = opts[:query_params] || {}
|
|
468
|
+
|
|
469
|
+
# header parameters
|
|
470
|
+
header_params = opts[:header_params] || {}
|
|
471
|
+
# HTTP header 'Accept' (if needed)
|
|
472
|
+
header_params['Accept'] = @api_client.select_header_accept(['application/json']) unless header_params['Accept']
|
|
473
|
+
|
|
474
|
+
# form parameters
|
|
475
|
+
form_params = opts[:form_params] || {}
|
|
476
|
+
|
|
477
|
+
# http body (model)
|
|
478
|
+
post_body = opts[:debug_body]
|
|
479
|
+
|
|
480
|
+
# return_type
|
|
481
|
+
return_type = opts[:debug_return_type] || 'GetListingMarkups200Response'
|
|
482
|
+
|
|
483
|
+
# auth_names
|
|
484
|
+
auth_names = opts[:debug_auth_names] || ['bearerAuth']
|
|
485
|
+
|
|
486
|
+
new_options = opts.merge(
|
|
487
|
+
:operation => :"ListingsApi.get_listing_markups",
|
|
488
|
+
:header_params => header_params,
|
|
489
|
+
:query_params => query_params,
|
|
490
|
+
:form_params => form_params,
|
|
491
|
+
:body => post_body,
|
|
492
|
+
:auth_names => auth_names,
|
|
493
|
+
:return_type => return_type
|
|
494
|
+
)
|
|
495
|
+
|
|
496
|
+
data, status_code, headers = @api_client.call_api(:GET, local_var_path, new_options)
|
|
497
|
+
if @api_client.config.debugging
|
|
498
|
+
@api_client.config.logger.debug "API called: ListingsApi#get_listing_markups\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
|
|
499
|
+
end
|
|
500
|
+
return data, status_code, headers
|
|
501
|
+
end
|
|
502
|
+
|
|
440
503
|
# Per-channel publish status
|
|
441
504
|
# Returns connection state and sync activity per channel. `channels` is sync activity (empty until first push). `connections` is connection state (populated as soon as a channel is linked). Recommended polling cadence: at most once per 30s per listing — for bulk views, prefer `GET /v1/listings` and filter client-side. **When a push fails, this endpoint says why.** `channels[].pushError` carries the channel's own reason for the last failed push, verbatim — `\"Links and contact info can't be shared\"`, `\"Check-in start time must be before end time\"`, `\"property_type_group must be one of […]\"`. It is free text written by the channel, so render it next to the retry button rather than parsing it. `null` when the last push succeeded or none has run; pair it with `pushStatus` to tell those two apart. **It also says what you will not be allowed to change.** The `airbnb` entry in `connections` carries `lockedFields` — attributes Airbnb has locked on this listing. Airbnb does not refuse a write to one: it answers 200, reports the field as locked, and applies nothing, so a locked write is indistinguishable from a successful one unless you looked first. Read it before you let someone edit. Airbnb-only; no other channel has the concept, and no other entry carries the field. 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.
|
|
442
505
|
# @param id [Integer]
|
|
@@ -884,6 +947,80 @@ module Repull
|
|
|
884
947
|
return data, status_code, headers
|
|
885
948
|
end
|
|
886
949
|
|
|
950
|
+
# Set a listing's markup on a channel
|
|
951
|
+
# Set the markup one channel adds to this listing's price. When the value changes, the affected listings' prices are re-sent to that channel straight away (`pricesResent`); nothing else is sent. A listing's price on a channel is its own nightly price plus the channel's markup: a $200 night with a 35% Airbnb markup is sent to Airbnb as $270. The calendar keeps the listing's own price (`GET /v1/availability/{propertyId}` returns it); the markup is added only when a price is sent to the channel. - **Airbnb** — one markup per listing. - **Booking.com** — one markup per **property**, shared by every listing priced through it (`listingIds` names them). Returns `404 not_found` for a listing that does not exist or is not in this workspace, and `403 listing_inactive` for an inactive one. On Booking.com the markup belongs to the property, so setting it reprices every listing on that property (`affectedListingIds`). A listing on more than one property must name one with `hotelId`; without it the request is refused with `409 ambiguous_booking_mapping` listing the candidates, rather than repricing a property it guessed. `markupPercent` is a percentage — `15` for 15%. A value between 0 and 1 is refused as a probable fraction, with the number to send instead.
|
|
952
|
+
# @param id [String] Repull listing id.
|
|
953
|
+
# @param set_listing_markup_request [SetListingMarkupRequest]
|
|
954
|
+
# @param [Hash] opts the optional parameters
|
|
955
|
+
# @return [nil]
|
|
956
|
+
def set_listing_markup(id, set_listing_markup_request, opts = {})
|
|
957
|
+
set_listing_markup_with_http_info(id, set_listing_markup_request, opts)
|
|
958
|
+
nil
|
|
959
|
+
end
|
|
960
|
+
|
|
961
|
+
# Set a listing's markup on a channel
|
|
962
|
+
# Set the markup one channel adds to this listing's price. When the value changes, the affected listings' prices are re-sent to that channel straight away (`pricesResent`); nothing else is sent. A listing's price on a channel is its own nightly price plus the channel's markup: a $200 night with a 35% Airbnb markup is sent to Airbnb as $270. The calendar keeps the listing's own price (`GET /v1/availability/{propertyId}` returns it); the markup is added only when a price is sent to the channel. - **Airbnb** — one markup per listing. - **Booking.com** — one markup per **property**, shared by every listing priced through it (`listingIds` names them). Returns `404 not_found` for a listing that does not exist or is not in this workspace, and `403 listing_inactive` for an inactive one. On Booking.com the markup belongs to the property, so setting it reprices every listing on that property (`affectedListingIds`). A listing on more than one property must name one with `hotelId`; without it the request is refused with `409 ambiguous_booking_mapping` listing the candidates, rather than repricing a property it guessed. `markupPercent` is a percentage — `15` for 15%. A value between 0 and 1 is refused as a probable fraction, with the number to send instead.
|
|
963
|
+
# @param id [String] Repull listing id.
|
|
964
|
+
# @param set_listing_markup_request [SetListingMarkupRequest]
|
|
965
|
+
# @param [Hash] opts the optional parameters
|
|
966
|
+
# @return [Array<(nil, Integer, Hash)>] nil, response status code and response headers
|
|
967
|
+
def set_listing_markup_with_http_info(id, set_listing_markup_request, opts = {})
|
|
968
|
+
if @api_client.config.debugging
|
|
969
|
+
@api_client.config.logger.debug 'Calling API: ListingsApi.set_listing_markup ...'
|
|
970
|
+
end
|
|
971
|
+
# verify the required parameter 'id' is set
|
|
972
|
+
if @api_client.config.client_side_validation && id.nil?
|
|
973
|
+
fail ArgumentError, "Missing the required parameter 'id' when calling ListingsApi.set_listing_markup"
|
|
974
|
+
end
|
|
975
|
+
# verify the required parameter 'set_listing_markup_request' is set
|
|
976
|
+
if @api_client.config.client_side_validation && set_listing_markup_request.nil?
|
|
977
|
+
fail ArgumentError, "Missing the required parameter 'set_listing_markup_request' when calling ListingsApi.set_listing_markup"
|
|
978
|
+
end
|
|
979
|
+
# resource path
|
|
980
|
+
local_var_path = '/v1/listings/{id}/markups'.sub('{id}', CGI.escape(id.to_s))
|
|
981
|
+
|
|
982
|
+
# query parameters
|
|
983
|
+
query_params = opts[:query_params] || {}
|
|
984
|
+
|
|
985
|
+
# header parameters
|
|
986
|
+
header_params = opts[:header_params] || {}
|
|
987
|
+
# HTTP header 'Accept' (if needed)
|
|
988
|
+
header_params['Accept'] = @api_client.select_header_accept(['application/json']) unless header_params['Accept']
|
|
989
|
+
# HTTP header 'Content-Type'
|
|
990
|
+
content_type = @api_client.select_header_content_type(['application/json'])
|
|
991
|
+
if !content_type.nil?
|
|
992
|
+
header_params['Content-Type'] = content_type
|
|
993
|
+
end
|
|
994
|
+
|
|
995
|
+
# form parameters
|
|
996
|
+
form_params = opts[:form_params] || {}
|
|
997
|
+
|
|
998
|
+
# http body (model)
|
|
999
|
+
post_body = opts[:debug_body] || @api_client.object_to_http_body(set_listing_markup_request)
|
|
1000
|
+
|
|
1001
|
+
# return_type
|
|
1002
|
+
return_type = opts[:debug_return_type]
|
|
1003
|
+
|
|
1004
|
+
# auth_names
|
|
1005
|
+
auth_names = opts[:debug_auth_names] || ['bearerAuth']
|
|
1006
|
+
|
|
1007
|
+
new_options = opts.merge(
|
|
1008
|
+
:operation => :"ListingsApi.set_listing_markup",
|
|
1009
|
+
:header_params => header_params,
|
|
1010
|
+
:query_params => query_params,
|
|
1011
|
+
:form_params => form_params,
|
|
1012
|
+
:body => post_body,
|
|
1013
|
+
:auth_names => auth_names,
|
|
1014
|
+
:return_type => return_type
|
|
1015
|
+
)
|
|
1016
|
+
|
|
1017
|
+
data, status_code, headers = @api_client.call_api(:PUT, local_var_path, new_options)
|
|
1018
|
+
if @api_client.config.debugging
|
|
1019
|
+
@api_client.config.logger.debug "API called: ListingsApi#set_listing_markup\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
|
|
1020
|
+
end
|
|
1021
|
+
return data, status_code, headers
|
|
1022
|
+
end
|
|
1023
|
+
|
|
887
1024
|
# Activate or deactivate listings in bulk
|
|
888
1025
|
# Sets up to 500 listings active or inactive in one call. Send `{ \"listingIds\": [\"4118\", \"4119\"], \"active\": false }` to deactivate them, or `\"active\": true` to activate them. An inactive listing is not counted toward your plan's listing limit or billed. It is NOT deleted and the upstream channel (Airbnb / Booking.com / your PMS) is never touched — its data keeps syncing, so it is complete the moment you activate it again. Until then it cannot be read, changed, or receive webhooks. **All or nothing.** Nothing changes unless the whole request can be applied: - If any id is not one of your listings, the call returns `404` naming those ids. - If activating would take you over your plan's listing limit, the call returns `402 listings_limit_exceeded`. Only listings that are currently inactive count toward the new total, so re-sending ids that are already active never trips the limit. Deactivating is always allowed, including when your account is already over its limit — it is how you get back under it. **Idempotent.** Ids already in the requested state are returned in `unchanged`; ids this call changed are returned in `updated`. For a single listing, `PATCH /v1/listings/{id}` does the same.
|
|
889
1026
|
# @param listing_status_batch_request [ListingStatusBatchRequest]
|
|
@@ -19,8 +19,8 @@ module Repull
|
|
|
19
19
|
def initialize(api_client = ApiClient.default)
|
|
20
20
|
@api_client = api_client
|
|
21
21
|
end
|
|
22
|
-
# Get property details
|
|
23
|
-
# Fetch a single property by Repull id. Property ids are workspace-scoped — an id from one workspace is not valid in another. 404 means the id does not exist OR belongs to a different workspace. **Optional expansions:** Pass `?include=amenities` to enrich the response with the property's amenities (sourced from the unified `listings_amenities` table). Returns `[]` when the property has no amenity rows. The default response stays lean; consumers must opt in. 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.
|
|
22
|
+
# Get property details (older name for /v1/listings/{id})
|
|
23
|
+
# **`/v1/properties` is the older name for `/v1/listings`** — the same listings, the same ids. It stays for existing integrations; new code should use `/v1/listings`, which is where create, content, publishing and markups live. Fetch a single property by Repull id. Property ids are workspace-scoped — an id from one workspace is not valid in another. 404 means the id does not exist OR belongs to a different workspace. **Optional expansions:** Pass `?include=amenities` to enrich the response with the property's amenities (sourced from the unified `listings_amenities` table). Returns `[]` when the property has no amenity rows. The default response stays lean; consumers must opt in. Returns `403 listing_inactive` when the listing is inactive. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated.
|
|
24
24
|
# @param id [Integer]
|
|
25
25
|
# @param [Hash] opts the optional parameters
|
|
26
26
|
# @option opts [String] :include Comma-separated optional expansions. Currently supported: `amenities`. Unknown values return 422.
|
|
@@ -30,8 +30,8 @@ module Repull
|
|
|
30
30
|
data
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
# Get property details
|
|
34
|
-
# Fetch a single property by Repull id. Property ids are workspace-scoped — an id from one workspace is not valid in another. 404 means the id does not exist OR belongs to a different workspace. **Optional expansions:** Pass `?include=amenities` to enrich the response with the property's amenities (sourced from the unified `listings_amenities` table). Returns `[]` when the property has no amenity rows. The default response stays lean; consumers must opt in. 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.
|
|
33
|
+
# Get property details (older name for /v1/listings/{id})
|
|
34
|
+
# **`/v1/properties` is the older name for `/v1/listings`** — the same listings, the same ids. It stays for existing integrations; new code should use `/v1/listings`, which is where create, content, publishing and markups live. Fetch a single property by Repull id. Property ids are workspace-scoped — an id from one workspace is not valid in another. 404 means the id does not exist OR belongs to a different workspace. **Optional expansions:** Pass `?include=amenities` to enrich the response with the property's amenities (sourced from the unified `listings_amenities` table). Returns `[]` when the property has no amenity rows. The default response stays lean; consumers must opt in. Returns `403 listing_inactive` when the listing is inactive. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated.
|
|
35
35
|
# @param id [Integer]
|
|
36
36
|
# @param [Hash] opts the optional parameters
|
|
37
37
|
# @option opts [String] :include Comma-separated optional expansions. Currently supported: `amenities`. Unknown values return 422.
|
|
@@ -89,8 +89,8 @@ module Repull
|
|
|
89
89
|
return data, status_code, headers
|
|
90
90
|
end
|
|
91
91
|
|
|
92
|
-
# List properties
|
|
93
|
-
# Cursor-paginated list of properties for the authenticated workspace. Walk pages with `?cursor=<pagination.nextCursor>`; stop when `pagination.hasMore` is `false`. Cursor is opaque base64 — do not parse it. `?offset=` is also accepted as a first-class alias for shallow paging (0..10000) — see the `offset` parameter below. Mutually exclusive with `cursor`. Filters: `q` (substring on name/street/city), `status` (active|inactive|all), `lifecycle_status` (exact match on the listing's lifecycle state). Other unknown params (e.g. `?search=` or `?propertyId=`) are rejected with 422 — no silent unfiltered results. **Incremental sync (only changes since last poll):** pass `?updated_since=<ISO8601>` to receive only properties changed at or after that instant. Each property carries `updatedAt` — the last row of the final page is your next watermark. `updated_since` changes the page ordering to `updatedAt ASC, id ASC` (and the cursor with it); see the parameter description. `GET /v1/listings` does NOT yet accept `updated_since` — use this endpoint for property-side incremental sync. **Inactive properties:** an inactive property keeps syncing, but cannot be read or changed through the API until it is activated. They are only listed when `status` asks for them, and then with `id`, `name`, `status`, `lifecycleStatus`, `channels` and `updatedAt` only — enough to choose what to activate with `PATCH /v1/listings/{id}`.
|
|
92
|
+
# List properties (older name for /v1/listings)
|
|
93
|
+
# **`/v1/properties` is the older name for `/v1/listings`** — the same listings, the same ids. It stays for existing integrations; new code should use `/v1/listings`, which is where create, content, publishing and markups live. Cursor-paginated list of properties for the authenticated workspace. Walk pages with `?cursor=<pagination.nextCursor>`; stop when `pagination.hasMore` is `false`. Cursor is opaque base64 — do not parse it. `?offset=` is also accepted as a first-class alias for shallow paging (0..10000) — see the `offset` parameter below. Mutually exclusive with `cursor`. Filters: `q` (substring on name/street/city), `status` (active|inactive|all), `lifecycle_status` (exact match on the listing's lifecycle state). Other unknown params (e.g. `?search=` or `?propertyId=`) are rejected with 422 — no silent unfiltered results. **Incremental sync (only changes since last poll):** pass `?updated_since=<ISO8601>` to receive only properties changed at or after that instant. Each property carries `updatedAt` — the last row of the final page is your next watermark. `updated_since` changes the page ordering to `updatedAt ASC, id ASC` (and the cursor with it); see the parameter description. `GET /v1/listings` does NOT yet accept `updated_since` — use this endpoint for property-side incremental sync. **Inactive properties:** an inactive property keeps syncing, but cannot be read or changed through the API until it is activated. They are only listed when `status` asks for them, and then with `id`, `name`, `status`, `lifecycleStatus`, `channels` and `updatedAt` only — enough to choose what to activate with `PATCH /v1/listings/{id}`.
|
|
94
94
|
# @param [Hash] opts the optional parameters
|
|
95
95
|
# @option opts [Integer] :limit Page size (max 100). Requests over the cap return 422. (default to 50)
|
|
96
96
|
# @option opts [String] :cursor Opaque cursor returned in the previous response's `pagination.nextCursor`. Omit to fetch the first page.
|
|
@@ -107,8 +107,8 @@ module Repull
|
|
|
107
107
|
data
|
|
108
108
|
end
|
|
109
109
|
|
|
110
|
-
# List properties
|
|
111
|
-
# Cursor-paginated list of properties for the authenticated workspace. Walk pages with `?cursor=<pagination.nextCursor>`; stop when `pagination.hasMore` is `false`. Cursor is opaque base64 — do not parse it. `?offset=` is also accepted as a first-class alias for shallow paging (0..10000) — see the `offset` parameter below. Mutually exclusive with `cursor`. Filters: `q` (substring on name/street/city), `status` (active|inactive|all), `lifecycle_status` (exact match on the listing's lifecycle state). Other unknown params (e.g. `?search=` or `?propertyId=`) are rejected with 422 — no silent unfiltered results. **Incremental sync (only changes since last poll):** pass `?updated_since=<ISO8601>` to receive only properties changed at or after that instant. Each property carries `updatedAt` — the last row of the final page is your next watermark. `updated_since` changes the page ordering to `updatedAt ASC, id ASC` (and the cursor with it); see the parameter description. `GET /v1/listings` does NOT yet accept `updated_since` — use this endpoint for property-side incremental sync. **Inactive properties:** an inactive property keeps syncing, but cannot be read or changed through the API until it is activated. They are only listed when `status` asks for them, and then with `id`, `name`, `status`, `lifecycleStatus`, `channels` and `updatedAt` only — enough to choose what to activate with `PATCH /v1/listings/{id}`.
|
|
110
|
+
# List properties (older name for /v1/listings)
|
|
111
|
+
# **`/v1/properties` is the older name for `/v1/listings`** — the same listings, the same ids. It stays for existing integrations; new code should use `/v1/listings`, which is where create, content, publishing and markups live. Cursor-paginated list of properties for the authenticated workspace. Walk pages with `?cursor=<pagination.nextCursor>`; stop when `pagination.hasMore` is `false`. Cursor is opaque base64 — do not parse it. `?offset=` is also accepted as a first-class alias for shallow paging (0..10000) — see the `offset` parameter below. Mutually exclusive with `cursor`. Filters: `q` (substring on name/street/city), `status` (active|inactive|all), `lifecycle_status` (exact match on the listing's lifecycle state). Other unknown params (e.g. `?search=` or `?propertyId=`) are rejected with 422 — no silent unfiltered results. **Incremental sync (only changes since last poll):** pass `?updated_since=<ISO8601>` to receive only properties changed at or after that instant. Each property carries `updatedAt` — the last row of the final page is your next watermark. `updated_since` changes the page ordering to `updatedAt ASC, id ASC` (and the cursor with it); see the parameter description. `GET /v1/listings` does NOT yet accept `updated_since` — use this endpoint for property-side incremental sync. **Inactive properties:** an inactive property keeps syncing, but cannot be read or changed through the API until it is activated. They are only listed when `status` asks for them, and then with `id`, `name`, `status`, `lifecycleStatus`, `channels` and `updatedAt` only — enough to choose what to activate with `PATCH /v1/listings/{id}`.
|
|
112
112
|
# @param [Hash] opts the optional parameters
|
|
113
113
|
# @option opts [Integer] :limit Page size (max 100). Requests over the cap return 422. (default to 50)
|
|
114
114
|
# @option opts [String] :cursor Opaque cursor returned in the previous response's `pagination.nextCursor`. Omit to fetch the first page.
|
|
@@ -40,7 +40,7 @@ module Repull
|
|
|
40
40
|
|
|
41
41
|
attr_accessor :primary
|
|
42
42
|
|
|
43
|
-
#
|
|
43
|
+
# The Airbnb markup as a fraction: \"0.35\" = +35% on the listing's own price. Read or set it as a percentage with `/v1/listings/{id}/markups`.
|
|
44
44
|
attr_accessor :markup
|
|
45
45
|
|
|
46
46
|
# Airbnb's own API sync decision for THIS listing, as Airbnb reports it. Airbnb authorises sync one listing at a time, so a connected account can still contain listings it will not accept writes for. - `sync_all` — Repull manages content, rates and availability. - `sync_rates_and_availability` — Repull manages rates and availability; listing content is managed by the host on Airbnb. - `none` — the listing is **not** connected to Repull on Airbnb's side. Every write to it is refused with `403 listing_not_api_connected`; reconnecting the Airbnb account does not change this, the host must switch the listing on in Airbnb. `null` when the listing has not synced yet. Not to be confused with `syncEnabled`, which is a Repull-side flag and says nothing about what Airbnb accepts.
|
|
@@ -28,6 +28,7 @@ module Repull
|
|
|
28
28
|
|
|
29
29
|
attr_accessor :booking_url
|
|
30
30
|
|
|
31
|
+
# The Booking.com markup on this property, as a fraction: \"0.18\" = +18%, shared by every listing on the property. Read or set it as a percentage with `/v1/listings/{id}/markups`.
|
|
31
32
|
attr_accessor :markup
|
|
32
33
|
|
|
33
34
|
attr_accessor :sync_category
|
|
@@ -0,0 +1,170 @@
|
|
|
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 GetListingMarkups200Response < ApiModelBase
|
|
18
|
+
# Repull listing id.
|
|
19
|
+
attr_accessor :id
|
|
20
|
+
|
|
21
|
+
attr_accessor :airbnb
|
|
22
|
+
|
|
23
|
+
attr_accessor :booking
|
|
24
|
+
|
|
25
|
+
# Attribute mapping from ruby-style variable name to JSON key.
|
|
26
|
+
def self.attribute_map
|
|
27
|
+
{
|
|
28
|
+
:'id' => :'id',
|
|
29
|
+
:'airbnb' => :'airbnb',
|
|
30
|
+
:'booking' => :'booking'
|
|
31
|
+
}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Returns attribute mapping this model knows about
|
|
35
|
+
def self.acceptable_attribute_map
|
|
36
|
+
attribute_map
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Returns all the JSON keys this model knows about
|
|
40
|
+
def self.acceptable_attributes
|
|
41
|
+
acceptable_attribute_map.values
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Attribute type mapping.
|
|
45
|
+
def self.openapi_types
|
|
46
|
+
{
|
|
47
|
+
:'id' => :'String',
|
|
48
|
+
:'airbnb' => :'Array<GetListingMarkups200ResponseAirbnbInner>',
|
|
49
|
+
:'booking' => :'Array<GetListingMarkups200ResponseBookingInner>'
|
|
50
|
+
}
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# List of attributes with nullable: true
|
|
54
|
+
def self.openapi_nullable
|
|
55
|
+
Set.new([
|
|
56
|
+
])
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Initializes the object
|
|
60
|
+
# @param [Hash] attributes Model attributes in the form of hash
|
|
61
|
+
def initialize(attributes = {})
|
|
62
|
+
if (!attributes.is_a?(Hash))
|
|
63
|
+
fail ArgumentError, "The input argument (attributes) must be a hash in `Repull::GetListingMarkups200Response` initialize method"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# check to see if the attribute exists and convert string to symbol for hash key
|
|
67
|
+
acceptable_attribute_map = self.class.acceptable_attribute_map
|
|
68
|
+
attributes = attributes.each_with_object({}) { |(k, v), h|
|
|
69
|
+
if (!acceptable_attribute_map.key?(k.to_sym))
|
|
70
|
+
fail ArgumentError, "`#{k}` is not a valid attribute in `Repull::GetListingMarkups200Response`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
|
|
71
|
+
end
|
|
72
|
+
h[k.to_sym] = v
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if attributes.key?(:'id')
|
|
76
|
+
self.id = attributes[:'id']
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
if attributes.key?(:'airbnb')
|
|
80
|
+
if (value = attributes[:'airbnb']).is_a?(Array)
|
|
81
|
+
self.airbnb = value
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
if attributes.key?(:'booking')
|
|
86
|
+
if (value = attributes[:'booking']).is_a?(Array)
|
|
87
|
+
self.booking = value
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Show invalid properties with the reasons. Usually used together with valid?
|
|
93
|
+
# @return Array for valid properties with the reasons
|
|
94
|
+
def list_invalid_properties
|
|
95
|
+
warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
|
|
96
|
+
invalid_properties = Array.new
|
|
97
|
+
invalid_properties
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Check to see if the all the properties in the model are valid
|
|
101
|
+
# @return true if the model is valid
|
|
102
|
+
def valid?
|
|
103
|
+
warn '[DEPRECATED] the `valid?` method is obsolete'
|
|
104
|
+
true
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Checks equality by comparing each attribute.
|
|
108
|
+
# @param [Object] Object to be compared
|
|
109
|
+
def ==(o)
|
|
110
|
+
return true if self.equal?(o)
|
|
111
|
+
self.class == o.class &&
|
|
112
|
+
id == o.id &&
|
|
113
|
+
airbnb == o.airbnb &&
|
|
114
|
+
booking == o.booking
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# @see the `==` method
|
|
118
|
+
# @param [Object] Object to be compared
|
|
119
|
+
def eql?(o)
|
|
120
|
+
self == o
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Calculates hash code according to all attributes.
|
|
124
|
+
# @return [Integer] Hash code
|
|
125
|
+
def hash
|
|
126
|
+
[id, airbnb, booking].hash
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Builds the object from hash
|
|
130
|
+
# @param [Hash] attributes Model attributes in the form of hash
|
|
131
|
+
# @return [Object] Returns the model itself
|
|
132
|
+
def self.build_from_hash(attributes)
|
|
133
|
+
return nil unless attributes.is_a?(Hash)
|
|
134
|
+
attributes = attributes.transform_keys(&:to_sym)
|
|
135
|
+
transformed_hash = {}
|
|
136
|
+
openapi_types.each_pair do |key, type|
|
|
137
|
+
if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
|
|
138
|
+
transformed_hash["#{key}"] = nil
|
|
139
|
+
elsif type =~ /\AArray<(.*)>/i
|
|
140
|
+
# check to ensure the input is an array given that the attribute
|
|
141
|
+
# is documented as an array but the input is not
|
|
142
|
+
if attributes[attribute_map[key]].is_a?(Array)
|
|
143
|
+
transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
|
|
144
|
+
end
|
|
145
|
+
elsif !attributes[attribute_map[key]].nil?
|
|
146
|
+
transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
new(transformed_hash)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Returns the object in the form of hash
|
|
153
|
+
# @return [Hash] Returns the object in the form of hash
|
|
154
|
+
def to_hash
|
|
155
|
+
hash = {}
|
|
156
|
+
self.class.attribute_map.each_pair do |attr, param|
|
|
157
|
+
value = self.send(attr)
|
|
158
|
+
if value.nil?
|
|
159
|
+
is_nullable = self.class.openapi_nullable.include?(attr)
|
|
160
|
+
next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
hash[param] = _to_hash(value)
|
|
164
|
+
end
|
|
165
|
+
hash
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
end
|
|
@@ -0,0 +1,159 @@
|
|
|
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 GetListingMarkups200ResponseAirbnbInner < ApiModelBase
|
|
18
|
+
# Airbnb listing id.
|
|
19
|
+
attr_accessor :airbnb_id
|
|
20
|
+
|
|
21
|
+
# Percent added to the listing's price on Airbnb. 35 = +35%. `null` = none.
|
|
22
|
+
attr_accessor :markup_percent
|
|
23
|
+
|
|
24
|
+
# Attribute mapping from ruby-style variable name to JSON key.
|
|
25
|
+
def self.attribute_map
|
|
26
|
+
{
|
|
27
|
+
:'airbnb_id' => :'airbnbId',
|
|
28
|
+
:'markup_percent' => :'markupPercent'
|
|
29
|
+
}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Returns attribute mapping this model knows about
|
|
33
|
+
def self.acceptable_attribute_map
|
|
34
|
+
attribute_map
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Returns all the JSON keys this model knows about
|
|
38
|
+
def self.acceptable_attributes
|
|
39
|
+
acceptable_attribute_map.values
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Attribute type mapping.
|
|
43
|
+
def self.openapi_types
|
|
44
|
+
{
|
|
45
|
+
:'airbnb_id' => :'String',
|
|
46
|
+
:'markup_percent' => :'Float'
|
|
47
|
+
}
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# List of attributes with nullable: true
|
|
51
|
+
def self.openapi_nullable
|
|
52
|
+
Set.new([
|
|
53
|
+
:'markup_percent'
|
|
54
|
+
])
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Initializes the object
|
|
58
|
+
# @param [Hash] attributes Model attributes in the form of hash
|
|
59
|
+
def initialize(attributes = {})
|
|
60
|
+
if (!attributes.is_a?(Hash))
|
|
61
|
+
fail ArgumentError, "The input argument (attributes) must be a hash in `Repull::GetListingMarkups200ResponseAirbnbInner` initialize method"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# check to see if the attribute exists and convert string to symbol for hash key
|
|
65
|
+
acceptable_attribute_map = self.class.acceptable_attribute_map
|
|
66
|
+
attributes = attributes.each_with_object({}) { |(k, v), h|
|
|
67
|
+
if (!acceptable_attribute_map.key?(k.to_sym))
|
|
68
|
+
fail ArgumentError, "`#{k}` is not a valid attribute in `Repull::GetListingMarkups200ResponseAirbnbInner`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
|
|
69
|
+
end
|
|
70
|
+
h[k.to_sym] = v
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if attributes.key?(:'airbnb_id')
|
|
74
|
+
self.airbnb_id = attributes[:'airbnb_id']
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
if attributes.key?(:'markup_percent')
|
|
78
|
+
self.markup_percent = attributes[:'markup_percent']
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Show invalid properties with the reasons. Usually used together with valid?
|
|
83
|
+
# @return Array for valid properties with the reasons
|
|
84
|
+
def list_invalid_properties
|
|
85
|
+
warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
|
|
86
|
+
invalid_properties = Array.new
|
|
87
|
+
invalid_properties
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Check to see if the all the properties in the model are valid
|
|
91
|
+
# @return true if the model is valid
|
|
92
|
+
def valid?
|
|
93
|
+
warn '[DEPRECATED] the `valid?` method is obsolete'
|
|
94
|
+
true
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Checks equality by comparing each attribute.
|
|
98
|
+
# @param [Object] Object to be compared
|
|
99
|
+
def ==(o)
|
|
100
|
+
return true if self.equal?(o)
|
|
101
|
+
self.class == o.class &&
|
|
102
|
+
airbnb_id == o.airbnb_id &&
|
|
103
|
+
markup_percent == o.markup_percent
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# @see the `==` method
|
|
107
|
+
# @param [Object] Object to be compared
|
|
108
|
+
def eql?(o)
|
|
109
|
+
self == o
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Calculates hash code according to all attributes.
|
|
113
|
+
# @return [Integer] Hash code
|
|
114
|
+
def hash
|
|
115
|
+
[airbnb_id, markup_percent].hash
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Builds the object from hash
|
|
119
|
+
# @param [Hash] attributes Model attributes in the form of hash
|
|
120
|
+
# @return [Object] Returns the model itself
|
|
121
|
+
def self.build_from_hash(attributes)
|
|
122
|
+
return nil unless attributes.is_a?(Hash)
|
|
123
|
+
attributes = attributes.transform_keys(&:to_sym)
|
|
124
|
+
transformed_hash = {}
|
|
125
|
+
openapi_types.each_pair do |key, type|
|
|
126
|
+
if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
|
|
127
|
+
transformed_hash["#{key}"] = nil
|
|
128
|
+
elsif type =~ /\AArray<(.*)>/i
|
|
129
|
+
# check to ensure the input is an array given that the attribute
|
|
130
|
+
# is documented as an array but the input is not
|
|
131
|
+
if attributes[attribute_map[key]].is_a?(Array)
|
|
132
|
+
transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
|
|
133
|
+
end
|
|
134
|
+
elsif !attributes[attribute_map[key]].nil?
|
|
135
|
+
transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
new(transformed_hash)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Returns the object in the form of hash
|
|
142
|
+
# @return [Hash] Returns the object in the form of hash
|
|
143
|
+
def to_hash
|
|
144
|
+
hash = {}
|
|
145
|
+
self.class.attribute_map.each_pair do |attr, param|
|
|
146
|
+
value = self.send(attr)
|
|
147
|
+
if value.nil?
|
|
148
|
+
is_nullable = self.class.openapi_nullable.include?(attr)
|
|
149
|
+
next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
hash[param] = _to_hash(value)
|
|
153
|
+
end
|
|
154
|
+
hash
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
end
|