Quick answer: Twilio error 30007 means Twilio or the carrier filtered your text as spam or a policy breach, and it is still billed. With an AI agent, first check whether its messages have drifted from your registered A2P 10DLC samples (public shorteners, foreign links, emoji, no brand, opt-out wording without STOP), then, if you believe the messages are compliant, send Twilio Support 3 or more Message SIDs from the last 7 days.
This page covers message-level delivery failure after your sender is registered, and the test that tells “the carrier did not like what my AI wrote” apart from “the number was a landline”. It covers Twilio Programmable Messaging, US A2P 10DLC long codes, toll-free and short code senders, the carrier filters run by AT&T, T-Mobile and Verizon, Twilio’s Messaging Policy and Acceptable Use Policy, Lookup Line Type Intelligence and SMS Pumping Protection. If your campaign was rejected before you ever sent, that is a different problem, covered in why an A2P 10DLC campaign for an AI SMS agent gets rejected.
Why are my AI agent’s text messages not being delivered?
Every undelivered or failed message in Twilio carries an error code, and the code sorts the problem into one of four groups before you read a single message body. The Message resource documentation lists the statuses a message can end in, including failed and undelivered, and the same code arrives in the ErrorCode field of your status callback.
- Filtered: 30007, and some 30004s. Twilio or a carrier looked at the message and blocked it. This is the only group where what your AI wrote is usually the cause.
- Unreachable destination: 30003, 30005, 30006, 30008. The handset is off, the number does not exist, it is a landline, or the carrier path failed. Your lead data is the usual suspect, not your model.
- Sender not registered or not ready: 30024, 30032, 30034, 30035. The number you sent from is not yet allowed to carry this traffic. No amount of prompt editing fixes these.
- Refused before sending: 21610 (the recipient opted out) and 30450 (SMS Pumping Protection held the message as suspicious).
The single most useful sentence on this page: a 30007 that clusters on messages your AI wrote differently from your registered samples points to a content problem; a 30007 spread evenly across on-script messages points instead to consent, opt-outs or volume.
What does Twilio error 30007 actually mean?
Twilio’s error 30007 page says the message “was filtered (blocked) by Twilio or by the carrier”. Twilio filters for breaches of its Messaging Policy or Acceptable Use Policy, and names spam, phishing and fraud as examples. Carriers filter for their own rules and for local regulation. The page lists two causes, and only two: Twilio’s filter identified the message as spam or unwanted, or a wireless carrier flagged it as objectionable.
How the carriers decide is described in Twilio’s SMS Message Filtering in the United States and Canada. Carriers there “use machine learning software systems to filter messages”, looking at both content and volume, and each message receives a cumulative score. The factors Twilio names are how many messages have come from a phone number in a period, how many similar messages have crossed the carrier’s network, and whether the content resembles known spam. Twilio adds that, in its experience, high opt-out rates and end-user complaints “also play a major role”. The same article gives the history: Verizon began accepting A2P messaging on 10-digit numbers in January 2019, and the registration-based A2P 10DLC system launched with AT&T and T-Mobile in 2021.
Two facts from Twilio’s How Does Message Filtering Work? change how you should treat 30007 in an automated agent. First, filtered messages are still billed, so an agent that retries a filtered follow-up pays for every retry. Second, “it is not always possible to know for certain when a message has been filtered by a carrier”, and in rare cases carriers report filtered messages as delivered. A clean 30007 count is therefore a floor, not a total.
Error 30007 is message-level. It is not an account suspension; if Twilio has restricted the whole account, that is a separate process, covered in what to do in the first 24 hours after a Twilio suspension.
The diagnostic table: every error code an AI SMS agent sees
The second column is Twilio’s own description, taken from each code’s page (linked in the first column, all read on 28 September 2026). The third column is our reading of how an AI-written message tends to produce that code; Twilio does not write about AI agents on these pages, so treat that column as a hypothesis the fourth column tests.
| Error code | What Twilio says it means | Likely cause when an AI writes the message | Test that tells the causes apart | Fix |
|---|---|---|---|---|
| 30007 | Message filtered: blocked by Twilio or by the carrier, for example as spam, phishing or fraud, or for breaking carrier rules. | The model drifted from the registered samples: public shorteners, links to someone else’s domain, emoji, shouty capitals, no brand name, or an opt-out paraphrase instead of STOP. | Run the sample-drift check. If the 30007s cluster on drifted bodies, it is content. If they spread evenly across on-sample bodies, look at consent, opt-outs and volume. | Constrain the agent to the registered skeletons, move links to your own branded domain, keep STOP wording fixed. Then send Twilio 3 or more SIDs. |
| 30004 | Message blocked: the destination is blocked from receiving the message; carrier or compliance filtering is one listed cause. | The same content causes as 30007 when filtering is behind it, or a destination that cannot take SMS. | Send a fresh, shorter single-segment test from a different Twilio sender to the same handset. | Fix content per Twilio’s Messaging Policy; if the recipient opted out, they must text START or UNSTOP. |
| 30003 | Unreachable destination handset: powered off, no service, roaming, or cannot receive SMS. | Rarely the AI. Repeated long code failures can also indicate carrier-side filtering, per Twilio’s own page. | Retry once; ask the recipient whether non-Twilio SMS arrives; try a one-segment body from another number. | Check line type with Lookup before sending; if long code failures repeat, review content for filtering risk. |
| 30005 | Unknown destination handset: the number is unknown and may no longer exist. | Bad data, not the model. An agent that extracts numbers from free text can also mangle the format. | Check the number is valid E.164 with the right country code. | Validate and normalise numbers before the agent ever sees them. |
| 30006 | Landline or unreachable carrier: a landline, or a short code that cannot reach the carrier. | The lead list, not the model: a form captured an office line. | Lookup Line Type Intelligence: if it says landline, do not retry. | Filter landlines out; route those leads to a voice agent instead. |
| 30008 | Unknown error: a generic carrier failure without enough detail to classify. | Occasionally length or encoding: long, emoji-heavy bodies split into more segments and switch character set. | Retry with a shorter body in simple characters; test other numbers on the same carrier. | Cap length in the prompt; if it persists, send 3 or more SIDs no older than 48 hours. |
| 21610 | Attempt to send to unsubscribed recipient: the number replied STOP and has not replied START. | The agent (or its CRM sync) does not know the lead opted out, so it keeps following up. | Search inbound logs for STOP from that number. | Sync opt-outs to the agent’s suppression list before every send. |
| 30024 | Numeric sender not provisioned on the carrier, including a newly registered 10DLC number still provisioning. | Not content. A new number went live before provisioning finished. | Check brand, campaign and number status in Console. | Wait for provisioning; do not send production traffic until it completes. |
| 30034 | US A2P 10DLC: message from a +1 10DLC number not associated with an approved campaign. | Not content. A new number was added outside the campaign’s Messaging Service. | Is the sending number in the Sender Pool of the approved campaign’s Messaging Service? | Add the number to that Sender Pool, or finish registration. |
| 30035 | US A2P 10DLC: number still being configured (pending registration or deregistration). | Not content. Numbers were moved between Messaging Services. | Check the number shows REGISTERED. | Wait up to 24 hours; do not remove and re-add the number. |
| 30032 | Toll-free number has not been verified; unverified traffic to the US and Canada is blocked. | Not content. The agent was switched to toll-free before verification. | Regulatory Information tab on the number in Console. | Complete toll-free verification before sending. |
| 30450 | Message delivery blocked by SMS Pumping Protection as suspicious; a temporary block. | An agent messaging destinations you do not normally message, at volume. | Were the blocked numbers in regions or prefixes you do not usually send to? | Wait out the 15 to 30 minute window; review the traffic pattern before bypassing. |
| Delivered, not received | Status says Delivered but the handset never showed it; false positives happen. | If many users are affected on US or Canadian long codes, carrier filtering reported as delivered. | One device or many? Many points at filtering; one points at the device. | Treat as a 30007 investigation when it is many users. |
Ordering is deliberately not by “most common”. Twilio publishes no cross-customer frequency for these codes on the pages above, and your mix depends on your lead source, your sender type and your content. The tally in the next section gives you your own order in about a minute.
Step 1: count your error codes before you touch the prompt
Do not rewrite the prompt yet. If most of your failures are 30006 landlines or 30034 unregistered numbers, a new prompt changes nothing and destroys the evidence you need for the 30007s.
Pull a window of outbound messages from the Messages list endpoint (GET /2010-04-01/Accounts/{AccountSid}/Messages.json). Twilio’s Message resource page gives the page size as 50 by default and 1,000 at most, and returns a next_page_uri for the next page; save each page as its own JSON file. Then tally them:
import json, sys, collections
# usage: python3 tally.py page1.json [page2.json ...] (saved Messages.json list pages)
by_code = collections.Counter(); by_status = collections.Counter(); ex = {}
for path in sys.argv[1:]:
for m in json.load(open(path))["messages"]:
if not m["direction"].startswith("outbound"):
continue
by_status[m["status"]] += 1
if m["status"] in ("failed", "undelivered"):
code = str(m["error_code"])
by_code[code] += 1
ex.setdefault(code, []).append(m["sid"])
total = sum(by_status.values())
print(f"outbound messages: {total}")
for s, n in by_status.most_common():
print(f" {s:<12}{n:>6} {100*n/total:5.1f}%")
print("failed/undelivered by error code:")
for c, n in by_code.most_common():
print(f" {c:<8}{n:>6} e.g. {', '.join(ex[c][:3])}")
We ran this against a synthetic fixture we built for this page: two saved list pages, 13 messages, one of them inbound (which the script skips). The output:
outbound messages: 12
undelivered 8 66.7%
delivered 3 25.0%
sent 1 8.3%
failed/undelivered by error code:
30007 4 e.g. SM03, SM04, SM09
30003 1 e.g. SM05
30006 1 e.g. SM06
30005 1 e.g. SM08
30008 1 e.g. SM11
Read the result in this order. If one code dominates and it is not 30007, go to that row of the table and stop reading this page. If 30007 is the largest group, carry on to the sample-drift check. If 30007 has appeared recently at volume where it did not before, Twilio’s US and Canada filtering article says a filtering system “has probably recently identified a pattern in your messages that triggered a block”, which is exactly what a prompt or model change produces.
One caution from Twilio’s own documentation: the Message resource page says the value returned for a given error “is subject to change as Twilio improves errors” and that users should not use the error fields programmatically. Use this tally for a human diagnosis. Do not wire it into automatic suppression rules.
The sample-drift check: is your AI still sending what you registered?
When you registered your A2P 10DLC campaign you submitted sample messages. Twilio’s campaign registration recommendations say those samples “should reflect actual messages to be sent under campaign”, with templated fields in brackets, and should be consistent with the use case and campaign description. The campaign onboarding guide also has you declare whether messages will include embedded links and whether they will include phone numbers (the has_embedded_links and has_embedded_phone fields in the API).
A templated sender cannot drift from its samples. A language model can, one plausible sentence at a time: a friendlier sign-off, a helpful link to a third-party page, a “text 2 if you’re not interested”, an emoji because the lead used one. Together they move live traffic away from what was approved and towards the patterns Twilio’s filtering prevention article says get filtered.
The sample-drift check compares each outbound body with the nearest registered sample and flags the specific content patterns Twilio names. It has two parts.
Part one: similarity to the nearest sample. Replace the bracketed fields in your samples and the digits in each live body with the same placeholder, then score each body against every sample and keep the best match. A body that scores well matches a skeleton you registered. A body that scores low is a message nobody approved.
Part two: eight named flags, each traced to a Twilio page.
- public-shortener: a shared public shortener such as TinyURL or bit.ly. Twilio’s article on sending shortened links says these carry a higher risk of filtering “with no recourse if filtering does occur”.
- foreign-domain: a link to a domain you do not control. The prevention article says links on shared domains are permitted but increase filtering risk, and recommends domains you control.
- link-not-registered / phone-not-registered: a link or phone number in a campaign registered as not containing them.
- no-brand: the prevention article asks that messages “clearly identify who is sending the message”.
- emoji and caps: the prevention article says “Don’t use emojis, or unnecessary special characters/capitalization”.
- optout-without-STOP: opt-out wording that paraphrases the keyword. Twilio says phrases like “text 2 to opt out” are not compliant “and will result in filtering”; in the US and Canada the keyword is typically STOP.
The samples file carries your registration as data (an invented example clinic below; replace every field with your own):
{"brand": "Example Clinic",
"own_domains": ["clinic.example"],
"has_embedded_links": true, "has_embedded_phone": false, "cutoff": 0.6,
"samples": [
"Example Clinic: Hi [Name], your check-up is due. Book a time at clinic.example/book or reply with a day that suits. Reply STOP to opt out.",
"Example Clinic: Thanks [Name], you're booked for [Date] at [Time]. Reply C to confirm or R to reschedule.",
"Example Clinic: Hi [Name], just following up on your check-up. Want us to hold [Date] for you?"]}
The script:
import json, re, sys, difflib
# usage: python3 drift.py samples.json page1.json [...]
cfg = json.load(open(sys.argv[1]))
brand = cfg["brand"].lower(); own = [d.lower() for d in cfg["own_domains"]]
skel = [re.sub(r"\[[^\]]*\]", "[x]", s).lower() for s in cfg["samples"]]
SHORT = ("bit.ly", "tinyurl.com", "t.co", "is.gd", "ow.ly", "rb.gy", "cutt.ly")
URL = re.compile(r"(?:https?://)?((?:[a-z0-9-]+\.)+[a-z]{2,})(?:/\S*)?", re.I)
PHONE = re.compile(r"\+?\d[\d\s().-]{8,}\d")
EMOJI = re.compile("[\U0001F300-\U0001FAFF\u2600-\u27BF]")
rows = []
for path in sys.argv[2:]:
for m in json.load(open(path))["messages"]:
if not m["direction"].startswith("outbound"):
continue
body = m["body"]
norm = re.sub(r"\d+", "[x]", body.lower())
best = max(difflib.SequenceMatcher(None, norm, s).ratio() for s in skel)
flags = []
doms = [d.lower() for d in URL.findall(body)]
if any(d in SHORT for d in doms): flags.append("public-shortener")
if any(d not in SHORT and not any(d == o or d.endswith("." + o) for o in own) for d in doms): flags.append("foreign-domain")
if doms and not cfg["has_embedded_links"]: flags.append("link-not-registered")
if PHONE.search(body) and not cfg["has_embedded_phone"]: flags.append("phone-not-registered")
if brand not in body.lower(): flags.append("no-brand")
if EMOJI.search(body): flags.append("emoji")
if re.search(r"opt.?out|unsubscribe|stop hearing", body, re.I) and "STOP" not in body: flags.append("optout-without-STOP")
if re.search(r"\b[A-Z]{4,}\b", body.replace("STOP", "")): flags.append("caps")
rows.append((best, m["sid"], m["status"], m["error_code"], flags))
rows.sort(key=lambda r: r[0])
print(f"{'sim':>5} {'sid':<10}{'status':<12}{'code':<7}flags")
for best, sid, st, code, flags in rows:
print(f"{best:5.2f} {sid:<10}{st:<12}{str(code or '-'):<7}{','.join(flags) or '-'}")
low = [r for r in rows if r[0] < cfg.get("cutoff", 0.6) or r[4]]
print(f"drifted (sim < {cfg.get('cutoff', 0.6)} or any flag): {len(low)} of {len(rows)}")
Run against the same synthetic fixture, sorted with the least similar first:
sim sid status code flags
0.25 SM03 undelivered 30007 public-shortener,no-brand,emoji,caps
0.28 SM04 undelivered 30007 foreign-domain,phone-not-registered,no-brand
0.32 SM09 undelivered 30007 public-shortener,no-brand
0.92 SM13 undelivered 30007 optout-without-STOP
0.93 SM02 delivered - -
0.93 SM10 delivered - -
0.94 SM05 undelivered 30003 -
0.94 SM12 sent - -
0.95 SM08 undelivered 30005 -
0.98 SM01 delivered - -
0.98 SM06 undelivered 30006 -
0.98 SM11 undelivered 30008 -
drifted (sim < 0.6 or any flag): 4 of 12
Read the output against the status column, because that is the distinguishing test. In this fixture all four 30007s are drifted, and none of the eight other outbound messages is. That is the content pattern: fix the agent’s output and the 30007s should fall. Note SM13: it scores 0.92, close to a registered sample, and is still flagged, because one paraphrased opt-out line is enough. Similarity alone would have missed it, which is why the check has both parts.
If your own output shows the opposite pattern (30007s on bodies that score high and carry no flags), the content is not the problem. Go to the factors Twilio lists that are not about the words: consent, opt-out rates, complaints, the volume sent from each number, and how many near-identical messages are crossing the carrier network.
Limits we know about. The 0.6 cut-off in the samples file is a starting point we picked for the fixture, not a carrier threshold; none of the Twilio pages we read gives one. The Twilio pages we read describe sample messages as a registration requirement and describe content scoring on live traffic, but they stop short of saying each live message is compared with your samples. Treat drift as a strong signal to fix, not as proof of the mechanism. The flag list is not exhaustive: it does not check grammar, spelling or forbidden message categories, which Twilio also names.
Why AI-written texts get filtered when templated texts did not
Most of the content patterns on Twilio’s list are things a language model does by default when asked to be friendly and persuasive. Models add emoji to mirror a casual lead. They reach for “limited time” urgency and capitalised words when told to improve reply rates. They paraphrase “Reply STOP to unsubscribe” into something warmer, and the warmer version is the one Twilio says will be filtered. They add a link to whatever page answers the question, whether or not the domain is yours.
The opt-out rules also interact badly with free-form conversation. Twilio’s prevention article says to include opt-out language in your first message, and that carriers in the US and Canada “expect to see opt-out language in every third message or at least once per month if sending fewer than 3 messages per month”. A model deciding each reply fresh has no reliable way to count; the messaging layer around it has to track the count and append the wording.
Split-testing multiplies drift. If a platform generates many variants of an opener, which is what continuous script testing such as Zian’s PrecisionPitch AI™ does, every variant is a new body that your registered samples have to cover. The fix is to test inside the registered skeletons, not around them.
“Delivered” but the lead never got it
Twilio sets a message to Delivered when the carrier reports it delivered, and its article on Delivered messages that are not showing up is explicit that this can be a false positive. False positives to a single device are likely device-specific. False positives to multiple users can be caused by carrier filtering, local telecom infrastructure or technical limitations.
For AI agents on US or Canadian long codes, the practical test is breadth. One lead who never saw a message is a handset problem. Several leads on the same campaign in the same week is a filtering investigation, and the sample-drift check applies exactly as it does to 30007, run on the Delivered-but-unanswered bodies instead.
The fix for 30007, in order
- Stop retrying filtered messages. Each retry is billed and adds volume from the same number, one of the scored factors.
- Tally the codes for the affected window and confirm 30007 is the group you are fixing.
- Run the sample-drift check on the same window and compare the drifted set with the 30007 set.
- If it is content: constrain the agent to your registered skeletons with only the bracketed fields free, move links to a branded domain you own, and have the messaging layer (not the model) append brand name and STOP wording. The Bracket Contract for registering an AI SMS agent sets out how to structure those skeletons.
- If it is not content: audit consent for the affected leads, sync opt-outs (a 21610 in the tally means the agent is already messaging people who said STOP), and check your per-number volume. Twilio also asks you to re-check consent at least once every 18 months for long-running lists.
- If you believe the messages are compliant: collect 3 or more Message SIDs with status undelivered and error 30007 from within the previous 7 days, and contact Twilio Support, which can review the messaging and involve its Compliance team.
Do not respond by adding more numbers. Twilio’s prevention article says its Messaging Policy forbids “snowshoeing”, spreading sending across numbers to evade filtering. If your real problem is peak volume rather than filtering, plan it as throughput, as in the 8-week SMS throughput plan for Black Friday.
What running this yourself costs
The first pass with the two scripts on this page is an afternoon: export a week, run both, read the drifted bodies, rewrite the prompt. The ongoing cost is the part that is easy to underestimate.
- The check has to be rerun after every prompt change, model upgrade or new split-test variant, because each one moves the output.
- The samples file has to be kept in step with the registration; a campaign edited in Console and not in your file makes every score meaningless.
- The opt-out cadence (every third message, or monthly) and opt-out sync have to live in the messaging layer, with tests, because the model cannot be trusted to count.
- Someone has to read the flagged bodies. The script finds them; deciding whether a flagged link is acceptable is a judgement call.
For a single number sending a few hundred messages a week, a monthly run by hand is proportionate. At the volumes AI outbound runs at (Zian’s learning engine tracks around 420,000 data points across more than 10,000 leads a day), the check becomes part of the release process for every prompt, with the same weight as a unit test.
Want AI agents whose SMS copy is split-tested continuously for meetings booked? Zian is in partnership-application beta. Apply For Partnership.
Where every figure on this page comes from
Twilio’s help articles render client-side at help.twilio.com; we read their text through the help centre’s public article API on the date shown, and the links go to the public pages.
| Figure | Who published it | Link | Date read |
|---|---|---|---|
| Error 30007 = message filtered by Twilio or a carrier | Twilio (Docs, error 30007) | www.twilio.com/docs/api/errors/30007 | 28 September 2026 |
| 3 or more Message SIDs to Support for 30007 | Twilio (Docs, error 30007) | www.twilio.com/docs/api/errors/30007 | 28 September 2026 |
| SIDs from within the previous 7 days | Twilio help centre, How do I prevent my Twilio messages from being filtered (blocked)? | help.twilio.com/articles/1260803966670-How-do-I-prevent-my-Twilio-messages-from-being-filtered-blocked | 28 September 2026 |
| Opt-out language every third message, or at least once per month under 3 messages a month | Twilio help centre, same article | help.twilio.com/articles/1260803966670-How-do-I-prevent-my-Twilio-messages-from-being-filtered-blocked | 28 September 2026 |
| Re-check consent at least once every 18 months | Twilio help centre, same article | help.twilio.com/articles/1260803966670-How-do-I-prevent-my-Twilio-messages-from-being-filtered-blocked | 28 September 2026 |
| Filtered messages are still billed | Twilio help centre, How Does Message Filtering Work? | help.twilio.com/articles/223181848-How-Does-Message-Filtering-Work | 28 September 2026 |
| Verizon accepted A2P on 10DLC in January 2019; registration-based A2P 10DLC launched with AT&T and T-Mobile in 2021 | Twilio help centre, SMS Message Filtering in the United States and Canada | help.twilio.com/articles/360022449893-SMS-Message-Filtering-in-the-United-States-and-Canada | 28 September 2026 |
| Carrier filter score factors (volume per number, similar messages, spam resemblance) | Twilio help centre, same article | help.twilio.com/articles/360022449893-SMS-Message-Filtering-in-the-United-States-and-Canada | 28 September 2026 |
| 30008: 3 or more SIDs no older than 48 hours | Twilio (Docs, error 30008) | www.twilio.com/docs/api/errors/30008 | 28 September 2026 |
| 30035: allow up to 24 hours for number registration | Twilio (Docs, error 30035) | www.twilio.com/docs/api/errors/30035 | 28 September 2026 |
| 30450: temporary block typically 15 to 30 minutes | Twilio (Docs, error 30450) | www.twilio.com/docs/api/errors/30450 | 28 September 2026 |
| Messages list page size: default 50, maximum 1,000 | Twilio (Docs, Message resource) | www.twilio.com/docs/messaging/api/message-resource | 28 September 2026 |
The tally and drift outputs above come from a synthetic fixture of 13 invented messages built for this page, not from any customer’s traffic.
Frequently asked questions
Why are my AI agent’s text messages not being delivered?
Read the error code on each undelivered message first. Twilio’s error 30007 page says the message was filtered (blocked) by Twilio or by the carrier; 30003, 30005, 30006 and 30008 point at the handset, the number or the carrier path instead; 30024, 30032, 30034 and 30035 point at sender registration. Only the 30007 group is usually about what your AI wrote.
Am I charged for messages that fail with error 30007?
Yes. Twilio’s help article How Does Message Filtering Work? says messages are still billed when they are filtered, whether Twilio’s own filter or a downstream carrier blocked them. An AI agent that keeps retrying filtered messages keeps paying for them.
How many examples does Twilio Support need to review 30007 filtering?
Three or more Message SIDs with the undelivered status and error 30007. Twilio’s filtering prevention article adds that the examples should be from within the previous 7 days, and asks you to review the Messaging Policy and its filtering tips before you contact Support.
Can a message show Delivered and still never arrive?
Yes. Twilio’s article on Delivered messages that are not showing up says a false positive to one device is likely a device issue, while false positives to many users can be caused by carrier filtering, local telecom infrastructure or technical limitations. Its filtering overview adds that carriers may, in rare cases, report filtered messages as delivered.
Does my AI have to send the exact sample messages I registered for A2P 10DLC?
Not word for word, but close. Twilio’s campaign registration recommendations say sample messages should reflect actual messages to be sent under the campaign, with templated fields in brackets, and should be consistent with the use case and campaign description. The sample-drift check measures how far live messages have moved from those samples.
Is it safe to use a Bitly or TinyURL link in an AI-written text?
Not for US traffic. Twilio’s article on sending shortened links says public shared shorteners such as free TinyUrl or Bitly links carry a higher risk of filtering, with no recourse if filtering does occur. It asks for a proprietary short domain that matches the brand named in the message.