Handling Failed Delivery Attempts and NDR Codes
Doorstep delivery failures are a primary driver of Return to Origin (RTO) in Indian e-commerce. When a delivery agent marks an order as undelivered, merchants typically have a 24- to 48-hour window to contact the buyer, rectify issues, and request a re-attempt before the carrier routes the package back to the origin warehouse.
Standardizing this feedback is essential for automating customer communication. This guide outlines how to handle failed delivery attempts and NDR reason codes using ClearTrack.
The Structure of Delivery Attempts
ClearTrack extracts and normalizes delivery outcomes into a dedicated delivery_attempts object in the API response:
{
"tracking_number": "1000000000001",
"carrier": "delhivery",
"status": "in_transit",
"insights": {
"current_stage": "delivery_attempted"
},
"delivery_attempts": {
"count": 1,
"attempts": [
{
"at": "2026-03-21T16:30:00.000Z",
"outcome": "failed",
"reason_code": "customer_unavailable",
"reason_text": "Customer not available at delivery address"
}
]
}
}
Standardized NDR Reason Codes
ClearTrack maps courier remarks to the following normalized reason codes:
customer_unavailable: The recipient was not at the location or the phone was unanswered.address_issue: Incomplete address, missing landmark, or incorrect pin code.refused: Consignee refused the parcel or rejected Cash on Delivery payment.premises_closed: Commercial premises or residential gate was locked.cod_not_ready: Cash on Delivery funds were not available at the doorstep.other: Operational constraints, weather holds, or route delays.
Automated Action Dispatcher Example
By mapping reason codes to targeted actions, you can trigger specific recovery flows. Below is a TypeScript implementation:
import axios from "axios";
type NdrReason =
| "customer_unavailable"
| "address_issue"
| "refused"
| "premises_closed"
| "cod_not_ready"
| "other";
async function processNdrEvent(carrier: string, awb: string) {
const response = await axios.get(
`https://api.cleartrackpromise.in/v1/track/${carrier}/${awb}`,
{
headers: { "X-API-Key": process.env.CLEARTRACK_API_KEY }
}
);
const { status, insights, delivery_attempts } = response.data;
const failedAttempts = delivery_attempts?.attempts?.filter((a: any) => a.outcome === "failed") || [];
if (insights?.current_stage !== "delivery_attempted" || !failedAttempts.length) {
return;
}
const latestAttempt = failedAttempts[failedAttempts.length - 1];
const reason = latestAttempt.reason_code as NdrReason;
switch (reason) {
case "customer_unavailable":
case "premises_closed":
// Send automated WhatsApp message asking for preferred re-attempt time
console.log(`Dispatching re-attempt availability check for ${awb}`);
break;
case "address_issue":
// Send address verification link to buyer
console.log(`Dispatching address update portal link for ${awb}`);
break;
case "cod_not_ready":
// Send digital doorstep UPI payment link
console.log(`Sending UPI prepayment link for ${awb}`);
break;
case "refused":
// Flag order to customer experience team for cancellation review
console.log(`Flagging refused delivery for order ${awb}`);
break;
default:
console.log(`Logging generic NDR attempt for ${awb}`);
break;
}
}
Best Practices for NDR Management
- Act Within 2 Hours: Couriers often re-schedule deliveries for the subsequent morning. Contacting the customer quickly increases the likelihood of a successful second attempt.
- Collect Pin Code and Landmark: Address issues are often resolved simply by confirming a nearby landmark or phone number.
- Offer Digital Payment Options: For COD orders where cash was not ready, sending an instant payment link avoids cash handling friction.
For technical reference details, see the NDR Codes Documentation, compare Prepaid Lookup Plans, and review the NDR Reason Codes Overview.