repull 0.2.39 → 0.2.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 05f8dcbf939588a31a5e66d89b6009ae1ec20c56f90f172f664b3cb3317657b4
4
- data.tar.gz: c2083ff59fa0e0df5010ba404f922b6b94551120d7887f13df6e587543be9c77
3
+ metadata.gz: 788a3e7ef0f0cf6d27c2878a4d1f371512e027fe45c8f73bb02ad92cd4763a37
4
+ data.tar.gz: 9ac321f22b18e15297cefb4d33c11154cabcc201d54afc5e4414b648c059a12f
5
5
  SHA512:
6
- metadata.gz: 8176bc233194e36040c4f103241232c72545b716c1619d3e16bf2ed0c0f9725da0ff1b3df772237f70a519b679266432bd844e268c25955418805e140a9710f5
7
- data.tar.gz: 152383381f99200bd26b99008c17400dd415390d7a50871e29f7af166105be9739337598317467f7a4ccad7e4067b3d49c013d3a09a264c4e274b53a5d5d3c4f
6
+ metadata.gz: 694072b548f15e571cd46db0b9f20e6350875a75092dad2d1a23b8c6836c74cdf37ba6e602d59210d0093cc4283eb8df57a092bba6b7f645d91e004085518a81
7
+ data.tar.gz: 6cea703371296e9db874f27902f774b75c3b89df6262cb7c99da017b9805c94be5e9060836d39c2604bad59119305af69fc66a9d9d75d4a6652a803858cc6a72
@@ -809,7 +809,7 @@ module Repull
809
809
  end
810
810
 
811
811
  # List PMS/OTA connections
812
- # Returns every PMS and OTA connection in the workspace, each with its `status`. **Spot connections that need attention.** A connection whose `status` is not `active` may need the host to do something before it works — most commonly a Booking.com Extranet connection where the invited user was granted only partial access (`status: \"needs_permissions\"`). A Smoobu connection still on a legacy single API key carries `action.reason: \"reauth_required\"` while its `status` is `active`: Smoobu stops accepting those keys on October 31, 2026, and `fixUrl` opens the form for a new API key + secret (the connection id stays the same). These connections carry two extra fields: - `action` — `{ required: true, reason, message }`. `reason` is a stable machine code (e.g. `needs_permissions`); `message` is a host-facing one-liner describing what to do. - `fixUrl` — a durable link that reopens the hosted Connect flow **bound to that account, on the fix screen** (e.g. \"grant full access\" + a Re-check button). It is safe to store and show in your own dashboard. **Self-serve repair:** when `action.required` is true, surface a \"Fix\" button that opens `fixUrl` in a new tab (or embed it). The host resolves the issue (e.g. grants the user full access in Booking.com) and clicks Re-check; the import finishes on its own and the connection flips back to `active` — no re-invite, no support ticket. Poll this endpoint (or read it after the host returns) to confirm `action` has cleared.
812
+ # Returns every PMS and OTA connection in the workspace, each with its `status`. **One entry per Booking.com Extranet hotel login.** Each hotel that invites the Repull user connects as its own login, with its own `externalAccountId` (handle `booking_extranet:{externalAccountId}`). A new hotel adds an entry next to the existing ones and never replaces them; the entries share the workspace's Extranet `id`, and each hotel's listings, reservations, conversations and reviews stay under its own login (filter them with `?account=booking_extranet:{externalAccountId}`). **Spot connections that need attention.** A connection whose `status` is not `active` may need the host to do something before it works — most commonly a Booking.com Extranet connection where the invited user was granted only partial access (`status: \"needs_permissions\"`). A Smoobu connection still on a legacy single API key carries `action.reason: \"reauth_required\"` while its `status` is `active`: Smoobu stops accepting those keys on October 31, 2026, and `fixUrl` opens the form for a new API key + secret (the connection id stays the same). These connections carry two extra fields: - `action` — `{ required: true, reason, message }`. `reason` is a stable machine code (e.g. `needs_permissions`); `message` is a host-facing one-liner describing what to do. - `fixUrl` — a durable link that reopens the hosted Connect flow **bound to that account, on the fix screen** (e.g. \"grant full access\" + a Re-check button). It is safe to store and show in your own dashboard. **Self-serve repair:** when `action.required` is true, surface a \"Fix\" button that opens `fixUrl` in a new tab (or embed it). The host resolves the issue (e.g. grants the user full access in Booking.com) and clicks Re-check; the import finishes on its own and the connection flips back to `active` — no re-invite, no support ticket. Poll this endpoint (or read it after the host returns) to confirm `action` has cleared.
813
813
  # @param [Hash] opts the optional parameters
814
814
  # @return [ConnectionListResponse]
815
815
  def list_connections(opts = {})
@@ -818,7 +818,7 @@ module Repull
818
818
  end
819
819
 
820
820
  # List PMS/OTA connections
