Failed-Delivery (NDR) Recovery
Call failed deliveries the same day, decode vague landmark addresses, and book a reattempt within 24 hours.
Last updated 2026-07-12
Screenshots




About Failed-Delivery (NDR) Recovery
Failed-Delivery (NDR) Recovery
Drain the failed-delivery queue same-day — decode the vague landmark address the rider couldn't find, and book a reattempt before the parcel is returned to origin.
Built on the Telenow App Platform as a pure declarative app: the data model, the agent tools, the courier NDR webhook, the rescue workflow, the vernacular agent, and the address-decoding knowledge base all run on-platform. No external server.
The problem (and the number)
In Indian e-commerce, first-attempt delivery fails on roughly 8–20% of shipments — and more than 45% of the resulting returns-to-origin (RTO) trace back to landmark-style addresses that geocoders and new riders simply can't decode: no house number, informal directions ("near Ganesh temple, second lane"), or a landmark that changed. Every failed attempt starts a clock — couriers hold the parcel for a limited reattempt window (commonly 24h) and then auto-return it. An RTO is pure loss: forward freight, reverse freight, and re-handling on a parcel that earned nothing.
The single biggest lever is a fast, same-day call in the customer's own language that turns the informal address into something a rider can actually follow and books a redelivery slot inside the window. Failed-Delivery (NDR) Recovery does exactly that, automatically.
How it works
Courier / aggregator ──(NDR / failed-delivery webhook)──► ndr_case object (status: open)
│ │
│ fires object.ndr_case.created
▼ ▼
dedupe on AWB call_ndr workflow
├─ delay ~2 min
└─ outbound-call {{settings.ndr_agent_id}}
→ dials {{trigger.data.phone}}
→ passes awb, address, landmark, reason
│
▼
Failed-Delivery (NDR) Recovery Agent (Sarvam, vernacular)
find_case → confirm they want the parcel
→ decode landmark address (update_address)
→ book reattempt slot (book_reattempt)
→ already delivered? mark_resolved
→ refuse? mark_rto · stuck? flag_review
Everything the agent does on the call updates the same ndr_case rows you see on the dashboard — and the dashboard's Call now button dials through the same agent and tools.
Agent tools (used mid-call — all declarative)
| Tool | Does | Handler |
|---|---|---|
find_case | Look up the customer's failed-delivery case by phone (loads AWB, address, reason) | object.query ndr_case |
update_address | Save the corrected address + decoded landmark (shop/temple/floor/gate, call-on-arrival) | object.update ndr_case (match awb) |
book_reattempt | Book the redelivery slot the customer picks | object.update ndr_case (match awb → status reattempt_booked) |
mark_resolved | Parcel already reached the customer (neighbour/guard took it, or a prior attempt succeeded) — an RTO prevented | object.update ndr_case (match awb → status resolved) |
mark_rto | Customer refuses / no longer wants it — release from the queue | object.update ndr_case (match awb → status rto) |
flag_review | Escalate to a human (address still undecodable, disputed order) | object.create human_review |
The bundled Failed-Delivery (NDR) Recovery Agent is a multi-context flow: a deterministic find_case tool node (looks the caller up in this app's data) → a conversation node that confirms intent, decodes the address, and books the reattempt. STT/TTS default to Sarvam (anushka) for Tier-2/3 vernacular customers.
Dashboard pages
- Failed-Delivery (NDR) Recovery (dashboard) — KPI tiles (open cases, at-risk on the RTO clock, reattempts booked, RTO prevented, rescue rate %), a live rescue clock ranking open cases by hours-left, and a case-status mix. Also powers the platform
dashboard_widgetslot in a compact form. - Cases — the NDR queue sorted by age (oldest failed delivery first) with an hours-left countdown per open case, status filters, search, and Call now to trigger a rescue call for any case (passes the case's context variables to the agent).
- Review — the
human_reviewqueue: cases the agent escalated because the address still couldn't be decoded or the order was disputed. Mark each resolved once handled. - Setup — a configuration checklist, a one-click Create NDR agent button, and the post-install wiring steps.
Knowledge base
ndr-playbook ships four real scripts the agent answers from: decoding a vague landmark address (ask for the nearest shop/temple/school, floor, gate colour, and a call-on-arrival number), handling "I wasn't home" and refusals, reattempt policy and the return-to-origin clock, and first-attempt-failure & landmark-address facts.
Install & post-install wiring
- Install Failed-Delivery (NDR) Recovery into your org.
- Open Setup → Create NDR agent (builds the bundled Sarvam agent, auto-wired to the tools + KB).
- Copy the new agent's ID into the app's NDR agent ID setting (
ndr_agent_id) socall_ndrcan dial. - (Optional) Set Reattempt window (hours) (
reattempt_window_hours, default 24) to match your courier's hold time, and Courier API key (courier_api_key) to push corrected addresses back to the courier. - Point your courier's non-delivery (NDR) webhook at the inbound hook
courier_ndr(verified withx-courier-signature, deduped on AWB). Failed deliveries now flow in and auto-dial. Works with Delhivery, Shiprocket, Xpressbees, Ecom Express, or any courier that can POST an NDR webhook.
Settings
| Key | Type | Notes |
|---|---|---|
ndr_agent_id | text (required) | The agent the workflow + "Call now" dial. |
courier_api_key | secret | Optional courier API key (encrypted; server-side only). |
reattempt_window_hours | number | Hours before a failed parcel auto-RTOs (default 24) — drives the clock. |
Bulk dialing your backlog
The real-time path (webhook → workflow → call) covers new failed deliveries. To sweep an existing backlog of open NDRs, use the app-key campaign API:
POST /api/app-campaigns
{ "agentId": "<ndr agent id>",
"targetQuery": { "status": "open" }, // over the `ndr_case` object
"result": { ... write-back ... } }
Monetization
Failed-Delivery (NDR) Recovery is billed on outcomes, not seats: a fee per resolved NDR — each failed delivery the agent rescues (address decoded, reattempt booked, and delivered) avoids a return-to-origin, so the fee comes straight out of freight that would otherwise have been burned. Suspect refusals turned to rto and cases sent to human review are surfaced on the dashboard so the ROI is obvious.
Ready-made agents it ships
A vernacular (Sarvam) agent that calls customers the moment a delivery fails, confirms they still want the parcel, decodes the vague landmark address the rider couldn't find, and books a same-day reattempt inside the courier window — before the shipment is returned to origin.
What your agents can do with it
Look up the failed-delivery (NDR) case for the customer you are calling, by their phone number, to load the AWB, the address on file, and why the delivery failed before you speak.
Save the corrected, human-readable delivery address and the decoded landmark the customer gives you (nearby shop, temple, floor number, gate colour) so the courier's rider can actually find the door on the reattempt.
Book a same-cycle redelivery for the customer in the time slot they choose and mark the case as reattempt booked. Only book a slot that falls inside the courier's reattempt window.
Mark the case as rescued & delivered when the customer confirms the parcel has already reached them — a neighbour, guard, or family member accepted it, or an earlier reattempt actually succeeded — so it counts as an RTO prevented and leaves the rescue queue. Do not use this to book a future slot; that is book_reattempt.
Mark the case as RTO (return to origin) when the customer refuses the parcel outright, no longer wants it, or is unreachable/uninterested — so it stops occupying the rescue queue.
Escalate a case to a human agent when the address still cannot be decoded, the customer disputes the order, or something needs manual handling before a reattempt can be booked.
Data it manages
Permissions it requests
Apps run inside your workspace under least-privilege scopes you can see up front. This app asks for:
objects:ndr_caseobjects:human_reviewagents:readcalls:initiatecalls:readai:llmcampaigns:readuser:profileWhat's new in v1.1.0
Changelog
1.1.0 — 2026-07-12
- Renamed to Failed-Delivery (NDR) Recovery (business-friendly) with a marketplace icon.
- Added real UI screenshots (dashboard + key pages).
- Added
mark_resolvedso the “RTO prevented” KPI can be reached from a live call. - Verified end-to-end loop closure: trigger → workflow → call → agent tools → write-back → dashboard.
1.0.0
- Initial release.
- Data model:
ndr_caseobject (AWB, phone, customer, address, landmark, reason, reattempt slot, status, created_at) withopen_queue/reattempt_booked/rto/resolvedsaved views, plus ahuman_reviewobject (AWB, note, resolved) with aopen_reviewsview. - Agent tools (declarative):
find_case,update_address,book_reattempt,mark_rto,flag_review. - Bundled agent: NDR Rescue Agent — a Sarvam vernacular multi-context flow (deterministic
find_caselookup → confirm intent → decode landmark address → book reattempt) auto-wired to the tools and the NDR rescue knowledge base. - Knowledge base:
ndr-playbook— decoding a vague landmark address, handling "I wasn't home" and refusals, reattempt policy and the RTO clock, and first-attempt-failure & landmark-address facts. - Automation:
courier_ndrinbound webhook (HMAC-SHA256 verified, dedupe on AWB);call_ndrworkflow (delay ~2 min → outbound rescue call passing awb/address/landmark/reason). - Dashboard UI: KPI tiles (open, at-risk, reattempts booked, RTO prevented, rescue rate), a live 24h rescue clock ranking open cases by hours-left, and a case-status mix; also renders into the
dashboard_widgetslot in compact form. - Cases page: age-sorted NDR queue with per-case hours-left countdown, status filters, search, and per-case Call now (passes case context variables to the agent).
- Review page: the human-review queue with one-click Mark resolved.
- Setup page: configuration checklist + one-click Create NDR agent and post-install wiring steps.
- Self-seed: a fresh install auto-loads six realistic demo cases across every status (plus one human-review flag), so the dashboard and rescue clock are populated on first open.
Publisher
Marketplace publisher · app reviewed by Telenow before listing.
Your data, your keys
Secrets, carrier credentials and API keys stored AES-GCM encrypted; TLS in transit; HMAC-signed webhooks.
Strict per-organization data isolation with role-based access for every member.
Every mutating action is logged and filterable, with CSV export for your records.
In-app DLT / regulatory flows, TCPA calling windows, and org-wide Do-Not-Call enforcement.
Install Failed-Delivery (NDR) Recovery
Sign up free and get ₹300.00 in credit — no card required. Connect your number, pick a template, and go live in minutes.
