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 +4 -4
- data/lib/repull/api/connect_api.rb +2 -2
- data/lib/repull/api/conversations_api.rb +2 -2
- data/lib/repull/models/conversation.rb +1 -1
- data/lib/repull/models/conversation_detail.rb +1 -1
- data/lib/repull/models/listing.rb +23 -1
- data/lib/repull/version.rb +1 -1
- data/openapi/v1.json +47 -6
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 788a3e7ef0f0cf6d27c2878a4d1f371512e027fe45c8f73bb02ad92cd4763a37
|
|
4
|
+
data.tar.gz: 9ac321f22b18e15297cefb4d33c11154cabcc201d54afc5e4414b648c059a12f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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 `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.
|
|
699
|
+
# 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.
|
|
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.
|
|
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.
|
|
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
|
data/lib/repull/version.rb
CHANGED
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.
|
|
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": "
|
|
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.
|
|
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-
|
|
11
|
+
date: 2026-11-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: typhoeus
|