repull 0.2.34 → 0.2.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/lib/repull/api/connect_api.rb +6 -6
  3. data/lib/repull/api/health_api.rb +3 -3
  4. data/lib/repull/api/listings_api.rb +8 -8
  5. data/lib/repull/api/migrate_api.rb +68 -0
  6. data/lib/repull/models/{calendar_updated_event.rb → booking_unacknowledged_event.rb} +4 -4
  7. data/lib/repull/models/booking_unacknowledged_payload.rb +229 -0
  8. data/lib/repull/models/channel_degraded_event.rb +279 -0
  9. data/lib/repull/models/channel_degraded_payload.rb +174 -0
  10. data/lib/repull/models/channel_degraded_payload_object.rb +262 -0
  11. data/lib/repull/models/channel_sync_failed_event.rb +280 -0
  12. data/lib/repull/models/channel_sync_failure_payload.rb +214 -0
  13. data/lib/repull/models/channel_sync_failure_payload_failures_inner.rb +213 -0
  14. data/lib/repull/models/channel_sync_failure_payload_object.rb +289 -0
  15. data/lib/repull/models/charge_per.rb +42 -0
  16. data/lib/repull/models/connect_session_completed_payload.rb +1 -1
  17. data/lib/repull/models/connect_status_accounts_inner.rb +12 -1
  18. data/lib/repull/models/create_connect_session_request.rb +26 -2
  19. data/lib/repull/models/create_connection_request.rb +3 -23
  20. data/lib/repull/models/{plumguide_listing_list_response.rb → import_from_channex200_response.rb} +8 -19
  21. data/lib/repull/models/import_from_channex200_response_data.rb +324 -0
  22. data/lib/repull/models/import_from_channex200_response_data_channels_inner.rb +263 -0
  23. data/lib/repull/models/import_from_channex200_response_data_properties_inner.rb +222 -0
  24. data/lib/repull/models/import_from_channex200_response_data_summary.rb +201 -0
  25. data/lib/repull/models/import_from_channex200_response_data_summary_bookings.rb +165 -0
  26. data/lib/repull/models/import_from_channex200_response_data_summary_properties.rb +165 -0
  27. data/lib/repull/models/import_from_channex_request.rb +223 -0
  28. data/lib/repull/models/list_connection_units200_response.rb +12 -1
  29. data/lib/repull/models/list_connection_units200_response_units_inner.rb +1 -0
  30. data/lib/repull/models/listing.rb +82 -1
  31. data/lib/repull/models/listing_address.rb +62 -5
  32. data/lib/repull/models/listing_content_photo.rb +206 -0
  33. data/lib/repull/models/listing_fee.rb +229 -0
  34. data/lib/repull/models/listing_policies.rb +257 -0
  35. data/lib/repull/models/{calendar_updated_payload.rb → listing_policies_check_in.rb} +33 -38
  36. data/lib/repull/models/listing_policies_check_out.rb +148 -0
  37. data/lib/repull/models/{calendar_updated_payload_range.rb → listing_policies_quiet_hours.rb} +5 -5
  38. data/lib/repull/models/listing_pricing_settings.rb +233 -0
  39. data/lib/repull/models/listing_room.rb +190 -0
  40. data/lib/repull/models/{plumguide_listing.rb → listing_room_beds_inner.rb} +16 -27
  41. data/lib/repull/models/listing_rules.rb +212 -0
  42. data/lib/repull/models/listing_tax.rb +241 -0
  43. data/lib/repull/models/message.rb +24 -1
  44. data/lib/repull/models/postal_address.rb +216 -0
  45. data/lib/repull/models/property.rb +12 -2
  46. data/lib/repull/models/reservation_thread_assigned_event.rb +279 -0
  47. data/lib/repull/models/reservation_thread_assigned_payload.rb +174 -0
  48. data/lib/repull/models/reservation_thread_assigned_payload_object.rb +249 -0
  49. data/lib/repull/models/webhook_event.rb +8 -2
  50. data/lib/repull/models/webhook_event_type.rb +5 -2
  51. data/lib/repull/version.rb +1 -1
  52. data/lib/repull.rb +33 -6
  53. data/openapi/v1.json +1712 -352
  54. metadata +35 -10
  55. data/lib/repull/api/plumguide_api.rb +0 -552
  56. data/spec/api/plumguide_api_spec.rb +0 -85
data/openapi/v1.json CHANGED
@@ -110,10 +110,6 @@
110
110
  "name": "VRBO",
111
111
  "description": "VRBO channel management \u2014 listings and reservations"
112
112
  },
113
- {
114
- "name": "Plumguide",
115
- "description": "Plumguide channel management \u2014 availability, pricing, bookings"
116
- },
117
113
  {
118
114
  "name": "AI",
119
115
  "description": "AI-powered operations \u2014 guest responses, intent classification, listing generation, pricing suggestions"
@@ -190,12 +186,17 @@
190
186
  "address": {
191
187
  "type": "string",
192
188
  "nullable": true,
193
- "description": "Street address (from the listing's `street` field)."
189
+ "description": "Street line only, as stored on the listing \u2014 no unit, state or postal code. Kept for existing integrations; read `addressDetails` for the full postal address.",
190
+ "example": "2700 Northwest 2nd Avenue"
194
191
  },
195
192
  "city": {
196
193
  "type": "string",
197
194
  "nullable": true,
198
- "example": "Miami Beach"
195
+ "description": "City as stored on the listing. Kept for existing integrations; `addressDetails.city` is the resolved city.",
196
+ "example": "Miami"
197
+ },
198
+ "addressDetails": {
199
+ "$ref": "#/components/schemas/PostalAddress"
199
200
  },
200
201
  "latitude": {
201
202
  "type": "string",
@@ -254,6 +255,55 @@
254
255
  }
255
256
  }
256
257
  },
258
+ "PostalAddress": {
259
+ "type": "object",
260
+ "description": "The full postal address, unit included. Returned on every active row of `GET /v1/properties`, `GET /v1/properties/{id}`, `GET /v1/listings` and `GET /v1/listings/{id}` (on listings, these fields sit inside `address`). Each part is read from the listing first, then from the connected channels (Airbnb, Vrbo, Booking.com), so `line2` carries the apartment or unit number that tells units in the same building apart. A part nobody has stored is `null`.",
261
+ "required": [
262
+ "line1",
263
+ "line2",
264
+ "city",
265
+ "state",
266
+ "postalCode",
267
+ "countryCode"
268
+ ],
269
+ "properties": {
270
+ "line1": {
271
+ "type": "string",
272
+ "nullable": true,
273
+ "description": "Street address: number and street.",
274
+ "example": "2700 Northwest 2nd Avenue"
275
+ },
276
+ "line2": {
277
+ "type": "string",
278
+ "nullable": true,
279
+ "description": "Apartment, unit, suite or building.",
280
+ "example": "Unit 241"
281
+ },
282
+ "city": {
283
+ "type": "string",
284
+ "nullable": true,
285
+ "example": "Miami"
286
+ },
287
+ "state": {
288
+ "type": "string",
289
+ "nullable": true,
290
+ "description": "State, province or region.",
291
+ "example": "FL"
292
+ },
293
+ "postalCode": {
294
+ "type": "string",
295
+ "nullable": true,
296
+ "description": "Postal or ZIP code.",
297
+ "example": "33127"
298
+ },
299
+ "countryCode": {
300
+ "type": "string",
301
+ "nullable": true,
302
+ "description": "ISO 3166-1 alpha-2 country code.",
303
+ "example": "US"
304
+ }
305
+ }
306
+ },
257
307
  "PropertyAvailabilityDay": {
258
308
  "type": "object",
259
309
  "description": "One calendar day in the availability window.",
@@ -1294,6 +1344,15 @@
1294
1344
  "direction": {
1295
1345
  "type": "string"
1296
1346
  },
1347
+ "status": {
1348
+ "type": "string",
1349
+ "description": "Delivery state. Inbound messages are `received`. An outbound message is `sending` while it is queued to the channel, `sent` once the channel accepted it, or `failed`. Only `sent` (or `received`) means the guest can see it."
1350
+ },
1351
+ "statusReason": {
1352
+ "type": "string",
1353
+ "nullable": true,
1354
+ "description": "Why a message is still `sending` or `failed`, in plain words. `null` otherwise."
1355
+ },
1297
1356
  "senderType": {
1298
1357
  "type": "string",
1299
1358
  "nullable": true,
@@ -1342,7 +1401,9 @@
1342
1401
  },
1343
1402
  "deliveredAt": {
1344
1403
  "type": "string",
1345
- "format": "date-time"
1404
+ "format": "date-time",
1405
+ "nullable": true,
1406
+ "description": "When the message reached the channel. `null` while it is `sending` or when it `failed`."
1346
1407
  },
1347
1408
  "readAt": {
1348
1409
  "type": "string",
@@ -2246,6 +2307,11 @@
2246
2307
  ],
2247
2308
  "description": "Vrbo only."
2248
2309
  },
2310
+ "notificationEmail": {
2311
+ "type": "string",
2312
+ "nullable": true,
2313
+ "description": "Vrbo only. The address the host can add on Vrbo as a secondary email (with message and reservation notifications on) so new bookings, inquiries and messages arrive within a minute instead of at the scheduled check. Ask every host to add it: notifications are how Vrbo updates reach Repull, the scheduled check is the backup. Hosted Connect shows it on its mapping screen; show it in your own app when you create sessions with `mapping: \"api\"`."
2314
+ },
2249
2315
  "import": {
2250
2316
  "nullable": true,
2251
2317
  "allOf": [
@@ -2683,6 +2749,10 @@
2683
2749
  "reservation.alteration.responded",
2684
2750
  "reservation.request.created",
2685
2751
  "reservation.request.updated",
2752
+ "booking.unacknowledged",
2753
+ "channel.sync.failed",
2754
+ "channel.degraded",
2755
+ "reservation.thread.assigned",
2686
2756
  "inquiry.created",
2687
2757
  "inquiry.updated",
2688
2758
  "listing.created",
@@ -2690,7 +2760,6 @@
2690
2760
  "listing.deleted",
2691
2761
  "listing.suspended",
2692
2762
  "listing.reactivated",
2693
- "calendar.updated",
2694
2763
  "account.created",
2695
2764
  "connect.session.completed",
2696
2765
  "account.disconnected",
@@ -3724,43 +3793,6 @@
3724
3793
  }
3725
3794
  }
3726
3795
  },
3727
- "CalendarUpdatedPayload": {
3728
- "type": "object",
3729
- "description": "Payload for `calendar.updated`. Availability or pricing for a listing was updated.",
3730
- "properties": {
3731
- "listingId": {
3732
- "type": "integer",
3733
- "example": 6250
3734
- },
3735
- "range": {
3736
- "type": "object",
3737
- "properties": {
3738
- "start": {
3739
- "type": "string",
3740
- "format": "date",
3741
- "example": "2026-06-01"
3742
- },
3743
- "end": {
3744
- "type": "string",
3745
- "format": "date",
3746
- "example": "2026-06-15"
3747
- }
3748
- }
3749
- },
3750
- "affectedDates": {
3751
- "type": "integer",
3752
- "example": 14
3753
- },
3754
- "pricingChanged": {
3755
- "type": "boolean",
3756
- "example": true
3757
- },
3758
- "availabilityChanged": {
3759
- "type": "boolean",
3760
- "example": false
3761
- }
3762
- }
3763
- },
3764
3796
  "AccountCreatedPayload": {
3765
3797
  "type": "object",
3766
3798
  "description": "Payload for `account.created`. An OAuth or API credential connection was completed by an end user.",
@@ -3807,7 +3839,7 @@
3807
3839
  "provider": {
3808
3840
  "type": "string",
3809
3841
  "nullable": true,
3810
- "description": "Channel or PMS: airbnb, booking, booking_extranet, vrbo, plumguide, hostaway, \u2026",
3842
+ "description": "Channel or PMS: airbnb, booking, booking_extranet, vrbo, hostaway, \u2026",
3811
3843
  "example": "vrbo"
3812
3844
  },
3813
3845
  "externalAccountId": {
@@ -4590,7 +4622,103 @@
4590
4622
  }
4591
4623
  }
4592
4624
  },
4593
- "InquiryCreatedEvent": {
4625
+ "ChannelSyncFailurePayload": {
4626
+ "type": "object",
4627
+ "description": "Payload for `channel.sync.failed`. A push of availability, rates or content to a connected channel did not land.",
4628
+ "required": [
4629
+ "object",
4630
+ "failures"
4631
+ ],
4632
+ "properties": {
4633
+ "object": {
4634
+ "type": "object",
4635
+ "required": [
4636
+ "listingId",
4637
+ "customerId",
4638
+ "operation",
4639
+ "total"
4640
+ ],
4641
+ "properties": {
4642
+ "listingId": {
4643
+ "type": "integer"
4644
+ },
4645
+ "customerId": {
4646
+ "type": "integer"
4647
+ },
4648
+ "operation": {
4649
+ "type": "string",
4650
+ "enum": [
4651
+ "availability",
4652
+ "rate",
4653
+ "restriction",
4654
+ "content",
4655
+ "reservation"
4656
+ ],
4657
+ "description": "Which wire failed. A refused rate and a closed connection call for different responses."
4658
+ },
4659
+ "total": {
4660
+ "type": "boolean",
4661
+ "description": "true when NO mapping accepted the push. false means some did \u2014 the more dangerous case, because the listing is live somewhere and inconsistent."
4662
+ },
4663
+ "from": {
4664
+ "type": "string",
4665
+ "format": "date",
4666
+ "nullable": true,
4667
+ "description": "Start of the date range the push covered, when the operation is date-scoped."
4668
+ },
4669
+ "to": {
4670
+ "type": "string",
4671
+ "format": "date",
4672
+ "nullable": true
4673
+ }
4674
+ }
4675
+ },
4676
+ "failures": {
4677
+ "type": "array",
4678
+ "description": "One entry per channel mapping that refused the push.",
4679
+ "items": {
4680
+ "type": "object",
4681
+ "properties": {
4682
+ "channel": {
4683
+ "type": "string",
4684
+ "example": "airbnb"
4685
+ },
4686
+ "externalListingId": {
4687
+ "type": "string",
4688
+ "nullable": true,
4689
+ "description": "The channel's own id for the room or listing."
4690
+ },
4691
+ "kind": {
4692
+ "type": "string",
4693
+ "enum": [
4694
+ "rejected",
4695
+ "auth",
4696
+ "not_mapped",
4697
+ "unreachable",
4698
+ "unknown"
4699
+ ],
4700
+ "description": "`unknown` means we could not classify it \u2014 never that the channel refused."
4701
+ },
4702
+ "message": {
4703
+ "type": "string",
4704
+ "nullable": true,
4705
+ "description": "The channel's own message, verbatim."
4706
+ }
4707
+ }
4708
+ }
4709
+ },
4710
+ "reservationId": {
4711
+ "type": "integer",
4712
+ "nullable": true,
4713
+ "description": "Set when the push was blocking dates for a booking just taken. Those nights are sold on one channel and still open on another \u2014 treat as urgent."
4714
+ },
4715
+ "occurredAt": {
4716
+ "type": "string",
4717
+ "format": "date-time"
4718
+ }
4719
+ }
4720
+ },
4721
+ "ChannelSyncFailedEvent": {
4594
4722
  "type": "object",
4595
4723
  "required": [
4596
4724
  "event",
@@ -4615,18 +4743,64 @@
4615
4743
  },
4616
4744
  "timestamp": {
4617
4745
  "type": "string",
4618
- "format": "date-time",
4619
- "description": "When this delivery was built."
4746
+ "format": "date-time"
4620
4747
  },
4621
4748
  "account": {
4622
4749
  "$ref": "#/components/schemas/WebhookEventAccount"
4623
4750
  },
4624
4751
  "data": {
4625
- "$ref": "#/components/schemas/InquiryCreatedPayload"
4752
+ "$ref": "#/components/schemas/ChannelSyncFailurePayload"
4626
4753
  }
4627
4754
  }
4628
4755
  },
4629
- "InquiryUpdatedEvent": {
4756
+ "ChannelDegradedPayload": {
4757
+ "type": "object",
4758
+ "description": "Payload for `channel.degraded`. A connection is failing repeatedly and will stop working. Sent on the transition into degraded or down, not on every health check.",
4759
+ "required": [
4760
+ "object"
4761
+ ],
4762
+ "properties": {
4763
+ "object": {
4764
+ "type": "object",
4765
+ "required": [
4766
+ "customerId",
4767
+ "provider",
4768
+ "status"
4769
+ ],
4770
+ "properties": {
4771
+ "customerId": {
4772
+ "type": "integer"
4773
+ },
4774
+ "provider": {
4775
+ "type": "string",
4776
+ "example": "booking"
4777
+ },
4778
+ "externalAccountId": {
4779
+ "type": "string",
4780
+ "nullable": true,
4781
+ "description": "The provider's own account, host or hotel id."
4782
+ },
4783
+ "status": {
4784
+ "type": "string",
4785
+ "enum": [
4786
+ "degraded",
4787
+ "down"
4788
+ ]
4789
+ },
4790
+ "detail": {
4791
+ "type": "string",
4792
+ "nullable": true,
4793
+ "description": "What we observed, in the provider's words where possible. A bare \"degraded\" tells nobody what to fix."
4794
+ }
4795
+ }
4796
+ },
4797
+ "occurredAt": {
4798
+ "type": "string",
4799
+ "format": "date-time"
4800
+ }
4801
+ }
4802
+ },
4803
+ "ChannelDegradedEvent": {
4630
4804
  "type": "object",
4631
4805
  "required": [
4632
4806
  "event",
@@ -4642,8 +4816,7 @@
4642
4816
  },
4643
4817
  "eventId": {
4644
4818
  "type": "string",
4645
- "format": "uuid",
4646
- "description": "Stable across every delivery and replay of this logical event \u2014 dedupe on it."
4819
+ "format": "uuid"
4647
4820
  },
4648
4821
  "apiVersion": {
4649
4822
  "type": "string",
@@ -4651,18 +4824,64 @@
4651
4824
  },
4652
4825
  "timestamp": {
4653
4826
  "type": "string",
4654
- "format": "date-time",
4655
- "description": "When this delivery was built."
4827
+ "format": "date-time"
4656
4828
  },
4657
4829
  "account": {
4658
4830
  "$ref": "#/components/schemas/WebhookEventAccount"
4659
4831
  },
4660
4832
  "data": {
4661
- "$ref": "#/components/schemas/InquiryUpdatedPayload"
4833
+ "$ref": "#/components/schemas/ChannelDegradedPayload"
4662
4834
  }
4663
4835
  }
4664
4836
  },
4665
- "ListingCreatedEvent": {
4837
+ "ReservationThreadAssignedPayload": {
4838
+ "type": "object",
4839
+ "description": "Payload for `reservation.thread.assigned`. A message thread was attached to a booking. Threads are often born orphaned \u2014 a guest messages about a booking whose import has not landed \u2014 and adopted when the reservation arrives.",
4840
+ "required": [
4841
+ "object"
4842
+ ],
4843
+ "properties": {
4844
+ "object": {
4845
+ "type": "object",
4846
+ "required": [
4847
+ "reservationId",
4848
+ "customerId",
4849
+ "threadId"
4850
+ ],
4851
+ "properties": {
4852
+ "reservationId": {
4853
+ "type": "integer"
4854
+ },
4855
+ "customerId": {
4856
+ "type": "integer"
4857
+ },
4858
+ "listingId": {
4859
+ "type": "integer",
4860
+ "nullable": true
4861
+ },
4862
+ "threadId": {
4863
+ "type": "string",
4864
+ "description": "Repull conversation id."
4865
+ },
4866
+ "externalThreadId": {
4867
+ "type": "string",
4868
+ "nullable": true,
4869
+ "description": "The channel's own conversation id."
4870
+ },
4871
+ "previousReservationId": {
4872
+ "type": "integer",
4873
+ "nullable": true,
4874
+ "description": "What the thread pointed at before. Null on the common orphan-adoption case; set when a thread moved between bookings."
4875
+ }
4876
+ }
4877
+ },
4878
+ "occurredAt": {
4879
+ "type": "string",
4880
+ "format": "date-time"
4881
+ }
4882
+ }
4883
+ },
4884
+ "ReservationThreadAssignedEvent": {
4666
4885
  "type": "object",
4667
4886
  "required": [
4668
4887
  "event",
@@ -4678,8 +4897,7 @@
4678
4897
  },
4679
4898
  "eventId": {
4680
4899
  "type": "string",
4681
- "format": "uuid",
4682
- "description": "Stable across every delivery and replay of this logical event \u2014 dedupe on it."
4900
+ "format": "uuid"
4683
4901
  },
4684
4902
  "apiVersion": {
4685
4903
  "type": "string",
@@ -4687,18 +4905,45 @@
4687
4905
  },
4688
4906
  "timestamp": {
4689
4907
  "type": "string",
4690
- "format": "date-time",
4691
- "description": "When this delivery was built."
4908
+ "format": "date-time"
4692
4909
  },
4693
4910
  "account": {
4694
4911
  "$ref": "#/components/schemas/WebhookEventAccount"
4695
4912
  },
4696
4913
  "data": {
4697
- "$ref": "#/components/schemas/ListingCreatedPayload"
4914
+ "$ref": "#/components/schemas/ReservationThreadAssignedPayload"
4698
4915
  }
4699
4916
  }
4700
4917
  },
4701
- "ListingUpdatedEvent": {
4918
+ "BookingUnacknowledgedPayload": {
4919
+ "type": "object",
4920
+ "description": "Payload for `booking.unacknowledged`. A booking changed and your system has not acknowledged the change through the revision feed. Sent once per outstanding revision \u2014 not once per check \u2014 so a booking that keeps waiting does not keep alerting. A booking that changes AGAIN mints a new revision and does alert again, because that is a new thing to acknowledge. Acknowledging the revision stops it.",
4921
+ "required": [
4922
+ "object",
4923
+ "revisionId",
4924
+ "outstandingSince"
4925
+ ],
4926
+ "properties": {
4927
+ "object": {
4928
+ "$ref": "#/components/schemas/ReservationWebhookObject"
4929
+ },
4930
+ "revisionId": {
4931
+ "type": "string",
4932
+ "format": "uuid",
4933
+ "description": "The outstanding revision. Acknowledge this to stop the alert."
4934
+ },
4935
+ "outstandingSince": {
4936
+ "type": "string",
4937
+ "format": "date-time",
4938
+ "description": "When the booking actually changed \u2014 NOT when we noticed. Revisions are minted when you first poll the feed, so a mint timestamp would measure how recently you looked rather than how long the booking has waited."
4939
+ },
4940
+ "outstandingHours": {
4941
+ "type": "integer",
4942
+ "description": "Whole hours since `outstandingSince`, for convenience."
4943
+ }
4944
+ }
4945
+ },
4946
+ "BookingUnacknowledgedEvent": {
4702
4947
  "type": "object",
4703
4948
  "required": [
4704
4949
  "event",
@@ -4730,11 +4975,11 @@
4730
4975
  "$ref": "#/components/schemas/WebhookEventAccount"
4731
4976
  },
4732
4977
  "data": {
4733
- "$ref": "#/components/schemas/ListingUpdatedPayload"
4978
+ "$ref": "#/components/schemas/BookingUnacknowledgedPayload"
4734
4979
  }
4735
4980
  }
4736
4981
  },
4737
- "ListingDeletedEvent": {
4982
+ "InquiryCreatedEvent": {
4738
4983
  "type": "object",
4739
4984
  "required": [
4740
4985
  "event",
@@ -4766,11 +5011,11 @@
4766
5011
  "$ref": "#/components/schemas/WebhookEventAccount"
4767
5012
  },
4768
5013
  "data": {
4769
- "$ref": "#/components/schemas/ListingDeletedPayload"
5014
+ "$ref": "#/components/schemas/InquiryCreatedPayload"
4770
5015
  }
4771
5016
  }
4772
5017
  },
4773
- "ListingSuspendedEvent": {
5018
+ "InquiryUpdatedEvent": {
4774
5019
  "type": "object",
4775
5020
  "required": [
4776
5021
  "event",
@@ -4802,11 +5047,11 @@
4802
5047
  "$ref": "#/components/schemas/WebhookEventAccount"
4803
5048
  },
4804
5049
  "data": {
4805
- "$ref": "#/components/schemas/ListingSuspensionPayload"
5050
+ "$ref": "#/components/schemas/InquiryUpdatedPayload"
4806
5051
  }
4807
5052
  }
4808
5053
  },
4809
- "ListingReactivatedEvent": {
5054
+ "ListingCreatedEvent": {
4810
5055
  "type": "object",
4811
5056
  "required": [
4812
5057
  "event",
@@ -4838,11 +5083,11 @@
4838
5083
  "$ref": "#/components/schemas/WebhookEventAccount"
4839
5084
  },
4840
5085
  "data": {
4841
- "$ref": "#/components/schemas/ListingSuspensionPayload"
5086
+ "$ref": "#/components/schemas/ListingCreatedPayload"
4842
5087
  }
4843
5088
  }
4844
5089
  },
