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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5a69a00fe63398e0ad342ed03ad9ddf38d668fe0d2ddd85533a2aa43e534eacb
4
- data.tar.gz: 8488579a38c0f09720a8d9e67a5084819eb884dfe6cc99afc66be5d143ae5323
3
+ metadata.gz: e684d2e1e6cb9addd168326d6874152b070b68ab599ba9370eca565a8a70d3ce
4
+ data.tar.gz: 13ddbe1ae8aed4e2683515a8a7de05f135c037dd12984974a92e173158cf2843
5
5
  SHA512:
6
- metadata.gz: caa9cd2bb16dc70c5eea42f760fe9295587e0f3b8c7a83bb4de6af903b5ba29ff6ec89c6c53ab211fc630c68d8139648516a95dccd27412382be08012ba922ed
7
- data.tar.gz: b5ef93d9ce46c42dd53ef375b23aa66a5027e6534bf93425ab507d37f4c2f17311cdefbda52269e2fbad9b167808ad96abae255fd0b216942d5af1873d5f8337
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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sendly (4.4.0)
4
+ sendly (4.5.1)
5
5
  faraday (~> 2.0)
6
6
  faraday-retry (~> 2.0)
7
7
 
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 is a one-time $19 setup (no monthly fee). The first number always
1157
- ends with a human step: the signup returns a connect URL a person must open in
1158
- a browser and log in with Facebook to link their WhatsApp Business Account.
1159
- More numbers can then be added to that account with a 6-digit code Meta sends
1160
- to the number, with no Facebook step (same $19 fee, refunded if it fails).
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 ($19 one-time; a human must open the connect URL)
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 $19 fee is refunded automatically; once a
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 502 whatsapp_verification_unavailable
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` (502) when the message
1355
- provably never reached the carrier, so it was not sent and is safe to send
1356
- again; the 502 is never cached and the client retries it first under the
1357
- same idempotency key. Neither is charged.
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 502 `whatsapp_verification_start_failed` (WhatsApp
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 502
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` (502).
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 502 `whatsapp_profile_update_failed`, and the
1415
- conversational component methods for 502
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 502 `whatsapp_calling_update_failed`.
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 502
1773
- `voice_attach_failed` and `carrier_refused` and 503 `voice_unavailable`,
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: 400)
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
@@ -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 502 +whatsapp_send_failed+:
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sendly
4
- VERSION = "4.4.0"
4
+ VERSION = "4.5.1"
5
5
  end
@@ -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 502 +voice_attach_failed+ (voice could
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 502 +carrier_refused+ when the
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+ (502), +voice_unavailable+ (503) and
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 $19 fee is refunded automatically.
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 502 +whatsapp_verification_unavailable+ is not counted, so the same
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 $19 setup fee (no monthly fee) and returns a
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 $19 fee is refunded automatically; once the number has
552
- # connected there is no refund, and a later disconnect gets nothing
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 $19 fee is charged, Meta sends the number a
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; try again
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 $19 fee can't be charged.
601
- # @raise [Sendly::ServerError] +whatsapp_verification_start_failed+ (502)
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] 502 +whatsapp_verification_unavailable+
659
- # (WhatsApp couldn't check the code; the attempt isn't counted) or 502
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
- # (502) when WhatsApp couldn't be reached. The client retries a 5xx
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+ (502)
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+ (502).
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+ (502). The client
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+ (502). The client
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+ (502).
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 is a one-time $19 setup (no monthly fee). The first
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 ($19 one-time; a human must open the connect URL)
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.0
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-17 00:00:00.000000000 Z
11
+ date: 2026-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday