repull 0.2.16 → 0.2.17
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 +6 -6
- data/lib/repull/api/booking_com_api.rb +86 -2
- data/lib/repull/api/conversations_api.rb +8 -8
- data/lib/repull/api/listings_api.rb +182 -12
- data/lib/repull/api/reservations_api.rb +4 -4
- data/lib/repull/models/airbnb_publish_result.rb +41 -2
- data/lib/repull/models/booking_property_action_request.rb +176 -0
- data/lib/repull/models/booking_property_action_response.rb +281 -0
- data/lib/repull/models/booking_publish_result.rb +245 -0
- data/lib/repull/models/booking_publish_section_error.rb +220 -0
- data/lib/repull/models/booking_setup_request.rb +44 -5
- data/lib/repull/models/booking_setup_request_legal_entity.rb +235 -0
- data/lib/repull/models/channel_market_state_item.rb +291 -0
- data/lib/repull/models/error_error.rb +11 -1
- data/lib/repull/models/inquiry_updated_payload.rb +1 -1
- data/lib/repull/models/list_inquiries200_response_data_inner.rb +1 -1
- data/lib/repull/models/listing_address_readiness.rb +171 -0
- data/lib/repull/models/listing_content_update_request_address.rb +40 -3
- data/lib/repull/models/listing_create_request.rb +48 -2
- data/lib/repull/models/listing_market_state_request.rb +149 -0
- data/lib/repull/models/listing_market_state_response.rb +221 -0
- data/lib/repull/models/listing_publish_booking_request.rb +149 -0
- data/lib/repull/models/{listing_publish_response.rb → listing_publish_booking_response.rb} +4 -5
- data/lib/repull/models/listing_publish_status_channel.rb +32 -1
- data/lib/repull/models/listing_publish_status_connection.rb +17 -5
- data/lib/repull/models/listing_publish_status_response.rb +13 -1
- data/lib/repull/models/reservation_request_updated_payload.rb +1 -1
- data/lib/repull/version.rb +1 -1
- data/lib/repull.rb +11 -1
- data/openapi/v1.json +855 -72
- data/scripts/regen.sh +1 -1
- metadata +13 -3
data/openapi/v1.json
CHANGED
|
@@ -2232,7 +2232,7 @@
|
|
|
2232
2232
|
},
|
|
2233
2233
|
"ReservationRequestUpdatedPayload": {
|
|
2234
2234
|
"type": "object",
|
|
2235
|
-
"description": "Payload for `reservation.request.updated`. A booking request stopped waiting on the host. `requestStatus` says how; `data.object` is the reservation after the change (`status` `confirmed` once accepted, `cancelled` otherwise). An accepted request also fires `reservation.created`. Fires when the channel reports the outcome, whoever acted \u2014 the API,
|
|
2235
|
+
"description": "Payload for `reservation.request.updated`. A booking request stopped waiting on the host. `requestStatus` says how; `data.object` is the reservation after the change (`status` `confirmed` once accepted, `cancelled` otherwise). An accepted request also fires `reservation.created`. Fires when the channel reports the outcome, whoever acted \u2014 the API, a connected app or the channel's own app.",
|
|
2236
2236
|
"required": [
|
|
2237
2237
|
"object",
|
|
2238
2238
|
"requestStatus",
|
|
@@ -2412,7 +2412,7 @@
|
|
|
2412
2412
|
},
|
|
2413
2413
|
"InquiryUpdatedPayload": {
|
|
2414
2414
|
"type": "object",
|
|
2415
|
-
"description": "Payload for `inquiry.updated`. The inquiry's status, dates, guest count or the reservation it became changed. `previousAttributes` holds only what moved, with prior values. Fires whether the host acted through the API,
|
|
2415
|
+
"description": "Payload for `inquiry.updated`. The inquiry's status, dates, guest count or the reservation it became changed. `previousAttributes` holds only what moved, with prior values. Fires whether the host acted through the API, a connected app or the Airbnb app. An inquiry whose dates simply pass is `expired` in `GET /v1/inquiries` but fires no event unless the channel reports it.",
|
|
2416
2416
|
"required": [
|
|
2417
2417
|
"object",
|
|
2418
2418
|
"previousAttributes"
|
|
@@ -5291,6 +5291,12 @@
|
|
|
5291
5291
|
"description": "Suggestion for typos and near-matches. Present when the server can guess the intent.",
|
|
5292
5292
|
"example": "check_in_after"
|
|
5293
5293
|
},
|
|
5294
|
+
"previous_code": {
|
|
5295
|
+
"type": "string",
|
|
5296
|
+
"deprecated": true,
|
|
5297
|
+
"description": "The `code` THIS response used to carry, for callers whose branch still matches the old string. A migration aid with a deprecation window \u2014 **`code` is canonical, always match on that.**\n\nPresent only where an endpoint's classification actually changed, never as a permanent synonym, and it disappears from a response as soon as the canonical code and the old one agree.\n\nThe live case: the reviews, messaging, check-in-guide, alteration-answer and Airbnb-pull endpoints used to report EVERY Airbnb failure as `500 airbnb_error`, including refusals Airbnb will repeat forever. They now classify the same way every other Airbnb write does \u2014 an Airbnb 4xx is `422 airbnb_rejected` (fix the request), 5xx and timeouts stay `502 airbnb_error` (retry with backoff), and a dead grant is `403 connection_reauth_required`. Those responses carry `previous_code: \"airbnb_error\"`. **Removed in v2** \u2014 migrate your branches to `code` before then.",
|
|
5298
|
+
"example": "airbnb_error"
|
|
5299
|
+
},
|
|
5294
5300
|
"listing_ids": {
|
|
5295
5301
|
"type": "array",
|
|
5296
5302
|
"items": {
|
|
@@ -6025,7 +6031,7 @@
|
|
|
6025
6031
|
"required": [
|
|
6026
6032
|
"name"
|
|
6027
6033
|
],
|
|
6028
|
-
"description": "Inputs for `POST /v1/listings
|
|
6034
|
+
"description": "Inputs for `POST /v1/listings`.\n\n**Address requirements \u2014 read this before you build the payload.** Publishing to Airbnb runs a create preflight that refuses the listing outright if the address is incomplete, and the refusal only surfaces later, at publish time. Airbnb requires `street` and `city` for every country. For a **US** property it additionally requires `state` and `postalCode`. Crucially, **omitting `countryCode` makes the listing behave as US**, so a listing created without a country needs `state` and `postalCode` too. Send `countryCode` explicitly for a non-US property. `lat`/`lng` alone are not enough \u2014 Airbnb rejects coordinates that are not backed by a full postal address. Use `GET /v1/listings/{id}/publish-status` to see which parts are still missing before you attempt a publish.",
|
|
6029
6035
|
"properties": {
|
|
6030
6036
|
"name": {
|
|
6031
6037
|
"type": "string",
|
|
@@ -6036,29 +6042,54 @@
|
|
|
6036
6042
|
"type": "string",
|
|
6037
6043
|
"example": "apartment"
|
|
6038
6044
|
},
|
|
6045
|
+
"roomTypeCategory": {
|
|
6046
|
+
"type": "string",
|
|
6047
|
+
"example": "entire_home",
|
|
6048
|
+
"description": "What the guest actually gets. Airbnb refuses to activate a listing that has not stated one, answering \"Please specify a valid room type\" \u2014 which reads like a beds problem and is not. It is never defaulted: most listings are an entire home, but hundreds are a private or hotel room, and publishing one of those as an entire home is a false claim about someone's property. Settable later with `PUT /v1/listings/{id}/content` under `details`."
|
|
6049
|
+
},
|
|
6050
|
+
"propertyTypeCategory": {
|
|
6051
|
+
"type": "string",
|
|
6052
|
+
"description": "Airbnb's finer property-type category, when you know it. Optional."
|
|
6053
|
+
},
|
|
6039
6054
|
"street": {
|
|
6040
6055
|
"type": "string",
|
|
6041
|
-
"example": "123 Main St"
|
|
6056
|
+
"example": "123 Main St",
|
|
6057
|
+
"description": "Street address including the number. Required by Airbnb for every country \u2014 a publish is refused without it."
|
|
6042
6058
|
},
|
|
6043
6059
|
"city": {
|
|
6044
6060
|
"type": "string",
|
|
6045
|
-
"example": "Miami Beach"
|
|
6061
|
+
"example": "Miami Beach",
|
|
6062
|
+
"description": "City / town. Required by Airbnb for every country \u2014 a publish is refused without it."
|
|
6046
6063
|
},
|
|
6047
6064
|
"state": {
|
|
6048
6065
|
"type": "string",
|
|
6049
|
-
"example": "FL"
|
|
6066
|
+
"example": "FL",
|
|
6067
|
+
"description": "State, province or region. **Required for a US property**, and a listing with no `countryCode` counts as US. Optional elsewhere, but stored and used wherever the channel carries it."
|
|
6068
|
+
},
|
|
6069
|
+
"postalCode": {
|
|
6070
|
+
"type": "string",
|
|
6071
|
+
"example": "33139",
|
|
6072
|
+
"description": "Postal code \u2014 ZIP in the US, postcode in the UK, and so on. **Required for a US property**, and a listing with no `countryCode` counts as US. Send the complete code: Booking.com rejects a partial postcode such as `SW6` where the full value is `SW6 1EP`. Alias: `zipcode`."
|
|
6073
|
+
},
|
|
6074
|
+
"zipcode": {
|
|
6075
|
+
"type": "string",
|
|
6076
|
+
"example": "33139",
|
|
6077
|
+
"description": "Alias for `postalCode`, accepted because it is the field name on the Airbnb mirror. `postalCode` wins if you send both. Prefer `postalCode` \u2014 the field holds non-US postcodes too."
|
|
6050
6078
|
},
|
|
6051
6079
|
"countryCode": {
|
|
6052
6080
|
"type": "string",
|
|
6053
|
-
"example": "US"
|
|
6081
|
+
"example": "US",
|
|
6082
|
+
"description": "ISO-3166 alpha-2 country code. **Send this for any non-US property.** Omitting it does not mean \"unknown\" \u2014 the publish path treats a listing with no country as US, which then requires `state` and `postalCode` and will refuse the listing when they are absent."
|
|
6054
6083
|
},
|
|
6055
6084
|
"lat": {
|
|
6056
6085
|
"type": "number",
|
|
6057
|
-
"example": 25.7617
|
|
6086
|
+
"example": 25.7617,
|
|
6087
|
+
"description": "Latitude. Useful for map search, but never a substitute for the postal address \u2014 Airbnb rejects coordinates it cannot reconcile with a full address."
|
|
6058
6088
|
},
|
|
6059
6089
|
"lng": {
|
|
6060
6090
|
"type": "number",
|
|
6061
|
-
"example": -80.1918
|
|
6091
|
+
"example": -80.1918,
|
|
6092
|
+
"description": "Longitude. See `lat`."
|
|
6062
6093
|
},
|
|
6063
6094
|
"bedrooms": {
|
|
6064
6095
|
"type": "integer",
|
|
@@ -6274,28 +6305,51 @@
|
|
|
6274
6305
|
},
|
|
6275
6306
|
"address": {
|
|
6276
6307
|
"type": "object",
|
|
6277
|
-
"description": "Partial address. Only provided sub-fields are written.",
|
|
6308
|
+
"description": "Partial address. Only provided sub-fields are written; the ones you omit keep their current value, and an explicit `null` clears one.\n\nThis is also the repair path for a listing that cannot be published: Airbnb requires `street` and `city` for every country and additionally `state` and `postalCode` for a **US** property \u2014 and a listing with no `countryCode` behaves as US. Send just the missing part, e.g. `{ \"address\": { \"state\": \"FL\" } }`. `GET /v1/listings/{id}/publish-status` names what is missing.",
|
|
6278
6309
|
"properties": {
|
|
6279
6310
|
"street": {
|
|
6280
6311
|
"type": "string",
|
|
6281
|
-
"nullable": true
|
|
6312
|
+
"nullable": true,
|
|
6313
|
+
"description": "Street address including the number. Required by Airbnb for every country."
|
|
6282
6314
|
},
|
|
6283
6315
|
"city": {
|
|
6284
6316
|
"type": "string",
|
|
6285
|
-
"nullable": true
|
|
6317
|
+
"nullable": true,
|
|
6318
|
+
"description": "City / town. Required by Airbnb for every country."
|
|
6319
|
+
},
|
|
6320
|
+
"state": {
|
|
6321
|
+
"type": "string",
|
|
6322
|
+
"nullable": true,
|
|
6323
|
+
"example": "FL",
|
|
6324
|
+
"description": "State, province or region. **Required for a US property**, and a listing with no `countryCode` counts as US."
|
|
6325
|
+
},
|
|
6326
|
+
"postalCode": {
|
|
6327
|
+
"type": "string",
|
|
6328
|
+
"nullable": true,
|
|
6329
|
+
"example": "33139",
|
|
6330
|
+
"description": "Postal code \u2014 ZIP in the US, postcode in the UK, and so on. **Required for a US property**, and a listing with no `countryCode` counts as US. Send the complete code; a partial postcode is rejected downstream. Alias: `zipcode`."
|
|
6331
|
+
},
|
|
6332
|
+
"zipcode": {
|
|
6333
|
+
"type": "string",
|
|
6334
|
+
"nullable": true,
|
|
6335
|
+
"example": "33139",
|
|
6336
|
+
"description": "Alias for `postalCode`, accepted because it is the field name on the Airbnb mirror. `postalCode` wins if you send both."
|
|
6286
6337
|
},
|
|
6287
6338
|
"countryCode": {
|
|
6288
6339
|
"type": "string",
|
|
6289
6340
|
"nullable": true,
|
|
6290
|
-
"
|
|
6341
|
+
"example": "US",
|
|
6342
|
+
"description": "ISO-3166 alpha-2 country code. **Send this for any non-US property.** Leaving it unset does not mean \"unknown\" \u2014 the publish path treats a listing with no country as US and then demands `state` and `postalCode`."
|
|
6291
6343
|
},
|
|
6292
6344
|
"lat": {
|
|
6293
6345
|
"type": "number",
|
|
6294
|
-
"nullable": true
|
|
6346
|
+
"nullable": true,
|
|
6347
|
+
"description": "Latitude. Never a substitute for the postal address \u2014 Airbnb rejects coordinates it cannot reconcile with a full address."
|
|
6295
6348
|
},
|
|
6296
6349
|
"lng": {
|
|
6297
6350
|
"type": "number",
|
|
6298
|
-
"nullable": true
|
|
6351
|
+
"nullable": true,
|
|
6352
|
+
"description": "Longitude. See `lat`."
|
|
6299
6353
|
}
|
|
6300
6354
|
}
|
|
6301
6355
|
},
|
|
@@ -6878,18 +6932,13 @@
|
|
|
6878
6932
|
}
|
|
6879
6933
|
}
|
|
6880
6934
|
},
|
|
6881
|
-
"
|
|
6935
|
+
"ListingPublishBookingRequest": {
|
|
6882
6936
|
"type": "object",
|
|
6937
|
+
"description": "Optional. Omit the body entirely when the listing is mapped to exactly one Booking.com property.",
|
|
6883
6938
|
"properties": {
|
|
6884
|
-
"
|
|
6885
|
-
"type": "string"
|
|
6886
|
-
|
|
6887
|
-
"channel": {
|
|
6888
|
-
"type": "string"
|
|
6889
|
-
},
|
|
6890
|
-
"result": {
|
|
6891
|
-
"type": "object",
|
|
6892
|
-
"description": "Channel-specific push result (sections pushed, errors, etc.)"
|
|
6939
|
+
"hotelId": {
|
|
6940
|
+
"type": "string",
|
|
6941
|
+
"description": "Booking.com property to publish into. Required when this listing is mapped to more than one \u2014 without it the push is refused with `409 ambiguous_booking_mapping` rather than written into a property chosen for you. `GET /v1/channels/booking/properties` lists every property in the workspace with the listings mapped under it. `?hotel_id=` in the query string is accepted as well and means the same thing; the body wins if you send both."
|
|
6893
6942
|
}
|
|
6894
6943
|
}
|
|
6895
6944
|
},
|
|
@@ -6959,6 +7008,7 @@
|
|
|
6959
7008
|
},
|
|
6960
7009
|
"ListingPublishStatusChannel": {
|
|
6961
7010
|
"type": "object",
|
|
7011
|
+
"description": "Sync activity for one channel. `pushStatus` says whether the last push landed; `pushError` says why it did not.",
|
|
6962
7012
|
"properties": {
|
|
6963
7013
|
"platform": {
|
|
6964
7014
|
"type": "string",
|
|
@@ -6968,6 +7018,12 @@
|
|
|
6968
7018
|
"type": "string",
|
|
6969
7019
|
"nullable": true
|
|
6970
7020
|
},
|
|
7021
|
+
"pushError": {
|
|
7022
|
+
"type": "string",
|
|
7023
|
+
"nullable": true,
|
|
7024
|
+
"description": "Why the last push failed \u2014 the channel's own reason, verbatim, sanitised for display.\n\nThis is the field to render when `pushStatus` is `error`. It carries what Airbnb or Booking.com actually objected to, which is almost always something the operator can fix in the listing content: `\"Airbnb error (400): We can't save your info yet. Links and contact info can't be shared.\"`, `\"Check-in start time must be before end time\"`, `\"property_type_group must be one of [apartments, houses, \u2026]\"`, `\"Rate limited by provider\"`.\n\n**Free text, not an enum.** It is written by the channel and changes without notice: show it to a human, log it, put it next to the retry button \u2014 but never parse it or branch on its contents. When a push fails for several reasons at once the reasons are joined with `; `.\n\n`null` when the last push succeeded, and when no push has run yet \u2014 the two are told apart by `pushStatus` and `lastPushedAt`, not by this field.",
|
|
7025
|
+
"example": "Airbnb error (400): property_type_group must be one of [apartments, houses, secondary_units, unique_homes, bnb]"
|
|
7026
|
+
},
|
|
6971
7027
|
"lastPushedAt": {
|
|
6972
7028
|
"type": "string",
|
|
6973
7029
|
"format": "date-time",
|
|
@@ -6987,7 +7043,11 @@
|
|
|
6987
7043
|
"platformHasChanges": {
|
|
6988
7044
|
"type": "boolean"
|
|
6989
7045
|
}
|
|
6990
|
-
}
|
|
7046
|
+
},
|
|
7047
|
+
"required": [
|
|
7048
|
+
"platform",
|
|
7049
|
+
"pushError"
|
|
7050
|
+
]
|
|
6991
7051
|
},
|
|
6992
7052
|
"ListingPublishStatusConnection": {
|
|
6993
7053
|
"type": "object",
|
|
@@ -7011,6 +7071,43 @@
|
|
|
7011
7071
|
"format": "date-time",
|
|
7012
7072
|
"nullable": true,
|
|
7013
7073
|
"description": "ISO timestamp the connection was first established."
|
|
7074
|
+
},
|
|
7075
|
+
"lockedFields": {
|
|
7076
|
+
"type": "array",
|
|
7077
|
+
"items": {
|
|
7078
|
+
"type": "string"
|
|
7079
|
+
},
|
|
7080
|
+
"description": "Fields the channel will not let this listing change. **Airbnb only** \u2014 present on the `airbnb` entry and absent on every other channel, because no other channel has the concept.\n\nAirbnb does not refuse a write to a locked field: the request returns 200, reports the field as locked, and applies nothing. So a write to one of these looks exactly like a write that worked. Read this before you let a user edit \u2014 it is here, rather than only on `GET /v1/channels/airbnb/listings/{id}`, because this is the endpoint a listing editor already calls.\n\nEmpty for a listing with nothing locked, and for one that has not synced since we began recording them \u2014 the two are not distinguished, because a caller acts the same way on both. This is what Airbnb last told us, not a promise: a lock can appear between syncs, which is why a publish result also reports `lockedFields`.",
|
|
7081
|
+
"example": [
|
|
7082
|
+
"name",
|
|
7083
|
+
"property_type_category"
|
|
7084
|
+
]
|
|
7085
|
+
}
|
|
7086
|
+
}
|
|
7087
|
+
},
|
|
7088
|
+
"ListingAddressReadiness": {
|
|
7089
|
+
"type": "object",
|
|
7090
|
+
"description": "Whether one channel would accept this listing's postal address, answered WITHOUT attempting a publish.",
|
|
7091
|
+
"properties": {
|
|
7092
|
+
"ready": {
|
|
7093
|
+
"type": "boolean",
|
|
7094
|
+
"description": "True when the address satisfies this channel's create preflight. False means a publish would be refused for the address alone."
|
|
7095
|
+
},
|
|
7096
|
+
"missing": {
|
|
7097
|
+
"type": "array",
|
|
7098
|
+
"items": {
|
|
7099
|
+
"type": "string"
|
|
7100
|
+
},
|
|
7101
|
+
"description": "The address parts still needed, named as the REQUEST fields you send \u2014 `street`, `city`, `state`, `postalCode` \u2014 so the value can be acted on directly. Empty when `ready` is true.",
|
|
7102
|
+
"example": [
|
|
7103
|
+
"state",
|
|
7104
|
+
"postalCode"
|
|
7105
|
+
]
|
|
7106
|
+
},
|
|
7107
|
+
"have": {
|
|
7108
|
+
"type": "string",
|
|
7109
|
+
"description": "The address as currently resolved, for debugging.",
|
|
7110
|
+
"example": "street=123 Main St, city=Miami Beach, state=\u2205, postalCode=\u2205, country=US"
|
|
7014
7111
|
}
|
|
7015
7112
|
}
|
|
7016
7113
|
},
|
|
@@ -7020,6 +7117,22 @@
|
|
|
7020
7117
|
"listingId": {
|
|
7021
7118
|
"type": "string"
|
|
7022
7119
|
},
|
|
7120
|
+
"addressReadiness": {
|
|
7121
|
+
"type": "object",
|
|
7122
|
+
"description": "Address readiness per channel, keyed by channel name (`airbnb` today). Airbnb requires `street` and `city` for every country and additionally `state` and `postalCode` for a **US** property \u2014 and a listing with no `countryCode` behaves as US. Check this BEFORE calling a publish endpoint: an incomplete address is refused at the create preflight and never reaches the channel.\n\nIt sits here rather than inside `channels[]` because `channels` reports sync activity and is empty for a listing that has never been pushed \u2014 exactly the listing whose address blocker you need to see. Repair a gap with `PUT /v1/listings/{id}/content`, sending only the missing parts under `address`. An empty object means readiness was not reported; it never means ready.",
|
|
7123
|
+
"additionalProperties": {
|
|
7124
|
+
"$ref": "#/components/schemas/ListingAddressReadiness"
|
|
7125
|
+
},
|
|
7126
|
+
"example": {
|
|
7127
|
+
"airbnb": {
|
|
7128
|
+
"ready": false,
|
|
7129
|
+
"missing": [
|
|
7130
|
+
"state",
|
|
7131
|
+
"postalCode"
|
|
7132
|
+
]
|
|
7133
|
+
}
|
|
7134
|
+
}
|
|
7135
|
+
},
|
|
7023
7136
|
"channels": {
|
|
7024
7137
|
"type": "array",
|
|
7025
7138
|
"description": "Sync activity per channel \u2014 empty if the listing has never been pushed/pulled. Empty does NOT mean \"not connected\"; check `connections` for that.",
|
|
@@ -10518,11 +10631,12 @@
|
|
|
10518
10631
|
},
|
|
10519
10632
|
"AirbnbPublishResult": {
|
|
10520
10633
|
"type": "object",
|
|
10521
|
-
"description": "A publish is not one call to Airbnb: it is up to eight independent ones (details, description, amenities, rooms, policies, photos, pricing, checkout_tasks), each of which can fail on its own. A PARTIAL publish is normal \u2014 what succeeded stays applied; there is no rollback.",
|
|
10634
|
+
"description": "A publish is not one call to Airbnb: it is up to eight independent ones (details, description, amenities, rooms, policies, photos, pricing, checkout_tasks), each of which can fail on its own. A PARTIAL publish is normal \u2014 what succeeded stays applied; there is no rollback.\n\n**Content landing and the listing being live are two different answers.** `published` is about content; `live` is about whether the listing takes bookings. Read both.",
|
|
10522
10635
|
"required": [
|
|
10523
10636
|
"published",
|
|
10524
10637
|
"sections",
|
|
10525
10638
|
"errors",
|
|
10639
|
+
"warnings",
|
|
10526
10640
|
"lockedFields"
|
|
10527
10641
|
],
|
|
10528
10642
|
"properties": {
|
|
@@ -10530,6 +10644,10 @@
|
|
|
10530
10644
|
"type": "boolean",
|
|
10531
10645
|
"description": "True only when EVERY attempted section reached Airbnb."
|
|
10532
10646
|
},
|
|
10647
|
+
"live": {
|
|
10648
|
+
"type": "boolean",
|
|
10649
|
+
"description": "Whether the listing is active and bookable on Airbnb \u2014 that is, whether activation was actually performed and succeeded.\n\n`published: true` with `live: false` is a real and common outcome: every content section landed, but the listing was never activated, because activation is skipped when instant-booking cannot be confirmed to be off. `warnings` says why.\n\n**Absent is not `false`.** The field is omitted entirely when activation was never part of the operation \u2014 publishing to an already-mapped Airbnb listing updates content and activates nothing, so there is nothing to report. Only treat the listing as not-live when `live` is present and false."
|
|
10650
|
+
},
|
|
10533
10651
|
"sections": {
|
|
10534
10652
|
"type": "array",
|
|
10535
10653
|
"items": {
|
|
@@ -10549,6 +10667,16 @@
|
|
|
10549
10667
|
},
|
|
10550
10668
|
"description": "Per-section failures. Empty when `published` is true."
|
|
10551
10669
|
},
|
|
10670
|
+
"warnings": {
|
|
10671
|
+
"type": "array",
|
|
10672
|
+
"items": {
|
|
10673
|
+
"type": "string"
|
|
10674
|
+
},
|
|
10675
|
+
"description": "Steps that failed WITHOUT failing the publish \u2014 optional work the push carried on past, each in the push's own words. These used to be swallowed silently, so the only sign of one was a listing that was somehow not quite right afterwards. A publish can be `published: true` and still carry warnings; read them before concluding nothing needs doing.",
|
|
10676
|
+
"example": [
|
|
10677
|
+
"instant booking could not be confirmed off \u2014 listing left inactive"
|
|
10678
|
+
]
|
|
10679
|
+
},
|
|
10552
10680
|
"reason": {
|
|
10553
10681
|
"type": "string",
|
|
10554
10682
|
"description": "Set when the publish never started at all (no connection, address missing, subscription gate)."
|
|
@@ -10576,6 +10704,227 @@
|
|
|
10576
10704
|
}
|
|
10577
10705
|
}
|
|
10578
10706
|
},
|
|
10707
|
+
"BookingPublishSectionError": {
|
|
10708
|
+
"type": "object",
|
|
10709
|
+
"description": "One section of a publish that did not reach Booking.com.",
|
|
10710
|
+
"required": [
|
|
10711
|
+
"section",
|
|
10712
|
+
"message",
|
|
10713
|
+
"code"
|
|
10714
|
+
],
|
|
10715
|
+
"properties": {
|
|
10716
|
+
"section": {
|
|
10717
|
+
"type": "string",
|
|
10718
|
+
"description": "Which part of the listing this failure is about \u2014 e.g. `details`, `description`, `amenities`, `rooms`, `photos`, `pricing`.",
|
|
10719
|
+
"example": "description"
|
|
10720
|
+
},
|
|
10721
|
+
"message": {
|
|
10722
|
+
"type": "string",
|
|
10723
|
+
"description": "Booking.com's own reason, verbatim, or ours when we refused to send an empty section."
|
|
10724
|
+
},
|
|
10725
|
+
"code": {
|
|
10726
|
+
"type": "string",
|
|
10727
|
+
"description": "`no_content` \u2014 there was nothing canonical to send for this section; write the content, then publish again. `rejected` \u2014 Booking.com refused the section as sent; fix the content, or the property's Content API permissions, and publish again.\n\nAirbnb's third code, `locked`, has no Booking.com counterpart and never appears here."
|
|
10728
|
+
}
|
|
10729
|
+
}
|
|
10730
|
+
},
|
|
10731
|
+
"BookingPublishResult": {
|
|
10732
|
+
"type": "object",
|
|
10733
|
+
"description": "A publish is not one call to Booking.com: it is several independent Content API calls (details, description, amenities, rooms, photos, pricing), each of which can fail on its own. A PARTIAL publish is normal \u2014 what succeeded stays applied; there is no rollback. Fix the failing sections and publish again; re-publishing an unchanged section is harmless.\n\nA property whose Content API credentials do not cover a section answers 403 for that section alone \u2014 the rest still land, and the failure is reported here rather than swallowed.",
|
|
10734
|
+
"required": [
|
|
10735
|
+
"published",
|
|
10736
|
+
"sections",
|
|
10737
|
+
"errors"
|
|
10738
|
+
],
|
|
10739
|
+
"properties": {
|
|
10740
|
+
"published": {
|
|
10741
|
+
"type": "boolean",
|
|
10742
|
+
"description": "True only when EVERY attempted section reached Booking.com."
|
|
10743
|
+
},
|
|
10744
|
+
"sections": {
|
|
10745
|
+
"type": "array",
|
|
10746
|
+
"items": {
|
|
10747
|
+
"type": "string"
|
|
10748
|
+
},
|
|
10749
|
+
"description": "Sections that landed on Booking.com.",
|
|
10750
|
+
"example": [
|
|
10751
|
+
"details",
|
|
10752
|
+
"description",
|
|
10753
|
+
"photos"
|
|
10754
|
+
]
|
|
10755
|
+
},
|
|
10756
|
+
"errors": {
|
|
10757
|
+
"type": "array",
|
|
10758
|
+
"items": {
|
|
10759
|
+
"$ref": "#/components/schemas/BookingPublishSectionError"
|
|
10760
|
+
},
|
|
10761
|
+
"description": "Per-section failures. Empty when `published` is true."
|
|
10762
|
+
},
|
|
10763
|
+
"reason": {
|
|
10764
|
+
"type": "string",
|
|
10765
|
+
"description": "Set when the publish never started at all \u2014 most often because the listing is not mapped to any Booking.com property yet. Finish the Connect flow (`POST /v1/connect/booking/map-rooms`) and publish again."
|
|
10766
|
+
},
|
|
10767
|
+
"hotelId": {
|
|
10768
|
+
"type": "string",
|
|
10769
|
+
"nullable": true,
|
|
10770
|
+
"description": "The Booking.com property this publish wrote into \u2014 resolved from the listing's mapping, or the one you named. Always read it back: a listing can be mapped to several properties, and this states which one actually received the content. Null when the listing is mapped to no property, in which case nothing was pushed."
|
|
10771
|
+
}
|
|
10772
|
+
}
|
|
10773
|
+
},
|
|
10774
|
+
"ListingPublishBookingResponse": {
|
|
10775
|
+
"type": "object",
|
|
10776
|
+
"properties": {
|
|
10777
|
+
"listingId": {
|
|
10778
|
+
"type": "string"
|
|
10779
|
+
},
|
|
10780
|
+
"channel": {
|
|
10781
|
+
"type": "string"
|
|
10782
|
+
},
|
|
10783
|
+
"result": {
|
|
10784
|
+
"$ref": "#/components/schemas/BookingPublishResult"
|
|
10785
|
+
}
|
|
10786
|
+
}
|
|
10787
|
+
},
|
|
10788
|
+
"ListingMarketStateRequest": {
|
|
10789
|
+
"type": "object",
|
|
10790
|
+
"description": "Optional. Send no body at all unless this listing is mapped to more than one Booking.com property.",
|
|
10791
|
+
"properties": {
|
|
10792
|
+
"hotelId": {
|
|
10793
|
+
"type": "string",
|
|
10794
|
+
"description": "Booking.com property to act on, for a listing mapped to more than one. Without it the Booking.com item comes back refused with `ambiguous_booking_mapping` \u2014 closing the wrong property's availability takes real inventory off sale, so it is never guessed. The Airbnb items are unaffected and still run. `GET /v1/channels/booking/properties` lists every property in the workspace with the listings mapped under it. `?hotel_id=` in the query string means the same thing; the body wins if you send both."
|
|
10795
|
+
}
|
|
10796
|
+
}
|
|
10797
|
+
},
|
|
10798
|
+
"ChannelMarketStateItem": {
|
|
10799
|
+
"type": "object",
|
|
10800
|
+
"description": "What happened on ONE channel item \u2014 one Airbnb connection, or one Booking.com property. A listing can carry several Airbnb connections (a re-list, or a move between host accounts) and each gets its own entry.",
|
|
10801
|
+
"required": [
|
|
10802
|
+
"channel",
|
|
10803
|
+
"state",
|
|
10804
|
+
"ok"
|
|
10805
|
+
],
|
|
10806
|
+
"properties": {
|
|
10807
|
+
"channel": {
|
|
10808
|
+
"type": "string"
|
|
10809
|
+
},
|
|
10810
|
+
"state": {
|
|
10811
|
+
"type": "string",
|
|
10812
|
+
"description": "**What is now true of this item**, not what you asked for.\n\n`offline` \u2014 it is off the market. `online` \u2014 it is back on. `unchanged` \u2014 nothing was sent, or what was sent did not take; `code` and `message` say why.\n\n`unchanged` never means \"it was already like that\": it means we did not put it there, and it is still in whatever state it was in before the call."
|
|
10813
|
+
},
|
|
10814
|
+
"ok": {
|
|
10815
|
+
"type": "boolean",
|
|
10816
|
+
"description": "True only when the channel confirmed the change."
|
|
10817
|
+
},
|
|
10818
|
+
"connectionId": {
|
|
10819
|
+
"type": "string",
|
|
10820
|
+
"nullable": true,
|
|
10821
|
+
"description": "Airbnb connection row id \u2014 the `id` from `GET /v1/channels/airbnb/listings/{id}`. Present on Airbnb items."
|
|
10822
|
+
},
|
|
10823
|
+
"hotelId": {
|
|
10824
|
+
"type": "string",
|
|
10825
|
+
"nullable": true,
|
|
10826
|
+
"description": "The Booking.com property acted on. Present on Booking.com items; null when the property could not be resolved."
|
|
10827
|
+
},
|
|
10828
|
+
"code": {
|
|
10829
|
+
"type": "string",
|
|
10830
|
+
"description": "Error code when `ok` is false \u2014 the SAME code the channel-specific endpoint returns for this failure, so one vocabulary covers both surfaces. Absent when `ok` is true.\n\nThe channel codes come in pairs, and the pair is the retryable split \u2014 the most useful bit in the whole item:\n\n- `airbnb_rejected` / `booking_rejected` \u2014 the channel refused the request AS SENT. `message` carries its own reason. Correct it and send again; resending the same thing is refused again.\n- `airbnb_error` / `booking_error` \u2014 the channel did not complete the request (outage, timeout, server error). Nothing about the request needs to change: retry with backoff.\n\nPlus `ambiguous_booking_mapping` (name the property with `hotelId`) and `payment_required` (a billing refusal, which keeps its own code rather than being buried under a channel one)."
|
|
10831
|
+
},
|
|
10832
|
+
"previousCode": {
|
|
10833
|
+
"type": "string",
|
|
10834
|
+
"deprecated": true,
|
|
10835
|
+
"description": "The `code` this item used to carry, for callers still branching on the old string. A migration aid with a deprecation window \u2014 **`code` is canonical.**\n\nThis fan-out reaches Airbnb through an internal hop that flattens a refusal into its own 500, so an unambiguous Airbnb 400 (\"Please specify a valid room type\") was reported as `airbnb_error` \u2014 whose published advice is to retry with backoff, forever, for something Airbnb will never accept. It now reads Airbnb's real status and answers `airbnb_rejected`, and the classification covers the whole 4xx range rather than only `400`. Items whose code changed carry `previousCode`. **Removed in v2.**",
|
|
10836
|
+
"example": "airbnb_error"
|
|
10837
|
+
},
|
|
10838
|
+
"message": {
|
|
10839
|
+
"type": "string",
|
|
10840
|
+
"description": "The channel's own reason, verbatim. Absent when `ok` is true."
|
|
10841
|
+
},
|
|
10842
|
+
"fix": {
|
|
10843
|
+
"type": "string",
|
|
10844
|
+
"description": "What to do about it, phrased for the direction you asked for \u2014 \"still live and taking bookings\" and \"still down\" call for different reactions. Absent when `ok` is true."
|
|
10845
|
+
},
|
|
10846
|
+
"verified": {
|
|
10847
|
+
"type": "boolean",
|
|
10848
|
+
"description": "Airbnb only, and only when going offline: the listing was READ BACK after the deactivation and confirmed down. Airbnb accepts a deactivation and leaves some listings live, so \"we sent the request\" is a weaker claim than this one and is never reported as success."
|
|
10849
|
+
}
|
|
10850
|
+
}
|
|
10851
|
+
},
|
|
10852
|
+
"ListingMarketStateResponse": {
|
|
10853
|
+
"type": "object",
|
|
10854
|
+
"description": "The per-item result of a fan-out. **There is deliberately no top-level success flag**: a listing can sit on two Airbnb connections and a Booking.com property, they fail independently, and partial success is the ordinary outcome \u2014 any single boolean would be wrong for exactly the calls that need reading. Walk `channels` and check each `ok`.\n\nNothing here is rolled back. What landed stays landed; re-send the same request to retry the items that did not, which is safe.",
|
|
10855
|
+
"required": [
|
|
10856
|
+
"listingId",
|
|
10857
|
+
"state",
|
|
10858
|
+
"channels"
|
|
10859
|
+
],
|
|
10860
|
+
"properties": {
|
|
10861
|
+
"listingId": {
|
|
10862
|
+
"type": "string"
|
|
10863
|
+
},
|
|
10864
|
+
"state": {
|
|
10865
|
+
"type": "string",
|
|
10866
|
+
"description": "The state you asked for. Compare each item's own `state` against it."
|
|
10867
|
+
},
|
|
10868
|
+
"channels": {
|
|
10869
|
+
"type": "array",
|
|
10870
|
+
"description": "One entry per channel item acted on \u2014 Airbnb connections first, then the Booking.com property. Never empty: a listing connected to nothing is refused with `422 no_connected_channels` rather than answered with an empty array.",
|
|
10871
|
+
"items": {
|
|
10872
|
+
"$ref": "#/components/schemas/ChannelMarketStateItem"
|
|
10873
|
+
}
|
|
10874
|
+
}
|
|
10875
|
+
}
|
|
10876
|
+
},
|
|
10877
|
+
"BookingPropertyActionRequest": {
|
|
10878
|
+
"type": "object",
|
|
10879
|
+
"required": [
|
|
10880
|
+
"action"
|
|
10881
|
+
],
|
|
10882
|
+
"description": "Take this listing's Booking.com property off sale, or put it back.",
|
|
10883
|
+
"properties": {
|
|
10884
|
+
"action": {
|
|
10885
|
+
"type": "string",
|
|
10886
|
+
"description": "`unlist` closes the room's availability across the whole forward window, so the property stops selling. `relist` re-syncs the real calendar: dates that are genuinely blocked (a reservation, an owner stay) stay blocked, and only the closure `unlist` wrote lifts. They are not mirror images, and that is deliberate."
|
|
10887
|
+
},
|
|
10888
|
+
"hotelId": {
|
|
10889
|
+
"type": "string",
|
|
10890
|
+
"description": "Booking.com property to act on, for a listing mapped to more than one. Without it the request is refused with `409 ambiguous_booking_mapping` and nothing is written. `?hotel_id=` means the same thing; the body wins if you send both."
|
|
10891
|
+
}
|
|
10892
|
+
}
|
|
10893
|
+
},
|
|
10894
|
+
"BookingPropertyActionResponse": {
|
|
10895
|
+
"type": "object",
|
|
10896
|
+
"required": [
|
|
10897
|
+
"listingId",
|
|
10898
|
+
"channel",
|
|
10899
|
+
"action",
|
|
10900
|
+
"hotelId",
|
|
10901
|
+
"selling"
|
|
10902
|
+
],
|
|
10903
|
+
"properties": {
|
|
10904
|
+
"listingId": {
|
|
10905
|
+
"type": "string"
|
|
10906
|
+
},
|
|
10907
|
+
"channel": {
|
|
10908
|
+
"type": "string"
|
|
10909
|
+
},
|
|
10910
|
+
"action": {
|
|
10911
|
+
"type": "string"
|
|
10912
|
+
},
|
|
10913
|
+
"hotelId": {
|
|
10914
|
+
"type": "string",
|
|
10915
|
+
"description": "The Booking.com property that was acted on. Always read it back \u2014 a listing can be mapped to several, and this states which one changed."
|
|
10916
|
+
},
|
|
10917
|
+
"roomBookingId": {
|
|
10918
|
+
"type": "string",
|
|
10919
|
+
"nullable": true,
|
|
10920
|
+
"description": "Booking.com's own room id the availability write addressed."
|
|
10921
|
+
},
|
|
10922
|
+
"selling": {
|
|
10923
|
+
"type": "boolean",
|
|
10924
|
+
"description": "Whether the property is now on sale. **This is the state of the property on Booking.com, not of the listing in Repull** \u2014 `active` (what Repull bills and serves) is untouched by both actions and is deliberately not echoed here so the two can never be read as one field."
|
|
10925
|
+
}
|
|
10926
|
+
}
|
|
10927
|
+
},
|
|
10579
10928
|
"AirbnbDescriptionWriteRequest": {
|
|
10580
10929
|
"type": "object",
|
|
10581
10930
|
"required": [
|
|
@@ -11400,7 +11749,7 @@
|
|
|
11400
11749
|
}
|
|
11401
11750
|
},
|
|
11402
11751
|
"AirbnbWriteRejected": {
|
|
11403
|
-
"description": "The request was refused as sent; resending the same body will be refused again. Two cases:\n\n- `invalid_params` \u2014 the body failed validation before anything was sent to Airbnb. `field` names the offending field (e.g. `operations.0.max_nights`), `value_received` echoes it, and `fix` says what to send.\n- `airbnb_rejected` \u2014 Airbnb refused the change; `message` carries Airbnb's own reason.",
|
|
11752
|
+
"description": "The request was refused as sent; resending the same body will be refused again. Two cases:\n\n- `invalid_params` \u2014 the body failed validation before anything was sent to Airbnb. `field` names the offending field (e.g. `operations.0.max_nights`), `value_received` echoes it, and `fix` says what to send.\n- `airbnb_rejected` \u2014 Airbnb refused the change; `message` carries Airbnb's own reason.\n\n**This is the opposite answer to `502 airbnb_error`, not another name for it.** A refusal is permanent until you change the request; `airbnb_error` means Airbnb did not answer and the same request should be retried. Branch on that split rather than on \"Airbnb failed\".\n\nSome endpoints \u2014 reviews, messaging, the check-in guide, alteration answers and the Airbnb pull \u2014 used to report every Airbnb failure as `500 airbnb_error`, refusals included. They now classify like every other Airbnb write, and the responses whose code changed carry a deprecated `previous_code: \"airbnb_error\"` so an existing handler keeps matching while you migrate.",
|
|
11404
11753
|
"content": {
|
|
11405
11754
|
"application/json": {
|
|
11406
11755
|
"schema": {
|
|
@@ -11507,7 +11856,7 @@
|
|
|
11507
11856
|
}
|
|
11508
11857
|
},
|
|
11509
11858
|
"AirbnbUpstreamError": {
|
|
11510
|
-
"description": "Airbnb did not complete the request \u2014 an outage, timeout or server error on their side (`airbnb_error`). The request itself is fine: retry with exponential backoff.",
|
|
11859
|
+
"description": "Airbnb did not complete the request \u2014 an outage, timeout or server error on their side (`airbnb_error`). The request itself is fine: retry with exponential backoff.\n\n**`airbnb_error` never means Airbnb refused something.** A refusal is `422 airbnb_rejected` and retrying it cannot succeed; an expired or revoked grant is `403 connection_reauth_required` and retrying that cannot succeed either. If you have one branch for \"Airbnb failed\", split it here \u2014 this is the only one of the three where a retry is the right move.",
|
|
11511
11860
|
"content": {
|
|
11512
11861
|
"application/json": {
|
|
11513
11862
|
"schema": {
|
|
@@ -11544,6 +11893,26 @@
|
|
|
11544
11893
|
}
|
|
11545
11894
|
}
|
|
11546
11895
|
},
|
|
11896
|
+
"PublishBillingRefused": {
|
|
11897
|
+
"description": "The publish was refused for BILLING reasons and **nothing was sent to the channel**. Two codes:\n\n - `payment_required` \u2014 publishing a listing to a channel needs an active paid subscription. `upgrade_url` is where to start or restore it.\n - `channel_publish_limit_reached` \u2014 the plan's published-listing quota is full. `used` and `limit` say by how much. Take another listing off the channel to free a slot, or raise the quota.\n\nThis is not a channel fault, and the two things that fix a channel fault \u2014 retrying with backoff, reconnecting the channel \u2014 do nothing here. Once the billing state changes, send exactly the same request again; it is safe to repeat.\n\n**It applies to putting a listing back on the market as well as to publishing content.** Taking a listing down passes no billing gate and putting it back up does, so a lapsed subscription can leave a listing unlisted until billing is sorted out.",
|
|
11898
|
+
"content": {
|
|
11899
|
+
"application/json": {
|
|
11900
|
+
"schema": {
|
|
11901
|
+
"$ref": "#/components/schemas/Error"
|
|
11902
|
+
}
|
|
11903
|
+
}
|
|
11904
|
+
}
|
|
11905
|
+
},
|
|
11906
|
+
"ChannelActionUnavailable": {
|
|
11907
|
+
"description": "The action is not reachable from the API yet and the request was refused before it got to the channel (`channel_action_unavailable`). **Nothing was changed** \u2014 whatever you were acting on is in the state it was in before the call.\n\nThis is a gap on our side, not a problem with your request: there is nothing to correct and retrying returns the same answer until the gap is closed. `fix` names where the operation can be performed in the meantime.",
|
|
11908
|
+
"content": {
|
|
11909
|
+
"application/json": {
|
|
11910
|
+
"schema": {
|
|
11911
|
+
"$ref": "#/components/schemas/Error"
|
|
11912
|
+
}
|
|
11913
|
+
}
|
|
11914
|
+
}
|
|
11915
|
+
},
|
|
11547
11916
|
"TooManyRequests": {
|
|
11548
11917
|
"description": "Quota exceeded. Wait `retry_after` seconds (or until `X-RateLimit-Reset`) before retrying.",
|
|
11549
11918
|
"headers": {
|
|
@@ -12819,7 +13188,7 @@
|
|
|
12819
13188
|
"post": {
|
|
12820
13189
|
"operationId": "send_conversation_message",
|
|
12821
13190
|
"summary": "Send a message to the guest",
|
|
12822
|
-
"description": "Sends a message to the guest on this conversation and records it in the thread.\n\nOmit `channel` and the message goes out on whichever channel the conversation already uses (Airbnb, Booking.com, SMS, email or the direct-booking site) \u2014 that is the right default. Pass `channel` only to force a specific one.\n\nThe message is attributed to the API
|
|
13191
|
+
"description": "Sends a message to the guest on this conversation and records it in the thread.\n\nOmit `channel` and the message goes out on whichever channel the conversation already uses (Airbnb, Booking.com, SMS, email or the direct-booking site) \u2014 that is the right default. Pass `channel` only to force a specific one.\n\nThe message is attributed to the API: it is recorded with `aiGenerated` false so an API send is never counted as an automated reply.\n\n### Airbnb rewrites links \u2014 check `contentRewritten`\n\nAirbnb rejects guest messages containing a link, an email address or a phone number, and names the offending text. When that happens the offending fragment is stripped and the remainder is re-sent once, which means **the guest receives a message that is not the one you wrote**. Reporting that as a plain success would be a lie, so every response carries `contentRewritten`; when it is `true`, `deliveredContent` is the text that actually reached the guest. Check it before assuming your message went out verbatim.\n\nWhen the text cannot be salvaged (the link is most of the message) nothing is delivered and the call returns `422 message_not_sent` with the channel's verbatim refusal in `statusReason`.\n\nSend `Idempotency-Key` \u2014 without it, retrying after a network timeout sends the guest the same message twice.\n\n### Attachments\n\nSend files with `attachments: [{ url, contentType?, filename? }]` \u2014 public `https://` URLs, up to 5 per request, 10 MB each. `message` may be omitted when there are attachments (except on Booking.com). Repull downloads each file, reads its real type from the bytes, keeps a durable copy and delivers it through the channel's own file flow. **Every file is checked before anything is sent**: if one is unreachable, too large or of a type the channel refuses, the call returns 422 naming the file (`index`) and the guest receives nothing.\n\n| Channel | Accepted types | Text | How it arrives |\n|---|---|---|---|\n| Airbnb | JPEG, PNG, GIF, WebP (converted to JPEG), MP4, QuickTime | optional | each file as its own message, then the text as a separate message |\n| Booking.com | JPEG, PNG | **required** | one message carrying the text and every file |\n| SMS, email, direct-booking site chat | \u2014 | \u2014 | `422 attachments_not_supported`, nothing sent |\n\nAirbnb does not allow files in pre-booking (inquiry) conversations; that refusal comes back as `422 message_not_sent`. Because Airbnb delivers files one message at a time, a later file can be refused after earlier ones arrived \u2014 that returns `422 message_partially_sent` with `parts` saying exactly which messages reached the guest; resend only the rest.\n\nThe response's `attachments` lists each file's durable `url`, and `parts` lists every channel message the send produced. Read-back (`GET /v1/conversations/{id}/messages`) shows the same files in each message's `attachments`.\n\n**Inactive listings:** a conversation that belongs to an inactive listing returns `403 listing_inactive` and no message is sent. Activate the listing first.",
|
|
12823
13192
|
"tags": [
|
|
12824
13193
|
"Conversations"
|
|
12825
13194
|
],
|
|
@@ -14808,7 +15177,13 @@
|
|
|
14808
15177
|
"$ref": "#/components/responses/NotFound"
|
|
14809
15178
|
},
|
|
14810
15179
|
"422": {
|
|
14811
|
-
"$ref": "#/components/responses/
|
|
15180
|
+
"$ref": "#/components/responses/AirbnbWriteRejected"
|
|
15181
|
+
},
|
|
15182
|
+
"429": {
|
|
15183
|
+
"$ref": "#/components/responses/AirbnbRateLimited"
|
|
15184
|
+
},
|
|
15185
|
+
"502": {
|
|
15186
|
+
"$ref": "#/components/responses/AirbnbUpstreamError"
|
|
14812
15187
|
}
|
|
14813
15188
|
}
|
|
14814
15189
|
}
|
|
@@ -15699,7 +16074,7 @@
|
|
|
15699
16074
|
"post": {
|
|
15700
16075
|
"operationId": "airbnb_listing_action",
|
|
15701
16076
|
"summary": "Listing action (delete/push/publish/unlist/relist)",
|
|
15702
|
-
"description": "Apply a state action to a listing by id. The path `id` is the canonical Repull listing id.\n\n
|
|
16077
|
+
"description": "Apply a state action to a listing by id. The path `id` is the canonical Repull listing id.\n\n**`delete` here never touches Airbnb. Read this before you call it.**\n\n| | `action: \"delete\"` (this endpoint) | `action: \"unlist\"` (this endpoint) |\n|---|---|---|\n| What it changes | The Repull record | The live Airbnb listing |\n| Calls Airbnb | **No. Never.** | Yes |\n| The guest-facing listing | Stays live and keeps taking bookings | **Goes down** and stops taking bookings |\n| Billing and plan limits | No longer billed, no longer counts toward the cap | Unchanged |\n| API access to the listing | `403 listing_inactive` until reactivated | Unchanged \u2014 you can still read and write it |\n| Reverse it with | `PATCH /v1/listings/{id}` `{ \"active\": true }` | `action: \"relist\"` |\n| Data kept | Yes, and it keeps syncing | Yes |\n\nNeither one deletes anything on Airbnb. **There is no endpoint on this API that deletes an Airbnb listing** \u2014 the word `delete` on this route means \"deactivate the Repull record\" and nothing else. (Main vanio's internal listing-sync layer has a same-named action that DOES hard-delete on Airbnb; it is not exposed here, by any endpoint, deliberately. If you have read that code, note that the two names do not mean the same thing.)\n\n`delete` is idempotent. To take a listing off the market on every channel at once \u2014 Airbnb and Booking.com together \u2014 use `POST /v1/listings/{id}/offline`.\n\n`unlist` calls Airbnb and **takes the live listing down**: it is deactivated with a valid deactivation reason and then READ BACK, so \"Airbnb accepted the call but the listing is still live\" is reported as a failure rather than a success. Requires `airbnbConnectionId` \u2014 a listing can be connected to more than one Airbnb listing, and taking down the wrong one is not undoable through this API. `relist` puts it back up (re-enables sync and makes the listing available again); it does not push content.\n\n`relist` goes through the channel-publish billing gate and `unlist` does not, so on a workspace whose subscription has lapsed a listing can be taken down and not put back until billing is sorted out. That refusal comes back as `402` with the action that fixes it \u2014 never as an Airbnb error, because retrying and reconnecting Airbnb do nothing for it.\n\n`push` / `publish` push the listing's content to Airbnb via the same host-side sync orchestrator as `POST /v1/listings/{id}/publish/airbnb` \u2014 pass `airbnbConnectionId` to update an already-mapped Airbnb listing, or `hostId` to create + publish a new one under that host. `force` re-pushes every field, ignoring dirty-field tracking. The result is per-section: see `AirbnbPublishResult`.\n\nAny other action (e.g. `pull`) returns a structured 422 naming the supported actions.\n\nReturns `403 listing_inactive` for `push`/`publish`/`unlist`/`relist` when the listing is inactive. `delete` (deactivation) is always accepted.",
|
|
15703
16078
|
"tags": [
|
|
15704
16079
|
"Airbnb"
|
|
15705
16080
|
],
|
|
@@ -15770,6 +16145,9 @@
|
|
|
15770
16145
|
}
|
|
15771
16146
|
}
|
|
15772
16147
|
},
|
|
16148
|
+
"402": {
|
|
16149
|
+
"$ref": "#/components/responses/PublishBillingRefused"
|
|
16150
|
+
},
|
|
15773
16151
|
"403": {
|
|
15774
16152
|
"$ref": "#/components/responses/AirbnbWriteForbidden"
|
|
15775
16153
|
},
|
|
@@ -16475,7 +16853,7 @@
|
|
|
16475
16853
|
"post": {
|
|
16476
16854
|
"operationId": "send_airbnb_message",
|
|
16477
16855
|
"summary": "Send Airbnb message",
|
|
16478
|
-
"description": "Send a message in an Airbnb thread as the host. Airbnb enforces content rules (no off-platform contact info, no external URLs) \u2014 violating messages are rejected upstream and surface as `airbnb_error
|
|
16856
|
+
"description": "Send a message in an Airbnb thread as the host. Airbnb enforces content rules (no off-platform contact info, no external URLs) \u2014 violating messages are rejected upstream and surface as `422 airbnb_rejected` carrying Airbnb's own reason. Resending the same text is refused again; edit it first. `502 airbnb_error` is the other answer and means something else entirely: Airbnb did not complete the send, so retry it unchanged.\n\n### Sending a photo or video (`mediaUrl`)\n\nAirbnb only accepts media uploaded to a signed URL it issues, one file per message and no text on the same message. With `mediaUrl`, Repull downloads the file (public `https://` only, 10 MB max), reads its real type from the bytes (JPEG, PNG, GIF, WebP \u2014 converted to JPEG \u2014 or MP4/QuickTime), uploads it to Airbnb and sends it; `message`, if given, follows as a separate message. This is the same flow as `POST /v1/conversations/{id}/messages` with `attachments` \u2014 prefer that endpoint, which also takes several files per request. The response is a `SendMessageResponse`, the send is recorded in the conversation, and failures are the 422 codes documented there (`attachment_type_not_supported`, `attachment_too_large`, `message_not_sent` for a pre-booking thread, \u2026). The thread must already be synced to Repull (`GET /v1/conversations` lists them), otherwise `404`.\n\nText-only sends (no `mediaUrl`) go straight to Airbnb and return Airbnb's message object.\n\nThe `{threadId}` is the Airbnb thread id \u2014 the `externalThreadId` field on a unified `Conversation` (`GET /v1/conversations`).\n\nReturns `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.",
|
|
16479
16857
|
"tags": [
|
|
16480
16858
|
"Airbnb"
|
|
16481
16859
|
],
|
|
@@ -16548,17 +16926,16 @@
|
|
|
16548
16926
|
"$ref": "#/components/responses/NotFound"
|
|
16549
16927
|
},
|
|
16550
16928
|
"422": {
|
|
16551
|
-
"
|
|
16552
|
-
|
|
16553
|
-
|
|
16554
|
-
|
|
16555
|
-
"$ref": "#/components/schemas/Error"
|
|
16556
|
-
}
|
|
16557
|
-
}
|
|
16558
|
-
}
|
|
16929
|
+
"$ref": "#/components/responses/AirbnbWriteRejected"
|
|
16930
|
+
},
|
|
16931
|
+
"429": {
|
|
16932
|
+
"$ref": "#/components/responses/AirbnbRateLimited"
|
|
16559
16933
|
},
|
|
16560
16934
|
"500": {
|
|
16561
16935
|
"$ref": "#/components/responses/InternalError"
|
|
16936
|
+
},
|
|
16937
|
+
"502": {
|
|
16938
|
+
"$ref": "#/components/responses/AirbnbUpstreamError"
|
|
16562
16939
|
}
|
|
16563
16940
|
}
|
|
16564
16941
|
}
|
|
@@ -16707,7 +17084,7 @@
|
|
|
16707
17084
|
"post": {
|
|
16708
17085
|
"operationId": "airbnb_reservation_action",
|
|
16709
17086
|
"summary": "Accept, decline or cancel an Airbnb reservation",
|
|
16710
|
-
"description": "Act on an Airbnb reservation by its Airbnb confirmation code. **Write-side** \u2014 calls Airbnb upstream, as the Airbnb account that owns the booking.\n\n- `accept` \u2014 accept a pending booking request.\n- `decline` \u2014 decline a pending booking request. Requires `reason` (one of Airbnb's decline reasons) and `message` (sent to the guest, at most 500 characters).\n- `cancel` \u2014 cancel a confirmed booking as the host. Requires `reason` (one of Airbnb's host-cancellation reasons). **Host cancellations carry Airbnb penalties.**\n\nThe body is validated before anything reaches Airbnb; unknown fields are refused. There is no `pre-approve` action: a pre-approval answers an inquiry, which has no confirmation code \u2014 use `POST /v1/conversations/{id}/pre-approval`. For accept/decline, `POST /v1/reservations/{id}/accept` and `/decline` do the same by Repull id and
|
|
17087
|
+
"description": "Act on an Airbnb reservation by its Airbnb confirmation code. **Write-side** \u2014 calls Airbnb upstream, as the Airbnb account that owns the booking.\n\n- `accept` \u2014 accept a pending booking request.\n- `decline` \u2014 decline a pending booking request. Requires `reason` (one of Airbnb's decline reasons) and `message` (sent to the guest, at most 500 characters).\n- `cancel` \u2014 cancel a confirmed booking as the host. Requires `reason` (one of Airbnb's host-cancellation reasons). **Host cancellations carry Airbnb penalties.**\n\nThe body is validated before anything reaches Airbnb; unknown fields are refused. There is no `pre-approve` action: a pre-approval answers an inquiry, which has no confirmation code \u2014 use `POST /v1/conversations/{id}/pre-approval`. For accept/decline, `POST /v1/reservations/{id}/accept` and `/decline` do the same by Repull id and keep the reservation in Repull in sync.\n\nAirbnb refusals are mapped rather than returned as a 500: a request that already moved on is `409 request_no_longer_pending` (do not retry), an expired one `409 request_expired`, any other refusal `422 airbnb_rejected` with Airbnb's reason.\n\nReturns `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.\n\nSend `Idempotency-Key` to make a retry safe.",
|
|
16711
17088
|
"tags": [
|
|
16712
17089
|
"Airbnb"
|
|
16713
17090
|
],
|
|
@@ -17065,6 +17442,15 @@
|
|
|
17065
17442
|
},
|
|
17066
17443
|
"403": {
|
|
17067
17444
|
"$ref": "#/components/responses/ListingInactive"
|
|
17445
|
+
},
|
|
17446
|
+
"422": {
|
|
17447
|
+
"$ref": "#/components/responses/AirbnbWriteRejected"
|
|
17448
|
+
},
|
|
17449
|
+
"429": {
|
|
17450
|
+
"$ref": "#/components/responses/AirbnbRateLimited"
|
|
17451
|
+
},
|
|
17452
|
+
"502": {
|
|
17453
|
+
"$ref": "#/components/responses/AirbnbUpstreamError"
|
|
17068
17454
|
}
|
|
17069
17455
|
}
|
|
17070
17456
|
}
|
|
@@ -17119,10 +17505,16 @@
|
|
|
17119
17505
|
"$ref": "#/components/responses/NotFound"
|
|
17120
17506
|
},
|
|
17121
17507
|
"422": {
|
|
17122
|
-
"$ref": "#/components/responses/
|
|
17508
|
+
"$ref": "#/components/responses/AirbnbWriteRejected"
|
|
17509
|
+
},
|
|
17510
|
+
"429": {
|
|
17511
|
+
"$ref": "#/components/responses/AirbnbRateLimited"
|
|
17123
17512
|
},
|
|
17124
17513
|
"500": {
|
|
17125
17514
|
"$ref": "#/components/responses/InternalError"
|
|
17515
|
+
},
|
|
17516
|
+
"502": {
|
|
17517
|
+
"$ref": "#/components/responses/AirbnbUpstreamError"
|
|
17126
17518
|
}
|
|
17127
17519
|
}
|
|
17128
17520
|
}
|
|
@@ -17187,10 +17579,16 @@
|
|
|
17187
17579
|
"$ref": "#/components/responses/NotFound"
|
|
17188
17580
|
},
|
|
17189
17581
|
"422": {
|
|
17190
|
-
"$ref": "#/components/responses/
|
|
17582
|
+
"$ref": "#/components/responses/AirbnbWriteRejected"
|
|
17583
|
+
},
|
|
17584
|
+
"429": {
|
|
17585
|
+
"$ref": "#/components/responses/AirbnbRateLimited"
|
|
17191
17586
|
},
|
|
17192
17587
|
"500": {
|
|
17193
17588
|
"$ref": "#/components/responses/InternalError"
|
|
17589
|
+
},
|
|
17590
|
+
"502": {
|
|
17591
|
+
"$ref": "#/components/responses/AirbnbUpstreamError"
|
|
17194
17592
|
}
|
|
17195
17593
|
}
|
|
17196
17594
|
}
|
|
@@ -17424,8 +17822,17 @@
|
|
|
17424
17822
|
"404": {
|
|
17425
17823
|
"$ref": "#/components/responses/NotFound"
|
|
17426
17824
|
},
|
|
17825
|
+
"422": {
|
|
17826
|
+
"$ref": "#/components/responses/AirbnbWriteRejected"
|
|
17827
|
+
},
|
|
17828
|
+
"429": {
|
|
17829
|
+
"$ref": "#/components/responses/AirbnbRateLimited"
|
|
17830
|
+
},
|
|
17427
17831
|
"500": {
|
|
17428
17832
|
"$ref": "#/components/responses/InternalError"
|
|
17833
|
+
},
|
|
17834
|
+
"502": {
|
|
17835
|
+
"$ref": "#/components/responses/AirbnbUpstreamError"
|
|
17429
17836
|
}
|
|
17430
17837
|
}
|
|
17431
17838
|
}
|
|
@@ -17474,8 +17881,17 @@
|
|
|
17474
17881
|
"404": {
|
|
17475
17882
|
"$ref": "#/components/responses/NotFound"
|
|
17476
17883
|
},
|
|
17884
|
+
"422": {
|
|
17885
|
+
"$ref": "#/components/responses/AirbnbWriteRejected"
|
|
17886
|
+
},
|
|
17887
|
+
"429": {
|
|
17888
|
+
"$ref": "#/components/responses/AirbnbRateLimited"
|
|
17889
|
+
},
|
|
17477
17890
|
"500": {
|
|
17478
17891
|
"$ref": "#/components/responses/InternalError"
|
|
17892
|
+
},
|
|
17893
|
+
"502": {
|
|
17894
|
+
"$ref": "#/components/responses/AirbnbUpstreamError"
|
|
17479
17895
|
}
|
|
17480
17896
|
}
|
|
17481
17897
|
}
|
|
@@ -17741,10 +18157,16 @@
|
|
|
17741
18157
|
"$ref": "#/components/responses/NotFound"
|
|
17742
18158
|
},
|
|
17743
18159
|
"422": {
|
|
17744
|
-
"$ref": "#/components/responses/
|
|
18160
|
+
"$ref": "#/components/responses/AirbnbWriteRejected"
|
|
18161
|
+
},
|
|
18162
|
+
"429": {
|
|
18163
|
+
"$ref": "#/components/responses/AirbnbRateLimited"
|
|
17745
18164
|
},
|
|
17746
18165
|
"500": {
|
|
17747
18166
|
"$ref": "#/components/responses/InternalError"
|
|
18167
|
+
},
|
|
18168
|
+
"502": {
|
|
18169
|
+
"$ref": "#/components/responses/AirbnbUpstreamError"
|
|
17748
18170
|
}
|
|
17749
18171
|
}
|
|
17750
18172
|
}
|
|
@@ -18084,8 +18506,17 @@
|
|
|
18084
18506
|
"404": {
|
|
18085
18507
|
"$ref": "#/components/responses/NotFound"
|
|
18086
18508
|
},
|
|
18509
|
+
"422": {
|
|
18510
|
+
"$ref": "#/components/responses/AirbnbWriteRejected"
|
|
18511
|
+
},
|
|
18512
|
+
"429": {
|
|
18513
|
+
"$ref": "#/components/responses/AirbnbRateLimited"
|
|
18514
|
+
},
|
|
18087
18515
|
"500": {
|
|
18088
18516
|
"$ref": "#/components/responses/InternalError"
|
|
18517
|
+
},
|
|
18518
|
+
"502": {
|
|
18519
|
+
"$ref": "#/components/responses/AirbnbUpstreamError"
|
|
18089
18520
|
}
|
|
18090
18521
|
}
|
|
18091
18522
|
}
|
|
@@ -20161,7 +20592,7 @@
|
|
|
20161
20592
|
"post": {
|
|
20162
20593
|
"operationId": "publishListingToAirbnb",
|
|
20163
20594
|
"summary": "Publish a listing to Airbnb",
|
|
20164
|
-
"description": "Push a Repull listing's canonical content to Airbnb. Pass `airbnbConnectionId` to update an already-mapped Airbnb listing, or `hostId` to create a brand-new Airbnb listing under that host.\n\n**A publish is not one call to Airbnb.** It is up to eight independent ones \u2014 details, description, amenities, rooms, policies, photos, pricing, checkout_tasks \u2014 and each can fail on its own. `result.published` is true only when every attempted section landed; `result.sections` lists the ones that did and `result.errors[]` carries Airbnb's own reason, per section, for the ones that did not. **A partial publish is normal and is not rolled back**: what succeeded stays applied. Publish again once you have fixed the failing sections \u2014 a re-publish of an unchanged section is harmless.\n\n`result.lockedFields` names the fields Airbnb will not let this listing change at all. They are not retryable by anyone: Airbnb answers 200 and applies nothing. `GET /v1/channels/airbnb/listings/{id}` reports the same list up front.\n\n**Which fields this pushes** \u2014 title, description sections and house rules (English/primary locale), amenities, rooms and beds, photos, nightly price and fees, cancellation policy and guest controls, check-in/out times, quiet hours, property and room type, checkout tasks. **Not pushed by this endpoint:** non-primary locales (`PUT /v1/channels/airbnb/listings/{id}/descriptions`), guest-safety disclosures (`PUT \u2026/safety-disclosures`), check-in method (`PUT \u2026/details`), permits (`PUT \u2026/permits`), and the calendar (`PUT \u2026/availability`).\n\n`force: true` re-pushes every section, ignoring dirty-field tracking. Without it only the sections changed since the last successful publish are sent.\n\nSend `Idempotency-Key` to make a retry safe: a timeout on a publish otherwise leaves you unable to tell whether it ran.\n\nReturns `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.",
|
|
20595
|
+
"description": "Push a Repull listing's canonical content to Airbnb. Pass `airbnbConnectionId` to update an already-mapped Airbnb listing, or `hostId` to create a brand-new Airbnb listing under that host.\n\n**A publish is not one call to Airbnb.** It is up to eight independent ones \u2014 details, description, amenities, rooms, policies, photos, pricing, checkout_tasks \u2014 and each can fail on its own. `result.published` is true only when every attempted section landed; `result.sections` lists the ones that did and `result.errors[]` carries Airbnb's own reason, per section, for the ones that did not. **A partial publish is normal and is not rolled back**: what succeeded stays applied. Publish again once you have fixed the failing sections \u2014 a re-publish of an unchanged section is harmless.\n\n`result.live` is a different question from `result.published`. `published` is about CONTENT \u2014 every attempted section landed. `live` is about whether the listing takes bookings: it is true only when activation was actually performed and succeeded. A create can land all eight sections and still leave the listing inactive, because activation is skipped when instant-booking cannot be confirmed to be off \u2014 so `published: true` with `live: false` is a real and common outcome, and `result.warnings` says why. `live` is ABSENT, not `false`, when activation was never part of the operation: publishing to an already-mapped listing updates content and activates nothing. Only treat a listing as not-live when `live` is present and false.\n\n`result.warnings[]` lists steps that failed WITHOUT failing the publish \u2014 optional work the push carried on past. They were previously swallowed, so the only sign of one was a listing that was somehow not quite right afterwards. A publish can be `published: true` and still carry warnings; read them before concluding nothing needs doing.\n\n`result.lockedFields` names the fields Airbnb will not let this listing change at all. They are not retryable by anyone: Airbnb answers 200 and applies nothing. `GET /v1/channels/airbnb/listings/{id}` reports the same list up front.\n\n**Which fields this pushes** \u2014 title, description sections and house rules (English/primary locale), amenities, rooms and beds, photos, nightly price and fees, cancellation policy and guest controls, check-in/out times, quiet hours, property and room type, checkout tasks. **Not pushed by this endpoint:** non-primary locales (`PUT /v1/channels/airbnb/listings/{id}/descriptions`), guest-safety disclosures (`PUT \u2026/safety-disclosures`), check-in method (`PUT \u2026/details`), permits (`PUT \u2026/permits`), and the calendar (`PUT \u2026/availability`).\n\n`force: true` re-pushes every section, ignoring dirty-field tracking. Without it only the sections changed since the last successful publish are sent.\n\nSend `Idempotency-Key` to make a retry safe: a timeout on a publish otherwise leaves you unable to tell whether it ran.\n\nReturns `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.",
|
|
20165
20596
|
"tags": [
|
|
20166
20597
|
"Listings"
|
|
20167
20598
|
],
|
|
@@ -20201,6 +20632,9 @@
|
|
|
20201
20632
|
"400": {
|
|
20202
20633
|
"$ref": "#/components/responses/BadRequest"
|
|
20203
20634
|
},
|
|
20635
|
+
"402": {
|
|
20636
|
+
"$ref": "#/components/responses/PublishBillingRefused"
|
|
20637
|
+
},
|
|
20204
20638
|
"403": {
|
|
20205
20639
|
"$ref": "#/components/responses/ListingInactive"
|
|
20206
20640
|
},
|
|
@@ -20214,7 +20648,7 @@
|
|
|
20214
20648
|
"post": {
|
|
20215
20649
|
"operationId": "publishListingToBooking",
|
|
20216
20650
|
"summary": "Publish a listing to Booking.com",
|
|
20217
|
-
"description": "Push a Repull listing to Booking.com. The listing must already be mapped to a Booking property + room
|
|
20651
|
+
"description": "Push a Repull listing's content to Booking.com. The listing must already be mapped to a Booking.com property + room \u2014 claim the hotel through the Connect Booking flow, then map its rooms with `POST /v1/connect/booking/map-rooms`.\n\n**Which property the content lands in.** A listing can be mapped to more than one Booking.com property; the same unit re-listed under a new property keeps its old mapping, and workspaces routinely sit on five or six. When the listing has exactly one property you need send nothing. When it has several, name one with `hotelId` in the body (or `?hotel_id=` \u2014 the same value, accepted either way, body wins if you send both). Omit it on such a listing and the push is refused with **`409 ambiguous_booking_mapping`**, listing the candidate ids: content pushed into a property chosen for you lands on the wrong listing and reports success, which is worse than a refusal. `GET /v1/channels/booking/properties` lists every property with the listings mapped under it. Naming a property this listing is not mapped to is a `404` that names the ones it is.\n\nThe property that actually received the content comes back as `result.hotelId`.\n\n**A publish is not one call to Booking.com.** It is several independent Content API calls \u2014 details, description, amenities, rooms, photos, pricing \u2014 and each can fail on its own. `result.published` is true only when every attempted section landed; `result.sections` lists the ones that did and `result.errors[]` carries Booking.com's own reason, per section, for the ones that did not. A property whose Content API credentials do not cover a section answers 403 for that section alone. **A partial publish is normal and is not rolled back**: what succeeded stays applied. Fix the failing sections and publish again \u2014 re-publishing an unchanged section is harmless.\n\nA listing with no Booking.com property mapped at all is not an error: the call returns `result.published: false` with `result.reason` and `result.hotelId: null`, and nothing is pushed.\n\nReturns `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.",
|
|
20218
20652
|
"tags": [
|
|
20219
20653
|
"Listings"
|
|
20220
20654
|
],
|
|
@@ -20225,16 +20659,36 @@
|
|
|
20225
20659
|
"required": true,
|
|
20226
20660
|
"schema": {
|
|
20227
20661
|
"type": "integer"
|
|
20228
|
-
}
|
|
20662
|
+
},
|
|
20663
|
+
"description": "Repull listing id \u2014 NOT a Booking.com hotel id."
|
|
20664
|
+
},
|
|
20665
|
+
{
|
|
20666
|
+
"name": "hotel_id",
|
|
20667
|
+
"in": "query",
|
|
20668
|
+
"required": false,
|
|
20669
|
+
"schema": {
|
|
20670
|
+
"type": "string"
|
|
20671
|
+
},
|
|
20672
|
+
"description": "Booking.com property to publish into, for a listing mapped to more than one. The query-string spelling of the body's `hotelId`, accepted so this route reads the same as every other Booking listing-addressed route. The body wins when both are sent."
|
|
20229
20673
|
}
|
|
20230
20674
|
],
|
|
20675
|
+
"requestBody": {
|
|
20676
|
+
"required": false,
|
|
20677
|
+
"content": {
|
|
20678
|
+
"application/json": {
|
|
20679
|
+
"schema": {
|
|
20680
|
+
"$ref": "#/components/schemas/ListingPublishBookingRequest"
|
|
20681
|
+
}
|
|
20682
|
+
}
|
|
20683
|
+
}
|
|
20684
|
+
},
|
|
20231
20685
|
"responses": {
|
|
20232
20686
|
"200": {
|
|
20233
|
-
"description": "
|
|
20687
|
+
"description": "Publish attempted \u2014 read `result.published`, `result.errors` and `result.hotelId`",
|
|
20234
20688
|
"content": {
|
|
20235
20689
|
"application/json": {
|
|
20236
20690
|
"schema": {
|
|
20237
|
-
"$ref": "#/components/schemas/
|
|
20691
|
+
"$ref": "#/components/schemas/ListingPublishBookingResponse"
|
|
20238
20692
|
}
|
|
20239
20693
|
}
|
|
20240
20694
|
}
|
|
@@ -20242,8 +20696,17 @@
|
|
|
20242
20696
|
"400": {
|
|
20243
20697
|
"$ref": "#/components/responses/BadRequest"
|
|
20244
20698
|
},
|
|
20699
|
+
"402": {
|
|
20700
|
+
"$ref": "#/components/responses/PublishBillingRefused"
|
|
20701
|
+
},
|
|
20245
20702
|
"403": {
|
|
20246
20703
|
"$ref": "#/components/responses/ListingInactive"
|
|
20704
|
+
},
|
|
20705
|
+
"404": {
|
|
20706
|
+
"$ref": "#/components/responses/NotFound"
|
|
20707
|
+
},
|
|
20708
|
+
"409": {
|
|
20709
|
+
"$ref": "#/components/responses/Conflict"
|
|
20247
20710
|
}
|
|
20248
20711
|
}
|
|
20249
20712
|
}
|
|
@@ -20252,7 +20715,7 @@
|
|
|
20252
20715
|
"get": {
|
|
20253
20716
|
"operationId": "getListingPublishStatus",
|
|
20254
20717
|
"summary": "Per-channel publish status",
|
|
20255
|
-
"description": "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 \u2014 for bulk views, prefer `GET /v1/listings` and filter client-side.\n\nReturns `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.",
|
|
20718
|
+
"description": "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 \u2014 for bulk views, prefer `GET /v1/listings` and filter client-side.\n\n**When a push fails, this endpoint says why.** `channels[].pushError` carries the channel's own reason for the last failed push, verbatim \u2014 `\"Links and contact info can't be shared\"`, `\"Check-in start time must be before end time\"`, `\"property_type_group must be one of [\u2026]\"`. 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.\n\n**It also says what you will not be allowed to change.** The `airbnb` entry in `connections` carries `lockedFields` \u2014 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.\n\nReturns `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.",
|
|
20256
20719
|
"tags": [
|
|
20257
20720
|
"Listings"
|
|
20258
20721
|
],
|
|
@@ -21175,13 +21638,52 @@
|
|
|
21175
21638
|
"$ref": "#/components/responses/InternalError"
|
|
21176
21639
|
}
|
|
21177
21640
|
}
|
|
21178
|
-
}
|
|
21179
|
-
},
|
|
21180
|
-
"/v1/channels/booking/properties/{id}": {
|
|
21181
|
-
"get": {
|
|
21182
|
-
"operationId": "get_booking_property",
|
|
21183
|
-
"summary": "Get Booking.com connection for a listing",
|
|
21184
|
-
"description": "Return the Booking.com connection record(s) for a Repull listing \u2014 the linked Booking hotel id, sync flags, markup, sync category, suspension state, and the Booking room the mapping runs through.\n\n`id` is a **Repull listing id**, not a Booking.com hotel id, despite the `properties` segment. (The hotel-id surface is `/v1/channels/booking/availability`.) The mapping is read from wherever the Connect flow recorded it \u2014 `listings_booking_rooms` for anything mapped through `POST /v1/connect/booking/map-rooms`, which is essentially every live mapping.\n\nAn ARRAY, because one listing can be published under several Booking.com properties at once; `mappedVia` says which record carries each mapping. A listing with no Booking.com mapping returns 404, and the message says which id space the path takes.\n\nReturns `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.",
|
|
21641
|
+
}
|
|
21642
|
+
},
|
|
21643
|
+
"/v1/channels/booking/properties/{id}": {
|
|
21644
|
+
"get": {
|
|
21645
|
+
"operationId": "get_booking_property",
|
|
21646
|
+
"summary": "Get Booking.com connection for a listing",
|
|
21647
|
+
"description": "Return the Booking.com connection record(s) for a Repull listing \u2014 the linked Booking hotel id, sync flags, markup, sync category, suspension state, and the Booking room the mapping runs through.\n\n`id` is a **Repull listing id**, not a Booking.com hotel id, despite the `properties` segment. (The hotel-id surface is `/v1/channels/booking/availability`.) The mapping is read from wherever the Connect flow recorded it \u2014 `listings_booking_rooms` for anything mapped through `POST /v1/connect/booking/map-rooms`, which is essentially every live mapping.\n\nAn ARRAY, because one listing can be published under several Booking.com properties at once; `mappedVia` says which record carries each mapping. A listing with no Booking.com mapping returns 404, and the message says which id space the path takes.\n\nReturns `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.",
|
|
21648
|
+
"tags": [
|
|
21649
|
+
"Booking.com"
|
|
21650
|
+
],
|
|
21651
|
+
"parameters": [
|
|
21652
|
+
{
|
|
21653
|
+
"name": "id",
|
|
21654
|
+
"in": "path",
|
|
21655
|
+
"required": true,
|
|
21656
|
+
"schema": {
|
|
21657
|
+
"type": "integer"
|
|
21658
|
+
},
|
|
21659
|
+
"description": "Repull listing id \u2014 NOT a Booking.com hotel id."
|
|
21660
|
+
}
|
|
21661
|
+
],
|
|
21662
|
+
"responses": {
|
|
21663
|
+
"200": {
|
|
21664
|
+
"description": "Booking.com connection rows"
|
|
21665
|
+
},
|
|
21666
|
+
"400": {
|
|
21667
|
+
"$ref": "#/components/responses/BadRequest"
|
|
21668
|
+
},
|
|
21669
|
+
"401": {
|
|
21670
|
+
"$ref": "#/components/responses/Unauthorized"
|
|
21671
|
+
},
|
|
21672
|
+
"403": {
|
|
21673
|
+
"$ref": "#/components/responses/ListingInactive"
|
|
21674
|
+
},
|
|
21675
|
+
"404": {
|
|
21676
|
+
"$ref": "#/components/responses/NotFound"
|
|
21677
|
+
},
|
|
21678
|
+
"500": {
|
|
21679
|
+
"$ref": "#/components/responses/InternalError"
|
|
21680
|
+
}
|
|
21681
|
+
}
|
|
21682
|
+
},
|
|
21683
|
+
"post": {
|
|
21684
|
+
"operationId": "booking_property_action",
|
|
21685
|
+
"summary": "Take a property off sale / put it back (unlist/relist)",
|
|
21686
|
+
"description": "Stop this listing's Booking.com property being sold, or start it again. `id` is a **Repull listing id**, not a Booking.com hotel id, as on the GET.\n\n**Booking.com has no unlist, so this is an availability write.** Airbnb has a real deactivate; Booking.com does not. `unlist` closes the mapped room across the whole forward window, so the property stops selling. `relist` is not its mirror image: it re-syncs the true calendar, so dates that are genuinely blocked (a reservation, an owner stay) stay blocked and only the closure `unlist` wrote lifts. Re-opening everything would sell dates that are not for sale.\n\n**Which property gets closed.** A listing can be mapped to more than one Booking.com property \u2014 the same unit re-listed under a new property keeps its old mapping, and workspaces routinely sit on five or six. With exactly one, send nothing. With several, name one with `hotelId` (or `?hotel_id=`); omit it and the request is refused with **`409 ambiguous_booking_mapping`** listing the candidates, and nothing is written. That refusal matters more here than on a publish: writing content into the wrong property is recoverable, closing the wrong property's availability takes real inventory off sale while the property you meant keeps selling. Naming a property this listing is not mapped to is a `404` that names the ones it is.\n\n**This does not change the listing in Repull.** `active` \u2014 what Repull bills and serves \u2014 is untouched by both actions and is deliberately not echoed in the response, so the two ideas can never be read as one field. To take a listing off the market on every channel at once, use `POST /v1/listings/{id}/offline`.\n\nAny other action returns a structured `422` naming the ones that are supported. To push content use `POST /v1/listings/{id}/publish/booking`; to map rooms use `POST /v1/connect/booking/map-rooms`.\n\nReturns `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.",
|
|
21185
21687
|
"tags": [
|
|
21186
21688
|
"Booking.com"
|
|
21187
21689
|
],
|
|
@@ -21194,11 +21696,40 @@
|
|
|
21194
21696
|
"type": "integer"
|
|
21195
21697
|
},
|
|
21196
21698
|
"description": "Repull listing id \u2014 NOT a Booking.com hotel id."
|
|
21699
|
+
},
|
|
21700
|
+
{
|
|
21701
|
+
"name": "hotel_id",
|
|
21702
|
+
"in": "query",
|
|
21703
|
+
"required": false,
|
|
21704
|
+
"schema": {
|
|
21705
|
+
"type": "string"
|
|
21706
|
+
},
|
|
21707
|
+
"description": "Booking.com property to act on, for a listing mapped to more than one. The query-string spelling of the body's `hotelId`; the body wins when both are sent."
|
|
21708
|
+
},
|
|
21709
|
+
{
|
|
21710
|
+
"$ref": "#/components/parameters/IdempotencyKey"
|
|
21197
21711
|
}
|
|
21198
21712
|
],
|
|
21713
|
+
"requestBody": {
|
|
21714
|
+
"required": true,
|
|
21715
|
+
"content": {
|
|
21716
|
+
"application/json": {
|
|
21717
|
+
"schema": {
|
|
21718
|
+
"$ref": "#/components/schemas/BookingPropertyActionRequest"
|
|
21719
|
+
}
|
|
21720
|
+
}
|
|
21721
|
+
}
|
|
21722
|
+
},
|
|
21199
21723
|
"responses": {
|
|
21200
21724
|
"200": {
|
|
21201
|
-
"description": "
|
|
21725
|
+
"description": "Done \u2014 `hotelId` names the property that changed and `selling` says whether it is now on sale",
|
|
21726
|
+
"content": {
|
|
21727
|
+
"application/json": {
|
|
21728
|
+
"schema": {
|
|
21729
|
+
"$ref": "#/components/schemas/BookingPropertyActionResponse"
|
|
21730
|
+
}
|
|
21731
|
+
}
|
|
21732
|
+
}
|
|
21202
21733
|
},
|
|
21203
21734
|
"400": {
|
|
21204
21735
|
"$ref": "#/components/responses/BadRequest"
|
|
@@ -21206,14 +21737,29 @@
|
|
|
21206
21737
|
"401": {
|
|
21207
21738
|
"$ref": "#/components/responses/Unauthorized"
|
|
21208
21739
|
},
|
|
21740
|
+
"402": {
|
|
21741
|
+
"$ref": "#/components/responses/PublishBillingRefused"
|
|
21742
|
+
},
|
|
21209
21743
|
"403": {
|
|
21210
21744
|
"$ref": "#/components/responses/ListingInactive"
|
|
21211
21745
|
},
|
|
21212
21746
|
"404": {
|
|
21213
21747
|
"$ref": "#/components/responses/NotFound"
|
|
21214
21748
|
},
|
|
21749
|
+
"409": {
|
|
21750
|
+
"$ref": "#/components/responses/Conflict"
|
|
21751
|
+
},
|
|
21752
|
+
"422": {
|
|
21753
|
+
"$ref": "#/components/responses/BookingWriteRejected"
|
|
21754
|
+
},
|
|
21215
21755
|
"500": {
|
|
21216
21756
|
"$ref": "#/components/responses/InternalError"
|
|
21757
|
+
},
|
|
21758
|
+
"502": {
|
|
21759
|
+
"$ref": "#/components/responses/BookingUpstreamError"
|
|
21760
|
+
},
|
|
21761
|
+
"503": {
|
|
21762
|
+
"$ref": "#/components/responses/ChannelActionUnavailable"
|
|
21217
21763
|
}
|
|
21218
21764
|
}
|
|
21219
21765
|
}
|
|
@@ -21351,7 +21897,7 @@
|
|
|
21351
21897
|
"post": {
|
|
21352
21898
|
"operationId": "booking_setup",
|
|
21353
21899
|
"summary": "Booking.com property setup actions",
|
|
21354
|
-
"description": "Action-router for
|
|
21900
|
+
"description": "Action-router for putting a property onto Booking.com \u2014 including building one from nothing. Select the step with `action`.\n\n## Opening a property\n\n- `create-property` \u2014 create a NEW Booking.com property for a Repull listing (`listing_id`). Creates the property, its first room, a rate plan and the room-rate product that makes the room sellable, seeds availability and rates, syncs the calendar, then sends the notification that starts Booking's validation. Returns 201.\n- `add-room` \u2014 add another room type (and its sellable product) to a property (`listing_id`, `property_id`). Returns 201.\n- `add-unit` \u2014 raise the number of identical units on an existing room (`listing_id`, `property_id`, `room_id`).\n- `advance` \u2014 re-send the summary notification for a property (`property_id`) to move it out of the \"XML: Being built\" stage.\n\n## Account and policy steps\n\n- `create-legal-entity` \u2014 register a legal entity directly (returns 201). Not normally needed: see the legal-entity rules below.\n- `check-legal-status` \u2014 always `404`. A legal entity's details are readable for any id on the connectivity-provider credentials every workspace shares, and nothing records which workspace registered which entity, so no entity can be shown to be yours. `create-property` resolves it for you.\n- `check-readiness` \u2014 check whether a property is ready to open (`property_id`).\n- `open-property` \u2014 open the property for sale (`property_id`).\n- `set-contacts` \u2014 set property contacts (`property_id`, `contacts`).\n- `set-policies` \u2014 set property policies (`property_id`, plus policy fields).\n\n## Three things about Booking.com that cost real money\n\n**A newly created property is NOT sellable.** Booking holds it at \"XML: Being built\" until it validates the summary notification. `create-property` sends that notification, but it can fail on its own after everything else succeeded \u2014 the response always reports `status: \"being_built\"` and `sellable: false`, never a guess. Use `advance` to re-send it, and check the Extranet for the stage.\n\n**A room with no ACTIVE rate plan is invisible.** Booking only renders rooms that have at least one active product linkage (room \u00d7 rate plan). A room can be created successfully, return a `roomId`, and never appear on the property page. If `rateId` comes back `null` from `create-property` or `add-room`, that is exactly what happened: activate a rate plan on the property in the Extranet, then add the room again.\n\n**The room name is shown to travellers.** It is taken from the listing's name and appears on the Booking.com property page. Internal nicknames belong on the property's partner reference, not on the room.\n\n## The legal entity is resolved, not asked for\n\nA property is created against the legal entity Booking.com contracts with, invoices and pays. You do not normally send one:\n\n1. If this workspace already creates properties under a legal entity, that one is reused. A second is never registered.\n2. If it has none and the request carries `legal_entity` (`company_name`, `legal_contact_name`, `legal_contact_email`), one is registered and used. Booking.com emails the legal contact a contract; creation only succeeds once it is signed.\n3. If it has none and no `legal_entity`, the request is refused with `422 legal_entity_required` naming the fields \u2014 a contracted company is never invented.\n\n`legal_entity_id` overrides all of that. An id that already carries another workspace's properties is refused with `403 legal_entity_not_yours` before anything is created.\n\n## What you do not control\n\nProperties are created against Booking's **production** target only. A test-target property cannot be sold through and there is no route back from one, so `target` is not a parameter \u2014 sending it changes nothing.\n\nThese are fixed on every created property and are not parameters: property category (Apartment), initial room count (1), and the property contact record (a placeholder name, email and phone). Set the real contacts afterwards with `set-contacts`. Latitude and longitude come from the listing and are adjusted slightly to clear Booking.com's duplicate detection \u2014 send the property's true position on the listing and do not pre-adjust it yourself.\n\nThe listing's name, check-in/check-out times, currency, capacity and price come from the listing. Its postal code is taken from the listing's own `postalCode`; when the listing has none, it falls back to a connected Airbnb listing. A listing with neither is created without a postal code, so set `postalCode` on the listing first.\n\n## Guards\n\nEvery action that takes a `property_id` requires a property connected to this workspace; any other id returns `404 not_found`. Every action that takes a `listing_id` requires a listing in this workspace; any other id returns `404 not_found`.\n\n`create-property` refuses a listing with no coordinates (`422 missing_coordinates`) before anything is created \u2014 creating a Booking.com property cannot be undone.\n\n`create-property` is subject to the same published-listing gate as the dashboard: no plan, or the plan's listing limit reached, returns `403 billing_error` with `used` and `limit`, and nothing is created.\n\nReturns `403 listing_inactive` when the listing \u2014 or any listing mapped to the Booking.com property \u2014 is inactive. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated.\n\nIf a property is created and a later step fails, the response is `422 booking_create_partial` carrying `property_id`. The property EXISTS. Do not retry `create-property`, which would open a second one \u2014 continue with `add-room` and `advance`.",
|
|
21355
21901
|
"tags": [
|
|
21356
21902
|
"Booking.com"
|
|
21357
21903
|
],
|
|
@@ -21368,6 +21914,10 @@
|
|
|
21368
21914
|
"action": {
|
|
21369
21915
|
"type": "string",
|
|
21370
21916
|
"enum": [
|
|
21917
|
+
"create-property",
|
|
21918
|
+
"add-room",
|
|
21919
|
+
"add-unit",
|
|
21920
|
+
"advance",
|
|
21371
21921
|
"create-legal-entity",
|
|
21372
21922
|
"check-legal-status",
|
|
21373
21923
|
"check-readiness",
|
|
@@ -21376,13 +21926,53 @@
|
|
|
21376
21926
|
"set-policies"
|
|
21377
21927
|
]
|
|
21378
21928
|
},
|
|
21929
|
+
"listing_id": {
|
|
21930
|
+
"type": "integer",
|
|
21931
|
+
"description": "Repull listing id \u2014 required for `create-property`, `add-room` and `add-unit`. NOT a Booking.com Hotel ID. `listingId` is accepted as an alias."
|
|
21932
|
+
},
|
|
21379
21933
|
"property_id": {
|
|
21380
21934
|
"type": "string",
|
|
21381
|
-
"description": "Booking.com
|
|
21935
|
+
"description": "Booking.com Hotel ID \u2014 required for `add-room`, `add-unit`, `advance`, and the readiness/open/contacts/policies actions."
|
|
21936
|
+
},
|
|
21937
|
+
"room_id": {
|
|
21938
|
+
"type": "integer",
|
|
21939
|
+
"description": "Booking.com room id \u2014 required for `add-unit`. `GET /v1/channels/booking/properties/{listingId}/rooms` lists them. `roomId` is accepted as an alias."
|
|
21940
|
+
},
|
|
21941
|
+
"legal_entity_id": {
|
|
21942
|
+
"type": "integer",
|
|
21943
|
+
"description": "Optional override for `create-property`. Omit it: the legal entity this workspace already uses is resolved automatically. An id that carries another workspace's properties is refused with `403 legal_entity_not_yours`. `legalEntityId` is accepted as an alias."
|
|
21944
|
+
},
|
|
21945
|
+
"legal_entity": {
|
|
21946
|
+
"type": "object",
|
|
21947
|
+
"description": "Used by `create-property` ONLY when this workspace has no legal entity yet \u2014 one is registered with Booking.com from these details and used for the property. Ignored when the workspace already has one, so a second is never registered.",
|
|
21948
|
+
"properties": {
|
|
21949
|
+
"company_name": {
|
|
21950
|
+
"type": "string"
|
|
21951
|
+
},
|
|
21952
|
+
"legal_contact_name": {
|
|
21953
|
+
"type": "string"
|
|
21954
|
+
},
|
|
21955
|
+
"legal_contact_email": {
|
|
21956
|
+
"type": "string",
|
|
21957
|
+
"format": "email"
|
|
21958
|
+
},
|
|
21959
|
+
"country": {
|
|
21960
|
+
"type": "string"
|
|
21961
|
+
},
|
|
21962
|
+
"city": {
|
|
21963
|
+
"type": "string"
|
|
21964
|
+
}
|
|
21965
|
+
},
|
|
21966
|
+
"required": [
|
|
21967
|
+
"company_name",
|
|
21968
|
+
"legal_contact_name",
|
|
21969
|
+
"legal_contact_email"
|
|
21970
|
+
],
|
|
21971
|
+
"additionalProperties": true
|
|
21382
21972
|
},
|
|
21383
21973
|
"leid": {
|
|
21384
21974
|
"type": "integer",
|
|
21385
|
-
"description": "Legal entity id \u2014 required for `check-legal-status
|
|
21975
|
+
"description": "Legal entity id \u2014 required for `check-legal-status`, which always answers 404."
|
|
21386
21976
|
},
|
|
21387
21977
|
"contacts": {
|
|
21388
21978
|
"type": "array",
|
|
@@ -21400,10 +21990,10 @@
|
|
|
21400
21990
|
},
|
|
21401
21991
|
"responses": {
|
|
21402
21992
|
"200": {
|
|
21403
|
-
"description": "Action result"
|
|
21993
|
+
"description": "Action result. `add-unit` returns `{ action, listingId, propertyId, roomId, units }`; `advance` returns `{ action, propertyId, checked, opened, sellable }`."
|
|
21404
21994
|
},
|
|
21405
21995
|
"201": {
|
|
21406
|
-
"description": "
|
|
21996
|
+
"description": "Created. `create-property` returns `{ action, listingId, propertyId, roomId, legalEntity: { id, source }, target, status, sellable, nextSteps }` \u2014 `status` is `being_built` and `sellable` is `false` until Booking.com validates the property. `add-room` returns `{ action, listingId, propertyId, roomId, rateId, guestFacingName, nextSteps }` \u2014 a `null` `rateId` means the room has no sellable product and will not appear on Booking.com. `create-legal-entity` returns Booking.com's response."
|
|
21407
21997
|
},
|
|
21408
21998
|
"400": {
|
|
21409
21999
|
"$ref": "#/components/responses/BadRequest"
|
|
@@ -21412,13 +22002,40 @@
|
|
|
21412
22002
|
"$ref": "#/components/responses/Unauthorized"
|
|
21413
22003
|
},
|
|
21414
22004
|
"403": {
|
|
21415
|
-
"
|
|
22005
|
+
"description": "`listing_inactive` \u2014 the listing is inactive. `billing_error` \u2014 no plan, or the published-listing limit is reached (carries `used` and `limit`). `legal_entity_not_yours` \u2014 the named legal entity carries another workspace's properties. Nothing was created in any case.",
|
|
22006
|
+
"content": {
|
|
22007
|
+
"application/json": {
|
|
22008
|
+
"schema": {
|
|
22009
|
+
"$ref": "#/components/schemas/Error"
|
|
22010
|
+
}
|
|
22011
|
+
}
|
|
22012
|
+
}
|
|
21416
22013
|
},
|
|
21417
22014
|
"404": {
|
|
21418
22015
|
"$ref": "#/components/responses/NotFound"
|
|
21419
22016
|
},
|
|
22017
|
+
"422": {
|
|
22018
|
+
"description": "`missing_coordinates` \u2014 the listing has no latitude/longitude and nothing was created. `legal_entity_required` \u2014 this workspace has no legal entity and the request carried no details to register one. `booking_create_partial` \u2014 the property WAS created (see `property_id`) and a later step failed; do not retry `create-property`. `booking_error` \u2014 Booking.com refused the request as sent.",
|
|
22019
|
+
"content": {
|
|
22020
|
+
"application/json": {
|
|
22021
|
+
"schema": {
|
|
22022
|
+
"$ref": "#/components/schemas/Error"
|
|
22023
|
+
}
|
|
22024
|
+
}
|
|
22025
|
+
}
|
|
22026
|
+
},
|
|
21420
22027
|
"500": {
|
|
21421
22028
|
"$ref": "#/components/responses/InternalError"
|
|
22029
|
+
},
|
|
22030
|
+
"502": {
|
|
22031
|
+
"description": "`upstream_error` / `service_misconfigured` \u2014 the setup service could not be reached or could not complete the action. Nothing was created on Booking.com.",
|
|
22032
|
+
"content": {
|
|
22033
|
+
"application/json": {
|
|
22034
|
+
"schema": {
|
|
22035
|
+
"$ref": "#/components/schemas/Error"
|
|
22036
|
+
}
|
|
22037
|
+
}
|
|
22038
|
+
}
|
|
21422
22039
|
}
|
|
21423
22040
|
}
|
|
21424
22041
|
}
|
|
@@ -23731,8 +24348,17 @@
|
|
|
23731
24348
|
"404": {
|
|
23732
24349
|
"$ref": "#/components/responses/NotFound"
|
|
23733
24350
|
},
|
|
24351
|
+
"422": {
|
|
24352
|
+
"$ref": "#/components/responses/AirbnbWriteRejected"
|
|
24353
|
+
},
|
|
24354
|
+
"429": {
|
|
24355
|
+
"$ref": "#/components/responses/AirbnbRateLimited"
|
|
24356
|
+
},
|
|
23734
24357
|
"500": {
|
|
23735
24358
|
"$ref": "#/components/responses/InternalError"
|
|
24359
|
+
},
|
|
24360
|
+
"502": {
|
|
24361
|
+
"$ref": "#/components/responses/AirbnbUpstreamError"
|
|
23736
24362
|
}
|
|
23737
24363
|
}
|
|
23738
24364
|
}
|
|
@@ -23786,10 +24412,13 @@
|
|
|
23786
24412
|
"$ref": "#/components/responses/Conflict"
|
|
23787
24413
|
},
|
|
23788
24414
|
"422": {
|
|
23789
|
-
"$ref": "#/components/responses/
|
|
24415
|
+
"$ref": "#/components/responses/AirbnbWriteRejected"
|
|
23790
24416
|
},
|
|
23791
24417
|
"429": {
|
|
23792
24418
|
"$ref": "#/components/responses/TooManyRequests"
|
|
24419
|
+
},
|
|
24420
|
+
"502": {
|
|
24421
|
+
"$ref": "#/components/responses/AirbnbUpstreamError"
|
|
23793
24422
|
}
|
|
23794
24423
|
}
|
|
23795
24424
|
}
|
|
@@ -25116,7 +25745,7 @@
|
|
|
25116
25745
|
"post": {
|
|
25117
25746
|
"operationId": "preapprove_conversation",
|
|
25118
25747
|
"summary": "Pre-approve an inquiry",
|
|
25119
|
-
"description": "Pre-approve the Airbnb inquiry on this conversation: the guest who asked about dates may now book them at the listed price, without waiting on you. To change the dates, guests or price, send a special offer instead (`POST /v1/conversations/{id}/special-offers`).\n\nFind inquiries that need an answer with `GET /v1/inquiries` (default `status=open`); each carries the `conversationId` to use here.\n\n**Airbnb only**, and only for listings connected to Airbnb directly. A Booking.com, VRBO or direct-booking conversation, or an Airbnb one relayed through a PMS (Hostaway, Guesty), returns `422 channel_not_supported` and nothing is sent.\n\
|
|
25748
|
+
"description": "Pre-approve the Airbnb inquiry on this conversation: the guest who asked about dates may now book them at the listed price, without waiting on you. To change the dates, guests or price, send a special offer instead (`POST /v1/conversations/{id}/special-offers`).\n\nFind inquiries that need an answer with `GET /v1/inquiries` (default `status=open`); each carries the `conversationId` to use here.\n\n**Airbnb only**, and only for listings connected to Airbnb directly. A Booking.com, VRBO or direct-booking conversation, or an Airbnb one relayed through a PMS (Hostaway, Guesty), returns `422 channel_not_supported` and nothing is sent.\n\nThe inquiry is marked `pre_approved` everywhere, the same as pre-approving in Airbnb.\n\nAn Airbnb refusal is never reported as a success: an inquiry that already moved on is `409 inquiry_no_longer_open`, an expired one `409 inquiry_expired`, a conversation that already has a booking `409 conversation_already_booked`.\n\nSend `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 \u2014 nothing was done \u2014 so retrying with the same key reaches Airbnb again.",
|
|
25120
25749
|
"tags": [
|
|
25121
25750
|
"Conversations"
|
|
25122
25751
|
],
|
|
@@ -25465,7 +26094,7 @@
|
|
|
25465
26094
|
"post": {
|
|
25466
26095
|
"operationId": "create_conversation_special_offer",
|
|
25467
26096
|
"summary": "Send a special offer",
|
|
25468
|
-
"description": "Send the guest on this conversation an Airbnb special offer: your own dates, guest count and total price. The guest has 24 hours to book it. Use it to answer an inquiry with different terms, or to make a returning guest a custom price. To accept the guest\u2019s own dates and price as they asked, pre-approve instead (`POST /v1/conversations/{id}/pre-approval`).\n\n`listingId` is optional: omit it to offer the listing the guest asked about. It is a **Repull** listing id; Repull sends Airbnb its own listing id, using the link that belongs to this conversation\u2019s Airbnb account.\n\n`totalPrice` is the whole stay, in the listing\u2019s Airbnb currency \u2014 Airbnb does not take a currency on an offer.\n\n**Airbnb only**, and only for listings connected to Airbnb directly; anything else is `422 channel_not_supported` and nothing is sent.
|
|
26097
|
+
"description": "Send the guest on this conversation an Airbnb special offer: your own dates, guest count and total price. The guest has 24 hours to book it. Use it to answer an inquiry with different terms, or to make a returning guest a custom price. To accept the guest\u2019s own dates and price as they asked, pre-approve instead (`POST /v1/conversations/{id}/pre-approval`).\n\n`listingId` is optional: omit it to offer the listing the guest asked about. It is a **Repull** listing id; Repull sends Airbnb its own listing id, using the link that belongs to this conversation\u2019s Airbnb account.\n\n`totalPrice` is the whole stay, in the listing\u2019s Airbnb currency \u2014 Airbnb does not take a currency on an offer.\n\n**Airbnb only**, and only for listings connected to Airbnb directly; anything else is `422 channel_not_supported` and nothing is sent. The inquiry is marked `special_offer_sent`.\n\nAn offer Airbnb refuses is never a `201`: dates that are taken, a price below Airbnb\u2019s minimum, too many guests and the like are `422 airbnb_rejected` with Airbnb\u2019s own reason in `message`.\n\nSend `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 \u2014 nothing was done \u2014 so retrying with the same key reaches Airbnb again. Without it, a retry after a timeout can send the guest two offers.\n\nRead or withdraw the offer with `GET` / `DELETE /v1/conversations/{id}/special-offers/{offerId}`.",
|
|
25469
26098
|
"tags": [
|
|
25470
26099
|
"Conversations"
|
|
25471
26100
|
],
|
|
@@ -26294,7 +26923,7 @@
|
|
|
26294
26923
|
"delete": {
|
|
26295
26924
|
"operationId": "withdraw_conversation_special_offer",
|
|
26296
26925
|
"summary": "Withdraw a special offer",
|
|
26297
|
-
"description": "Withdraw a special offer the guest has not booked yet, so it can no longer be booked.
|
|
26926
|
+
"description": "Withdraw a special offer the guest has not booked yet, so it can no longer be booked. An offer the guest already booked cannot be withdrawn \u2014 Airbnb refuses with `409 inquiry_no_longer_open`; cancel the booking instead.",
|
|
26298
26927
|
"tags": [
|
|
26299
26928
|
"Conversations"
|
|
26300
26929
|
],
|
|
@@ -26689,7 +27318,7 @@
|
|
|
26689
27318
|
"declined",
|
|
26690
27319
|
"not_possible"
|
|
26691
27320
|
],
|
|
26692
|
-
"description": "`open` \u2014 nobody has answered and the stay is still ahead; `pre_approved`; `special_offer_sent` (from the API,
|
|
27321
|
+
"description": "`open` \u2014 nobody has answered and the stay is still ahead; `pre_approved`; `special_offer_sent` (from the API, a connected app, or Airbnb\u2019s own app); `booked` \u2014 the guest booked (`reservationId`); `expired` \u2014 the stay has started or Airbnb expired it; `declined`; `not_possible` \u2014 Airbnb says the dates cannot be booked."
|
|
26693
27322
|
},
|
|
26694
27323
|
"checkIn": {
|
|
26695
27324
|
"type": "string",
|
|
@@ -26807,7 +27436,7 @@
|
|
|
26807
27436
|
"post": {
|
|
26808
27437
|
"operationId": "accept_reservation_request",
|
|
26809
27438
|
"summary": "Accept a booking request",
|
|
26810
|
-
"description": "Accept a pending Airbnb booking request \u2014 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.\n\
|
|
27439
|
+
"description": "Accept a pending Airbnb booking request \u2014 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.\n\nAirbnb confirms asynchronously: the reservation\u2019s status moves to confirmed, and a `reservation.updated` webhook fires, when Airbnb\u2019s notification lands (usually within seconds). The response reports what Airbnb was asked to do.\n\n**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.\n\nTakes no body.\n\nSend `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 \u2014 nothing was done \u2014 so retrying with the same key reaches Airbnb again.",
|
|
26811
27440
|
"tags": [
|
|
26812
27441
|
"Reservations"
|
|
26813
27442
|
],
|
|
@@ -27155,7 +27784,7 @@
|
|
|
27155
27784
|
"post": {
|
|
27156
27785
|
"operationId": "decline_reservation_request",
|
|
27157
27786
|
"summary": "Decline a booking request",
|
|
27158
|
-
"description": "Decline a pending Airbnb booking request (a reservation with status `pending`; find them with `GET /v1/reservations?status=pending`).\n\n`reason` must be one of Airbnb\u2019s own decline reasons. `message` is required: Airbnb sends it to the guest with the decline (at most 500 characters). It is not defaulted \u2014 a canned message would put words in your mouth.\n\
|
|
27787
|
+
"description": "Decline a pending Airbnb booking request (a reservation with status `pending`; find them with `GET /v1/reservations?status=pending`).\n\n`reason` must be one of Airbnb\u2019s own decline reasons. `message` is required: Airbnb sends it to the guest with the decline (at most 500 characters). It is not defaulted \u2014 a canned message would put words in your mouth.\n\nAirbnb confirms asynchronously; the reservation\u2019s status moves, and `reservation.updated` fires, when its notification lands. Same channel and status rules as `POST /v1/reservations/{id}/accept`.\n\nSend `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 \u2014 nothing was done \u2014 so retrying with the same key reaches Airbnb again.",
|
|
27159
27788
|
"tags": [
|
|
27160
27789
|
"Reservations"
|
|
27161
27790
|
],
|
|
@@ -27546,6 +28175,160 @@
|
|
|
27546
28175
|
}
|
|
27547
28176
|
}
|
|
27548
28177
|
}
|
|
28178
|
+
},
|
|
28179
|
+
"/v1/listings/{id}/offline": {
|
|
28180
|
+
"post": {
|
|
28181
|
+
"operationId": "takeListingOffline",
|
|
28182
|
+
"summary": "Take a listing off the market",
|
|
28183
|
+
"description": "Stop this listing being sold, on every channel it is connected to, in one call.\n\nWhat that means differs per channel and you do not have to know which is which. On **Airbnb** the live listing is deactivated with a valid deactivation reason and then READ BACK \u2014 Airbnb accepts some deactivations and leaves the listing up, so \"we sent the request\" is never reported as success. On **Booking.com** there is no unlist at all; the equivalent is closing the room's availability across the whole forward window, which is what happens.\n\n**This is not the same as deactivating the listing in Repull.** The two get confused because both sound like removal, and they have opposite consequences:\n\n| | Take offline (this endpoint) | Deactivate in Repull (`PATCH /v1/listings/{id}` `{\"active\": false}`) |\n|---|---|---|\n| The guest-facing listing | **Stops taking bookings** | Stays live and keeps taking bookings |\n| Billing and plan limits | Unchanged | No longer billed, no longer counts toward the cap |\n| API access to the listing | Unchanged \u2014 you can still read and write it | `403 listing_inactive` until reactivated |\n| Reverse it with | `POST /v1/listings/{id}/online` | `PATCH /v1/listings/{id}` `{\"active\": true}` |\n| Data kept | Yes | Yes, and it keeps syncing |\n\nNeither one deletes anything, on either side.\n\n**The answer is per channel item.** A listing can sit on several Airbnb connections and a Booking.com property at once; they fail independently and a partial result is the ordinary outcome, so every item reports its own `state`, `code` and `message` and there is no top-level success flag to mislead you. Nothing is rolled back \u2014 re-send the same request to retry the items that did not land.\n\n**Booking.com ambiguity is reported, not fanned out.** A listing mapped to more than one active Booking.com property comes back with that item refused (`ambiguous_booking_mapping`) while the Airbnb items still run: closing the wrong property's availability takes real inventory off sale, and taking a listing off Airbnb is not less urgent because its Booking.com mapping is untidy. Name the property with `hotelId` and send it again.\n\nReturns `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.",
|
|
28184
|
+
"tags": [
|
|
28185
|
+
"Listings"
|
|
28186
|
+
],
|
|
28187
|
+
"parameters": [
|
|
28188
|
+
{
|
|
28189
|
+
"name": "id",
|
|
28190
|
+
"in": "path",
|
|
28191
|
+
"required": true,
|
|
28192
|
+
"schema": {
|
|
28193
|
+
"type": "integer"
|
|
28194
|
+
},
|
|
28195
|
+
"description": "Repull listing id."
|
|
28196
|
+
},
|
|
28197
|
+
{
|
|
28198
|
+
"name": "hotel_id",
|
|
28199
|
+
"in": "query",
|
|
28200
|
+
"required": false,
|
|
28201
|
+
"schema": {
|
|
28202
|
+
"type": "string"
|
|
28203
|
+
},
|
|
28204
|
+
"description": "Booking.com property to act on, for a listing mapped to more than one. The query-string spelling of the body's `hotelId`; the body wins when both are sent."
|
|
28205
|
+
},
|
|
28206
|
+
{
|
|
28207
|
+
"$ref": "#/components/parameters/IdempotencyKey"
|
|
28208
|
+
}
|
|
28209
|
+
],
|
|
28210
|
+
"requestBody": {
|
|
28211
|
+
"required": false,
|
|
28212
|
+
"content": {
|
|
28213
|
+
"application/json": {
|
|
28214
|
+
"schema": {
|
|
28215
|
+
"$ref": "#/components/schemas/ListingMarketStateRequest"
|
|
28216
|
+
}
|
|
28217
|
+
}
|
|
28218
|
+
}
|
|
28219
|
+
},
|
|
28220
|
+
"responses": {
|
|
28221
|
+
"200": {
|
|
28222
|
+
"description": "Attempted on every connected channel \u2014 read each item's `ok` and `state`",
|
|
28223
|
+
"content": {
|
|
28224
|
+
"application/json": {
|
|
28225
|
+
"schema": {
|
|
28226
|
+
"$ref": "#/components/schemas/ListingMarketStateResponse"
|
|
28227
|
+
}
|
|
28228
|
+
}
|
|
28229
|
+
}
|
|
28230
|
+
},
|
|
28231
|
+
"402": {
|
|
28232
|
+
"$ref": "#/components/responses/PublishBillingRefused"
|
|
28233
|
+
},
|
|
28234
|
+
"403": {
|
|
28235
|
+
"$ref": "#/components/responses/ListingInactive"
|
|
28236
|
+
},
|
|
28237
|
+
"404": {
|
|
28238
|
+
"$ref": "#/components/responses/NotFound"
|
|
28239
|
+
},
|
|
28240
|
+
"422": {
|
|
28241
|
+
"description": "`no_connected_channels` \u2014 this listing is not connected to any channel, so there was nothing to take offline. Connect one with `POST /v1/connect/sessions` and publish it first. Answered as a refusal rather than a 200 with an empty array, because \"taken off the market everywhere\" over zero channels is not something a caller should have to notice for themselves.",
|
|
28242
|
+
"content": {
|
|
28243
|
+
"application/json": {
|
|
28244
|
+
"schema": {
|
|
28245
|
+
"$ref": "#/components/schemas/Error"
|
|
28246
|
+
}
|
|
28247
|
+
}
|
|
28248
|
+
}
|
|
28249
|
+
},
|
|
28250
|
+
"429": {
|
|
28251
|
+
"$ref": "#/components/responses/TooManyRequests"
|
|
28252
|
+
}
|
|
28253
|
+
}
|
|
28254
|
+
}
|
|
28255
|
+
},
|
|
28256
|
+
"/v1/listings/{id}/online": {
|
|
28257
|
+
"post": {
|
|
28258
|
+
"operationId": "takeListingOnline",
|
|
28259
|
+
"summary": "Put a listing back on the market",
|
|
28260
|
+
"description": "Put this listing back on sale, on every channel it is connected to. The counterpart of `POST /v1/listings/{id}/offline`, which documents the per-item response and the difference between this and deactivating a listing in Repull.\n\n**It does not push content.** On **Airbnb** it re-enables sync and makes the listing available again; anything that changed while the listing was down is still unpublished, so follow with `POST /v1/listings/{id}/publish/airbnb` if the content moved. On **Booking.com** it re-syncs the true calendar rather than opening everything: dates that are genuinely blocked \u2014 a reservation, an owner stay \u2014 stay blocked, and only the closure `offline` wrote lifts. The two directions are not mirror images, and that is deliberate.\n\n**One asymmetry worth planning for.** Taking a listing down passes no billing gate; putting it back up goes through the channel-publish gate. So on a workspace whose subscription has lapsed, `offline` still works and this endpoint answers `402 payment_required` \u2014 a listing can be left off the market until billing is sorted out. That refusal is reported as a billing refusal with the action that fixes it, never as a channel error: retrying, or reconnecting the channel, does nothing for it.\n\nReturns `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.",
|
|
28261
|
+
"tags": [
|
|
28262
|
+
"Listings"
|
|
28263
|
+
],
|
|
28264
|
+
"parameters": [
|
|
28265
|
+
{
|
|
28266
|
+
"name": "id",
|
|
28267
|
+
"in": "path",
|
|
28268
|
+
"required": true,
|
|
28269
|
+
"schema": {
|
|
28270
|
+
"type": "integer"
|
|
28271
|
+
},
|
|
28272
|
+
"description": "Repull listing id."
|
|
28273
|
+
},
|
|
28274
|
+
{
|
|
28275
|
+
"name": "hotel_id",
|
|
28276
|
+
"in": "query",
|
|
28277
|
+
"required": false,
|
|
28278
|
+
"schema": {
|
|
28279
|
+
"type": "string"
|
|
28280
|
+
},
|
|
28281
|
+
"description": "Booking.com property to act on, for a listing mapped to more than one. The query-string spelling of the body's `hotelId`; the body wins when both are sent."
|
|
28282
|
+
},
|
|
28283
|
+
{
|
|
28284
|
+
"$ref": "#/components/parameters/IdempotencyKey"
|
|
28285
|
+
}
|
|
28286
|
+
],
|
|
28287
|
+
"requestBody": {
|
|
28288
|
+
"required": false,
|
|
28289
|
+
"content": {
|
|
28290
|
+
"application/json": {
|
|
28291
|
+
"schema": {
|
|
28292
|
+
"$ref": "#/components/schemas/ListingMarketStateRequest"
|
|
28293
|
+
}
|
|
28294
|
+
}
|
|
28295
|
+
}
|
|
28296
|
+
},
|
|
28297
|
+
"responses": {
|
|
28298
|
+
"200": {
|
|
28299
|
+
"description": "Attempted on every connected channel \u2014 read each item's `ok` and `state`",
|
|
28300
|
+
"content": {
|
|
28301
|
+
"application/json": {
|
|
28302
|
+
"schema": {
|
|
28303
|
+
"$ref": "#/components/schemas/ListingMarketStateResponse"
|
|
28304
|
+
}
|
|
28305
|
+
}
|
|
28306
|
+
}
|
|
28307
|
+
},
|
|
28308
|
+
"402": {
|
|
28309
|
+
"$ref": "#/components/responses/PublishBillingRefused"
|
|
28310
|
+
},
|
|
28311
|
+
"403": {
|
|
28312
|
+
"$ref": "#/components/responses/ListingInactive"
|
|
28313
|
+
},
|
|
28314
|
+
"404": {
|
|
28315
|
+
"$ref": "#/components/responses/NotFound"
|
|
28316
|
+
},
|
|
28317
|
+
"422": {
|
|
28318
|
+
"description": "`no_connected_channels` \u2014 this listing is not connected to any channel, so there was nothing to put back on the market. Connect one with `POST /v1/connect/sessions` and publish it first.",
|
|
28319
|
+
"content": {
|
|
28320
|
+
"application/json": {
|
|
28321
|
+
"schema": {
|
|
28322
|
+
"$ref": "#/components/schemas/Error"
|
|
28323
|
+
}
|
|
28324
|
+
}
|
|
28325
|
+
}
|
|
28326
|
+
},
|
|
28327
|
+
"429": {
|
|
28328
|
+
"$ref": "#/components/responses/TooManyRequests"
|
|
28329
|
+
}
|
|
28330
|
+
}
|
|
28331
|
+
}
|
|
27549
28332
|
}
|
|
27550
28333
|
}
|
|
27551
28334
|
}
|