By Sagar Shankaran, Founder of CallSphere
Build an AI agent that handles the complete order support lifecycle — from tracking shipments and processing returns to managing exchanges and order modifications — reducing support ticket volume significantly.
Key takeaways
Order-related inquiries account for 40 to 60 percent of all e-commerce customer support tickets. "Where is my order?", "I want to return this", and "Can I change my shipping address?" are repetitive, high-volume questions that follow predictable patterns. An AI agent can handle most of these autonomously while escalating edge cases to human agents.
The foundation of an order support agent is reliable order retrieval. The agent needs to look up orders by order number, email address, or phone number and present the current status clearly.
flowchart LR
USER(["Customer"])
CHANNEL{"Channel"}
CHAT["Chat agent"]
VOICE["Voice agent"]
EMAIL["Email agent"]
TRIAGE["Triage and<br/>intent detection"]
KB[("Knowledge base<br/>RAG")]
CRM[("CRM context")]
AUTORES{"Auto resolvable?"}
RESOLVE(["Resolved with<br/>cited answer"])
HUMAN(["Tier 2 agent"])
USER --> CHANNEL --> CHAT --> TRIAGE
CHANNEL --> VOICE --> TRIAGE
CHANNEL --> EMAIL --> TRIAGE
TRIAGE --> KB
TRIAGE --> CRM
TRIAGE --> AUTORES
AUTORES -->|Yes| RESOLVE
AUTORES -->|No| HUMAN
style TRIAGE fill:#4f46e5,stroke:#4338ca,color:#fff
style AUTORES fill:#f59e0b,stroke:#d97706,color:#1f2937
style RESOLVE fill:#059669,stroke:#047857,color:#fff
style HUMAN fill:#0ea5e9,stroke:#0369a1,color:#fff
from agents import Agent, Runner, function_tool
from datetime import datetime, timedelta
from enum import Enum
class OrderStatus(str, Enum):
PROCESSING = "processing"
SHIPPED = "shipped"
DELIVERED = "delivered"
RETURN_REQUESTED = "return_requested"
RETURN_COMPLETED = "return_completed"
CANCELLED = "cancelled"
# Simulated order database
ORDERS_DB = {
"ORD-10042": {
"customer_email": "alex@example.com",
"items": [
{"sku": "SKU-001", "name": "Merino Wool Jacket", "qty": 1,
"price": 189.99, "returnable": True}
],
"status": OrderStatus.SHIPPED,
"tracking": "1Z999AA10123456784",
"carrier": "UPS",
"ordered_at": "2026-03-10",
"shipped_at": "2026-03-12",
"estimated_delivery": "2026-03-18",
"shipping_address": "123 Main St, Portland, OR 97201",
},
}
@function_tool
def lookup_order(order_id: str) -> str:
"""Look up an order by its order ID."""
order = ORDERS_DB.get(order_id.upper())
if not order:
return f"No order found with ID {order_id}. Please verify the order number."
return (
f"Order {order_id}: Status={order['status'].value}, "
f"Items={[i['name'] for i in order['items']]}, "
f"Carrier={order['carrier']}, Tracking={order['tracking']}, "
f"Est. Delivery={order['estimated_delivery']}"
)
@function_tool
def get_tracking_details(tracking_number: str) -> str:
"""Get real-time tracking details for a shipment."""
# In production, call carrier API (UPS, FedEx, USPS)
return (
f"Tracking {tracking_number}: "
f"Mar 12 - Picked up, Portland OR | "
f"Mar 14 - In transit, Sacramento CA | "
f"Mar 16 - Out for delivery, San Francisco CA"
)
Returns require careful validation: Is the item within the return window? Is it in a returnable category? Has the customer already initiated a return for this item?
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
RETURN_WINDOW_DAYS = 30
NON_RETURNABLE = ["underwear", "swimwear", "customized"]
@function_tool
def initiate_return(order_id: str, item_sku: str, reason: str) -> str:
"""Initiate a return for a specific item in an order."""
order = ORDERS_DB.get(order_id.upper())
if not order:
return "Order not found."
if order["status"] not in (OrderStatus.DELIVERED, OrderStatus.SHIPPED):
return "Returns can only be initiated for shipped or delivered orders."
# Check return window
order_date = datetime.strptime(order["ordered_at"], "%Y-%m-%d")
if (datetime.now() - order_date).days > RETURN_WINDOW_DAYS:
return f"Return window of {RETURN_WINDOW_DAYS} days has expired."
item = next((i for i in order["items"] if i["sku"] == item_sku), None)
if not item:
return f"Item {item_sku} not found in order {order_id}."
if not item.get("returnable", True):
return f"{item['name']} is not eligible for return."
return_id = f"RET-{order_id}-{item_sku}"
return (
f"Return {return_id} initiated for {item['name']}. "
f"Reason: {reason}. A prepaid return label has been emailed. "
f"Refund of ${item['price']:.2f} will be processed within "
f"5-7 business days after we receive the item."
)
@function_tool
def initiate_exchange(order_id: str, item_sku: str,
new_sku: str, reason: str) -> str:
"""Exchange an item for a different variant."""
order = ORDERS_DB.get(order_id.upper())
if not order:
return "Order not found."
item = next((i for i in order["items"] if i["sku"] == item_sku), None)
if not item:
return f"Item {item_sku} not found in this order."
exchange_id = f"EXC-{order_id}-{item_sku}"
return (
f"Exchange {exchange_id} created. Returning {item['name']} "
f"for {new_sku}. Ship the original item back using the prepaid "
f"label sent to your email. The replacement ships once we "
f"receive your return."
)
Customers frequently want to change shipping addresses or cancel orders before shipment. The agent should check whether modifications are still possible.
@function_tool
def modify_order(order_id: str, modification_type: str,
new_value: str) -> str:
"""Modify an order (address change, cancellation) if still possible."""
order = ORDERS_DB.get(order_id.upper())
if not order:
return "Order not found."
if order["status"] in (OrderStatus.SHIPPED, OrderStatus.DELIVERED):
return (
"This order has already shipped. Address changes are no "
"longer possible. You may initiate a return after delivery."
)
if modification_type == "cancel":
return f"Order {order_id} has been cancelled. Refund processing in 3-5 days."
elif modification_type == "address":
return f"Shipping address updated to: {new_value}"
else:
return f"Modification type '{modification_type}' is not supported."
order_agent = Agent(
name="Order Support Agent",
instructions="""You are a customer service agent for an online retailer.
Help customers with order tracking, returns, exchanges, and modifications.
Rules:
- Always verify the order exists before taking any action
- Explain return policies clearly before processing returns
- Confirm the customer's intent before making changes
- If an order cannot be modified, explain why and offer alternatives
- Provide tracking links when available
- Escalate to a human agent if the customer is upset or the issue
is outside your capabilities""",
tools=[lookup_order, get_tracking_details, initiate_return,
initiate_exchange, modify_order],
)
result = Runner.run_sync(order_agent, "Where is my order ORD-10042?")
print(result.final_output)
Most carriers provide REST APIs. UPS offers the Tracking API, FedEx has Track API v1, and USPS provides the Web Tools API. Wrap each carrier's API in a unified tracking tool that accepts a tracking number and carrier name, normalizes the response into a common format (timestamp, location, status), and returns it. Cache responses for 15 minutes to reduce API calls.
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
Build promo-aware return logic that calculates the actual paid amount after discounts. If the returned item triggers a threshold change (for example, "buy 2 get 10% off" and the customer returns one), recalculate the order total and issue a partial refund reflecting the adjusted discount. Document this policy clearly in the agent's instructions.
Include a sentiment detection step in the agent loop. If the customer uses aggressive language or repeats the same complaint more than twice, the agent should acknowledge their frustration, apologize, and offer to transfer the conversation to a human supervisor. Never argue or become defensive in automated responses.
#OrderManagement #CustomerSupportAI #ReturnsProcessing #ECommerce #RetailAI #AgenticAI #LearnAI #AIEngineering

Written by
Sagar Shankaran· Founder, CallSphere
LinkedInSagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
A 2026 market read on Indonesian SMBs across Jakarta, Surabaya, and Bali — a mobile-first, Bahasa-speaking, WhatsApp-native market — and why CallSphere AI voice and chat agents fit the moment.
South African retailers and online stores lose sales to unanswered order, stock and delivery calls. Here is how CallSphere AI voice and chat agents plug the leak 24/7, in local languages.
Market data on Korea's retail and online-selling boom, and how CallSphere AI agents help sellers in Seoul, Busan and Incheon handle order, sizing and return calls 24/7 in Korean.
A 2026 market read on Malaysian SMBs across Kuala Lumpur, Penang, and Johor Bahru — juggling Malay, English, and Mandarin customers on WhatsApp — and why CallSphere AI voice and chat agents are the fix.
A practical playbook for Kuwait online sellers and retailers in Kuwait City and Hawalli to recover abandoned orders using a CallSphere AI voice and chat agent that answers 24/7 in Arabic, English and expat languages.
Llama Guard 4 ships as Meta's safety classifier for the Llama 4 era — input/output classification with multimodal support. Lens: e-commerce.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco