<!--
- "MDR" is the human term for the Sent activities surface: GET /v3/messages/{id}/activities. There is no separate MDR endpoint.
- Lifecycle: QUEUED -> ROUTED -> SENT -> DELIVERED -> READ (WhatsApp/RCS only), with FAILED at any stage and RECEIVED for inbound.
- Sent exposes its own normalized error codes (AUTH_*, VALIDATION_*, RESOURCE_*, BUSINESS_*, CONFLICT_001, SERVICE_001, INTERNAL_*) on the HTTP envelope, plus send-time per-message codes (ERR_CONSENT_BLOCKED, ERR_ROUTE_DENIED, ERR_TEMPLATE_PARAMS_INVALID) on the message `description` field. See references/mdr-status-codes.md.
-->
Messaging performance analyzer
Overview
Use this skill to turn raw Sent message evidence into a concise diagnosis of what changed, where the funnel leaks, and what to fix first. Anchor every analysis to Sent message IDs, message status, message activities, and webhook events before interpreting carrier, WhatsApp, or RCS provider codes.
Sent’s v3 send endpoint accepts a template-based request and returns per-recipient
values for asynchronous tracking. Status is retrieved with
, and detailed lifecycle evidence is retrieved with
GET /v3/messages/{id}/activities
. Webhook endpoints support event ingestion, event-type discovery, event history, test delivery, and secret rotation.
When to use
Use this skill when the user asks why messages failed, why delivery or read rate dropped, whether fallback is working, whether a provider is filtering traffic, or how a campaign performed. Trigger on words such as “MDR,” “delivery report,” “webhook event,” “activities,” “status,” “failed,” “undelivered,” “read rate,” “fallback,” “filtering,” “throttling,” or “carrier reject.”
Do not use this skill to register 10DLC, design a Sender Profile, onboard RCS, or author WhatsApp templates. Hand those workflows to the related skills after the performance symptom is isolated.
Evidence hierarchy
Start with Sent-owned evidence, then enrich it with provider context. This prevents overfitting to a carrier code that may be missing, stale, or normalized differently across channels.
| Evidence | Sent-verified path | Use it for |
|---|
| Send response | | Identify request ID, accepted recipients, channel fan-out, and Sent values. |
| Current status | | Confirm the latest known lifecycle status and any error details exposed by the API. |
| Activity timeline | GET /v3/messages/{id}/activities
| Reconstruct acceptance, routing, sending, delivery, read, and error transitions. |
| Webhook configuration | , GET /v3/webhooks/event-types
| Confirm whether the customer subscribed to the events needed for analysis. |
| Webhook event history | GET /v3/webhooks/{id}/events
| Compare delivered events against API status and customer ingestion logs. |
| Webhook connectivity | POST /v3/webhooks/{id}/test
| Verify endpoint reachability before blaming delivery infrastructure. |
Process
1. Pin the question before slicing the funnel
Restate the user’s exact question as a measurable comparison. “WhatsApp is bad” becomes “Did WhatsApp
rate fall for order templates sent from profile A between Monday and Wednesday?” A precise question keeps the cohort stable and prevents mixed-channel averages from hiding the failure mode.
Capture these dimensions before calculating anything: profile or sender identity, template ID/name, channel, country, send window, recipient segment, and whether fallback or multi-channel broadcast was requested.
Example. If a user says “RCS fallback stopped working,” define the cohort as messages sent with
during the affected window, then compare RCS statuses, SMS fallback statuses, and duplicate recipient/channel pairs separately.
2. Build cohorts from Sent message IDs
Use Sent
as the primary unit. A v3 send can create separate messages for each recipient and channel pair when multiple channels are specified. Count each Sent message once at its latest status, then add recipient-level or campaign-level rollups only after deduplication.
Do not use provider IDs such as WhatsApp
, SMS carrier IDs, or RCS message IDs as the primary join key unless the exported evidence lacks Sent IDs. Provider IDs are useful for escalation, but the Sent API and dashboard track status by Sent message ID.
3. Normalize lifecycle stages to Sent’s documented statuses
Use Sent’s documented lifecycle as the first-pass funnel:
,
,
,
, and
for WhatsApp and RCS. Keep failed and error states in a separate terminal bucket using the exact status/error fields present in the evidence.
| Stage | Interpretation | Common diagnostic question |
|---|
| Sent accepted the request for processing. | Is the backlog growing or did the request never route? |
| Sent selected a channel/provider path. | Did routing choose the expected channel or fallback path? |
| The message left Sent/provider processing toward the destination network. | Are provider accepts high but downstream delivery low? |
| Delivery was confirmed where supported. | Did the destination network confirm receipt? |
| WhatsApp/RCS read receipt was observed where available. | Did users open the message after delivery? |
| Error/failure | A terminal or recoverable error occurred. | Is the root cause compliance, payload, throughput, opt-out, or provider outage? |
4. Check webhook health before diagnosing delivery
A drop in dashboard activity or customer-side events can be a webhook ingestion problem, not a delivery problem. Confirm webhook existence, active status, event subscriptions, recent event history, and test delivery. Rotate secrets only when the user explicitly asks or when a credential compromise is suspected, because rotation immediately invalidates the old secret.
Example. If Sent status shows
but the customer database shows “no delivery callbacks,” inspect
and the customer’s endpoint logs. If Sent has events but the endpoint returned failures, the fix is webhook handling, not campaign routing.
5. Split by channel before naming a root cause
SMS, WhatsApp, and RCS fail differently. Do not average them together unless the user explicitly asked for a blended KPI. Compare each channel’s funnel and then compare the aggregate.
| Channel | First cuts | Typical next evidence |
|---|
| SMS | Country, sender/profile, 10DLC campaign, opt-out, carrier family | Compliance status, brand/campaign readiness, opt-out logs, throughput patterns. |
| WhatsApp | Template, language, category, recipient country, quality/tier symptoms | Template status, read receipts, conversation window, Meta-side errors if present. |
| RCS | Agent readiness, fallback behavior, capability gaps, rich content rendering | Sent RCS setup status, fallback SMS results, capability/error details if present. |
6. Quantify impact before recommending fixes
Report raw counts and rates together. A 40% failure rate over 15 messages is a different decision than a 4% failure rate over 150,000 messages. Include exclusions such as pending messages, test traffic, sandbox sends, retries, and duplicate channel fan-out.
A practical analysis table should include: sent count, latest status distribution, failure count, failure-rate delta versus baseline, top exact error strings/codes, first observed timestamp, affected templates, affected countries, and affected profiles.
7. Convert the diagnosis into the next action
End with one primary diagnosis, one confidence level, and the next verification step. Avoid long lists of generic fixes. Tie every recommendation to observed evidence.
Example. “The largest leak is after
for SMS traffic on profile
, starting at 14:10 UTC. WhatsApp and RCS cohorts are stable. The affected traffic uses the same order-update template and a US A2P route. Verify the Sent brand/campaign status and opt-out handling next; if compliant, escalate the exact message IDs and activity timestamps.”
Common rationalizations to avoid
Do not infer delivery failure from missing customer-side webhooks until Sent webhook event history and endpoint responses are checked. Webhook ingestion failures often mimic delivery failures.
Do not label a campaign “carrier filtered” from a small sample without comparing baseline, country, sender/profile, and template. Filtering is a conclusion after cohort isolation, not a synonym for “failed.”
Do not treat
as a universal stage. Sent documents read receipts for WhatsApp and RCS; SMS generally does not support read receipts.
Do not collapse RCS fallback into SMS delivery. For
, count RCS attempts and SMS attempts separately, then report recipient-level success if the user asks for it.
Verification checklist
Related skills
Use
when the leak points to US A2P SMS compliance, brand registration, campaign registration, or opt-in/opt-out evidence.
Use
when the symptom points to RCS agent approval, launch readiness, capability gaps, or fallback design rather than live delivery analytics.
Use
when the issue is tenant/profile isolation, webhook routing, credential scoping, or multi-brand sender design.
Use
or
when the root cause is WhatsApp template category, review status, template payload structure, or authoring workflow.
Use the
skill for shared Sent terminology and routing.
Bundled references and scripts
| File | Type | Purpose |
|---|
references/mdr-status-codes.md
| Lookup table | Normalize observed SMS, WhatsApp, and RCS provider errors without putting long code dictionaries in the skill body. |
references/performance-diagnosis-playbook.md
| Worked examples | Decision tree for which signal to investigate first, channel-specific diagnostic patterns, cross-skill handoff matrix, and escalation criteria. |
scripts/analyze_mdr_funnel.py
| Validation script | Reads an MDR export (CSV or JSON), prints per-stage counts and drop-off percentages, exits non-zero on anomalies. Run from the skill root: python scripts/analyze_mdr_funnel.py path/to/mdr.csv
(use to tune, default 20; pass to also tally codes parsed from FAILED message fields). |
scripts/fixtures/good.json
| Fixture | Synthetic healthy-funnel MDR export. |
scripts/fixtures/bad.json
| Fixture | Synthetic MDR export with deliberate >50% SENT→DELIVERED drop. |
Unverified claims to confirm or remove
- Any fixed cohort-size threshold such as “1,000 messages minimum” is an analyst heuristic, not a documented Sent API rule.
- External provider identifiers such as carrier message IDs, WhatsApp , and RCS message IDs are not in the v3 docs as join keys; use Sent and treat provider IDs as escalation-only context.