# The same SMS was answered twice

A customer wrote once and two pieces of work exist. Almost always the provider delivered the same message twice under two different identifiers, so the key that normally makes a retry update in place had nothing to match. On the live carrier the duplicate cannot be a duplicate text — no SMS goes out — so what you are seeing is duplicated downstream work: two follow-ups, two cases, or two emails.

- **Status:** Foundation
- **Audience:** both
- **Channels:** sms
- **In the app:** #/inbox, #/follow-ups, #/needs-you
- **Last verified:** 2026-09-10
- **Canonical:** https://connectbyjbrh.com/docs/troubleshooting/sms-duplicate-reply/

## What the symptom looks like

Two conversations from the same mobile within seconds of each other with identical wording, or one conversation and two follow-ups booked for the same promise, or a customer who says they received two emails after sending one text. The tell is the timing: genuine repetition from a person comes minutes apart and usually reworded; a provider duplicate is near-simultaneous and character-identical.

## What it means

Messaging providers deliver at least once, never exactly once. A webhook Connect was slow to acknowledge, or whose acknowledgement was lost in transit, is indistinguishable at the provider's end from one that never arrived, so it is sent again. Connect keys each inbound message on the provider's own message identifier for exactly this reason, and a retry carrying the same identifier updates the existing record rather than creating a second.

The failure you are looking at is the case that key cannot cover: the two deliveries carried different identifiers. That is a provider behaviour, not a setting in the workspace, and it is why [Duplicate SMS](/docs/sms/sms-dedupe/) is careful to say that text is deliberately never used as a duplicate test — two people really can send the same three words.

## Causes, in order of likelihood

1. **The provider retried with a new identifier**, often after routing the second attempt differently. The two canonical messages are genuinely two as far as Connect can tell.
2. **The customer really did send twice** — an impatient resend a minute later. Not a defect, and the right answer is usually to close the second piece of work rather than the first.
3. **The same text reached two numbers you own**, both configured in the same workspace. Two conversations, two identities, two decisions, all correct individually.
4. **A follow-up and a reply covered the same promise.** Not a duplicate message at all: one inbound produced two commitments because two different rules matched it.

## What Connect completed

- Stored and attributed both deliveries correctly, each to the right Person, with the provider's timestamps rather than the moment of processing.
- Applied the deduplication key to every delivery that carried a repeated identifier — the duplicates you can see are the ones it could not have caught.
- Recorded each decision separately in the audit trail, with the rule behind it, so which piece of work came from which delivery is answerable.
- Enforced suppression and autonomy independently on both, so a duplicate never bypasses a block.

## What Connect did NOT complete

- It did not compare message text to catch the second copy, and will not — that test loses genuine messages, which is a worse failure than a visible duplicate.
- It did not merge the two pieces of work for you. Deciding which follow-up or case survives is a judgement about a customer relationship, not a database operation.
- It did not send a duplicate text: outbound SMS is unavailable on the live carrier, so whatever went out twice went out on another channel.
- It did not raise this to the provider. If the identifiers differed on two deliveries of one message, that conversation belongs with the provider and nobody here starts it for you.

## Cleaning up safely

1. Compare the two records before deleting anything, and note which follow-ups, cases or opportunities each produced.
   - Result: You can close the duplicate work without closing the original by accident — the common way a promise disappears.
2. Close the later duplicate rather than the earlier record.
   - Result: The surviving record keeps the earliest timestamp, which is the one a customer's expectation is measured from.
3. Tell the customer once if two answers already reached them.
   - Result: A short acknowledgement costs nothing and prevents a second confused reply that would start the whole cycle again.
4. If it recurs on the same number, gather the two provider identifiers and raise it with the provider.
   - Result: Different identifiers for one message is evidence they can act on; 'we saw a duplicate' is not.

> **Careful** Do not close both pieces of work to tidy the screen. A duplicate follow-up and its original look identical, and closing the pair leaves a customer waiting on a promise nobody holds any more.

## Questions

### Can deduplication be made stricter?

It could be widened to compare sender, text and a time window, and it is deliberately not. That test discards real messages — a customer confirming twice, two colleagues sending the same request — and a lost message is a worse outcome than a duplicate somebody can see and close.

### Does this happen on other channels?

The same at-least-once contract governs WhatsApp and retried telephony webhooks, and the same identifier-keyed defence applies to each. It is one idea per channel rather than three different mechanisms.

### Is the customer charged or messaged twice?

No text goes out twice, because none goes out at all on the live carrier. If the duplicate produced two emails or two calls, those are metered like any other outbound work on a customer plan, and both appear in the usage record.

## Related

- [Duplicate SMS](https://connectbyjbrh.com/docs/sms/sms-dedupe/)
- [An inbound SMS, end to end](https://connectbyjbrh.com/docs/workflows/sms-inbound/)
- [SMS in Connect](https://connectbyjbrh.com/docs/sms/)
- [The same call-back was booked twice](https://connectbyjbrh.com/docs/troubleshooting/duplicate-follow-up/)
- [Idempotency for retried telephony webhooks](https://connectbyjbrh.com/research/idempotent-telephony-webhooks/)
- [SMS will not send](https://connectbyjbrh.com/docs/troubleshooting/sms-not-sending/)

## What this page is based on

- `docs-source/sources/CHANNELS.md` §3 — SMS dedupe
- `docs-source/sources/GENERAL.md` §3 and §7 — canonical records and follow-ups
- Connect capability registry (docs-source/facts.py) — `sms_inbound`, `sms_outbound`