4845
- "CalendarUpdatedEvent": {
5090
+ "ListingUpdatedEvent": {
4846
5091
  "type": "object",
4847
5092
  "required": [
4848
5093
  "event",
@@ -4874,7 +5119,115 @@
4874
5119
  "$ref": "#/components/schemas/WebhookEventAccount"
4875
5120
  },
4876
5121
  "data": {
4877
- "$ref": "#/components/schemas/CalendarUpdatedPayload"
5122
+ "$ref": "#/components/schemas/ListingUpdatedPayload"
5123
+ }
5124
+ }
5125
+ },
5126
+ "ListingDeletedEvent": {
5127
+ "type": "object",
5128
+ "required": [
5129
+ "event",
5130
+ "eventId",
5131
+ "apiVersion",
5132
+ "timestamp",
5133
+ "data"
5134
+ ],
5135
+ "properties": {
5136
+ "event": {
5137
+ "type": "string",
5138
+ "description": "The event name. This field is `event`, not `type`."
5139
+ },
5140
+ "eventId": {
5141
+ "type": "string",
5142
+ "format": "uuid",
5143
+ "description": "Stable across every delivery and replay of this logical event \u2014 dedupe on it."
5144
+ },
5145
+ "apiVersion": {
5146
+ "type": "string",
5147
+ "example": "2026-04"
5148
+ },
5149
+ "timestamp": {
5150
+ "type": "string",
5151
+ "format": "date-time",
5152
+ "description": "When this delivery was built."
5153
+ },
5154
+ "account": {
5155
+ "$ref": "#/components/schemas/WebhookEventAccount"
5156
+ },
5157
+ "data": {
5158
+ "$ref": "#/components/schemas/ListingDeletedPayload"
5159
+ }
5160
+ }
5161
+ },
5162
+ "ListingSuspendedEvent": {
5163
+ "type": "object",
5164
+ "required": [
5165
+ "event",
5166
+ "eventId",
5167
+ "apiVersion",
5168
+ "timestamp",
5169
+ "data"
5170
+ ],
5171
+ "properties": {
5172
+ "event": {
5173
+ "type": "string",
5174
+ "description": "The event name. This field is `event`, not `type`."
5175
+ },
5176
+ "eventId": {
5177
+ "type": "string",
5178
+ "format": "uuid",
5179
+ "description": "Stable across every delivery and replay of this logical event \u2014 dedupe on it."
5180
+ },
5181
+ "apiVersion": {
5182
+ "type": "string",
5183
+ "example": "2026-04"
5184
+ },
5185
+ "timestamp": {
5186
+ "type": "string",
5187
+ "format": "date-time",
5188
+ "description": "When this delivery was built."
5189
+ },
5190
+ "account": {
5191
+ "$ref": "#/components/schemas/WebhookEventAccount"
5192
+ },
5193
+ "data": {
5194
+ "$ref": "#/components/schemas/ListingSuspensionPayload"
5195
+ }
5196
+ }
5197
+ },
5198
+ "ListingReactivatedEvent": {
5199
+ "type": "object",
5200
+ "required": [
5201
+ "event",
5202
+ "eventId",
5203
+ "apiVersion",
5204
+ "timestamp",
5205
+ "data"
5206
+ ],
5207
+ "properties": {
5208
+ "event": {
5209
+ "type": "string",
5210
+ "description": "The event name. This field is `event`, not `type`."
5211
+ },
5212
+ "eventId": {
5213
+ "type": "string",
5214
+ "format": "uuid",
5215
+ "description": "Stable across every delivery and replay of this logical event \u2014 dedupe on it."
5216
+ },
5217
+ "apiVersion": {
5218
+ "type": "string",
5219
+ "example": "2026-04"
5220
+ },
5221
+ "timestamp": {
5222
+ "type": "string",
5223
+ "format": "date-time",
5224
+ "description": "When this delivery was built."
5225
+ },
5226
+ "account": {
5227
+ "$ref": "#/components/schemas/WebhookEventAccount"
5228
+ },
5229
+ "data": {
5230
+ "$ref": "#/components/schemas/ListingSuspensionPayload"
4878
5231
  }
4879
5232
  }
4880
5233
  },
@@ -5749,6 +6102,18 @@
5749
6102
  {
5750
6103
  "$ref": "#/components/schemas/ReservationRequestUpdatedEvent"
5751
6104
  },
6105
+ {
6106
+ "$ref": "#/components/schemas/BookingUnacknowledgedEvent"
6107
+ },
6108
+ {
6109
+ "$ref": "#/components/schemas/ChannelSyncFailedEvent"
6110
+ },
6111
+ {
6112
+ "$ref": "#/components/schemas/ChannelDegradedEvent"
6113
+ },
6114
+ {
6115
+ "$ref": "#/components/schemas/ReservationThreadAssignedEvent"
6116
+ },
5752
6117
  {
5753
6118
  "$ref": "#/components/schemas/InquiryCreatedEvent"
5754
6119
  },
@@ -5770,9 +6135,6 @@
5770
6135
  {
5771
6136
  "$ref": "#/components/schemas/ListingReactivatedEvent"
5772
6137
  },
5773
- {
5774
- "$ref": "#/components/schemas/CalendarUpdatedEvent"
5775
- },
5776
6138
  {
5777
6139
  "$ref": "#/components/schemas/AccountCreatedEvent"
5778
6140
  },
@@ -5838,6 +6200,10 @@
5838
6200
  "reservation.alteration.responded": "#/components/schemas/ReservationAlterationRespondedEvent",
5839
6201
  "reservation.request.created": "#/components/schemas/ReservationRequestCreatedEvent",
5840
6202
  "reservation.request.updated": "#/components/schemas/ReservationRequestUpdatedEvent",
6203
+ "booking.unacknowledged": "#/components/schemas/BookingUnacknowledgedEvent",
6204
+ "channel.sync.failed": "#/components/schemas/ChannelSyncFailedEvent",
6205
+ "channel.degraded": "#/components/schemas/ChannelDegradedEvent",
6206
+ "reservation.thread.assigned": "#/components/schemas/ReservationThreadAssignedEvent",
5841
6207
  "inquiry.created": "#/components/schemas/InquiryCreatedEvent",
5842
6208
  "inquiry.updated": "#/components/schemas/InquiryUpdatedEvent",
5843
6209
  "listing.created": "#/components/schemas/ListingCreatedEvent",
@@ -5845,7 +6211,6 @@
5845
6211
  "listing.deleted": "#/components/schemas/ListingDeletedEvent",
5846
6212
  "listing.suspended": "#/components/schemas/ListingSuspendedEvent",
5847
6213
  "listing.reactivated": "#/components/schemas/ListingReactivatedEvent",
5848
- "calendar.updated": "#/components/schemas/CalendarUpdatedEvent",
5849
6214
  "account.created": "#/components/schemas/AccountCreatedEvent",
5850
6215
  "connect.session.completed": "#/components/schemas/ConnectSessionCompletedEvent",
5851
6216
  "account.disconnected": "#/components/schemas/AccountDisconnectedEvent",
@@ -6160,22 +6525,6 @@
6160
6525
  }
6161
6526
  }
6162
6527
  },
6163
- "PlumguideListing": {
6164
- "type": "object",
6165
- "description": "A Plumguide listing.",
6166
- "properties": {
6167
- "id": {
6168
- "type": "string"
6169
- },
6170
- "name": {
6171
- "type": "string"
6172
- },
6173
- "status": {
6174
- "type": "string",
6175
- "nullable": true
6176
- }
6177
- }
6178
- },
6179
6528
  "AirbnbReservation": {
6180
6529
  "type": "object",
6181
6530
  "description": "An Airbnb reservation as returned by the channel API. Use `confirmationCode` to address it in Airbnb operations.",
@@ -7039,8 +7388,7 @@
7039
7388
  "example": [
7040
7389
  "airbnb",
7041
7390
  "booking",
7042
- "vrbo",
7043
- "plumguide"
7391
+ "vrbo"
7044
7392
  ]
7045
7393
  },
7046
7394
  "validParams": {
@@ -8008,20 +8356,6 @@
8008
8356
  }
8009
8357
  }
8010
8358
  },
8011
- "PlumguideListingListResponse": {
8012
- "type": "object",
8013
- "properties": {
8014
- "data": {
8015
- "type": "array",
8016
- "items": {
8017
- "$ref": "#/components/schemas/PlumguideListing"
8018
- }
8019
- },
8020
- "pagination": {
8021
- "$ref": "#/components/schemas/Pagination"
8022
- }
8023
- }
8024
- },
8025
8359
  "ListingCreateRequest": {
8026
8360
  "type": "object",
8027
8361
  "required": [
@@ -9459,6 +9793,341 @@
9459
9793
  "isPresent"
9460
9794
  ]
9461
9795
  },
