Phone Reputation
How we measure reputation of a phone line and how to check it before you send.
Review your setup with an agent. Copy this prompt into your own AI coding agent to check your integration against these guidelines.
You are auditing a codebase that integrates with the Linq Partner API
(iMessage / RCS / SMS messaging). Verify it follows Linq's best practices for
deliverability, chat health, and line reputation. This is READ-ONLY — do not
change code unless I ask.
Step 1 — Ground yourself in Linq's public docs. Start with the index at
https://docs.linqapp.com/llms.txt, then fetch the pages you need — at minimum
Best Practices, Chat Health, Phone Reputation, Sending Messages, and Webhooks,
plus the /v3 API reference for the endpoints below. (https://docs.linqapp.com/llms-full.txt
has every page in one file, but it is large — prefer the index and targeted
pages.) If you cannot fetch these, stop and tell me rather than auditing from
memory.
Step 2 — Locate the integration. Search the codebase for the Linq base URL
(api.linqapp.com/api/partner), "/v3/" request paths, an official SDK — Node
`@linqapp/sdk`, Python `linq-python` (imported as `linq`), or Go
`github.com/linq-team/linq-go` — and the inbound webhook handler, so you know
where sending, onboarding, and webhook handling live.
Step 3 — Audit against these requirements. Each item is something my code is
supposed to do — confirm whether it actually does, and cite the file and line:
Opt-out (compliance — most important)
- The code should scan every inbound message on the message.received webhook for
opt-out keywords — STOP, UNSUBSCRIBE, OPTOUT, CANCEL, END, QUIT (whole message;
exact and case-sensitive, except OPT OUT which matches in any casing, spaced,
hyphenated or not) — plus any clear "stop messaging me" intent, and a match
should immediately stop all outbound to that recipient. Linq rejects sends to
a keyword-opted-out recipient with 403 (error code 2024), but only the exact
keywords trigger that block — conversational stop requests are the code's job
to catch — and a 2024 rejection should be honored, not retried.
- Every send to an opted-out recipient is rejected, including a final courtesy
message. If the code sends one confirmation telling the recipient they can
reply any time to resume, that single request should set override_optout: true.
The override applies only to the request it is set on and does not lift the
block; each use is recorded, so it should appear once per opt-out, never in a
retry loop.
- The code should treat a chat whose health_status is OPTED_OUT as never-send
until Linq clears the status. Linq clears it as soon as the recipient replies
again in any chat with you (any inbound that is not itself an opt-out
keyword), so the code should gate on the current health_status rather than
tracking opt-ins itself.
Sending & line selection
- The code should send with POST /v3/messages using `to` and NO `from`. Linq
then picks the best line, load-balances across your pool, reuses the
recipient's existing healthy line, and fails over off a flagged line
automatically (see from_selection.reason in the response).
- The code should NOT call GET /v3/available_number (or pin a fixed `from`)
before each send — that defeats the automatic load-balancing and failover.
Onboarding new users
- The code should use GET /v3/available_number when onboarding a NEW user, to
get the best available line (and its vcf_url contact card) to show them — e.g.
a number or deeplink shown at signup — so new users spread evenly across the
pool. That is what available_number is for; it is not a per-message call.
Contact card
- The code should create the contact card once per line with
POST /v3/contact_card (initial setup only — later changes use
PATCH /v3/contact_card), and share it through the dedicated
POST /v3/chats/{chatId}/share_contact_card endpoint.
- New contacts should be inbound-first — let the recipient message first. The
card should be shared only after at least one outbound message exists in the
chat, and re-shared about once a day, since there's no confirmation the user
saved it.
Health & reputation gating
- Before sending, the code should check the chat's health_status and the line's
reputation from GET /v3/phone_numbers, and slow or pause on AT_RISK /
CRITICAL. It should also handle the phone_number.status_updated webhook to
react when a line's reputation changes.
- New users should onboard onto HEALTHY lines. The code should NOT migrate users
off an AT_RISK line to escape the status — improve engagement and let the line
recover instead.
Engagement & cadence
- Outbound should be built to get replies (aim for 3+ replies early and roughly
a 1:2 inbound:outbound ratio). When a recipient stops replying, the code
should slow down and then stop, rather than keep messaging someone who isn't
responding.
Volume & ramp
- The code should keep each line under ~7,000 messages/day (inbound + outbound).
That is a performance guideline, not a reputation threshold — steady high
volume with healthy reply rates is fine.
- The code should not start roughly 50 or more brand-new conversations per line
in a rolling 24 hours. Check bulk import, list upload, and campaign kickoff
paths for anything that opens a whole audience at once, and confirm first
contact is spread across days and across lines.
- The code should ramp a line's daily volume gradually rather than jumping
several-fold above what that line has recently been sending. Look for
scheduled or triggered sends that can take a quiet line to a large day in one
step.
Step 4 — Report:
1. A table: Check | Status (pass / gap / n/a / unknown) | Where (file:line) | Fix.
2. A short action list, highest deliverability and compliance risk first.
Ground every finding in code you actually read. If you cannot determine an item,
mark it unknown rather than guessing. Every phone line carries a reputation — a line-level read on whether the
line as a whole is in good standing. It’s the line-wide companion to
chat health, but it is not simply a sum of it.
Phone reputation draws on two kinds of signals:
- Patterns across the conversations on the line — engagement and deliverability across the line’s chats, in aggregate. This is the larger driver, and it’s closely related to chat health.
- Line-level activity that no single conversation reveals — how many different recipients the line messages in a short window, how many brand-new conversations it starts in a day, and its overall send pace.
You’ll see reputation on each number returned by
GET /v3/phone_numbers. It’s a
prediction of where the line is heading — treat it as a pre-send gate, not a
report.
How to use it
Section titled “How to use it”GET /v3/phone_numbers— every line in the list response carries its currentreputation.phone_number.status_updatedwebhook — fires whenreputationchanges. The payload carriesprevious_reputationandnew_reputation, so you can react the moment a line moves toAT_RISKorCRITICAL.
Check reputation shape and value before you queue outbound messages
for a line — the same pre-send gate pattern as chat health, one level up. Use
it to route work toward your healthiest lines: if a line is CRITICAL, onboard
new recipients onto a HEALTHY line instead and let the CRITICAL one recover
before you send more on it.
const { phone_numbers } = await client.phoneNumbers.list();
for (const pn of phone_numbers) { switch (pn.reputation.status) { case 'HEALTHY': break; // send normally, safe to onboard new recipients case 'AT_RISK': reviewLine(pn); break; // slow the pace, check chat health case 'CRITICAL': pauseLine(pn); break; // stop outbound, route new recipients elsewhere }}Acting on the status before each send is what turns the signal into delivery improvement — ultimately leading to a healthier line.
Statuses
Section titled “Statuses”| status | What it means | What to do |
|---|---|---|
HEALTHY | The line is in good standing. | Send normally. |
AT_RISK | Warning signs: low engagement or too many new conversations. | Slow the line’s send pace and use chat health to find conversations to fix. |
CRITICAL | Strong signals that messages from this line aren’t landing well. | Pause outbound on the line until it recovers. |
HEALTHY
Section titled “HEALTHY”The line looks like it’s operating normally. Engagement and deliverability across its conversations look good, and its overall activity is within a normal range. No action needed.
AT_RISK
Section titled “AT_RISK”One or more soft signals suggest the line as a whole is heading in the wrong direction. Common drivers fall into two groups:
- Conversation patterns. Engagement is low across many of the line’s chats. Chat health is the best place to see this per-conversation.
- Line-level activity. Starting too many brand-new conversations in a single day can move the line to at-risk on its own, even when individual chats are fine. A spike in overall send volume adds to that risk when engagement is low — but a high-volume line with healthy replies stays fine.
See What moves a line’s reputation for the specific thresholds behind each of these.
AT_RISK is a warning, not a hard stop. Recommended playbook:
- Check chat health. Pull chat health for the
line’s conversations to find the
AT_RISKandCRITICALchats, and fix those first. - Slow the line’s overall pace. Reduce total send volume until signals recover.
- Bias outbound toward messages that elicit replies. Questions and follow-ups outperform broadcasts.
- Spread activity out. Avoid contacting many new recipients or opening many new conversations in a single burst.
- Vary your content. Repeated near-identical messages across the line amplify the signal.
Watch for the line moving back to HEALTHY (good) or down to CRITICAL
(act fast).
CRITICAL
Section titled “CRITICAL”Strong signals that messages from this line aren’t reaching recipients the way you expect. Continuing to send is unlikely to help and may make the situation worse.
In practice a line reaches CRITICAL one of two ways: a large share of its
active conversations are themselves CRITICAL, or the line has been
FLAGGED. Line activity on its own —
volume, pace, new conversations — doesn’t get a line to CRITICAL without weak
engagement alongside it.
Recommended action: pause outbound on the line. Re-engage only after it returns
to HEALTHY.
What moves a line’s reputation
Section titled “What moves a line’s reputation”1. Health of the conversations on the line
Section titled “1. Health of the conversations on the line”This is the largest driver. We look at the line’s active conversations — those with a message in either direction in the last 7 days — and what share of them are unhealthy.
- Nothing counts here until the line has at least 5 active conversations
that are
AT_RISKorCRITICAL. A new line with one bad chat is not penalized for it. - Above that floor, the share of active conversations that are unhealthy is what matters — not the raw count. A line with 40 unhealthy chats out of 800 active is in better shape than one with 8 out of 10.
- Conversations that are
AT_RISKcan carry a line toAT_RISK, but never on their own toCRITICAL, no matter how large the share. Only the share that isCRITICALescalates the line that far.
| Of the line’s active conversations | Where the line tends to land |
|---|---|
| Under about a third unhealthy | HEALTHY |
Around half or more AT_RISK, few or no CRITICAL | AT_RISK |
Nearly all AT_RISK, none CRITICAL | AT_RISK — at-risk conversations alone never reach CRITICAL |
A large majority CRITICAL | CRITICAL |
A conversation where the recipient has opted out counts as CRITICAL for as
long as it stays active — that is, for as long as you keep messaging someone
who asked you to stop. Stop sending and it ages out of the 7-day window on its
own.
Use chat health to see which conversations are dragging the line down.
2. New conversations started in a day
Section titled “2. New conversations started in a day”Starting roughly 50 or more brand-new conversations in a rolling 24 hours
will move a line to AT_RISK on its own, even when every individual chat looks
fine.
“New” means a first-ever outbound to that person from this line. Re-messaging people you’ve already talked to doesn’t count toward this signal — it’s the cold-start breadth that carriers may react to hardest.
If you need to reach a large list, spread the first touch across days rather than opening the whole list at once.
3. Send volume relative to the line’s own normal
Section titled “3. Send volume relative to the line’s own normal”We compare a line’s outbound today against that line’s own recent typical daily volume, not against a fixed number. A line that has consistently sent high volume with healthy replies isn’t penalized for its size; a line that jumps several times above its own normal is what we react to.
- The signal scales with the size of the jump — a several-fold increase is a soft contribution, a ten-fold increase a much stronger one.
- It needs real volume behind it. Small day-to-day swings on a low-volume line don’t register.
- A very large absolute day (in the thousands of messages) also contributes when the line’s reply rate is low. If people are replying, it doesn’t.
- Volume never flags a line by itself. Every level of this signal is a
contributing factor only — it moves a line to
AT_RISKonly alongside low engagement or another driver. - A spike keeps counting for about a week afterward, so a single quiet day right after a burst won’t clear it.
The practical read: ramp gradually rather than spiking, spread large sends across days, and prioritize recipients who have already engaged with you.
4. The line being flagged
Section titled “4. The line being flagged”If the line’s status goes to
FLAGGED, reputation goes to CRITICAL immediately regardless of every
other signal, and its messages may not be reaching recipients at all.
Move active traffic to a HEALTHY line right away and let this one recover.
reputation returns to the line’s current signals once the flag clears.
You don’t have to route that yourself. Send with
POST /v3/messages and no from,
and Linq picks the line: it reuses the recipient’s existing chat while that
line can still send, and moves them onto a fresh line when it can’t.
from_selection.reason in the response tells you which happened —
failover_flagged means the recipient was moved off a flagged line.
How quickly it moves
Section titled “How quickly it moves”Each signal runs on its own window: conversation health on a rolling 7 days, new conversations on a rolling 24 hours, a volume spike for about a week after it fires. Reputation is re-evaluated as the line sends and receives, and quiet lines are re-checked on a regular sweep — so a line that stops the behavior recovers as the signals age out of their windows rather than needing any manual reset.
Scenarios
Section titled “Scenarios”| Scenario | Likely status |
|---|---|
| Send volume with engaging reply rates from users | HEALTHY |
| Steady high volume the line has always sent, replies healthy | HEALTHY |
| Volume jumps several times above the line’s normal, replies still good | HEALTHY |
4 of the line’s 60 active chats are AT_RISK | HEALTHY |
| 50+ brand-new conversations opened in one day | AT_RISK |
| Volume jumps several times above the line’s normal, replies drying up | AT_RISK |
| Rapid increase in new conversations with little to no engagement | AT_RISK or CRITICAL |
Around half the line’s active chats are AT_RISK, none CRITICAL | AT_RISK |
Nearly all the line’s active chats are AT_RISK, none CRITICAL | AT_RISK |
More than two-thirds of the line’s active chats are CRITICAL | CRITICAL |
| Still messaging recipients who opted out | AT_RISK or CRITICAL |
The line’s status is FLAGGED | CRITICAL |
Patterns that can flag a line
Section titled “Patterns that can flag a line”Ramp with collapsing replies. A line running a few hundred sends/day with a reply to most of them ramps to a few thousand a day while replies fall to near zero — a single-digit reply rate.
Dormant line to full blast. A mostly idle line sends a couple thousand messages one day and twice that the next. Even at a ~50% reply rate that leaves thousands of messages a day unanswered — a spike and weak engagement in absolute terms at the same time. Watch the absolute number of unanswered messages per day, not only the ratio.
Migrating a list onto a new line and resuming cadence. Contact card, intro message, then straight back into the previous daily cadence without waiting for anyone to reply. Those conversations have no history with the new number, so every send lands cold. Gate cadence on replies — hold at one message until the recipient responds.
Fleet-wide low reply rates. When every line in a fleet sits in the same low reply band, they tend to degrade one at a time rather than all at once. A line that looks fine today isn’t necessarily safe if its peers share the same sending pattern.
Phone reputation and chat health
Section titled “Phone reputation and chat health”Chat health and phone reputation are related but answer different questions:
- Chat health scores a single conversation — is this recipient engaging, are messages landing.
- Phone reputation scores the line — both the aggregate of its conversations and line-level activity that no single conversation reveals, like how broadly and how fast the line is messaging.
- New lines start as
HEALTHYand move toAT_RISKorCRITICALas signals warrant. - Let Linq route around reputation for you. Send with
POST /v3/messagesand nofrom: the platform keeps traffic spread across your pool, prefers healthier lines for new conversations, reuses the line a recipient is already on, and fails over off a line that can’t send. Pinning afromon every send — or callingGET /v3/available_numberbefore each one — opts you out of that. See Choosing a line. - Onboard new users onto healthy lines.
available_numberis the onboarding call: it hands you the best available line and a contact card to show a new user, and successive calls cycle through the pool so signups spread evenly instead of piling onto one number. - Watch reputation, don’t hand-pick on it. Subscribe to
phone_number.status_updatedand readreputationfromGET /v3/phone_numbersto know when a line needs attention — then fix the sending behavior on that line rather than routing around it by hand.
Does phone reputation read message content or store any PII?
No. Phone reputation scoring runs on anonymous, aggregate signals — line-level
volume, send/receive ratios, recipient counts, conversation pace, and similar
metadata. Linq does not collect or store message content or other PII to
compute reputation for phone numbers.
Why is there no OPTED_OUT on phone reputation?
Unlike chat health, phone reputation has no OPTED_OUT status. Opt-out is a
per-recipient signal scoped to a single conversation — it can’t apply to a whole
line. You’ll only ever see OPTED_OUT on chat health.
Why are most of my high-volume lines AT_RISK?
Volume alone can’t cause this — send volume never flags a line by itself, and a line that has always sent high volume isn’t penalized for its size. Check two things instead: whether reply rates dropped on those lines as they scaled, and whether you’re opening many brand-new conversations at once, which can move a line on its own.
Once a chat has 3+ replies, are we in the clear with Apple?
No. Behavior changes week to week — a recipient who once engaged can fall off, decide to opt out, or report the conversation as spam if they get annoyed after a while. A reply history doesn’t bank you any credit.
Treat engagement as something you maintain rather than something you earn once: keep each recipient engaged at 2–3 replies a week. At that level you know you’re clear. When someone does go quiet, back off on an escalating schedule rather than sending harder into silence.
How many new conversations can I start per day?
Stay meaningfully under 50 first-touch conversations per line per rolling 24 hours, and spread a large list across days instead of opening it in one burst. See new conversations started in a day.
Is AT_RISK reversible?
Yes. The status reflects recent behavior. Improving send pace and engagement
on the line returns it to HEALTHY as the signals age out of their windows —
see how quickly it moves. No manual reset is needed.
Should I migrate users off an AT_RISK line?
No — fix the line. Migrating users off carries the same underlying sending pattern to a new line and spreads the issue rather than solving it. Use chat health to find the conversations dragging the line down, address those, and let the line recover.
Related
Section titled “Related”- Phone Numbers — discover and monitor your lines
- Chat Health — per-conversation health scoring
- API Reference: List Phone Numbers