821
- # Returns every PMS and OTA connection in the workspace, each with its `status`. **Spot connections that need attention.** A connection whose `status` is not `active` may need the host to do something before it works — most commonly a Booking.com Extranet connection where the invited user was granted only partial access (`status: \"needs_permissions\"`). A Smoobu connection still on a legacy single API key carries `action.reason: \"reauth_required\"` while its `status` is `active`: Smoobu stops accepting those keys on October 31, 2026, and `fixUrl` opens the form for a new API key + secret (the connection id stays the same). These connections carry two extra fields: - `action` — `{ required: true, reason, message }`. `reason` is a stable machine code (e.g. `needs_permissions`); `message` is a host-facing one-liner describing what to do. - `fixUrl` — a durable link that reopens the hosted Connect flow **bound to that account, on the fix screen** (e.g. \"grant full access\" + a Re-check button). It is safe to store and show in your own dashboard. **Self-serve repair:** when `action.required` is true, surface a \"Fix\" button that opens `fixUrl` in a new tab (or embed it). The host resolves the issue (e.g. grants the user full access in Booking.com) and clicks Re-check; the import finishes on its own and the connection flips back to `active` — no re-invite, no support ticket. Poll this endpoint (or read it after the host returns) to confirm `action` has cleared.
821
+ # Returns every PMS and OTA connection in the workspace, each with its `status`. **One entry per Booking.com Extranet hotel login.** Each hotel that invites the Repull user connects as its own login, with its own `externalAccountId` (handle `booking_extranet:{externalAccountId}`). A new hotel adds an entry next to the existing ones and never replaces them; the entries share the workspace's Extranet `id`, and each hotel's listings, reservations, conversations and reviews stay under its own login (filter them with `?account=booking_extranet:{externalAccountId}`). **Spot connections that need attention.** A connection whose `status` is not `active` may need the host to do something before it works — most commonly a Booking.com Extranet connection where the invited user was granted only partial access (`status: \"needs_permissions\"`). A Smoobu connection still on a legacy single API key carries `action.reason: \"reauth_required\"` while its `status` is `active`: Smoobu stops accepting those keys on October 31, 2026, and `fixUrl` opens the form for a new API key + secret (the connection id stays the same). These connections carry two extra fields: - `action` — `{ required: true, reason, message }`. `reason` is a stable machine code (e.g. `needs_permissions`); `message` is a host-facing one-liner describing what to do. - `fixUrl` — a durable link that reopens the hosted Connect flow **bound to that account, on the fix screen** (e.g. \"grant full access\" + a Re-check button). It is safe to store and show in your own dashboard. **Self-serve repair:** when `action.required` is true, surface a \"Fix\" button that opens `fixUrl` in a new tab (or embed it). The host resolves the issue (e.g. grants the user full access in Booking.com) and clicks Re-check; the import finishes on its own and the connection flips back to `active` — no re-invite, no support ticket. Poll this endpoint (or read it after the host returns) to confirm `action` has cleared.
822
822
  # @param [Hash] opts the optional parameters
823
823
  # @return [Array<(ConnectionListResponse, Integer, Hash)>] ConnectionListResponse data, response status code and response headers
824
824
  def list_connections_with_http_info(opts = {})
@@ -684,7 +684,7 @@ module Repull
684
684
  end
685
685
 
686
686
  # Send a message to the guest
687
- # Sends a message to the guest on this conversation and records it in the thread. Omit `channel` and the message goes out on whichever channel the conversation already uses (Airbnb, Booking.com, VRBO, SMS, email or the direct-booking site) — that is the right default. Pass `channel` only to force a specific one. The message is attributed to the API: it is recorded with `aiGenerated` false so an API send is never counted as an automated reply. ### Airbnb rewrites links — check `contentRewritten` Airbnb rejects guest messages containing a link, an email address or a phone number, and names the offending text. When that happens the offending fragment is stripped and the remainder is re-sent once, which means **the guest receives a message that is not the one you wrote**. Reporting that as a plain success would be a lie, so every response carries `contentRewritten`; when it is `true`, `deliveredContent` is the text that actually reached the guest. Check it before assuming your message went out verbatim. When the text cannot be salvaged (the link is most of the message) nothing is delivered and the call returns `422 message_not_sent` with the channel's verbatim refusal in `statusReason`. Send `Idempotency-Key` — without it, retrying after a network timeout sends the guest the same message twice. ### Attachments Send files with `attachments: [{ url, contentType?, filename? }]` — public `https://` URLs, up to 5 per request, 10 MB each. `message` may be omitted when there are attachments (except on Booking.com). Repull downloads each file, reads its real type from the bytes, keeps a durable copy and delivers it through the channel's own file flow. **Every file is checked before anything is sent**: if one is unreachable, too large or of a type the channel refuses, the call returns 422 naming the file (`index`) and the guest receives nothing. | Channel | Accepted types | Text | How it arrives | |---|---|---|---| | Airbnb | JPEG, PNG, GIF, WebP (converted to JPEG), MP4, QuickTime | optional | each file as its own message, then the text as a separate message | | Booking.com | JPEG, PNG | **required** | one message carrying the text and every file | | VRBO, SMS, email, direct-booking site chat | — | — | `422 attachments_not_supported`, nothing sent | Airbnb does not allow files in pre-booking (inquiry) conversations; that refusal comes back as `422 message_not_sent`. Because Airbnb delivers files one message at a time, a later file can be refused after earlier ones arrived — that returns `422 message_partially_sent` with `parts` saying exactly which messages reached the guest; resend only the rest. The response's `attachments` lists each file's durable `url`, and `parts` lists every channel message the send produced. Read-back (`GET /v1/conversations/{id}/messages`) shows the same files in each message's `attachments`. **Inactive listings:** a conversation that belongs to an inactive listing returns `403 listing_inactive` and no message is sent. Activate the listing first.
687
+ # Sends a message to the guest on this conversation and records it in the thread. Omit `channel` and the message goes out on whichever channel the conversation already uses (Airbnb, Booking.com, VRBO, SMS, email or the direct-booking site) — that is the right default. Pass `channel` only to force a specific one. The message is attributed to the API: it is recorded with `aiGenerated` false so an API send is never counted as an automated reply. ### Airbnb rewrites links — check `contentRewritten` Airbnb rejects guest messages containing a link, an email address or a phone number, and names the offending text. When that happens the offending fragment is stripped and the remainder is re-sent once, which means **the guest receives a message that is not the one you wrote**. Reporting that as a plain success would be a lie, so every response carries `contentRewritten`; when it is `true`, `deliveredContent` is the text that actually reached the guest. Check it before assuming your message went out verbatim. When the text cannot be salvaged (the link is most of the message) nothing is delivered and the call returns `422 message_not_sent` with the channel's verbatim refusal in `statusReason`. `message_not_sent` only ever means the channel refused: a fault on Repull's side (a dropped database connection, a timeout) is `503 internal_error` with `sent: false` when nothing was delivered — retry it unchanged with the same `Idempotency-Key`. Send `Idempotency-Key` — without it, retrying after a network timeout sends the guest the same message twice. ### Attachments Send files with `attachments: [{ url, contentType?, filename? }]` — public `https://` URLs, up to 5 per request, 10 MB each. `message` may be omitted when there are attachments (except on Booking.com). Repull downloads each file, reads its real type from the bytes, keeps a durable copy and delivers it through the channel's own file flow. **Every file is checked before anything is sent**: if one is unreachable, too large or of a type the channel refuses, the call returns 422 naming the file (`index`) and the guest receives nothing. | Channel | Accepted types | Text | How it arrives | |---|---|---|---| | Airbnb | JPEG, PNG, GIF, WebP (converted to JPEG), MP4, QuickTime | optional | each file as its own message, then the text as a separate message | | Booking.com | JPEG, PNG | **required** | one message carrying the text and every file | | VRBO, SMS, email, direct-booking site chat | — | — | `422 attachments_not_supported`, nothing sent | Airbnb does not allow files in pre-booking (inquiry) conversations; that refusal comes back as `422 message_not_sent`. Because Airbnb delivers files one message at a time, a later file can be refused after earlier ones arrived — that returns `422 message_partially_sent` with `parts` saying exactly which messages reached the guest; resend only the rest. The response's `attachments` lists each file's durable `url`, and `parts` lists every channel message the send produced. Read-back (`GET /v1/conversations/{id}/messages`) shows the same files in each message's `attachments`. **Inactive listings:** a conversation that belongs to an inactive listing returns `403 listing_inactive` and no message is sent. Activate the listing first.
688
688
  # @param id [Integer] Internal Repull thread id.
689
689
  # @param send_message_request [SendMessageRequest]
690
690
  # @param [Hash] opts the optional parameters
@@ -696,7 +696,7 @@ module Repull
696
696
  end
697
697
 
698
698
  # Send a message to the guest
699
- # Sends a message to the guest on this conversation and records it in the thread. Omit &#x60;channel&#x60; and the message goes out on whichever channel the conversation already uses (Airbnb, Booking.com, VRBO, SMS, email or the direct-booking site) — that is the right default. Pass &#x60;channel&#x60; only to force a specific one. The message is attributed to the API: it is recorded with &#x60;aiGenerated&#x60; false so an API send is never counted as an automated reply. ### Airbnb rewrites links — check &#x60;contentRewritten&#x60; Airbnb rejects guest messages containing a link, an email address or a phone number, and names the offending text. When that happens the offending fragment is stripped and the remainder is re-sent once, which means **the guest receives a message that is not the one you wrote**. Reporting that as a plain success would be a lie, so every response carries &#x60;contentRewritten&#x60;; when it is &#x60;true&#x60;, &#x60;deliveredContent&#x60; is the text that actually reached the guest. Check it before assuming your message went out verbatim. When the text cannot be salvaged (the link is most of the message) nothing is delivered and the call returns &#x60;422 message_not_sent&#x60; with the channel&#39;s verbatim refusal in &#x60;statusReason&#x60;. Send &#x60;Idempotency-Key&#x60; — without it, retrying after a network timeout sends the guest the same message twice. ### Attachments Send files with &#x60;attachments: [{ url, contentType?, filename? }]&#x60; — public &#x60;https://&#x60; URLs, up to 5 per request, 10 MB each. &#x60;message&#x60; may be omitted when there are attachments (except on Booking.com). Repull downloads each file, reads its real type from the bytes, keeps a durable copy and delivers it through the channel&#39;s own file flow. **Every file is checked before anything is sent**: if one is unreachable, too large or of a type the channel refuses, the call returns 422 naming the file (&#x60;index&#x60;) and the guest receives nothing. | Channel | Accepted types | Text | How it arrives | |---|---|---|---| | Airbnb | JPEG, PNG, GIF, WebP (converted to JPEG), MP4, QuickTime | optional | each file as its own message, then the text as a separate message | | Booking.com | JPEG, PNG | **required** | one message carrying the text and every file | | VRBO, SMS, email, direct-booking site chat | — | — | &#x60;422 attachments_not_supported&#x60;, nothing sent | Airbnb does not allow files in pre-booking (inquiry) conversations; that refusal comes back as &#x60;422 message_not_sent&#x60;. Because Airbnb delivers files one message at a time, a later file can be refused after earlier ones arrived — that returns &#x60;422 message_partially_sent&#x60; with &#x60;parts&#x60; saying exactly which messages reached the guest; resend only the rest. The response&#39;s &#x60;attachments&#x60; lists each file&#39;s durable &#x60;url&#x60;, and &#x60;parts&#x60; lists every channel message the send produced. Read-back (&#x60;GET /v1/conversations/{id}/messages&#x60;) shows the same files in each message&#39;s &#x60;attachments&#x60;. **Inactive listings:** a conversation that belongs to an inactive listing returns &#x60;403 listing_inactive&#x60; and no message is sent. Activate the listing first.
699
+ # Sends a message to the guest on this conversation and records it in the thread. Omit &#x60;channel&#x60; and the message goes out on whichever channel the conversation already uses (Airbnb, Booking.com, VRBO, SMS, email or the direct-booking site) — that is the right default. Pass &#x60;channel&#x60; only to force a specific one. The message is attributed to the API: it is recorded with &#x60;aiGenerated&#x60; false so an API send is never counted as an automated reply. ### Airbnb rewrites links — check &#x60;contentRewritten&#x60; Airbnb rejects guest messages containing a link, an email address or a phone number, and names the offending text. When that happens the offending fragment is stripped and the remainder is re-sent once, which means **the guest receives a message that is not the one you wrote**. Reporting that as a plain success would be a lie, so every response carries &#x60;contentRewritten&#x60;; when it is &#x60;true&#x60;, &#x60;deliveredContent&#x60; is the text that actually reached the guest. Check it before assuming your message went out verbatim. When the text cannot be salvaged (the link is most of the message) nothing is delivered and the call returns &#x60;422 message_not_sent&#x60; with the channel&#39;s verbatim refusal in &#x60;statusReason&#x60;. &#x60;message_not_sent&#x60; only ever means the channel refused: a fault on Repull&#39;s side (a dropped database connection, a timeout) is &#x60;503 internal_error&#x60; with &#x60;sent: false&#x60; when nothing was delivered — retry it unchanged with the same &#x60;Idempotency-Key&#x60;. Send &#x60;Idempotency-Key&#x60; — without it, retrying after a network timeout sends the guest the same message twice. ### Attachments Send files with &#x60;attachments: [{ url, contentType?, filename? }]&#x60; — public &#x60;https://&#x60; URLs, up to 5 per request, 10 MB each. &#x60;message&#x60; may be omitted when there are attachments (except on Booking.com). Repull downloads each file, reads its real type from the bytes, keeps a durable copy and delivers it through the channel&#39;s own file flow. **Every file is checked before anything is sent**: if one is unreachable, too large or of a type the channel refuses, the call returns 422 naming the file (&#x60;index&#x60;) and the guest receives nothing. | Channel | Accepted types | Text | How it arrives | |---|---|---|---| | Airbnb | JPEG, PNG, GIF, WebP (converted to JPEG), MP4, QuickTime | optional | each file as its own message, then the text as a separate message | | Booking.com | JPEG, PNG | **required** | one message carrying the text and every file | | VRBO, SMS, email, direct-booking site chat | — | — | &#x60;422 attachments_not_supported&#x60;, nothing sent | Airbnb does not allow files in pre-booking (inquiry) conversations; that refusal comes back as &#x60;422 message_not_sent&#x60;. Because Airbnb delivers files one message at a time, a later file can be refused after earlier ones arrived — that returns &#x60;422 message_partially_sent&#x60; with &#x60;parts&#x60; saying exactly which messages reached the guest; resend only the rest. The response&#39;s &#x60;attachments&#x60; lists each file&#39;s durable &#x60;url&#x60;, and &#x60;parts&#x60; lists every channel message the send produced. Read-back (&#x60;GET /v1/conversations/{id}/messages&#x60;) shows the same files in each message&#39;s &#x60;attachments&#x60;. **Inactive listings:** a conversation that belongs to an inactive listing returns &#x60;403 listing_inactive&#x60; and no message is sent. Activate the listing first.
700
700
  # @param id [Integer] Internal Repull thread id.
701
701
  # @param send_message_request [SendMessageRequest]
702
702
  # @param [Hash] opts the optional parameters
@@ -16,7 +16,7 @@ require 'time'
16
16
  module Repull
17
17
  # Channel-agnostic message thread between the host workspace and a guest. Returned by `GET /v1/conversations`. The `id` is the internal Repull thread id (integer) — pass it back as the `{id}` path param on detail / messages calls.
18
18
  class Conversation < ApiModelBase
19
- # The connected account this conversation belongs to. List endpoint.
19
+ # The connected account this conversation belongs to, the same block as the message webhooks. On the list and on `GET /v1/conversations/{id}`.
20
20
  attr_accessor :account
21
21
 
22
22
  attr_accessor :id
@@ -16,7 +16,7 @@ require 'time'
16
16
  module Repull
17
17
  # Returned by `GET /v1/conversations/{id}`. Extends the list-row `Conversation` shape with expanded `host` + `guest` blocks so SDK consumers can render thread headers without an extra round-trip.
18
18
  class ConversationDetail < ApiModelBase
19
- # The connected account this conversation belongs to. List endpoint.
19
+ # The connected account this conversation belongs to, the same block as the message webhooks. On the list and on `GET /v1/conversations/{id}`.
20
20
  attr_accessor :account
21
21
 
22
22
  attr_accessor :id
@@ -42,6 +42,12 @@ module Repull
42
42
 
43
43
  attr_accessor :address
44
44
 
45
+ # `GET /v1/listings/{id}` only. Map pin latitude in decimal degrees, as a string; the same value as `GET /v1/properties/{id}`. Null when the listing has no coordinates.
46
+ attr_accessor :latitude
47
+
48
+ # `GET /v1/listings/{id}` only. Map pin longitude in decimal degrees, as a string; the same value as `GET /v1/properties/{id}`. Null when the listing has no coordinates.
49
+ attr_accessor :longitude
50
+
45
51
  # Cover photo URL. Always present on an active listing. On an **inactive** one it is present only when the caller passes `?include=thumbnail`; `null` means the listing has no cover photo stored, absent means the expansion was not requested.
46
52
  attr_accessor :thumbnail_url
47
53
 
@@ -97,6 +103,8 @@ module Repull
97
103
  :'name' => :'name',
98
104
  :'public_name' => :'publicName',
99
105
  :'address' => :'address',
106
+ :'latitude' => :'latitude',
107
+ :'longitude' => :'longitude',
100
108
  :'thumbnail_url' => :'thumbnailUrl',
101
109
  :'status' => :'status',
102
110
  :'channels' => :'channels',
@@ -138,6 +146,8 @@ module Repull
138
146
  :'name' => :'String',
139
147
  :'public_name' => :'String',
140
148
  :'address' => :'ListingAddress',
149
+ :'latitude' => :'String',
150
+ :'longitude' => :'String',
141
151
  :'thumbnail_url' => :'String',
142
152
  :'status' => :'String',
143
153
  :'channels' => :'Array<ListingChannel>',
@@ -162,6 +172,8 @@ module Repull
162
172
  :'parent',
163
173
  :'hotel',
164
174
  :'public_name',
175
+ :'latitude',
176
+ :'longitude',
165
177
  :'thumbnail_url',
166
178
  :'content',
167
179
  :'details',
@@ -229,6 +241,14 @@ module Repull
229
241
  self.address = attributes[:'address']
230
242
  end
231
243
 
244
+ if attributes.key?(:'latitude')
245
+ self.latitude = attributes[:'latitude']
246
+ end
247
+
248
+ if attributes.key?(:'longitude')
249
+ self.longitude = attributes[:'longitude']
250
+ end
251
+
232
252
  if attributes.key?(:'thumbnail_url')
233
253
  self.thumbnail_url = attributes[:'thumbnail_url']
234
254
  end
@@ -351,6 +371,8 @@ module Repull
351
371
  name == o.name &&
352
372
  public_name == o.public_name &&
353
373
  address == o.address &&
374
+ latitude == o.latitude &&
375
+ longitude == o.longitude &&
354
376
  thumbnail_url == o.thumbnail_url &&
355
377
  status == o.status &&
356
378
  channels == o.channels &&
@@ -377,7 +399,7 @@ module Repull
377
399
  # Calculates hash code according to all attributes.
378
400
  # @return [Integer] Hash code
379
401
  def hash
380
- [capabilities, kind, parent, hotel, unit_count, units, id, name, public_name, address, thumbnail_url, status, channels, amenities, content, details, rooms, policies, rules, pricing, fees, taxes, photos, created_at, updated_at].hash
402
+ [capabilities, kind, parent, hotel, unit_count, units, id, name, public_name, address, latitude, longitude, thumbnail_url, status, channels, amenities, content, details, rooms, policies, rules, pricing, fees, taxes, photos, created_at, updated_at].hash
381
403
  end
382
404
 
383
405
  # Builds the object from hash
@@ -11,5 +11,5 @@ Generator version: 7.22.0
11
11
  =end
12
12
 
13
13
  module Repull
14
- VERSION = '0.2.39'
14
+ VERSION = '0.2.40'
15
15
  end
data/openapi/v1.json CHANGED
@@ -1233,7 +1233,7 @@
1233
1233
  "$ref": "#/components/schemas/RecordAccount"
1234
1234
  }
1235
1235
  ],
1236
- "description": "The connected account this conversation belongs to. List endpoint."
1236
+ "description": "The connected account this conversation belongs to, the same block as the message webhooks. On the list and on `GET /v1/conversations/{id}`."
1237
1237
  },
1238
1238
  "id": {
1239
1239
  "type": "string"
@@ -10482,6 +10482,18 @@
10482
10482
  }
10483
10483
  }
10484
10484
  },
