sendly 4.4.0 → 4.5.1
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/CHANGELOG.md +7 -0
- data/Gemfile.lock +1 -1
- data/README.md +94 -41
- data/lib/sendly/errors.rb +3 -3
- data/lib/sendly/messages.rb +1 -1
- data/lib/sendly/version.rb +1 -1
- data/lib/sendly/voice_resource.rb +3 -3
- data/lib/sendly/whatsapp_resource.rb +21 -20
- 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: e684d2e1e6cb9addd168326d6874152b070b68ab599ba9370eca565a8a70d3ce
|
|
4
|
+
data.tar.gz: 13ddbe1ae8aed4e2683515a8a7de05f135c037dd12984974a92e173158cf2843
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dab32a1714f5fbe937f3d109d03b4e634311ac890c7f3126dc98653eaa88631ddb2ba6591697f5be9b59595530e5e85d1932b951e645675b79e89b677adbc2db
|
|
7
|
+
data.tar.gz: 53bf4c50b966f79ca3221292ffd2095e6d21007e50421fbd0aa6e7f4c3067060c63ec6ff0524fe87ceeee62690cd83aaafd0bceb83534658d5243677e44d91b1
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# sendly (Ruby)
|
|
2
2
|
|
|
3
|
+
## 4.5.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- **`Sendly::ValidationError#status_code` is the response's real status.** It was always 400, so a 422 (such as `whatsapp_window_closed` or `sms_fallback_not_supported`) reported 400. Code that compared `status_code` with 400 to spot a validation error should check the class (or `code`) instead. `ValidationError.new` takes an optional `status_code:`, 400 by default.
|
|
8
|
+
- Docs give 503, the status the API sends, instead of 502 for the WhatsApp and voice errors raised when WhatsApp or the carrier couldn't be reached: `whatsapp_send_failed` when the message never reached WhatsApp (not sent, and safe to send again with the same idempotency key), the WhatsApp signup, profile, conversational-components and calling errors, `voice_attach_failed` and `carrier_refused`. The API answers every 502 as a 503 with a `Sendly-Upstream-Status: 502` header. Nothing changes at runtime.
|
|
9
|
+
|
|
3
10
|
## 4.4.0
|
|
4
11
|
|
|
5
12
|
### Minor Changes
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -1153,11 +1153,13 @@ puts status.disabled?
|
|
|
1153
1153
|
|
|
1154
1154
|
Connect a number you own to WhatsApp, create Meta-reviewed message
|
|
1155
1155
|
templates, and send via `client.messages.send(channel: "whatsapp", ...)`.
|
|
1156
|
-
Connecting
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1156
|
+
Connecting costs a one-time $9.99 fee per number (no monthly fee), charged to
|
|
1157
|
+
your card when you start connecting it, refunded automatically if the
|
|
1158
|
+
connection fails, and not refundable once the number is connected. The first
|
|
1159
|
+
number always ends with a human step: the signup returns a connect URL a person
|
|
1160
|
+
must open in a browser and log in with Facebook to link their WhatsApp Business
|
|
1161
|
+
Account. More numbers can then be added to that account with a 6-digit code Meta sends
|
|
1162
|
+
to the number, with no Facebook step (same $9.99 fee, refunded if it fails).
|
|
1161
1163
|
|
|
1162
1164
|
Sends go through `messages.send(channel: "whatsapp")` and need `sms:send`,
|
|
1163
1165
|
not `whatsapp:write`. Reads (`signup.get`, templates, the window, senders and
|
|
@@ -1191,7 +1193,7 @@ gives its slot back. Note: Meta
|
|
|
1191
1193
|
has paused marketing template delivery to US (+1) numbers.
|
|
1192
1194
|
|
|
1193
1195
|
```ruby
|
|
1194
|
-
# 1. Connect a number ($
|
|
1196
|
+
# 1. Connect a number ($9.99 one-time; a human must open the connect URL)
|
|
1195
1197
|
signup = client.whatsapp.signup.create(phone_number: "+15125550123")
|
|
1196
1198
|
puts "Have your user open: #{signup.connect_url}"
|
|
1197
1199
|
|
|
@@ -1199,7 +1201,7 @@ puts "Have your user open: #{signup.connect_url}"
|
|
|
1199
1201
|
# while WhatsApp activates the number. Activation usually takes a few minutes
|
|
1200
1202
|
# but can take hours. If it hasn't finished about 6 hours after the session
|
|
1201
1203
|
# began, the session fails with registration_timeout and the fee is refunded.
|
|
1202
|
-
# If the connection fails, the $
|
|
1204
|
+
# If the connection fails, the $9.99 fee is refunded automatically; once a
|
|
1203
1205
|
# number has connected, a later disconnect gets nothing back.
|
|
1204
1206
|
status = client.whatsapp.signup.get(signup.id)
|
|
1205
1207
|
puts status.failure_reasons if status.failed? # e.g. ["waba_mismatch"]
|
|
@@ -1257,7 +1259,7 @@ puts added.status # "verifying"
|
|
|
1257
1259
|
# code has been submitted it is the newest code since the signup started, so
|
|
1258
1260
|
# after a resend it still shows the earlier code until the new one arrives.
|
|
1259
1261
|
# Once WhatsApp has checked a code, only a code that arrived after the last
|
|
1260
|
-
# submission or resend is returned. A
|
|
1262
|
+
# submission or resend is returned. A 503 whatsapp_verification_unavailable
|
|
1261
1263
|
# isn't counted, so the same unchecked code can come back, and submitting it
|
|
1262
1264
|
# again is safe.
|
|
1263
1265
|
code = client.whatsapp.signup.get(added.id).verification_code
|
|
@@ -1316,25 +1318,6 @@ client.messages.send(
|
|
|
1316
1318
|
text: "Here is your receipt",
|
|
1317
1319
|
media_urls: ["https://acme.example/receipt.pdf"]
|
|
1318
1320
|
)
|
|
1319
|
-
|
|
1320
|
-
# Fall back to SMS from the same number when WhatsApp can't deliver: the
|
|
1321
|
-
# window is closed, WhatsApp refuses it, or reports it undeliverable later.
|
|
1322
|
-
# The SMS is billed as an SMS. The number must already be able to send SMS to
|
|
1323
|
-
# the recipient (US and Canada), or this raises 403 sms_fallback_unavailable;
|
|
1324
|
-
# marketing and authentication templates, and media without a caption, raise
|
|
1325
|
-
# 422 sms_fallback_not_supported.
|
|
1326
|
-
message = client.messages.send(
|
|
1327
|
-
channel: "whatsapp",
|
|
1328
|
-
to: "+15555550100",
|
|
1329
|
-
from: "+15125550123",
|
|
1330
|
-
text: "Your table is ready!",
|
|
1331
|
-
fallback_to_sms: true
|
|
1332
|
-
)
|
|
1333
|
-
message.fallback.status # "pending", "sent", "failed", "unavailable" or "skipped"
|
|
1334
|
-
message.fallback.reason # "window_closed", "whatsapp_refused" or "whatsapp_failed"
|
|
1335
|
-
message.fell_back? # true when the SMS went (message.status is then "failed")
|
|
1336
|
-
sms = client.messages.get(message.fallback.message_id) if message.fallback.message_id
|
|
1337
|
-
sms&.fallback_of # the WhatsApp message's id
|
|
1338
1321
|
```
|
|
1339
1322
|
|
|
1340
1323
|
WhatsApp errors map onto the usual classes:
|
|
@@ -1351,10 +1334,13 @@ WhatsApp errors map onto the usual classes:
|
|
|
1351
1334
|
`whatsapp_window_closed`); send a template instead.
|
|
1352
1335
|
- `whatsapp_send_failed` is a `Sendly::ValidationError` (422) when WhatsApp
|
|
1353
1336
|
refused the message, which is final (cached under the idempotency key and
|
|
1354
|
-
replayed for 24 hours), and a `Sendly::ServerError` (
|
|
1355
|
-
provably never reached
|
|
1356
|
-
|
|
1357
|
-
same
|
|
1337
|
+
replayed for 24 hours), and a `Sendly::ServerError` (503) when the message
|
|
1338
|
+
provably never reached WhatsApp, so it was not sent and is safe to resend
|
|
1339
|
+
under the same idempotency key; the 503 is never cached and the client
|
|
1340
|
+
retries it automatically, up to 3 times under the same key, before raising.
|
|
1341
|
+
Neither is charged. With `fallback_to_sms: true`, a 422 means the SMS
|
|
1342
|
+
couldn't go either, and `e.response_body["fallback"]` says why; see
|
|
1343
|
+
[SMS fallback](#sms-fallback).
|
|
1358
1344
|
- `whatsapp_send_unconfirmed` is a `Sendly::APIError` with `status_code` 409:
|
|
1359
1345
|
the outcome is unknown. The message was marked failed and refunded but may
|
|
1360
1346
|
still be delivered, so check before sending it again (it could arrive
|
|
@@ -1382,12 +1368,11 @@ WhatsApp errors map onto the usual classes:
|
|
|
1382
1368
|
400 `display_name_required` and for 422 `whatsapp_verification_start_failed`
|
|
1383
1369
|
(WhatsApp refused to verify the number; final), `Sendly::APIError` (409) for
|
|
1384
1370
|
`whatsapp_signup_in_progress` and `whatsapp_already_enabled`, and
|
|
1385
|
-
`Sendly::ServerError` for
|
|
1371
|
+
`Sendly::ServerError` for 503 `whatsapp_verification_start_failed` (WhatsApp
|
|
1386
1372
|
couldn't start verifying the number; start again). Either failure fails the
|
|
1387
1373
|
session and refunds its fee. With `business_account_id:` the client never
|
|
1388
1374
|
retries a 5xx, a timeout or a dropped connection, because each retry would
|
|
1389
|
-
start a new charged session. A
|
|
1390
|
-
Facebook signup for a number
|
|
1375
|
+
start a new charged session. A Facebook signup for a number
|
|
1391
1376
|
that is being added by code gets 409 `whatsapp_verification_in_progress`,
|
|
1392
1377
|
with that session's id in `e.response_body["id"]`.
|
|
1393
1378
|
- `signup.verify` raises `Sendly::ValidationError` for 400
|
|
@@ -1396,7 +1381,7 @@ WhatsApp errors map onto the usual classes:
|
|
|
1396
1381
|
`e.response_body["attemptsRemaining"]`); `Sendly::APIError` (409) for
|
|
1397
1382
|
`whatsapp_verification_failed` (after 5 wrong codes the session fails and
|
|
1398
1383
|
the fee is refunded), `whatsapp_verification_busy` (try again) and
|
|
1399
|
-
`signup_not_active`; and `Sendly::ServerError` for
|
|
1384
|
+
`signup_not_active`; and `Sendly::ServerError` for 503
|
|
1400
1385
|
`whatsapp_verification_unavailable` (the attempt isn't counted) and
|
|
1401
1386
|
`whatsapp_activation_pending` (the code was accepted but connecting didn't
|
|
1402
1387
|
finish; check back shortly with `signup.get`). The client never retries a
|
|
@@ -1406,13 +1391,13 @@ WhatsApp errors map onto the usual classes:
|
|
|
1406
1391
|
- `signup.resend` raises `Sendly::RateLimitError` for 429
|
|
1407
1392
|
`whatsapp_verification_resend_too_soon` at once, with the seconds to wait in
|
|
1408
1393
|
`e.retry_after`, and `whatsapp_verification_resend_failed` as a
|
|
1409
|
-
`Sendly::ValidationError` (422) or a `Sendly::ServerError` (
|
|
1394
|
+
`Sendly::ValidationError` (422) or a `Sendly::ServerError` (503).
|
|
1410
1395
|
- `senders.upload_profile_photo` raises `Sendly::ValidationError` for 400
|
|
1411
1396
|
`whatsapp_profile_photo_invalid` (not a JPEG or PNG) and `file_required`,
|
|
1412
1397
|
and `Sendly::APIError` with `status_code` 413 for
|
|
1413
1398
|
`whatsapp_profile_photo_too_large`. The photo methods raise
|
|
1414
|
-
`Sendly::ServerError` for
|
|
1415
|
-
conversational component methods for
|
|
1399
|
+
`Sendly::ServerError` for 503 `whatsapp_profile_update_failed`, and the
|
|
1400
|
+
conversational component methods for 503
|
|
1416
1401
|
`whatsapp_conversational_components_fetch_failed` and
|
|
1417
1402
|
`whatsapp_conversational_components_update_failed`; an invalid list is a
|
|
1418
1403
|
`Sendly::ValidationError` (400 `invalid_request`) with a message naming the
|
|
@@ -1422,10 +1407,78 @@ WhatsApp errors map onto the usual classes:
|
|
|
1422
1407
|
(switch voice on for the number first), `Sendly::ValidationError` for 422
|
|
1423
1408
|
`whatsapp_calling_unavailable` (Meta only allows calling once the account may
|
|
1424
1409
|
message at least 2,000 people a day and the display name is approved), and
|
|
1425
|
-
`Sendly::ServerError` for
|
|
1410
|
+
`Sendly::ServerError` for 503 `whatsapp_calling_update_failed`.
|
|
1426
1411
|
- A sender method for a number that isn't connected raises
|
|
1427
1412
|
`Sendly::NotFoundError` (404 `whatsapp_sender_not_connected`).
|
|
1428
1413
|
|
|
1414
|
+
### SMS fallback
|
|
1415
|
+
|
|
1416
|
+
Pass `fallback_to_sms: true` and a WhatsApp message that can't be delivered
|
|
1417
|
+
goes as an SMS from the same number instead.
|
|
1418
|
+
|
|
1419
|
+
```ruby
|
|
1420
|
+
begin
|
|
1421
|
+
message = client.messages.send(
|
|
1422
|
+
channel: "whatsapp",
|
|
1423
|
+
to: "+15555550100",
|
|
1424
|
+
from: "+15125550123",
|
|
1425
|
+
text: "Your table is ready!",
|
|
1426
|
+
fallback_to_sms: true
|
|
1427
|
+
)
|
|
1428
|
+
puts message.fallback.status # "pending", "sent", "failed", "unavailable" or "skipped"
|
|
1429
|
+
puts message.fallback.reason # "window_closed", "whatsapp_refused" or "whatsapp_failed"
|
|
1430
|
+
if message.fell_back? # the SMS went instead (message.status is "failed")
|
|
1431
|
+
sms = client.messages.get(message.fallback.message_id)
|
|
1432
|
+
puts sms.fallback_of # the WhatsApp message's id
|
|
1433
|
+
end
|
|
1434
|
+
rescue Sendly::Error => e
|
|
1435
|
+
body = e.response_body || {}
|
|
1436
|
+
case e.code
|
|
1437
|
+
when "sms_fallback_unavailable"
|
|
1438
|
+
# 403: this number can't send SMS to the recipient; nothing was sent
|
|
1439
|
+
when "sms_fallback_not_supported"
|
|
1440
|
+
puts body["reason"] # marketing_template, authentication_template or media_without_caption
|
|
1441
|
+
else
|
|
1442
|
+
raise unless body["fallback"]
|
|
1443
|
+
# 422 whatsapp_window_closed or whatsapp_send_failed: the SMS couldn't go
|
|
1444
|
+
# either. A closed window also carries the WhatsApp message's id.
|
|
1445
|
+
fallback = Sendly::WhatsAppSmsFallback.new(body["fallback"])
|
|
1446
|
+
puts "#{e.code} #{body["id"]} #{fallback.status}: #{fallback.error}"
|
|
1447
|
+
end
|
|
1448
|
+
end
|
|
1449
|
+
```
|
|
1450
|
+
|
|
1451
|
+
- It falls back when the 24-hour window is closed (the SMS goes at once:
|
|
1452
|
+
free-form text and media go only within 24 hours of the customer's last
|
|
1453
|
+
message, templates any time), when WhatsApp refuses the message, or when
|
|
1454
|
+
WhatsApp reports it undeliverable later. Never after WhatsApp reports it
|
|
1455
|
+
delivered or read, and at most once per message.
|
|
1456
|
+
- The number must already be able to send SMS to the recipient (a verified
|
|
1457
|
+
toll-free number, or a local number on a 10DLC campaign, to a US or Canada
|
|
1458
|
+
number), or the send is refused with 403 `sms_fallback_unavailable`
|
|
1459
|
+
before anything is sent.
|
|
1460
|
+
- Marketing and authentication templates, and media without a caption, can't
|
|
1461
|
+
fall back: 422 `sms_fallback_not_supported`. A utility template falls
|
|
1462
|
+
back as its text header, body and footer with the variables filled in, and
|
|
1463
|
+
its URL and phone buttons as `label: target`; quick replies are dropped and
|
|
1464
|
+
listed in `fallback.content_dropped`.
|
|
1465
|
+
- Billing: the WhatsApp charge is refunded (a closed window is never charged)
|
|
1466
|
+
and the SMS is billed as an SMS. A message that fell back at once comes
|
|
1467
|
+
back with `status` `"failed"`, `credits_used` 0 and `fallback.status` `"sent"`; `fallback.credits_used` is
|
|
1468
|
+
what the SMS cost.
|
|
1469
|
+
- No SMS goes on a 409 `whatsapp_send_unconfirmed` or a 503
|
|
1470
|
+
`whatsapp_send_failed`. The status is `"unavailable"` when SMS rules stop it
|
|
1471
|
+
(the contact opted out, a promotional-looking text in the recipient's quiet
|
|
1472
|
+
hours, restricted content), with the reason in `fallback.error`, and
|
|
1473
|
+
`"skipped"` for a WhatsApp error an SMS can't fix.
|
|
1474
|
+
- There is no time-based fallback: a message WhatsApp accepted but hasn't
|
|
1475
|
+
delivered, for example to a phone that is off, stays `"pending"`, and no SMS
|
|
1476
|
+
goes unless WhatsApp later reports a failure.
|
|
1477
|
+
- `messages.get` and `messages.list` return the same fallback on the WhatsApp message, so check a
|
|
1478
|
+
pending one later. The SMS carries `fallback_of`, the WhatsApp message's id.
|
|
1479
|
+
|
|
1480
|
+
Guide: [Send WhatsApp with an SMS Fallback](https://sendly.live/docs/whatsapp/send-with-fallback).
|
|
1481
|
+
|
|
1429
1482
|
## RCS
|
|
1430
1483
|
|
|
1431
1484
|
Send branded rich messages — text with suggested replies and actions, or
|
|
@@ -1769,8 +1822,8 @@ string), `invalid_voice_mode`, `agent_required`,
|
|
|
1769
1822
|
the address could not be validated, and `e.response_body["suggested"]` holds
|
|
1770
1823
|
a corrected address when one was found); `Sendly::APIError` with
|
|
1771
1824
|
`status_code` 409 for `agent_disabled`, `agent_limit` (20 agents per
|
|
1772
|
-
workspace) and `agent_in_use`; and `Sendly::ServerError` for
|
|
1773
|
-
`voice_attach_failed
|
|
1825
|
+
workspace) and `agent_in_use`; and `Sendly::ServerError` for 503
|
|
1826
|
+
`voice_attach_failed`, `carrier_refused` and `voice_unavailable`,
|
|
1774
1827
|
raised after the client has already retried the 5xx on its own. Not every
|
|
1775
1828
|
`carrier_refused` is worth retrying: when the message says the number
|
|
1776
1829
|
couldn't be found for emergency registration, retrying won't help, so
|
data/lib/sendly/errors.rb
CHANGED
|
@@ -73,9 +73,9 @@ module Sendly
|
|
|
73
73
|
# e.g. +[{ "path" => "brand.ein", "message" => "Enter a 9-digit EIN" }]+
|
|
74
74
|
attr_reader :field_errors
|
|
75
75
|
|
|
76
|
-
def initialize(message = "Validation failed", field_errors: nil, details: nil, code: nil)
|
|
76
|
+
def initialize(message = "Validation failed", field_errors: nil, details: nil, code: nil, status_code: 400)
|
|
77
77
|
@field_errors = field_errors
|
|
78
|
-
super(message, code: code || "VALIDATION_ERROR", details: details, status_code:
|
|
78
|
+
super(message, code: code || "VALIDATION_ERROR", details: details, status_code: status_code)
|
|
79
79
|
end
|
|
80
80
|
end
|
|
81
81
|
|
|
@@ -127,7 +127,7 @@ module Sendly
|
|
|
127
127
|
|
|
128
128
|
error = case status
|
|
129
129
|
when 400, 422
|
|
130
|
-
ValidationError.new(message, details: details, field_errors: body["errors"], code: code)
|
|
130
|
+
ValidationError.new(message, details: details, field_errors: body["errors"], code: code, status_code: status)
|
|
131
131
|
when 401
|
|
132
132
|
AuthenticationError.new(message, code: code)
|
|
133
133
|
when 402
|
data/lib/sendly/messages.rb
CHANGED
|
@@ -86,7 +86,7 @@ module Sendly
|
|
|
86
86
|
# WhatsApp the 422 +whatsapp_send_failed+ when WhatsApp refused the
|
|
87
87
|
# message (final, not retried, not charged; cached under the
|
|
88
88
|
# idempotency key and replayed for 24 hours)
|
|
89
|
-
# @raise [Sendly::ServerError] On WhatsApp, the
|
|
89
|
+
# @raise [Sendly::ServerError] On WhatsApp, the 503 +whatsapp_send_failed+:
|
|
90
90
|
# the message provably never reached the carrier, so it was not sent
|
|
91
91
|
# and is safe to send again. It isn't charged and is never cached, so
|
|
92
92
|
# the client retries it like any 5xx first under the same idempotency
|
data/lib/sendly/version.rb
CHANGED
|
@@ -402,7 +402,7 @@ module Sendly
|
|
|
402
402
|
# @raise [Sendly::NotFoundError] HTTP 404 +number_not_found+ / +agent_not_found+
|
|
403
403
|
# @raise [Sendly::APIError] HTTP 409 +agent_disabled+ (the agent is
|
|
404
404
|
# switched off), 403 +forbidden+ / +live_key_required+
|
|
405
|
-
# @raise [Sendly::ServerError] HTTP
|
|
405
|
+
# @raise [Sendly::ServerError] HTTP 503 +voice_attach_failed+ (voice could
|
|
406
406
|
# not be switched on; try again) or 503 +voice_unavailable+, after the
|
|
407
407
|
# client's automatic retries. Either can follow a mode alone on a number
|
|
408
408
|
# whose voice is off.
|
|
@@ -454,7 +454,7 @@ module Sendly
|
|
|
454
454
|
# 422 +invalid_address+ when the address could not be validated, with a
|
|
455
455
|
# corrected address (or +nil+) in +e.response_body["suggested"]+
|
|
456
456
|
# @raise [Sendly::NotFoundError] HTTP 404 +number_not_found+
|
|
457
|
-
# @raise [Sendly::ServerError] HTTP
|
|
457
|
+
# @raise [Sendly::ServerError] HTTP 503 +carrier_refused+ when the
|
|
458
458
|
# registration was refused, raised after the client has already retried
|
|
459
459
|
# the 5xx on its own. When the message says the number couldn't be
|
|
460
460
|
# found for emergency registration, retrying won't help: contact
|
|
@@ -691,7 +691,7 @@ module Sendly
|
|
|
691
691
|
# +agent_disabled+ / +agent_limit+ / +agent_in_use+ (409) and +forbidden+
|
|
692
692
|
# / +live_key_required+ / +insufficient_permissions+ (403); and
|
|
693
693
|
# {Sendly::ServerError} (not an +APIError+) for +voice_attach_failed+ /
|
|
694
|
-
# +carrier_refused+
|
|
694
|
+
# +carrier_refused+ / +voice_unavailable+ (503) and
|
|
695
695
|
# +voice_internal_error+ (500). Every API error keeps the parsed body on
|
|
696
696
|
# {Sendly::Error#response_body}. The full list is {Call::ERROR_CODES}.
|
|
697
697
|
#
|
|
@@ -80,7 +80,7 @@ module Sendly
|
|
|
80
80
|
# +verification_start_failed+ (WhatsApp couldn't start verifying an added
|
|
81
81
|
# number), +verification_failed+ (too many wrong codes) or
|
|
82
82
|
# +verification_expired+ (a verifying session left untouched for an hour).
|
|
83
|
-
# If the connection fails, the $
|
|
83
|
+
# If the connection fails, the $9.99 fee is refunded automatically.
|
|
84
84
|
#
|
|
85
85
|
# While the status is +"verifying"+, +verification_method+ (+"sms"+ or
|
|
86
86
|
# +"voice"+) and +verification_attempts_remaining+ are set, and on
|
|
@@ -90,7 +90,7 @@ module Sendly
|
|
|
90
90
|
# started, so after a resend it still shows the earlier code until the new
|
|
91
91
|
# one arrives. Once WhatsApp has checked a code, only a code that arrived
|
|
92
92
|
# after the last submission or resend is returned. A submission answered
|
|
93
|
-
# with
|
|
93
|
+
# with 503 +whatsapp_verification_unavailable+ is not counted, so the same
|
|
94
94
|
# unchecked code can come back, and submitting it again with
|
|
95
95
|
# {WhatsAppSignupResource#verify} is safe. All three are nil in any other
|
|
96
96
|
# status.
|
|
@@ -533,7 +533,8 @@ module Sendly
|
|
|
533
533
|
|
|
534
534
|
# Start connecting a number to WhatsApp.
|
|
535
535
|
#
|
|
536
|
-
# Charges a one-time $
|
|
536
|
+
# Charges a one-time $9.99 connection fee per number (no monthly fee) to
|
|
537
|
+
# your card when the connection starts, and returns a
|
|
537
538
|
# +connect_url+. Completing the connection requires a human: hand the
|
|
538
539
|
# URL to your user — they open it in a browser and log in with Facebook
|
|
539
540
|
# to link their WhatsApp Business Account. Then poll {#get} until the
|
|
@@ -548,14 +549,14 @@ module Sendly
|
|
|
548
549
|
# takes a few minutes but can take hours. If it hasn't finished about 6
|
|
549
550
|
# hours after the session began, the session fails with
|
|
550
551
|
# +registration_timeout+ and the fee is refunded. If the connection
|
|
551
|
-
# fails, the $
|
|
552
|
-
# connected
|
|
552
|
+
# fails, the $9.99 fee is refunded automatically; once the number has
|
|
553
|
+
# connected it is not refundable, and a later disconnect gets nothing
|
|
553
554
|
# back.
|
|
554
555
|
#
|
|
555
556
|
# To add a number to a WhatsApp Business Account this workspace has
|
|
556
557
|
# already connected, pass its +business_account_id+ (as shown on
|
|
557
558
|
# {WhatsAppSender#business_account_id}). There is no Facebook step and no
|
|
558
|
-
# +connect_url+: the same $
|
|
559
|
+
# +connect_url+: the same $9.99 fee is charged, Meta sends the number a
|
|
559
560
|
# 6-digit code by text or voice call, and the session is +"verifying"+
|
|
560
561
|
# until you submit the code with {#verify}. Calling again for a number
|
|
561
562
|
# that is verifying returns the same session without charging again or
|
|
@@ -580,8 +581,8 @@ module Sendly
|
|
|
580
581
|
# (+e.response_body["retryAfter"]+) and a +Retry-After: 3600+ header.
|
|
581
582
|
# The client retries it like any 5xx before raising.
|
|
582
583
|
# @raise [Sendly::RateLimitError] +whatsapp_signup_limit_reached+ (429)
|
|
583
|
-
# after 5 failed, charged signups in 24 hours. Not retried;
|
|
584
|
-
# the next day.
|
|
584
|
+
# after 5 failed, charged signups (or 20 cancelled) in 24 hours. Not retried;
|
|
585
|
+
# try again the next day.
|
|
585
586
|
# @raise [Sendly::NotFoundError] +whatsapp_business_account_not_found+
|
|
586
587
|
# (404) when +business_account_id+ isn't connected in this workspace
|
|
587
588
|
# with an active number.
|
|
@@ -597,8 +598,8 @@ module Sendly
|
|
|
597
598
|
# still being added, so try again in a moment) or 409
|
|
598
599
|
# +whatsapp_already_enabled+.
|
|
599
600
|
# @raise [Sendly::InsufficientCreditsError] 402 +payment_method_required+
|
|
600
|
-
# or +payment_failed+ when the $
|
|
601
|
-
# @raise [Sendly::ServerError] +whatsapp_verification_start_failed+ (
|
|
601
|
+
# or +payment_failed+ when the $9.99 fee can't be charged.
|
|
602
|
+
# @raise [Sendly::ServerError] +whatsapp_verification_start_failed+ (503)
|
|
602
603
|
# when WhatsApp couldn't start verifying the number: the session failed
|
|
603
604
|
# and its fee is refunded, so start again. With +business_account_id+,
|
|
604
605
|
# a 5xx is raised at once and never retried by the client, because
|
|
@@ -655,8 +656,8 @@ module Sendly
|
|
|
655
656
|
# 409 +signup_not_active+ when the signup isn't waiting for a code or is
|
|
656
657
|
# older than 3 hours
|
|
657
658
|
# @raise [Sendly::NotFoundError] +signup_not_found+ (404)
|
|
658
|
-
# @raise [Sendly::ServerError]
|
|
659
|
-
# (WhatsApp couldn't check the code; the attempt isn't counted) or
|
|
659
|
+
# @raise [Sendly::ServerError] 503 +whatsapp_verification_unavailable+
|
|
660
|
+
# (WhatsApp couldn't check the code; the attempt isn't counted) or 503
|
|
660
661
|
# +whatsapp_activation_pending+ (the code was accepted but connecting
|
|
661
662
|
# the number didn't finish; check back shortly with {#get}). A 5xx, a
|
|
662
663
|
# timeout or a dropped connection is raised at once and never retried
|
|
@@ -695,7 +696,7 @@ module Sendly
|
|
|
695
696
|
# waiting for a code or is older than 3 hours
|
|
696
697
|
# @raise [Sendly::NotFoundError] +signup_not_found+ (404)
|
|
697
698
|
# @raise [Sendly::ServerError] +whatsapp_verification_resend_failed+
|
|
698
|
-
# (
|
|
699
|
+
# (503) when WhatsApp couldn't be reached. The client retries a 5xx
|
|
699
700
|
# before raising.
|
|
700
701
|
#
|
|
701
702
|
# @example
|
|
@@ -847,7 +848,7 @@ module Sendly
|
|
|
847
848
|
# @raise [Sendly::APIError] +whatsapp_profile_photo_too_large+ with
|
|
848
849
|
# +status_code+ 413 when the photo is over 5 MB
|
|
849
850
|
# @raise [Sendly::NotFoundError] +whatsapp_sender_not_connected+ (404)
|
|
850
|
-
# @raise [Sendly::ServerError] +whatsapp_profile_update_failed+ (
|
|
851
|
+
# @raise [Sendly::ServerError] +whatsapp_profile_update_failed+ (503)
|
|
851
852
|
# when WhatsApp refused the image or couldn't be reached. A 5xx, a
|
|
852
853
|
# timeout or a dropped connection is raised at once and never retried
|
|
853
854
|
# by the client; check the image is
|
|
@@ -876,7 +877,7 @@ module Sendly
|
|
|
876
877
|
# @return [WhatsAppSenderProfile] The profile, normally with
|
|
877
878
|
# +profile_photo_url+ nil
|
|
878
879
|
# @raise [Sendly::NotFoundError] +whatsapp_sender_not_connected+ (404)
|
|
879
|
-
# @raise [Sendly::ServerError] +whatsapp_profile_update_failed+ (
|
|
880
|
+
# @raise [Sendly::ServerError] +whatsapp_profile_update_failed+ (503).
|
|
880
881
|
# The client retries a 5xx before raising.
|
|
881
882
|
#
|
|
882
883
|
# @example
|
|
@@ -899,7 +900,7 @@ module Sendly
|
|
|
899
900
|
# @return [WhatsAppConversationalComponents]
|
|
900
901
|
# @raise [Sendly::NotFoundError] +whatsapp_sender_not_connected+ (404)
|
|
901
902
|
# @raise [Sendly::ServerError]
|
|
902
|
-
# +whatsapp_conversational_components_fetch_failed+ (
|
|
903
|
+
# +whatsapp_conversational_components_fetch_failed+ (503). The client
|
|
903
904
|
# retries a 5xx before raising.
|
|
904
905
|
#
|
|
905
906
|
# @example
|
|
@@ -933,7 +934,7 @@ module Sendly
|
|
|
933
934
|
# +invalid_request+ (400) with a message naming the problem
|
|
934
935
|
# @raise [Sendly::NotFoundError] +whatsapp_sender_not_connected+ (404)
|
|
935
936
|
# @raise [Sendly::ServerError]
|
|
936
|
-
# +whatsapp_conversational_components_update_failed+ (
|
|
937
|
+
# +whatsapp_conversational_components_update_failed+ (503). The client
|
|
937
938
|
# retries a 5xx before raising.
|
|
938
939
|
#
|
|
939
940
|
# @example
|
|
@@ -974,7 +975,7 @@ module Sendly
|
|
|
974
975
|
# when Meta refused: calling needs the account at the 2,000
|
|
975
976
|
# recipients a day messaging limit and an approved display name
|
|
976
977
|
# @raise [Sendly::NotFoundError] +whatsapp_sender_not_connected+ (404)
|
|
977
|
-
# @raise [Sendly::ServerError] +whatsapp_calling_update_failed+ (
|
|
978
|
+
# @raise [Sendly::ServerError] +whatsapp_calling_update_failed+ (503).
|
|
978
979
|
# The client retries a 5xx before raising.
|
|
979
980
|
#
|
|
980
981
|
# @example
|
|
@@ -1153,7 +1154,7 @@ module Sendly
|
|
|
1153
1154
|
# create Meta-reviewed message templates, and send via
|
|
1154
1155
|
# +client.messages.send(channel: "whatsapp", ...)+.
|
|
1155
1156
|
#
|
|
1156
|
-
# Connecting a number
|
|
1157
|
+
# Connecting a number costs a one-time $9.99 fee (no monthly fee). The first
|
|
1157
1158
|
# number always ends with a human step: {WhatsAppSignupResource#create}
|
|
1158
1159
|
# returns a +connect_url+ that a person must open in a browser and log in
|
|
1159
1160
|
# with Facebook to link their WhatsApp Business Account. More numbers can
|
|
@@ -1195,7 +1196,7 @@ module Sendly
|
|
|
1195
1196
|
# every method on this resource gets 404 +not_found+.
|
|
1196
1197
|
#
|
|
1197
1198
|
# @example Connect a number, create a template, then send
|
|
1198
|
-
# # 1. Connect ($
|
|
1199
|
+
# # 1. Connect ($9.99 one-time; a human must open the connect URL)
|
|
1199
1200
|
# signup = client.whatsapp.signup.create(phone_number: "+15559876543")
|
|
1200
1201
|
# puts "Have your user open: #{signup.connect_url}"
|
|
1201
1202
|
#
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sendly
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.
|
|
4
|
+
version: 4.5.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sendly
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|