9796
+ "ChargePer": {
9797
+ "type": "string",
9798
+ "enum": [
9799
+ "stay",
9800
+ "night",
9801
+ "guest",
9802
+ "guest_night"
9803
+ ],
9804
+ "description": "How often an amount is charged: once per stay, per night, per guest, or per guest per night."
9805
+ },
9806
+ "ListingRoom": {
9807
+ "type": "object",
9808
+ "properties": {
9809
+ "type": {
9810
+ "type": "string",
9811
+ "description": "Room kind, Airbnb spelling: `bedroom`, `living_room`, `full_bathroom`, `kitchen`, \u2026",
9812
+ "example": "bedroom"
9813
+ },
9814
+ "name": {
9815
+ "type": "string",
9816
+ "nullable": true
9817
+ },
9818
+ "number": {
9819
+ "type": "integer",
9820
+ "nullable": true,
9821
+ "description": "Position among rooms of the same type (bedroom 1, 2, \u2026)."
9822
+ },
9823
+ "isPrivate": {
9824
+ "type": "boolean",
9825
+ "nullable": true
9826
+ },
9827
+ "beds": {
9828
+ "type": "array",
9829
+ "items": {
9830
+ "type": "object",
9831
+ "properties": {
9832
+ "type": {
9833
+ "type": "string",
9834
+ "example": "queen_bed"
9835
+ },
9836
+ "quantity": {
9837
+ "type": "integer",
9838
+ "example": 1
9839
+ }
9840
+ }
9841
+ }
9842
+ }
9843
+ }
9844
+ },
9845
+ "ListingPolicies": {
9846
+ "type": "object",
9847
+ "properties": {
9848
+ "cancellationPolicy": {
9849
+ "type": "string",
9850
+ "nullable": true,
9851
+ "example": "flexible"
9852
+ },
9853
+ "houseRules": {
9854
+ "type": "string",
9855
+ "nullable": true
9856
+ },
9857
+ "checkIn": {
9858
+ "type": "object",
9859
+ "properties": {
9860
+ "method": {
9861
+ "type": "string",
9862
+ "nullable": true,
9863
+ "description": "`lockbox`, `smartlock`, `keypad`, `doorman`, `host_greets`, `building_staff`, `other`.",
9864
+ "example": "lockbox"
9865
+ },
9866
+ "instructions": {
9867
+ "type": "string",
9868
+ "nullable": true
9869
+ },
9870
+ "from": {
9871
+ "type": "string",
9872
+ "nullable": true,
9873
+ "example": "15:00"
9874
+ },
9875
+ "until": {
9876
+ "type": "string",
9877
+ "nullable": true,
9878
+ "example": "22:00"
9879
+ }
9880
+ }
9881
+ },
9882
+ "checkOut": {
9883
+ "type": "object",
9884
+ "properties": {
9885
+ "until": {
9886
+ "type": "string",
9887
+ "nullable": true,
9888
+ "example": "11:00"
9889
+ }
9890
+ }
9891
+ },
9892
+ "allowsPets": {
9893
+ "type": "boolean",
9894
+ "nullable": true
9895
+ },
9896
+ "allowsSmoking": {
9897
+ "type": "boolean",
9898
+ "nullable": true
9899
+ },
9900
+ "allowsEvents": {
9901
+ "type": "boolean",
9902
+ "nullable": true
9903
+ },
9904
+ "allowsChildren": {
9905
+ "type": "boolean",
9906
+ "nullable": true
9907
+ },
9908
+ "allowsInfants": {
9909
+ "type": "boolean",
9910
+ "nullable": true
9911
+ },
9912
+ "childrenMinAge": {
9913
+ "type": "integer",
9914
+ "nullable": true
9915
+ },
9916
+ "quietHours": {
9917
+ "type": "object",
9918
+ "nullable": true,
9919
+ "properties": {
9920
+ "start": {
9921
+ "type": "string",
9922
+ "example": "22:00"
9923
+ },
9924
+ "end": {
9925
+ "type": "string",
9926
+ "example": "07:00"
9927
+ }
9928
+ }
9929
+ },
9930
+ "securityDeposit": {
9931
+ "type": "number",
9932
+ "nullable": true,
9933
+ "description": "In the listing currency."
9934
+ }
9935
+ }
9936
+ },
9937
+ "ListingRules": {
9938
+ "type": "object",
9939
+ "properties": {
9940
+ "minNights": {
9941
+ "type": "integer",
9942
+ "nullable": true
9943
+ },
9944
+ "maxNights": {
9945
+ "type": "integer",
9946
+ "nullable": true
9947
+ },
9948
+ "bookingWindowDays": {
9949
+ "type": "integer",
9950
+ "nullable": true,
9951
+ "description": "How far ahead a guest can book. `null` when unlimited or not set."
9952
+ },
9953
+ "advanceNoticeHours": {
9954
+ "type": "integer",
9955
+ "nullable": true,
9956
+ "description": "Hours of notice required before check-in."
9957
+ },
9958
+ "preparationDays": {
9959
+ "type": "integer",
9960
+ "nullable": true,
9961
+ "description": "Nights blocked between stays."
9962
+ },
9963
+ "allowsBookingRequests": {
9964
+ "type": "boolean",
9965
+ "nullable": true,
9966
+ "description": "Whether guests may send a booking request inside the notice window."
9967
+ },
9968
+ "instantBook": {
9969
+ "type": "string",
9970
+ "nullable": true
9971
+ }
9972
+ }
9973
+ },
9974
+ "ListingPricingSettings": {
9975
+ "type": "object",
9976
+ "description": "The listing's standing prices. Nightly rates per date are on `GET /v1/availability/{propertyId}`.",
9977
+ "properties": {
9978
+ "currency": {
9979
+ "type": "string",
9980
+ "nullable": true,
9981
+ "example": "GBP"
9982
+ },
9983
+ "basePrice": {
9984
+ "type": "number",
9985
+ "nullable": true,
9986
+ "description": "Default nightly rate."
9987
+ },
9988
+ "weekendPrice": {
9989
+ "type": "number",
9990
+ "nullable": true
9991
+ },
9992
+ "cleaningFee": {
9993
+ "type": "number",
9994
+ "nullable": true
9995
+ },
9996
+ "extraGuestFee": {
9997
+ "type": "number",
9998
+ "nullable": true,
9999
+ "description": "Per extra guest per night, above `guestsIncluded`."
10000
+ },
10001
+ "guestsIncluded": {
10002
+ "type": "integer",
10003
+ "nullable": true
10004
+ },
10005
+ "securityDeposit": {
10006
+ "type": "number",
10007
+ "nullable": true
10008
+ },
10009
+ "weeklyDiscountPercent": {
10010
+ "type": "number",
10011
+ "nullable": true,
10012
+ "description": "Percent off for 7+ nights: `10` is 10%."
10013
+ },
10014
+ "monthlyDiscountPercent": {
10015
+ "type": "number",
10016
+ "nullable": true,
10017
+ "description": "Percent off for 28+ nights."
10018
+ }
10019
+ }
10020
+ },
10021
+ "ListingFee": {
10022
+ "type": "object",
10023
+ "description": "A fee on top of the nightly rate, the cleaning fee included. One shape for every channel and PMS.",
10024
+ "properties": {
10025
+ "type": {
10026
+ "type": "string",
10027
+ "description": "`cleaning`, `pet`, `linen`, `resort`, `management`, `community`, or the source's own kind.",
10028
+ "example": "cleaning"
10029
+ },
10030
+ "name": {
10031
+ "type": "string",
10032
+ "nullable": true,
10033
+ "example": "Damage Waiver"
10034
+ },
10035
+ "amount": {
10036
+ "type": "number",
10037
+ "description": "In the listing currency when `amountType` is `flat`; a percent when `percent`.",
10038
+ "example": 35
10039
+ },
10040
+ "amountType": {
10041
+ "type": "string"
10042
+ },
10043
+ "chargedPer": {
10044
+ "$ref": "#/components/schemas/ChargePer"
10045
+ },
10046
+ "optional": {
10047
+ "type": "boolean",
10048
+ "description": "Offered to the guest (an add-on) rather than always charged."
10049
+ },
10050
+ "source": {
10051
+ "type": "string",
10052
+ "description": "Where it was read from: `airbnb`, `guesty`, \u2026",
10053
+ "example": "guesty"
10054
+ }
10055
+ }
10056
+ },
10057
+ "ListingTax": {
10058
+ "type": "object",
10059
+ "description": "A tax charged to the guest. One shape for every channel and PMS.",
10060
+ "properties": {
10061
+ "type": {
10062
+ "type": "string",
10063
+ "description": "`vat`, `vat_gst`, `city_tax`, `transient_occupancy_tax`, \u2026",
10064
+ "example": "vat"
10065
+ },
10066
+ "name": {
10067
+ "type": "string",
10068
+ "nullable": true,
10069
+ "example": "VAT"
10070
+ },
10071
+ "amount": {
10072
+ "type": "number",
10073
+ "example": 20
10074
+ },
10075
+ "amountType": {
10076
+ "type": "string"
10077
+ },
10078
+ "chargedPer": {
10079
+ "$ref": "#/components/schemas/ChargePer"
10080
+ },
10081
+ "appliesTo": {
10082
+ "type": "array",
10083
+ "nullable": true,
10084
+ "items": {
10085
+ "type": "string"
10086
+ },
10087
+ "description": "What it is charged on (`accommodation`, `cleaning`, other fee types). `null`: the whole stay."
10088
+ },
10089
+ "included": {
10090
+ "type": "boolean",
10091
+ "description": "Already included in the price rather than added on top."
10092
+ },
10093
+ "source": {
10094
+ "type": "string",
10095
+ "description": "`airbnb` (host-remitted), `airbnb_collected` (Airbnb collects and remits), `guesty`, \u2026"
10096
+ }
10097
+ }
10098
+ },
10099
+ "ListingContentPhoto": {
10100
+ "type": "object",
10101
+ "properties": {
10102
+ "url": {
10103
+ "type": "string",
10104
+ "format": "uri"
10105
+ },
10106
+ "thumbnailUrl": {
10107
+ "type": "string",
10108
+ "nullable": true
10109
+ },
10110
+ "caption": {
10111
+ "type": "string",
10112
+ "nullable": true
10113
+ },
10114
+ "category": {
10115
+ "type": "string",
10116
+ "nullable": true
10117
+ },
10118
+ "width": {
10119
+ "type": "integer",
10120
+ "nullable": true
10121
+ },
10122
+ "height": {
10123
+ "type": "integer",
10124
+ "nullable": true
10125
+ },
10126
+ "sortOrder": {
10127
+ "type": "integer"
10128
+ }
10129
+ }
10130
+ },
9462
10131
  "Listing": {
9463
10132
  "type": "object",
9464
10133
  "description": "A vacation rental listing in your Repull workspace.\n\nAn **inactive** listing appears only in `GET /v1/listings`, and only when `?status=` asks for it. Such a row carries identity fields only \u2014 `id`, `name`, `status`, `inactiveReason`, `address.city`, `channels` \u2014 so the street, `content`, `details`, `createdAt` and `updatedAt` are absent until the listing is activated. `inactiveReason` is `plan_limit` (held back by the plan; activating needs a free slot or an upgrade), `unlisted_on_airbnb`, or `deactivated` (switched off by you). `GET /v1/listings/{id}` and every other listing endpoint answer `403 listing_inactive` for it. The one field you can add back is `thumbnailUrl`, by passing `?include=thumbnail` \u2014 enough to render an activate/deactivate picker with pictures from a single request.",
@@ -9557,14 +10226,48 @@
9557
10226
  },
9558
10227
  "address": {
9559
10228
  "type": "object",
10229
+ "description": "The listing's postal address, unit included. Each part is read from the listing first, then from the connected channels (Airbnb, Vrbo, Booking.com). On an inactive row only `city` is present.",
9560
10230
  "properties": {
9561
10231
  "street": {
9562
10232
  "type": "string",
9563
- "nullable": true
10233
+ "nullable": true,
10234
+ "description": "Street line as stored on the listing. Kept for existing integrations; same value as `line1` unless the listing has no street of its own.",
10235
+ "example": "2700 Northwest 2nd Avenue"
10236
+ },
10237
+ "line1": {
10238
+ "type": "string",
10239
+ "nullable": true,
10240
+ "description": "Street address: number and street.",
10241
+ "example": "2700 Northwest 2nd Avenue"
10242
+ },
10243
+ "line2": {
10244
+ "type": "string",
10245
+ "nullable": true,
10246
+ "description": "Apartment, unit, suite or building.",
10247
+ "example": "Unit 241"
9564
10248
  },
9565
10249
  "city": {
9566
10250
  "type": "string",
9567
- "nullable": true
10251
+ "nullable": true,
10252
+ "example": "Miami"
10253
+ },
10254
+ "state": {
10255
+ "type": "string",
10256
+ "nullable": true,
10257
+ "description": "State, province or region.",
10258
+ "example": "FL"
10259
+ },
10260
+ "postalCode": {
10261
+ "type": "string",
10262
+ "nullable": true,
10263
+ "description": "Postal or ZIP code.",
10264
+ "example": "33127"
10265
+ },
10266
+ "countryCode": {
10267
+ "type": "string",
10268
+ "nullable": true,
10269
+ "description": "ISO 3166-1 alpha-2 country code.",
10270
+ "example": "US"
9568
10271
  }
9569
10272
  }
9570
10273
  },
@@ -9609,6 +10312,61 @@
9609
10312
  "nullable": true,
9610
10313
  "description": "**Only present when the caller passes `?include=details`.** Sourced from `listings_details`. `null` when the listing has no details row stored (vs the field being absent \u2014 that signals the caller did not opt into the expansion)."
9611
10314
  },
10315
+ "rooms": {
10316
+ "type": "array",
10317
+ "items": {
10318
+ "$ref": "#/components/schemas/ListingRoom"
10319
+ },
10320
+ "description": "**Only present with `?include=rooms`.** Each room and its beds. `[]` when none are stored."
10321
+ },
10322
+ "policies": {
10323
+ "allOf": [
10324
+ {
10325
+ "$ref": "#/components/schemas/ListingPolicies"
10326
+ }
10327
+ ],
10328
+ "nullable": true,
10329
+ "description": "**Only present with `?include=policies`.** Cancellation, house rules, check-in and check-out, pets/smoking/events/children, quiet hours, deposit."
10330
+ },
10331
+ "rules": {
10332
+ "allOf": [
10333
+ {
10334
+ "$ref": "#/components/schemas/ListingRules"
10335
+ }
10336
+ ],
10337
+ "nullable": true,
10338
+ "description": "**Only present with `?include=rules`.** Stay rules: min/max nights, booking window, advance notice, preparation time, and whether booking requests are allowed."
10339
+ },
10340
+ "pricing": {
10341
+ "allOf": [
10342
+ {
10343
+ "$ref": "#/components/schemas/ListingPricingSettings"
10344
+ }
10345
+ ],
10346
+ "nullable": true,
10347
+ "description": "**Only present with `?include=pricing`.** Standing prices: base and weekend rate, cleaning and extra-guest fees, deposit, weekly/monthly discounts. `null` when none are stored."
10348
+ },
10349
+ "fees": {
10350
+ "type": "array",
10351
+ "items": {
10352
+ "$ref": "#/components/schemas/ListingFee"
10353
+ },
10354
+ "description": "**Only present with `?include=fees`.** Every fee, the cleaning fee included, whatever channel or PMS it came from. `[]` when none."
10355
+ },
10356
+ "taxes": {
10357
+ "type": "array",
10358
+ "items": {
10359
+ "$ref": "#/components/schemas/ListingTax"
10360
+ },
10361
+ "description": "**Only present with `?include=taxes`.** Taxes charged to the guest. `[]` when none."
10362
+ },
10363
+ "photos": {
10364
+ "type": "array",
10365
+ "items": {
10366
+ "$ref": "#/components/schemas/ListingContentPhoto"
10367
+ },
10368
+ "description": "**Only present with `?include=photos`.** The listing photos in display order."
10369
+ },
9612
10370
  "createdAt": {
9613
10371
  "type": "string",
9614
10372
  "format": "date-time"
@@ -18279,6 +19037,15 @@
18279
19037
  "example": 24,
18280
19038
  "description": "Airbnb \u2014 how many months of past reservations the first import pulls (1\u201360). Omit it for the default window. Upcoming stays are always imported. A wider window takes longer to import, because every extra month is more stays to fetch."
18281
19039
  },