10485
+ "latitude": {
10486
+ "type": "string",
10487
+ "nullable": true,
10488
+ "description": "`GET /v1/listings/{id}` only. Map pin latitude in decimal degrees, as a string; the same value as `GET /v1/properties/{id}`. Null when the listing has no coordinates.",
10489
+ "example": "25.7617"
10490
+ },
10491
+ "longitude": {
10492
+ "type": "string",
10493
+ "nullable": true,
10494
+ "description": "`GET /v1/listings/{id}` only. Map pin longitude in decimal degrees, as a string; the same value as `GET /v1/properties/{id}`. Null when the listing has no coordinates.",
10495
+ "example": "-80.1918"
10496
+ },
10485
10497
  "thumbnailUrl": {
10486
10498
  "type": "string",
10487
10499
  "format": "uri",
@@ -18602,7 +18614,7 @@
18602
18614
  "post": {
18603
18615
  "operationId": "send_conversation_message",
18604
18616
  "summary": "Send a message to the guest",
18605
- "description": "Sends a message to the guest on this conversation and records it in the thread.\n\nOmit `channel` and the message goes out on whichever channel the conversation already uses (Airbnb, Booking.com, VRBO, SMS, email or the direct-booking site) \u2014 that is the right default. Pass `channel` only to force a specific one.\n\nThe message is attributed to the API: it is recorded with `aiGenerated` false so an API send is never counted as an automated reply.\n\n### Airbnb rewrites links \u2014 check `contentRewritten`\n\nAirbnb rejects guest messages containing a link, an email address or a phone number, and names the offending text. When that happens the offending fragment is stripped and the remainder is re-sent once, which means **the guest receives a message that is not the one you wrote**. Reporting that as a plain success would be a lie, so every response carries `contentRewritten`; when it is `true`, `deliveredContent` is the text that actually reached the guest. Check it before assuming your message went out verbatim.\n\nWhen the text cannot be salvaged (the link is most of the message) nothing is delivered and the call returns `422 message_not_sent` with the channel's verbatim refusal in `statusReason`.\n\nSend `Idempotency-Key` \u2014 without it, retrying after a network timeout sends the guest the same message twice.\n\n### Attachments\n\nSend files with `attachments: [{ url, contentType?, filename? }]` \u2014 public `https://` URLs, up to 5 per request, 10 MB each. `message` may be omitted when there are attachments (except on Booking.com). Repull downloads each file, reads its real type from the bytes, keeps a durable copy and delivers it through the channel's own file flow. **Every file is checked before anything is sent**: if one is unreachable, too large or of a type the channel refuses, the call returns 422 naming the file (`index`) and the guest receives nothing.\n\n| Channel | Accepted types | Text | How it arrives |\n|---|---|---|---|\n| Airbnb | JPEG, PNG, GIF, WebP (converted to JPEG), MP4, QuickTime | optional | each file as its own message, then the text as a separate message |\n| Booking.com | JPEG, PNG | **required** | one message carrying the text and every file |\n| VRBO, SMS, email, direct-booking site chat | \u2014 | \u2014 | `422 attachments_not_supported`, nothing sent |\n\nAirbnb does not allow files in pre-booking (inquiry) conversations; that refusal comes back as `422 message_not_sent`. Because Airbnb delivers files one message at a time, a later file can be refused after earlier ones arrived \u2014 that returns `422 message_partially_sent` with `parts` saying exactly which messages reached the guest; resend only the rest.\n\nThe response's `attachments` lists each file's durable `url`, and `parts` lists every channel message the send produced. Read-back (`GET /v1/conversations/{id}/messages`) shows the same files in each message's `attachments`.\n\n**Inactive listings:** a conversation that belongs to an inactive listing returns `403 listing_inactive` and no message is sent. Activate the listing first.",
18617
+ "description": "Sends a message to the guest on this conversation and records it in the thread.\n\nOmit `channel` and the message goes out on whichever channel the conversation already uses (Airbnb, Booking.com, VRBO, SMS, email or the direct-booking site) \u2014 that is the right default. Pass `channel` only to force a specific one.\n\nThe message is attributed to the API: it is recorded with `aiGenerated` false so an API send is never counted as an automated reply.\n\n### Airbnb rewrites links \u2014 check `contentRewritten`\n\nAirbnb rejects guest messages containing a link, an email address or a phone number, and names the offending text. When that happens the offending fragment is stripped and the remainder is re-sent once, which means **the guest receives a message that is not the one you wrote**. Reporting that as a plain success would be a lie, so every response carries `contentRewritten`; when it is `true`, `deliveredContent` is the text that actually reached the guest. Check it before assuming your message went out verbatim.\n\nWhen the text cannot be salvaged (the link is most of the message) nothing is delivered and the call returns `422 message_not_sent` with the channel's verbatim refusal in `statusReason`. `message_not_sent` only ever means the channel refused: a fault on Repull's side (a dropped database connection, a timeout) is `503 internal_error` with `sent: false` when nothing was delivered \u2014 retry it unchanged with the same `Idempotency-Key`.\n\nSend `Idempotency-Key` \u2014 without it, retrying after a network timeout sends the guest the same message twice.\n\n### Attachments\n\nSend files with `attachments: [{ url, contentType?, filename? }]` \u2014 public `https://` URLs, up to 5 per request, 10 MB each. `message` may be omitted when there are attachments (except on Booking.com). Repull downloads each file, reads its real type from the bytes, keeps a durable copy and delivers it through the channel's own file flow. **Every file is checked before anything is sent**: if one is unreachable, too large or of a type the channel refuses, the call returns 422 naming the file (`index`) and the guest receives nothing.\n\n| Channel | Accepted types | Text | How it arrives |\n|---|---|---|---|\n| Airbnb | JPEG, PNG, GIF, WebP (converted to JPEG), MP4, QuickTime | optional | each file as its own message, then the text as a separate message |\n| Booking.com | JPEG, PNG | **required** | one message carrying the text and every file |\n| VRBO, SMS, email, direct-booking site chat | \u2014 | \u2014 | `422 attachments_not_supported`, nothing sent |\n\nAirbnb does not allow files in pre-booking (inquiry) conversations; that refusal comes back as `422 message_not_sent`. Because Airbnb delivers files one message at a time, a later file can be refused after earlier ones arrived \u2014 that returns `422 message_partially_sent` with `parts` saying exactly which messages reached the guest; resend only the rest.\n\nThe response's `attachments` lists each file's durable `url`, and `parts` lists every channel message the send produced. Read-back (`GET /v1/conversations/{id}/messages`) shows the same files in each message's `attachments`.\n\n**Inactive listings:** a conversation that belongs to an inactive listing returns `403 listing_inactive` and no message is sent. Activate the listing first.",
18606
18618
  "tags": [
18607
18619
  "Conversations"
18608
18620
  ],
@@ -18723,7 +18735,7 @@
18723
18735
  "$ref": "#/components/responses/Unauthorized"
18724
18736
  },
18725
18737
  "403": {
18726
- "description": "`listing_inactive` \u2014 the conversation belongs to an inactive listing, so nothing was sent. The error names the listing.",
18738
+ "description": "`listing_inactive` \u2014 the conversation belongs to an inactive listing, so nothing was sent. The error names the listing. `connection_reauth_required` \u2014 the channel account behind this conversation has no working credentials (`reconnectRequired: true`); nothing was sent and the text was not refused. Reconnect via `POST /v1/connect/{provider}`, then send again.",
18727
18739
  "content": {
18728
18740
  "application/json": {
18729
18741
  "schema": {
@@ -18760,7 +18772,7 @@
18760
18772
  }
18761
18773
  },
18762
18774
  "422": {
18763
- "description": "Nothing was sent unless the code is `message_partially_sent`. Codes: `invalid_params` (malformed body, field named), `message_not_sent` (the channel refused \u2014 `statusReason` has its words), `attachments_not_supported`, `too_many_attachments`, `attachment_requires_message`, `attachment_url_not_allowed`, `attachment_unreachable`, `attachment_too_large`, `attachment_type_not_supported` (each names the file in `index`/`field` and the conversation's `channel`), and `message_partially_sent` (some channel messages were delivered \u2014 `parts` says which).",
18775
+ "description": "Nothing was sent unless the code is `message_partially_sent`. Codes: `invalid_params` (malformed body, field named), `message_not_sent` (the channel itself refused \u2014 `statusReason` has its words verbatim; a failure on Repull's side is never `message_not_sent`, it is `503 internal_error`), `attachments_not_supported`, `too_many_attachments`, `attachment_requires_message`, `attachment_url_not_allowed`, `attachment_unreachable`, `attachment_too_large`, `attachment_type_not_supported` (each names the file in `index`/`field` and the conversation's `channel`), and `message_partially_sent` (some channel messages were delivered \u2014 `parts` says which).",
18764
18776
  "content": {
18765
18777
  "application/json": {
18766
18778
  "schema": {
@@ -18951,11 +18963,30 @@
18951
18963
  }
18952
18964
  },
18953
18965
  "503": {
18954
- "description": "`attachment_storage_failed` \u2014 a file could not be stored for delivery. Nothing was sent; retry with the same `Idempotency-Key` after `retry_after` seconds.",
18966
+ "description": "A temporary fault on Repull's side \u2014 never a verdict on the message. `internal_error`: the send failed inside Repull (a dropped database connection, a timeout) before the channel refused anything. `sent` says whether the message reached the channel: with `messageId: null` and `sent: false` nothing was delivered or recorded, and retrying the same request with the same `Idempotency-Key` after `retry_after` seconds sends it once. With a `messageId`, check that message in `GET /v1/conversations/{id}/messages` before resending. `attachment_storage_failed`: a file could not be stored for delivery; nothing was sent, retry the same way. A 503 is never stored against the `Idempotency-Key`, so the retry runs for real. Do not edit the text: it was not refused.",
18955
18967
  "content": {
18956
18968
  "application/json": {
18957
18969
  "schema": {
18958
18970
  "$ref": "#/components/schemas/Error"
18971
+ },
18972
+ "examples": {
18973
+ "internalNotSent": {
18974
+ "summary": "Repull lost its database connection before the send reached Airbnb \u2014 not sent, retry with the same key",
18975
+ "value": {
18976
+ "error": {
18977
+ "code": "internal_error",
18978
+ "message": "The message was not sent: Repull hit a temporary fault on its side before the message reached Airbnb. Nothing was delivered to the guest and nothing was recorded in the conversation.",
18979
+ "fix": "Retry the same request with the same `Idempotency-Key` after `retry_after` seconds \u2014 this failure is not stored against the key, so the retry sends the message for real, once. Do not change the text: it was not refused.",
18980
+ "docs_url": "https://repull.dev/docs/errors/internal_error",
18981
+ "request_id": "req_01J5X7Y8Z9ABCDEF12345678",
18982
+ "retry_after": 5,
18983
+ "retryable": true,
18984
+ "sent": false,
18985
+ "channel": "airbnb",
18986
+ "messageId": null
18987
+ }
18988
+ }
18989
+ }
18959
18990
  }
18960
18991
  }
18961
18992
  }
@@ -19197,7 +19228,7 @@
19197
19228
  "get": {
19198
19229
  "operationId": "list_connections",
19199
19230
  "summary": "List PMS/OTA connections",
19200
- "description": "Returns every PMS and OTA connection in the workspace, each with its `status`.\n\n**Spot connections that need attention.** A connection whose `status` is not `active` may need the host to do something before it works \u2014 most commonly a Booking.com Extranet connection where the invited user was granted only partial access (`status: \"needs_permissions\"`). A Smoobu connection still on a legacy single API key carries `action.reason: \"reauth_required\"` while its `status` is `active`: Smoobu stops accepting those keys on October 31, 2026, and `fixUrl` opens the form for a new API key + secret (the connection id stays the same). These connections carry two extra fields:\n\n- `action` \u2014 `{ required: true, reason, message }`. `reason` is a stable machine code (e.g. `needs_permissions`); `message` is a host-facing one-liner describing what to do.\n- `fixUrl` \u2014 a durable link that reopens the hosted Connect flow **bound to that account, on the fix screen** (e.g. \"grant full access\" + a Re-check button). It is safe to store and show in your own dashboard.\n\n**Self-serve repair:** when `action.required` is true, surface a \"Fix\" button that opens `fixUrl` in a new tab (or embed it). The host resolves the issue (e.g. grants the user full access in Booking.com) and clicks Re-check; the import finishes on its own and the connection flips back to `active` \u2014 no re-invite, no support ticket. Poll this endpoint (or read it after the host returns) to confirm `action` has cleared.",
19231
+ "description": "Returns every PMS and OTA connection in the workspace, each with its `status`.\n\n**One entry per Booking.com Extranet hotel login.** Each hotel that invites the Repull user connects as its own login, with its own `externalAccountId` (handle `booking_extranet:{externalAccountId}`). A new hotel adds an entry next to the existing ones and never replaces them; the entries share the workspace's Extranet `id`, and each hotel's listings, reservations, conversations and reviews stay under its own login (filter them with `?account=booking_extranet:{externalAccountId}`).\n\n**Spot connections that need attention.** A connection whose `status` is not `active` may need the host to do something before it works \u2014 most commonly a Booking.com Extranet connection where the invited user was granted only partial access (`status: \"needs_permissions\"`). A Smoobu connection still on a legacy single API key carries `action.reason: \"reauth_required\"` while its `status` is `active`: Smoobu stops accepting those keys on October 31, 2026, and `fixUrl` opens the form for a new API key + secret (the connection id stays the same). These connections carry two extra fields:\n\n- `action` \u2014 `{ required: true, reason, message }`. `reason` is a stable machine code (e.g. `needs_permissions`); `message` is a host-facing one-liner describing what to do.\n- `fixUrl` \u2014 a durable link that reopens the hosted Connect flow **bound to that account, on the fix screen** (e.g. \"grant full access\" + a Re-check button). It is safe to store and show in your own dashboard.\n\n**Self-serve repair:** when `action.required` is true, surface a \"Fix\" button that opens `fixUrl` in a new tab (or embed it). The host resolves the issue (e.g. grants the user full access in Booking.com) and clicks Re-check; the import finishes on its own and the connection flips back to `active` \u2014 no re-invite, no support ticket. Poll this endpoint (or read it after the host returns) to confirm `action` has cleared.",
19201
19232
  "tags": [
19202
19233
  "Connect"
19203
19234
  ],
@@ -22534,6 +22565,16 @@
22534
22565
  },
22535
22566
  "502": {
22536
22567
  "$ref": "#/components/responses/AirbnbUpstreamError"
22568
+ },
22569
+ "503": {
22570
+ "description": "With `mediaUrl`: `internal_error` \u2014 the send failed on Repull's side (a dropped database connection, a timeout), not at Airbnb. With `sent: false` and `messageId: null` nothing reached the guest; retry the same request with the same `Idempotency-Key` after `retry_after` seconds. Never stored against the key. `message_not_sent` is reserved for Airbnb's own refusals.",
22571
+ "content": {
22572
+ "application/json": {
22573
+ "schema": {
22574
+ "$ref": "#/components/schemas/Error"
22575
+ }
22576
+ }
22577
+ }
22537
22578
  }
22538
22579
  }
22539
22580
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: repull
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.39
4
+ version: 0.2.40
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivan Nikolov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-11-03 00:00:00.000000000 Z
11
+ date: 2026-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: typhoeus