/en/articles/twilio-verify-events-goes-ga-and-shuts-down-attempt-dlr-if-your-bot-sends-otps-check-that-it-isnt

Bots

Twilio Verify Events goes GA and shuts down Attempt DLR: if your bot sends OTPs, check that it isn't listening to a dead channel

Twilio put Verify Events into GA and discontinued the Attempt DLR events. Subscriptions that depended on them stopped receiving delivery statuses without throwing any error; the replacement is Message Status Stream.

Twilio announced on November 4 that Verify Events is now generally available (GA). The announcement brings no new features, but it closes out a change that a lot of bots let slip by: the Attempt DLR events, which reported whether the verification code arrived by SMS or WhatsApp, are gone. If your bot sends OTP codes with Twilio Verify and your delivery alerts depended on those events, chances are they've been getting nothing for weeks. And without a single error, because Twilio doesn't reject the subscription: it just stops sending.

What Twilio announced

The November 4 changelog is short. It says the GA release includes "all fixes" for the bugs customers reported during the beta and that "no new functionality was introduced." The important part comes in the second point: the Attempt DLR event type was deprecated as part of this release, on September 21, 2026, and that same deprecation also stopped DLR status updates inside Verify Events.

The dates don't quite line up between the two notices. The original notice, published on September 22, says Attempt DLR would be discontinued after September 22 at 22:00 UTC (4:00 PM in Mexico City) and that from that point on Twilio "may stop sending" those events even if you have an active subscription. The other event types in the same subscription keep arriving as normal. Whether it's the 21st or the 22nd, the result is the same: today the Attempt DLR documentation marks all five types as discontinued.

What "discontinued" means in Event Streams

Twilio uses four states for an event type: available, deprecated, restricted, and discontinued. According to their lifecycle guide, a discontinued type no longer reaches existing subscriptions and can't be added to a new subscription or to one you already have. If a subscription mixes several types, the ones that are still available are delivered without any problem.

That's the dangerous detail. If your subscription had attempt-dlr.delivered alongside verification.approved, the second one keeps arriving and everything looks fine. The only thing that gives the problem away is that your delivery dashboard went flat, and a flat dashboard at three in the morning looks a lot like "there was no traffic."

The affected types are these five, all with the prefix com.twilio.accountsecurity.verify.:

  • attempt-dlr.sent
  • attempt-dlr.delivered
  • attempt-dlr.read
  • attempt-dlr.undelivered
  • attempt-dlr.failed

The replacement: Message Status Stream

Twilio launched the message status events pilot on February 27, 2026, and on April 1 it published a version 2 with tags. The Message Status Stream documentation lists five events that map one-to-one to the old ones:

Before (discontinued) Now When it fires, according to Twilio
attempt-dlr.sent message.sent The channel provider accepted the message; delivery is not yet confirmed
attempt-dlr.delivered message.delivered The provider confirms it reached the user
attempt-dlr.read message.read The user opened or read the message. Does not exist for SMS
attempt-dlr.undelivered message.undelivered The provider reports it could not be delivered
attempt-dlr.failed message.failed Delivery failed and there will be no more attempts unless you send a new one

Diagrama que relaciona cada evento attempt-dlr descontinuado de Twilio Verify con su equivalente message.* y los tres pasos para migrar un bot

The payload looks a lot like the old one: account_sid, service_sid, verification_sid, attempt_sid, channel, to, mcc, mnc, number_segments, has_fallback, and is_fallback. There are two practical changes. The status comes in message_status, whereas in the Attempt DLR examples it came in dlr_status. And version 2 adds tags: key-value pairs that you send when starting the verification and that come back in the event. For a WhatsApp bot, that's useful for, say, stuffing in the conversation or flow ID and later cross-referencing which codes didn't arrive without having to build a lookup table.

The supported channels are SMS, WhatsApp, RCS, and voice, according to the general Verify Events page. Twilio also clarifies that a message's status doesn't always arrive instantly: if the provider is slow, Verify polls it again several times for up to an hour.

Don't confuse message status with verification status

Verify Events has two distinct streams and it's worth being clear about which one to use. The verification stream follows the OTP lifecycle: pending, approved, canceled, expired, and max-attempts-reached. By default a verification expires after 10 minutes, and the max-attempts event fires after 5 or more send or check attempts. The message stream tells you whether the code reached the phone.

There's some background that explains why Twilio is pushing toward Message Status. Since April 1, 2026, new customers on the verification stream no longer receive delivery_status updates on each attempt: the value stays fixed at SENT and the error_code field disappears. Twilio says that for delivery status you should use Message Status. My reading of the GA notice is that the phrase about "stopping DLR status updates" extends that cutoff across the board, though Twilio doesn't explain it in more detail. If your code reads send_code_attempts[].delivery_status expecting to see DELIVERED, check it.

How to migrate your bot

I didn't test this on an account of my own. This comes from Twilio's official documentation.

  1. Confirm that the service has Verify Events turned on. In the console it's the "Verify Events Subscribed service" option on the service. Via API it's the service's VerifyEventSubscriptionEnabled parameter, according to the onboarding guide.
  2. Edit your subscription in Event Streams. Add the five message.* types (version 2 if you want tags) and remove the attempt-dlr.* ones, which no longer do anything.
  3. Update the consumer. In your webhook or your Kinesis reader, change the filter by type and read data.message_status. If you use a webhook, Twilio recommends setting Batch to false so you process each event separately.
  4. Review alerts and reports. Any delivery rate metric by country or carrier that came from Attempt DLR has to be rebuilt with the new events. To fill the gap you can use the Verification Attempts API, which isn't real-time, is still in public beta, has a limit of 100 requests per minute, and only keeps the last 30 days. Since the cutoff was in late September, the first weeks without events have already fallen outside that window.
  5. Use the fallback fields. has_fallback tells you whether an alternate channel is available when the message fails, and is_fallback whether that message is already the retry. With that your bot can decide whether to offer "want me to send it by SMS?" or to wait.

Verify Events has no additional cost for Verify customers, so the change doesn't raise your bill.

My take

This isn't an API change that blows up with a 400 and forces you to find out. It's a silence, and silences are the worst thing that can happen to an OTP system: the user doesn't get their code on WhatsApp, abandons the signup, and your "failed deliveries" alert doesn't ring because nothing is arriving anymore for it to count. The fact that the GA announcement comes six weeks after the cutoff, in a two-bullet changelog, doesn't help.

If you run a bot with OTP login, today's task is short: open your Event Streams subscription and search for attempt-dlr. If it shows up, now you know why your delivery charts look so calm.

Sources