19040
+ "mapping": {
19041
+ "type": "string",
19042
+ "enum": [
19043
+ "hosted",
19044
+ "api"
19045
+ ],
19046
+ "default": "hosted",
19047
+ "description": "Where the channel's units get linked to listings. `hosted` (default): after a Vrbo or Booking.com Extranet sign-in, Connect shows a mapping step and returns to `redirectUrl` when it's confirmed. `api`: Connect skips that step and finishes right after sign-in. The connection reaches you in the `connect.session.completed` webhook as `account.externalAccountId` (its `connectionId` is null for these two), and as `connectionId` in the popup message and `accountId` on the redirect, all the same id; its handle is `vrbo:{id}` or `booking_extranet:{id}`; you list the units with `GET /v1/connections/{id}/units` and link them with `POST /v1/connections/{id}/mappings`. Nothing is imported until you post the mappings. Other providers ignore it."
19048
+ },
18282
19049
  "accessType": {
18283
19050
  "type": "string",
18284
19051
  "enum": [
@@ -18304,7 +19071,7 @@
18304
19071
  "locale": {
18305
19072
  "type": "string",
18306
19073
  "nullable": true,
18307
- "description": "Optional UI language for the hosted Connect pages. Accepts any supported locale code (currently `en`, `fr`). When set it pins the language for the whole flow, overriding the workspace `default_language`. Unknown codes are ignored and the page falls back to the workspace default, then `Accept-Language`, then `en`. The end user can still override per-visit with a `?locale=` query param on the hosted page.",
19074
+ "description": "Optional UI language for the hosted Connect pages. Accepts any supported locale code (currently `en`, `fr`, `de`, `es`, `it`, `nl`). When set it pins the language for the whole flow, overriding the workspace `default_language`. Unknown codes are ignored and the page falls back to the workspace default, then `Accept-Language`, then `en`. The end user can still override per-visit with a `?locale=` query param on the hosted page.",
18308
19075
  "example": "fr"
18309
19076
  },
18310
19077
  "purpose": {
@@ -18517,7 +19284,7 @@
18517
19284
  "post": {
18518
19285
  "operationId": "create_connection",
18519
19286
  "summary": "Connect to PMS/OTA provider",
18520
- "description": "Establish a connection to a PMS or OTA platform. Credentials vary by provider \u2014 see docs for each provider.\n\nAirbnb-specific: pass `redirectUrl` (where to send the user after consent) and optionally `accessType`. Three tiers: `read_only` grants read-only scopes; `messaging` grants read scopes plus message read/send but NOT property management, so it can coexist with another app (e.g. an existing PMS) that already holds property management on the same Airbnb account; `full_access` \u2014 the default \u2014 grants full host scopes including the exclusive property management (only one app per Airbnb account can hold it). The response returns a hosted `url` to redirect the user to.\n\nBooking.com: pass `redirectUrl` (no `accessType`). The response returns a hosted `url` \u2014 send the user there to designate FantasticStay in their Booking.com Extranet and paste their Hotel ID. Same response shape as Airbnb (`url`, `sessionId`, `expiresAt`).\n\nPlumguide passes `clientId`/`clientSecret`. PMS providers are not connected by this call: send their credentials to `POST /v1/connect/{provider}/credentials`, or start a hosted session with `POST /v1/connect`.",
19287
+ "description": "Establish a connection to a PMS or OTA platform. Credentials vary by provider \u2014 see docs for each provider.\n\nAirbnb-specific: pass `redirectUrl` (where to send the user after consent) and optionally `accessType`. Three tiers: `read_only` grants read-only scopes; `messaging` (shown to hosts as \"Messaging & reviews\") grants read scopes plus message read/send and review writes (reply to guest reviews, submit host reviews \u2014 Airbnb's `reviews_write`) but NOT property management, so it can coexist with another app (e.g. an existing PMS) that already holds property management on the same Airbnb account; `full_access` \u2014 the default \u2014 grants full host scopes including the exclusive property management (only one app per Airbnb account can hold it). The response returns a hosted `url` to redirect the user to.\n\nBooking.com: pass `redirectUrl` (no `accessType`). The response returns a hosted `url` \u2014 send the user there to select our connectivity provider in their Booking.com Extranet and paste their Hotel ID. Same response shape as Airbnb (`url`, `sessionId`, `expiresAt`).\n\nPMS providers are not connected by this call: send their credentials to `POST /v1/connect/{provider}/credentials`, or start a hosted session with `POST /v1/connect`.",
18521
19288
  "tags": [
18522
19289
  "Connect"
18523
19290
  ],
@@ -18546,7 +19313,7 @@
18546
19313
  "messaging"
18547
19314
  ],
18548
19315
  "default": "full_access",
18549
- "description": "Airbnb only \u2014 selects the OAuth scope set. 'read_only' grants read-only scopes; 'messaging' grants read scopes plus message read/send but NOT property management, so it can coexist with another app (e.g. an existing PMS) that already holds property management on the same Airbnb account; 'full_access' (default) grants full host scopes including the exclusive property management (only one app per Airbnb account can hold it). The hosted consent screen normally lets the host pick a tier; passing `accessType` explicitly fixes the tier and hides that choice, so the host can only continue with the tier you requested. Omit it to let the host choose."
19316
+ "description": "Airbnb only \u2014 selects the OAuth scope set. 'read_only' grants read-only scopes; 'messaging' (shown to hosts as \"Messaging & reviews\") grants read scopes plus message read/send and review writes (reply to guest reviews, submit host reviews \u2014 Airbnb's reviews_write) but NOT property management, so it can coexist with another app (e.g. an existing PMS) that already holds property management on the same Airbnb account; 'full_access' (default) grants full host scopes including the exclusive property management (only one app per Airbnb account can hold it). The hosted consent screen normally lets the host pick a tier; passing `accessType` explicitly fixes the tier and hides that choice, so the host can only continue with the tier you requested. Omit it to let the host choose."
18550
19317
  },
18551
19318
  "reservationHistoryMonths": {
18552
19319
  "type": "integer",
@@ -18559,18 +19326,10 @@
18559
19326
  "type": "string",
18560
19327
  "description": "Airbnb + Booking.com \u2014 your own correlation token, e.g. your user id (at most 500 characters). Echoed on the redirect back (`&state=`) and in the `connect.session.completed` webhook."
18561
19328
  },
18562
- "clientId": {
18563
- "type": "string",
18564
- "description": "Plumguide \u2014 client ID."
18565
- },
18566
- "clientSecret": {
18567
- "type": "string",
18568
- "description": "Plumguide \u2014 client secret."
18569
- },
18570
19329
  "locale": {
18571
19330
  "type": "string",
18572
19331
  "nullable": true,
18573
- "description": "Airbnb only \u2014 optional UI language for the hosted Connect pages. Accepts any supported locale code (currently `en`, `fr`); unknown codes are ignored and resolution falls back to the workspace `default_language`, then `Accept-Language`, then `en`.",
19332
+ "description": "Airbnb and Booking.com \u2014 optional UI language for the hosted Connect pages. Accepts any supported locale code (currently `en`, `fr`, `de`, `es`, `it`, `nl`); unknown codes are ignored and resolution falls back to the workspace `default_language`, then `Accept-Language`, then `en`.",
18574
19333
  "example": "fr"
18575
19334
  }
18576
19335
  }
@@ -18594,7 +19353,7 @@
18594
19353
  "delete": {
18595
19354
  "operationId": "delete_connection",
18596
19355
  "summary": "Disconnect provider",
18597
- "description": "Disconnect ONE connected account of a provider from this workspace. Supported for `airbnb` and `booking`.\n\n**Which account.** Pass `accountId` \u2014 for Airbnb the host id (`accounts[].externalAccountId` from `GET /v1/connect/airbnb`), for Booking.com the hotel id. It is optional only when the workspace has exactly one account for the provider. With several and no `accountId`, the call returns `422` with the account ids in `valid_values` instead of guessing. An `accountId` that is not connected to this workspace returns `404`. Disconnecting one account leaves the others connected.\n\n**What happens.** The account's stored authorization is removed and it stops syncing. Its listings are **deactivated**, not deleted: they stop counting toward your plan's listing limit, their data is kept, and they are returned in `listingsDeactivated`. A listing that is still connected through another account or channel stays active. Reconnect the account, then activate the listings with `POST /v1/listings/status`.\n\nThe change is all or nothing. For Airbnb, the host can also revoke access on Airbnb's side (Account \u2192 Privacy & sharing \u2192 Connected apps); that alone does not update this workspace, so call this endpoint as well.\n\nOther providers return `501 not_implemented` with instructions for disconnecting on the provider's side. That answer depends only on the provider, not on your workspace: an unsupported provider returns `501` whether or not you have a connection to it. `404 not_found` on a supported provider means this workspace has no connection to it (or, with `accountId`, that the account is not connected here).",
19356
+ "description": "Disconnect ONE connected account of a provider from this workspace. Supported for `airbnb`, `booking` and `vrbo-login`.\n\n**Which account.** Pass `accountId` \u2014 for Airbnb the host id (`accounts[].externalAccountId` from `GET /v1/connect/airbnb`), for Booking.com the hotel id, for `vrbo-login` the sign-in's `accounts[].externalAccountId` from `GET /v1/connect/vrbo-login`. It is optional only when the workspace has exactly one account for the provider. With several and no `accountId`, the call returns `422` with the account ids in `valid_values` instead of guessing. An `accountId` that is not connected to this workspace returns `404`. Disconnecting one account leaves the others connected.\n\n**What happens.** The account's stored authorization is removed and it stops syncing. Its listings are **deactivated**, not deleted: they stop counting toward your plan's listing limit, their data is kept, and they are returned in `listingsDeactivated`. A listing that is still connected through another account or channel stays active. Reconnect the account, then activate the listings with `POST /v1/listings/status`.\n\nThe change is all or nothing. For Airbnb, the host can also revoke access on Airbnb's side (Account \u2192 Privacy & sharing \u2192 Connected apps); that alone does not update this workspace, so call this endpoint as well.\n\nOther providers return `501 not_implemented` with instructions for disconnecting on the provider's side. That answer depends only on the provider, not on your workspace: an unsupported provider returns `501` whether or not you have a connection to it. `404 not_found` on a supported provider means this workspace has no connection to it (or, with `accountId`, that the account is not connected here).",
18598
19357
  "tags": [
18599
19358
  "Connect"
18600
19359
  ],
@@ -19434,7 +20193,7 @@
19434
20193
  "get": {
19435
20194
  "operationId": "getChannelHealth",
19436
20195
  "summary": "Per-channel connectivity health",
19437
- "description": "Reports reachability and auth state for one channel (`airbnb`, `booking`, `vrbo`, `plumguide`). Use it to tell \"the channel is down\" apart from \"this workspace's connection expired\". `200` when `status` is `ok`, `503` when `degraded` or `down` (the body's `status` and `message` say which and why).\n\n**`vrbo`** reports the connector's own signals in a `vrbo` block: connected accounts, accounts VRBO signed out (their bookings, messages and calendar stop until reconnected \u2014 `down`), accounts whose inbox sync is late (`degraded`), and the calendar push queue backlog and its oldest wait (`degraded` past 3 hours). Its rate is calendar pushes VRBO refused over finished ones in the last 3 hours; failures inside Repull's own connector are reported apart as `vrbo.connector_errors` and do not count (`vrbo.window_hours`; `refresh_attempts_24h` / `refresh_rejections_24h` count that window for VRBO), judged only once at least 50 pushes finished and at least 5 failed \u2014 VRBO pushes run in bursts, so a day-long window would keep reporting a problem already fixed.",
20196
+ "description": "Reports reachability and auth state for one channel (`airbnb`, `booking`, `vrbo`). Use it to tell \"the channel is down\" apart from \"this workspace's connection expired\". `200` when `status` is `ok`, `503` when `degraded` or `down` (the body's `status` and `message` say which and why).\n\n**`vrbo`** reports the connector's own signals in a `vrbo` block: connected accounts, accounts VRBO signed out (their bookings, messages and calendar stop until reconnected \u2014 `down`), accounts whose inbox sync is late (`degraded`), and the calendar push queue backlog and its oldest wait (`degraded` past 3 hours). Its rate is calendar pushes VRBO refused over finished ones in the last 3 hours; failures inside Repull's own connector are reported apart as `vrbo.connector_errors` and do not count (`vrbo.window_hours`; `refresh_attempts_24h` / `refresh_rejections_24h` count that window for VRBO), judged only once at least 50 pushes finished and at least 5 failed \u2014 VRBO pushes run in bursts, so a day-long window would keep reporting a problem already fixed.",
19438
20197
  "tags": [
19439
20198
  "Health"
19440
20199
  ],
@@ -19449,8 +20208,7 @@
19449
20208
  "enum": [
19450
20209
  "airbnb",
19451
20210
  "booking",
19452
- "vrbo",
19453
- "plumguide"
20211
+ "vrbo"
19454
20212
  ]
19455
20213
  }
19456
20214
  }
@@ -19805,7 +20563,7 @@
19805
20563
  "post": {
19806
20564
  "operationId": "verifyBookingHotel",
19807
20565
  "summary": "Verify a Booking.com hotel ID for a Connect session",
19808
- "description": "Manual-paste fallback that closes the Booking.com claim flow. Call this after the customer completes Stage 1 designation in their Booking Extranet (ticking FantasticStay/Repull as their connectivity provider) and pastes their Hotel ID into the hosted picker.\n\nValidates the hotel against Booking's property API, persists the `pms_connections` row, kicks off the room import, and transitions the Connect session to `awaiting_room_mapping`.\n\nNo API key required \u2014 the `sessionId` is the capability token. Sessions in any terminal state are rejected.",
20566
+ "description": "Manual-paste fallback that closes the Booking.com claim flow. Call this after the customer completes Stage 1 designation in their Booking Extranet (selecting our connectivity provider, named on the hosted Connect page) and pastes their Hotel ID into the hosted picker.\n\nValidates the hotel against Booking's property API, persists the `pms_connections` row, kicks off the room import, and transitions the Connect session to `awaiting_room_mapping`.\n\nNo API key required \u2014 the `sessionId` is the capability token. Sessions in any terminal state are rejected.",
19809
20567
  "tags": [
19810
20568
  "Connect"
19811
20569
  ],
@@ -25152,7 +25910,7 @@
25152
25910
  "get": {
25153
25911
  "operationId": "listListings",
25154
25912
  "summary": "List listings",
25155
- "description": "Cursor-paginated list of listings owned by the authenticated workspace. Use `pagination.nextCursor` from one response as the `cursor` query param of the next request to walk the full set. `?offset=` is also accepted as a first-class alias for shallow paging (0..10000) \u2014 see the `offset` parameter below. Mutually exclusive with `cursor`. Filters: `q` (substring on name/street/city), `status`, `channel`.\n\n**Optional expansions:** Pass `?include=content` to enrich each row with the rich content slab (summary, description, space, house rules, etc. \u2014 sourced from `listings_descriptions` for the `en` locale). Pass `?include=details` for the structural slab (bedrooms, bathrooms, person capacity, check-in window, wifi, house manual, etc.). Both default to `null` per row when the underlying `listings_descriptions` / `listings_details` row is missing \u2014 distinct from the field being absent (which signals the expansion was not requested). Pass `?include=thumbnail` to guarantee `thumbnailUrl` on every returned row \u2014 including the reduced inactive ones. Combine comma-separated, e.g. `?include=content,thumbnail`. The default response stays lean; consumers must opt in.\n\n**Inactive listings:** by default only active listings are returned. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated, so when `status` asks for inactive ones they carry only `id`, `name`, `status` and `channels` \u2014 enough to choose what to activate with `PATCH /v1/listings/{id}`. The `content` and `details` expansions are not applied to them. `?include=thumbnail` is the one exception: it adds `thumbnailUrl` to an inactive row so a single request can render an active/inactive selection screen with pictures, instead of one follow-up call per listing (which an inactive listing would answer with `403 listing_inactive` anyway).",
25913
+ "description": "Cursor-paginated list of listings owned by the authenticated workspace. Use `pagination.nextCursor` from one response as the `cursor` query param of the next request to walk the full set. `?offset=` is also accepted as a first-class alias for shallow paging (0..10000) \u2014 see the `offset` parameter below. Mutually exclusive with `cursor`. Filters: `q` (substring on name/street/city), `status`, `channel`.\n\n**Optional expansions:** Pass `?include=content` to enrich each row with the rich content slab (summary, description, space, house rules, etc. \u2014 sourced from `listings_descriptions` for the `en` locale). Pass `?include=details` for the structural slab (bedrooms, bathrooms, person capacity, check-in window, wifi, house manual, etc.). Both default to `null` per row when the underlying `listings_descriptions` / `listings_details` row is missing \u2014 distinct from the field being absent (which signals the expansion was not requested). Pass `?include=thumbnail` to guarantee `thumbnailUrl` on every returned row \u2014 including the reduced inactive ones. Pass `rooms`, `policies`, `rules`, `pricing`, `fees`, `taxes` or `photos` for the same sections as `GET /v1/listings/{id}`, loaded for the whole page in one go. Combine comma-separated, e.g. `?include=content,thumbnail`. The default response stays lean; consumers must opt in.\n\n**Inactive listings:** by default only active listings are returned. An inactive listing keeps syncing, but cannot be read or changed through the API until it is activated, so when `status` asks for inactive ones they carry only `id`, `name`, `status` and `channels` \u2014 enough to choose what to activate with `PATCH /v1/listings/{id}`. The `content` and `details` expansions are not applied to them. `?include=thumbnail` is the one exception: it adds `thumbnailUrl` to an inactive row so a single request can render an active/inactive selection screen with pictures, instead of one follow-up call per listing (which an inactive listing would answer with `403 listing_inactive` anyway).",
25156
25914
  "tags": [
25157
25915
  "Listings"
25158
25916
  ],
@@ -25222,7 +25980,7 @@
25222
25980
  "type": "string",
25223
25981
  "example": "content,thumbnail"
25224
25982
  },
25225
- "description": "Comma-separated optional expansions. Currently supported: `content`, `details`, `thumbnail`. `thumbnail` guarantees `thumbnailUrl` on every row and is the only expansion that applies to inactive listings. Unknown values return 422 with a `valid_values` envelope. (Note: `amenities` is not yet supported on the list endpoint \u2014 use the detail endpoint to fetch amenity rows for a single listing.)"
25983
+ "description": "Comma-separated optional expansions. Currently supported: `content`, `details`, `thumbnail`, `rooms`, `policies`, `rules`, `pricing`, `fees`, `taxes`, `photos` (the last seven are described on `GET /v1/listings/{id}`; read for the whole page at once). `thumbnail` guarantees `thumbnailUrl` on every row and is the only expansion that applies to inactive listings. Unknown values return 422 with a `valid_values` envelope. (Note: `amenities` is not yet supported on the list endpoint \u2014 use the detail endpoint to fetch amenity rows for a single listing.)"
25226
25984
  }
25227
25985
  ],
25228
25986
  "responses": {
@@ -25285,7 +26043,7 @@
25285
26043
  "get": {
25286
26044
  "operationId": "getListing",
25287
26045
  "summary": "Get a listing",
25288
- "description": "Fetch a single listing by id. Returns the same shape as one element of the `GET /v1/listings` response, so you can bind the result to the same model. Cross-tenant access (a listing that belongs to a different workspace) returns 404 \u2014 never 403, never reveals the listing's existence.\n\n**Optional expansions:** Pass `?include=amenities` to enrich the response with the listing's amenity rows (`[]` when the listing has none). Pass `?include=content` for the rich content slab (summary, description, space, house rules, etc. \u2014 sourced from `listings_descriptions` for the `en` locale; `null` when no row is stored). Pass `?include=details` for the structural slab (bedrooms, bathrooms, person capacity, check-in window, wifi, house manual, etc.; `null` when no row is stored). Combine comma-separated, e.g. `?include=amenities,content,details`. The default response stays lean; consumers must opt in.\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.",
26046
+ "description": "Fetch a single listing by id. Returns the same shape as one element of the `GET /v1/listings` response, so you can bind the result to the same model. Cross-tenant access (a listing that belongs to a different workspace) returns 404 \u2014 never 403, never reveals the listing's existence.\n\n**Optional expansions:** Pass `?include=amenities` to enrich the response with the listing's amenity rows (`[]` when the listing has none). Pass `?include=content` for the rich content slab (summary, description, space, house rules, etc. \u2014 sourced from `listings_descriptions` for the `en` locale; `null` when no row is stored). Pass `?include=details` for the structural slab (bedrooms, bathrooms, person capacity, check-in window, wifi, house manual, etc.; `null` when no row is stored). Pass `?include=rooms` for rooms and beds, `policies` for cancellation, house rules, check-in/out and guest rules, `rules` for stay rules (min/max nights, booking window, notice, preparation time), `pricing` for standing prices and discounts, `fees` and `taxes` for every fee and tax in one shape whatever channel or PMS the listing comes from, and `photos`. Combine comma-separated, e.g. `?include=content,details,rooms,policies,pricing,fees,taxes`. The default response stays lean; consumers must opt in.\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.",
25289
26047
  "tags": [
25290
26048
  "Listings"
25291
26049
  ],
@@ -25310,7 +26068,7 @@
25310
26068
  "type": "string",
25311
26069
  "example": "content,details"
25312
26070
  },
25313
- "description": "Comma-separated optional expansions. Currently supported: `amenities`, `content`, `details`. Unknown values return 422 with a `valid_values` envelope."
26071
+ "description": "Comma-separated optional expansions. Currently supported: `amenities`, `content`, `details`, `rooms`, `policies`, `rules`, `pricing`, `fees`, `taxes`, `photos`. Unknown values return 422 with a `valid_values` envelope."
25314
26072
  }
25315
26073
  ],
25316
26074
  "responses": {
@@ -27386,226 +28144,6 @@
27386
28144
  }
27387
28145
  }
27388
28146
  },
27389
- "/v1/channels/plumguide/listings": {
27390
- "get": {
27391
- "operationId": "list_plumguide_listings",
27392
- "summary": "List Plumguide listings",
27393
- "description": "List Plumguide listings this workspace has access to. Plumguide is approval-based \u2014 listings appear once Plumguide has accepted them.",
27394
- "tags": [
27395
- "Plumguide"
27396
- ],
27397
- "responses": {
27398
- "200": {
27399
- "description": "Listings",
27400
- "content": {
27401
- "application/json": {
27402
- "schema": {
27403
- "$ref": "#/components/schemas/PlumguideListingListResponse"
27404
- }
27405
- }
27406
- }
27407
- }
27408
- }
27409
- }
27410
- },
27411
- "/v1/channels/plumguide/availability": {
27412
- "get": {
27413
- "operationId": "get_plumguide_availability",
27414
- "summary": "Get Plumguide availability",
27415
- "description": "Read the per-day availability calendar for a Plumguide listing. Returns the same row shape as Airbnb availability for SDK convenience.\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.",
27416
- "tags": [
27417
- "Plumguide"
27418
- ],
27419
- "responses": {
27420
- "200": {
27421
- "description": "Availability"
27422
- },
27423
- "403": {
27424
- "$ref": "#/components/responses/ListingInactive"
27425
- }
27426
- }
27427
- },
27428
- "put": {
27429
- "operationId": "update_plumguide_availability",
27430
- "summary": "Push availability to Plumguide",
27431
- "description": "Push per-day availability changes to Plumguide. Plumguide accepts only the next 24 months \u2014 dates beyond that are silently ignored.\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.",
27432
- "tags": [
27433
- "Plumguide"
27434
- ],
27435
- "responses": {
27436
- "200": {
27437
- "description": "Pushed"
27438
- },
27439
- "403": {
27440
- "$ref": "#/components/responses/ListingInactive"
27441
- }
27442
- }
27443
- }
27444
- },
27445
- "/v1/channels/plumguide/pricing": {
27446
- "get": {
27447
- "operationId": "get_plumguide_pricing",
27448
- "summary": "Get Plumguide pricing",
27449
- "description": "Read the current pricing for a Plumguide listing (base price, currency, weekend uplift).\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.",
27450
- "tags": [
27451
- "Plumguide"
27452
- ],
27453
- "responses": {
27454
- "200": {
27455
- "description": "Pricing"
27456
- },
27457
- "403": {
27458
- "$ref": "#/components/responses/ListingInactive"
27459
- }
27460
- }
27461
- },
27462
- "put": {
27463
- "operationId": "update_plumguide_pricing",
27464
- "summary": "Push pricing to Plumguide",
27465
- "description": "Push pricing changes to Plumguide. Plumguide rounds all prices to whole units of the listing currency \u2014 sub-unit precision is silently truncated.\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.",
27466
- "tags": [
27467
- "Plumguide"
27468
- ],
27469
- "responses": {
27470
- "200": {
27471
- "description": "Pushed"
27472
- },
27473
- "403": {
27474
- "$ref": "#/components/responses/ListingInactive"
27475
- }
27476
- }
27477
- }
27478
- },
27479
- "/v1/channels/plumguide/bookings": {
27480
- "get": {
27481
- "operationId": "list_plumguide_bookings",
27482
- "summary": "List Plumguide bookings",
27483
- "description": "List Plumguide bookings. Default returns all bookings; pass `listing_id` to filter to one listing, or `booking_code` to fetch a single booking.\n\nReturns `403 listing_inactive` when `listing_id` or `booking_code` resolves to an inactive listing. The unfiltered list is read straight from Plum Guide and is not filtered by listing status.",
27484
- "tags": [
27485
- "Plumguide"
27486
- ],
27487
- "parameters": [
27488
- {
27489
- "name": "listing_id",
27490
- "in": "query",
27491
- "required": false,
27492
- "schema": {
27493
- "type": "integer"
27494
- },
27495
- "description": "Filter to a single Plumguide listing."
27496
- },
27497
- {
27498
- "name": "booking_code",
27499
- "in": "query",
27500
- "required": false,
27501
- "schema": {
27502
- "type": "string"
27503
- },
27504
- "description": "Fetch a single booking by its Plumguide booking code."
27505
- }
27506
- ],
27507
- "responses": {
27508
- "200": {
27509
- "description": "Bookings"
27510
- },
27511
- "401": {
27512
- "$ref": "#/components/responses/Unauthorized"
27513
- },
27514
- "403": {
27515
- "$ref": "#/components/responses/ListingInactive"
27516
- },
27517
- "404": {
27518
- "$ref": "#/components/responses/NotFound"
27519
- },
27520
- "500": {
27521
- "$ref": "#/components/responses/InternalError"
27522
- }
27523
- }
27524
- }
27525
- },
27526
- "/v1/channels/plumguide/webhooks": {
27527
- "get": {
27528
- "operationId": "get_plumguide_webhooks",
27529
- "summary": "Get Plumguide webhook config",
27530
- "description": "Read the current Plumguide webhook configuration for this workspace.",
27531
- "tags": [
27532
- "Plumguide"
27533
- ],
27534
- "responses": {
27535
- "200": {
27536
- "description": "Webhook config"
27537
- },
27538
- "401": {
27539
- "$ref": "#/components/responses/Unauthorized"
27540
- },
27541
- "404": {
27542
- "$ref": "#/components/responses/NotFound"
27543
- },
27544
- "500": {
27545
- "$ref": "#/components/responses/InternalError"
27546
- }
27547
- }
27548
- },
27549
- "put": {
27550
- "operationId": "update_plumguide_webhooks",
27551
- "summary": "Replace Plumguide webhook config",
27552
- "description": "Replace the Plumguide webhook configuration. The body carries the full webhook config payload \u2014 this is a full replacement, not a patch.",
27553
- "tags": [
27554
- "Plumguide"
27555
- ],
27556
- "requestBody": {
27557
- "required": true,
27558
- "content": {
27559
- "application/json": {
27560
- "schema": {
27561
- "type": "object",
27562
- "additionalProperties": true,
27563
- "description": "Full Plumguide webhook config payload."
27564
- }
27565
- }
27566
- }
27567
- },
27568
- "responses": {
27569
- "200": {
27570
- "description": "Updated"
27571
- },
27572
- "400": {
27573
- "$ref": "#/components/responses/BadRequest"
27574
- },
27575
- "401": {
27576
- "$ref": "#/components/responses/Unauthorized"
27577
- },
27578
- "404": {
27579
- "$ref": "#/components/responses/NotFound"
27580
- },
27581
- "500": {
27582
- "$ref": "#/components/responses/InternalError"
27583
- }
27584
- }
27585
- },
27586
- "delete": {
27587
- "operationId": "delete_plumguide_webhooks",
27588
- "summary": "Remove Plumguide webhook config",
27589
- "description": "Delete the Plumguide webhook configuration for this workspace. Plumguide stops delivering webhooks until a new config is set.",
27590
- "tags": [
27591
- "Plumguide"
27592
- ],
27593
- "responses": {
27594
- "200": {
27595
- "description": "Deleted"
27596
- },
27597
- "401": {
27598
- "$ref": "#/components/responses/Unauthorized"
27599
- },
27600
- "404": {
27601
- "$ref": "#/components/responses/NotFound"
27602
- },
27603
- "500": {
27604
- "$ref": "#/components/responses/InternalError"
27605
- }
27606
- }
27607
- }
27608
- },
27609
28147
  "/v1/listings/{id}/pricing": {
27610
28148
  "get": {
27611
28149
  "operationId": "get_listing_pricing",
@@ -37098,6 +37636,11 @@
37098
37636
  "completed"
37099
37637
  ]
37100
37638
  },
37639
+ "notification_email": {
37640
+ "type": "string",
37641
+ "nullable": true,
37642
+ "description": "Vrbo only. Ask the host to add this address on Vrbo as a secondary email, with message and reservation notifications on. It is how new bookings, inquiries and guest messages reach Repull within a minute; without it they arrive at the next scheduled check. Hosted Connect asks for it on its mapping screen, so show it in your own flow when you map with `mapping: \"api\"`."
37643
+ },
37101
37644
  "units": {
37102
37645
  "type": "array",
37103
37646
  "items": {
@@ -37121,7 +37664,8 @@
37121
37664
  "nullable": true
37122
37665
  },
37123
37666
  "meta": {
37124
- "type": "object"
37667
+ "type": "object",
37668
+ "description": "Channel details that identify the unit. Booking.com Extranet: `hotel` (property name), `hotelId` (Booking.com property ID), `roomId` (Booking.com room ID), `city`. Vrbo: `headline`, `address`, `vrboStatus`; the Vrbo listing ID is `unit_id`."
37125
37669
  }
37126
37670
  }
37127
37671
  }
@@ -39498,6 +40042,822 @@
39498
40042
  }
39499
40043
  }
39500
40044
  }
40045
+ },
40046
+ "/v1/migrations/channex": {
40047
+ "post": {
40048
+ "operationId": "importFromChannex",
40049
+ "summary": "Import from Channex",
40050
+ "description": "Move a workspace off Channex without changing a single id on your side. Pass your Channex API key: Repull reads your Channex properties, room types, rate plans, webhooks, signing keys, channels and upcoming bookings through Channex's own API (read-only \u2014 nothing is written to Channex, and the key is not stored). Each Channex property is matched to your Repull listing or hotel (by Booking.com hotel/room and Airbnb/Vrbo listing ids, then by title and address) or created; every Channex id then resolves, and is returned, unchanged on the Channex-compatible API at `/channex/api/v1`. Webhooks are recreated inactive; activate them with `POST /channex/api/v1/migration/cutover`. Safe to re-run: a run that hits its time budget returns `complete: false` and the next run continues.",
40051
+ "tags": [
40052
+ "Migrate"
40053
+ ],
40054
+ "requestBody": {
40055
+ "required": true,
40056
+ "content": {
40057
+ "application/json": {
40058
+ "schema": {
40059
+ "type": "object",
40060
+ "required": [
40061
+ "apiKey"
40062
+ ],
40063
+ "properties": {
40064
+ "apiKey": {
40065
+ "type": "string",
40066
+ "description": "Your Channex API key (the `user-api-key` header value). Used for this request only."
40067
+ },
40068
+ "environment": {
40069
+ "type": "string",
40070
+ "enum": [
40071
+ "production",
40072
+ "staging"
40073
+ ],
40074
+ "default": "production",
40075
+ "description": "`production` reads app.channex.io, `staging` reads staging.channex.io."
40076
+ },
40077
+ "dryRun": {
40078
+ "type": "boolean",
40079
+ "default": false,
40080
+ "description": "Match and report without writing anything."
40081
+ }
40082
+ }
40083
+ }
40084
+ }
40085
+ }
40086
+ },
40087
+ "responses": {
40088
+ "200": {
40089
+ "description": "Dry run: what the import would do",
40090
+ "content": {
40091
+ "application/json": {
40092
+ "schema": {
40093
+ "type": "object",
40094
+ "properties": {
40095
+ "data": {
40096
+ "type": "object",
40097
+ "properties": {
40098
+ "id": {
40099
+ "type": "string",
40100
+ "format": "uuid"
40101
+ },
40102
+ "environment": {
40103
+ "type": "string",
40104
+ "enum": [
40105
+ "production",
40106
+ "staging"
40107
+ ]
40108
+ },
40109
+ "dryRun": {
40110
+ "type": "boolean"
40111
+ },
40112
+ "complete": {
40113
+ "type": "boolean",
40114
+ "description": "False when the time budget ran out; run the same request again to continue."
40115
+ },
40116
+ "startedAt": {
40117
+ "type": "string",
40118
+ "format": "date-time"
40119
+ },
40120
+ "finishedAt": {
40121
+ "type": "string",
40122
+ "format": "date-time"
40123
+ },
40124
+ "summary": {
40125
+ "type": "object",
40126
+ "properties": {
40127
+ "properties": {
40128
+ "type": "object",
40129
+ "properties": {
40130
+ "matched": {
40131
+ "type": "integer"
40132
+ },
40133
+ "created": {
40134
+ "type": "integer"
40135
+ },
40136
+ "needsAction": {
40137
+ "type": "integer"
40138
+ }
40139
+ }
40140
+ },
40141
+ "roomTypes": {
40142
+ "type": "object",
40143
+ "properties": {
40144
+ "matched": {
40145
+ "type": "integer"
40146
+ },
40147
+ "created": {
40148
+ "type": "integer"
40149
+ },
40150
+ "needsAction": {
40151
+ "type": "integer"
40152
+ }
40153
+ }
40154
+ },
40155
+ "ratePlans": {
40156
+ "type": "object",
40157
+ "properties": {
40158
+ "matched": {
40159
+ "type": "integer"
40160
+ },
40161
+ "created": {
40162
+ "type": "integer"
40163
+ },
40164
+ "needsAction": {
40165
+ "type": "integer"
40166
+ }
40167
+ }
40168
+ },
40169
+ "webhooks": {
40170
+ "type": "object",
40171
+ "properties": {
40172
+ "matched": {
40173
+ "type": "integer"
40174
+ },
40175
+ "created": {
40176
+ "type": "integer"
40177
+ },
40178
+ "needsAction": {
40179
+ "type": "integer"
40180
+ }
40181
+ }
40182
+ },
40183
+ "signingKeys": {
40184
+ "type": "object",
40185
+ "properties": {
40186
+ "matched": {
40187
+ "type": "integer"
40188
+ },
40189
+ "created": {
40190
+ "type": "integer"
40191
+ },
40192
+ "needsAction": {
40193
+ "type": "integer"
40194
+ }
40195
+ }
40196
+ },
40197
+ "channels": {
40198
+ "type": "object",
40199
+ "properties": {
40200
+ "matched": {
40201
+ "type": "integer"
40202
+ },
40203
+ "created": {
40204
+ "type": "integer"
40205
+ },
40206
+ "needsAction": {
40207
+ "type": "integer"
40208
+ }
40209
+ }
40210
+ },
40211
+ "bookings": {
40212
+ "type": "object",
40213
+ "properties": {
40214
+ "read": {
40215
+ "type": "integer"
40216
+ },
40217
+ "linked": {
40218
+ "type": "integer"
40219
+ },
40220
+ "waiting": {
40221
+ "type": "integer"
40222
+ }
40223
+ }
40224
+ }
40225
+ }
40226
+ },
40227
+ "properties": {
40228
+ "type": "array",
40229
+ "items": {
40230
+ "type": "object",
40231
+ "properties": {
40232
+ "channexId": {
40233
+ "type": "string",
40234
+ "format": "uuid",
40235
+ "description": "The Channex id, which keeps resolving on `/channex/api/v1`."
40236
+ },
40237
+ "title": {
40238
+ "type": "string",
40239
+ "nullable": true
40240
+ },
40241
+ "status": {
40242
+ "type": "string",
40243
+ "enum": [
40244
+ "matched",
40245
+ "created",
40246
+ "needs_action"
40247
+ ]
40248
+ },
40249
+ "detail": {
40250
+ "type": "string",
40251
+ "nullable": true,
40252
+ "description": "How it was matched, or what to do."
40253
+ },
40254
+ "repullListingId": {
40255
+ "type": "integer",
40256
+ "nullable": true
40257
+ }
40258
+ }
40259
+ }
40260
+ },
40261
+ "roomTypes": {
40262
+ "type": "array",
40263
+ "items": {
40264
+ "type": "object",
40265
+ "properties": {
40266
+ "channexId": {
40267
+ "type": "string",
40268
+ "format": "uuid",
40269
+ "description": "The Channex id, which keeps resolving on `/channex/api/v1`."
40270
+ },
40271
+ "title": {
40272
+ "type": "string",
40273
+ "nullable": true
40274
+ },
40275
+ "status": {
40276
+ "type": "string",
40277
+ "enum": [
40278
+ "matched",
40279
+ "created",
40280
+ "needs_action"
40281
+ ]
40282
+ },
40283
+ "detail": {
40284
+ "type": "string",
40285
+ "nullable": true,
40286
+ "description": "How it was matched, or what to do."
40287
+ },
40288
+ "repullListingId": {
40289
+ "type": "integer",
40290
+ "nullable": true
40291
+ }
40292
+ }
40293
+ }
40294
+ },
40295
+ "ratePlans": {
40296
+ "type": "array",
40297
+ "items": {
40298
+ "type": "object",
40299
+ "properties": {
40300
+ "channexId": {
40301
+ "type": "string",
40302
+ "format": "uuid",
40303
+ "description": "The Channex id, which keeps resolving on `/channex/api/v1`."
40304
+ },
40305
+ "title": {
40306
+ "type": "string",
40307
+ "nullable": true
40308
+ },
40309
+ "status": {
40310
+ "type": "string",
40311
+ "enum": [
40312
+ "matched",
40313
+ "created",
40314
+ "needs_action"
40315
+ ]
40316
+ },
40317
+ "detail": {
40318
+ "type": "string",
40319
+ "nullable": true,
40320
+ "description": "How it was matched, or what to do."
40321
+ },
40322
+ "repullListingId": {
40323
+ "type": "integer",
40324
+ "nullable": true
40325
+ }
40326
+ }
40327
+ }
40328
+ },
40329
+ "webhooks": {
40330
+ "type": "array",
40331
+ "items": {
40332
+ "type": "object",
40333
+ "properties": {
40334
+ "channexId": {
40335
+ "type": "string",
40336
+ "format": "uuid",
40337
+ "description": "The Channex id, which keeps resolving on `/channex/api/v1`."
40338
+ },
40339
+ "title": {
40340
+ "type": "string",
40341
+ "nullable": true
40342
+ },
40343
+ "status": {
40344
+ "type": "string",
40345
+ "enum": [
40346
+ "matched",
40347
+ "created",
40348
+ "needs_action"
40349
+ ]
40350
+ },
40351
+ "detail": {
40352
+ "type": "string",
40353
+ "nullable": true,
40354
+ "description": "How it was matched, or what to do."
40355
+ },
40356
+ "repullListingId": {
40357
+ "type": "integer",
40358
+ "nullable": true
40359
+ }
40360
+ }
40361
+ }
40362
+ },
40363
+ "signingKeys": {
40364
+ "type": "array",
40365
+ "items": {
40366
+ "type": "object",
40367
+ "properties": {
40368
+ "channexId": {
40369
+ "type": "string",
40370
+ "format": "uuid",
40371
+ "description": "The Channex id, which keeps resolving on `/channex/api/v1`."
40372
+ },
40373
+ "title": {
40374
+ "type": "string",
40375
+ "nullable": true
40376
+ },
40377
+ "status": {
40378
+ "type": "string",
40379
+ "enum": [
40380
+ "matched",
40381
+ "created",
40382
+ "needs_action"
40383
+ ]
40384
+ },
40385
+ "detail": {
40386
+ "type": "string",
40387
+ "nullable": true,
40388
+ "description": "How it was matched, or what to do."
40389
+ },
40390
+ "repullListingId": {
40391
+ "type": "integer",
40392
+ "nullable": true
40393
+ }
40394
+ }
40395
+ }
40396
+ },
40397
+ "channels": {
40398
+ "type": "array",
40399
+ "items": {
40400
+ "type": "object",
40401
+ "properties": {
40402
+ "channexId": {
40403
+ "type": "string",
40404
+ "format": "uuid",
40405
+ "description": "The Channex id, which keeps resolving on `/channex/api/v1`."
40406
+ },
40407
+ "title": {
40408
+ "type": "string",
40409
+ "nullable": true
40410
+ },
40411
+ "status": {
40412
+ "type": "string",
40413
+ "enum": [
40414
+ "matched",
40415
+ "created",
40416
+ "needs_action"
40417
+ ]
40418
+ },
40419
+ "detail": {
40420
+ "type": "string",
40421
+ "nullable": true,
40422
+ "description": "How it was matched, or what to do."
40423
+ },
40424
+ "repullListingId": {
40425
+ "type": "integer",
40426
+ "nullable": true
40427
+ },
40428
+ "channel": {
40429
+ "type": "string",
40430
+ "description": "Channex adapter code (BookingCom, AirBNB, VRBO\u2026)."
40431
+ },
40432
+ "providerSwitch": {
40433
+ "type": "string",
40434
+ "enum": [
40435
+ "switched",
40436
+ "required",
40437
+ "unsupported"
40438
+ ]
40439
+ },
40440
+ "instructions": {
40441
+ "type": "string",
40442
+ "nullable": true
40443
+ }
40444
+ }
40445
+ }
40446
+ },
40447
+ "warnings": {
40448
+ "type": "array",
40449
+ "items": {
40450
+ "type": "string"
40451
+ }
40452
+ },
40453
+ "nextSteps": {
40454
+ "type": "array",
40455
+ "items": {
40456
+ "type": "string"
40457
+ }
40458
+ }
40459
+ }
40460
+ }
40461
+ }
40462
+ }
40463
+ }
40464
+ }
40465
+ },
40466
+ "201": {
40467
+ "description": "The import report",
40468
+ "content": {
40469
+ "application/json": {
40470
+ "schema": {
40471
+ "type": "object",
40472
+ "properties": {
40473
+ "data": {
40474
+ "type": "object",
40475
+ "properties": {
40476
+ "id": {
40477
+ "type": "string",
40478
+ "format": "uuid"
40479
+ },
40480
+ "environment": {
40481
+ "type": "string",
40482
+ "enum": [
40483
+ "production",
40484
+ "staging"
40485
+ ]
40486
+ },
40487
+ "dryRun": {
40488
+ "type": "boolean"
40489
+ },
40490
+ "complete": {
40491
+ "type": "boolean",
40492
+ "description": "False when the time budget ran out; run the same request again to continue."
40493
+ },
40494
+ "startedAt": {
40495
+ "type": "string",
40496
+ "format": "date-time"
40497
+ },
40498
+ "finishedAt": {
40499
+ "type": "string",
40500
+ "format": "date-time"
40501
+ },
40502
+ "summary": {
40503
+ "type": "object",
40504
+ "properties": {
40505
+ "properties": {
40506
+ "type": "object",
40507
+ "properties": {
40508
+ "matched": {
40509
+ "type": "integer"
40510
+ },
40511
+ "created": {
40512
+ "type": "integer"
40513
+ },
40514
+ "needsAction": {
40515
+ "type": "integer"
40516
+ }
40517
+ }
40518
+ },
40519
+ "roomTypes": {
40520
+ "type": "object",
40521
+ "properties": {
40522
+ "matched": {
40523
+ "type": "integer"
40524
+ },
40525
+ "created": {
40526
+ "type": "integer"
40527
+ },
40528
+ "needsAction": {
40529
+ "type": "integer"
40530
+ }
40531
+ }
40532
+ },
40533
+ "ratePlans": {
40534
+ "type": "object",
40535
+ "properties": {
40536
+ "matched": {
40537
+ "type": "integer"
40538
+ },
40539
+ "created": {
40540
+ "type": "integer"
40541
+ },
40542
+ "needsAction": {
40543
+ "type": "integer"
40544
+ }
40545
+ }
40546
+ },
40547
+ "webhooks": {
40548
+ "type": "object",
40549
+ "properties": {
40550
+ "matched": {
40551
+ "type": "integer"
40552
+ },
40553
+ "created": {
40554
+ "type": "integer"
40555
+ },
40556
+ "needsAction": {
40557
+ "type": "integer"
40558
+ }
40559
+ }
40560
+ },
40561
+ "signingKeys": {
40562
+ "type": "object",
40563
+ "properties": {
40564
+ "matched": {
40565
+ "type": "integer"
40566
+ },
40567
+ "created": {
40568
+ "type": "integer"
40569
+ },
40570
+ "needsAction": {
40571
+ "type": "integer"
40572
+ }
40573
+ }
40574
+ },
40575
+ "channels": {
40576
+ "type": "object",
40577
+ "properties": {
40578
+ "matched": {
40579
+ "type": "integer"
40580
+ },
40581
+ "created": {
40582
+ "type": "integer"
40583
+ },
40584
+ "needsAction": {
40585
+ "type": "integer"
40586
+ }
40587
+ }
40588
+ },
40589
+ "bookings": {
40590
+ "type": "object",
40591
+ "properties": {
40592
+ "read": {
40593
+ "type": "integer"
40594
+ },
40595
+ "linked": {
40596
+ "type": "integer"
40597
+ },
40598
+ "waiting": {
40599
+ "type": "integer"
40600
+ }
40601
+ }
40602
+ }
40603
+ }
40604
+ },
40605
+ "properties": {
40606
+ "type": "array",
40607
+ "items": {
40608
+ "type": "object",
40609
+ "properties": {
40610
+ "channexId": {
40611
+ "type": "string",
40612
+ "format": "uuid",
40613
+ "description": "The Channex id, which keeps resolving on `/channex/api/v1`."
40614
+ },
40615
+ "title": {
40616
+ "type": "string",
40617
+ "nullable": true
40618
+ },
40619
+ "status": {
40620
+ "type": "string",
40621
+ "enum": [
40622
+ "matched",
40623
+ "created",
40624
+ "needs_action"
40625
+ ]
40626
+ },
40627
+ "detail": {
40628
+ "type": "string",
40629
+ "nullable": true,
40630
+ "description": "How it was matched, or what to do."
40631
+ },
40632
+ "repullListingId": {
40633
+ "type": "integer",
40634
+ "nullable": true
40635
+ }
40636
+ }
40637
+ }
40638
+ },
40639
+ "roomTypes": {
40640
+ "type": "array",
40641
+ "items": {
40642
+ "type": "object",
40643
+ "properties": {
40644
+ "channexId": {
40645
+ "type": "string",
40646
+ "format": "uuid",
40647
+ "description": "The Channex id, which keeps resolving on `/channex/api/v1`."
40648
+ },
40649
+ "title": {
40650
+ "type": "string",
40651
+ "nullable": true
40652
+ },
40653
+ "status": {
40654
+ "type": "string",
40655
+ "enum": [
40656
+ "matched",
40657
+ "created",
40658
+ "needs_action"
40659
+ ]
40660
+ },
40661
+ "detail": {
40662
+ "type": "string",
40663
+ "nullable": true,
40664
+ "description": "How it was matched, or what to do."
40665
+ },
40666
+ "repullListingId": {
40667
+ "type": "integer",
40668
+ "nullable": true
40669
+ }
40670
+ }
40671
+ }
40672
+ },
40673
+ "ratePlans": {
40674
+ "type": "array",
40675
+ "items": {
40676
+ "type": "object",
40677
+ "properties": {
40678
+ "channexId": {
40679
+ "type": "string",
40680
+ "format": "uuid",
40681
+ "description": "The Channex id, which keeps resolving on `/channex/api/v1`."
40682
+ },
40683
+ "title": {
40684
+ "type": "string",
40685
+ "nullable": true
40686
+ },
40687
+ "status": {
40688
+ "type": "string",
40689
+ "enum": [
40690
+ "matched",
40691
+ "created",
40692
+ "needs_action"
40693
+ ]
40694
+ },
40695
+ "detail": {
40696
+ "type": "string",
40697
+ "nullable": true,
40698
+ "description": "How it was matched, or what to do."
40699
+ },
40700
+ "repullListingId": {
40701
+ "type": "integer",
40702
+ "nullable": true
40703
+ }
40704
+ }
40705
+ }
40706
+ },
40707
+ "webhooks": {
40708
+ "type": "array",
40709
+ "items": {
40710
+ "type": "object",
40711
+ "properties": {
40712
+ "channexId": {
40713
+ "type": "string",
40714
+ "format": "uuid",
40715
+ "description": "The Channex id, which keeps resolving on `/channex/api/v1`."
40716
+ },
40717
+ "title": {
40718
+ "type": "string",
40719
+ "nullable": true
40720
+ },
40721
+ "status": {
40722
+ "type": "string",
40723
+ "enum": [
40724
+ "matched",
40725
+ "created",
40726
+ "needs_action"
40727
+ ]
40728
+ },
40729
+ "detail": {
40730
+ "type": "string",
40731
+ "nullable": true,
40732
+ "description": "How it was matched, or what to do."
40733
+ },
40734
+ "repullListingId": {
40735
+ "type": "integer",
40736
+ "nullable": true
40737
+ }
40738
+ }
40739
+ }
40740
+ },
40741
+ "signingKeys": {
40742
+ "type": "array",
40743
+ "items": {
40744
+ "type": "object",
40745
+ "properties": {
40746
+ "channexId": {
40747
+ "type": "string",
40748
+ "format": "uuid",
40749
+ "description": "The Channex id, which keeps resolving on `/channex/api/v1`."
40750
+ },
40751
+ "title": {
40752
+ "type": "string",
40753
+ "nullable": true
40754
+ },
40755
+ "status": {
40756
+ "type": "string",
40757
+ "enum": [
40758
+ "matched",
40759
+ "created",
40760
+ "needs_action"
40761
+ ]
40762
+ },
40763
+ "detail": {
40764
+ "type": "string",
40765
+ "nullable": true,
40766
+ "description": "How it was matched, or what to do."
40767
+ },
40768
+ "repullListingId": {
40769
+ "type": "integer",
40770
+ "nullable": true
40771
+ }
40772
+ }
40773
+ }
40774
+ },
40775
+ "channels": {
40776
+ "type": "array",
40777
+ "items": {
40778
+ "type": "object",
40779
+ "properties": {
40780
+ "channexId": {
40781
+ "type": "string",
40782
+ "format": "uuid",
40783
+ "description": "The Channex id, which keeps resolving on `/channex/api/v1`."
40784
+ },
40785
+ "title": {
40786
+ "type": "string",
40787
+ "nullable": true
40788
+ },
40789
+ "status": {
40790
+ "type": "string",
40791
+ "enum": [
40792
+ "matched",
40793
+ "created",
40794
+ "needs_action"
40795
+ ]
40796
+ },
40797
+ "detail": {
40798
+ "type": "string",
40799
+ "nullable": true,
40800
+ "description": "How it was matched, or what to do."
40801
+ },
40802
+ "repullListingId": {
40803
+ "type": "integer",
40804
+ "nullable": true
40805
+ },
40806
+ "channel": {
40807
+ "type": "string",
40808
+ "description": "Channex adapter code (BookingCom, AirBNB, VRBO\u2026)."
40809
+ },
40810
+ "providerSwitch": {
40811
+ "type": "string",
40812
+ "enum": [
40813
+ "switched",
40814
+ "required",
40815
+ "unsupported"
40816
+ ]
40817
+ },
40818
+ "instructions": {
40819
+ "type": "string",
40820
+ "nullable": true
40821
+ }
40822
+ }
40823
+ }
40824
+ },
40825
+ "warnings": {
40826
+ "type": "array",
40827
+ "items": {
40828
+ "type": "string"
40829
+ }
40830
+ },
40831
+ "nextSteps": {
40832
+ "type": "array",
40833
+ "items": {
40834
+ "type": "string"
40835
+ }
40836
+ }
40837
+ }
40838
+ }
40839
+ }
40840
+ }
40841
+ }
40842
+ }
40843
+ },
40844
+ "400": {
40845
+ "$ref": "#/components/responses/BadRequest"
40846
+ },
40847
+ "401": {
40848
+ "$ref": "#/components/responses/Unauthorized"
40849
+ },
40850
+ "422": {
40851
+ "$ref": "#/components/responses/UnprocessableEntity"
40852
+ },
40853
+ "500": {
40854
+ "$ref": "#/components/responses/InternalError"
40855
+ },
40856
+ "502": {
40857
+ "$ref": "#/components/responses/InternalError"
40858
+ }
40859
+ }
40860
+ }
39501
40861
  }
39502
40862
  }
39503
40863
  }