Skip to main content
Transform your returns process from a customer service burden into a seamless self-service experience. In this guide, you’ll build an AI-powered returns system that collects return information, validates eligibility, generates return labels, and updates your order system — all through natural conversation. What you’ll build: A complete returns handling system that:
  • Engages customers via chat, email, or SMS
  • Looks up their order automatically
  • Collects return reason and item condition
  • Validates against your return policy
  • Generates return labels (via API)
  • Updates your order management system
  • Notifies your fulfillment team
Time: 45-60 minutes

Prerequisites


The Business Problem

Returns are expensive — not just the refund, but the time your team spends:
  • Answering “what’s your return policy?”
  • Collecting order numbers and item details
  • Verifying return eligibility
  • Generating shipping labels
  • Updating inventory systems
  • Following up on status
With CogniAgent, customers handle their own returns through a friendly AI assistant. Your team only gets involved for exceptions.

Architecture Overview


Step 1: Create the Application

1

Create application

Create a new application called “Customer Service”.
2

Create workflow

Create a workflow called “Returns Handler”.

Step 2: Set Up the Trigger

We’ll use a web widget trigger so customers can initiate returns from your website.
1

Add Web Widget trigger

Drag a Start node for testing. Later, you’ll replace this with a web widget or email trigger.
2

Configure test data

Add test data:
{
  "customerEmail": "customer@example.com",
  "customerName": "Sarah"
}

Step 3: Build the Returns Skillset

The skillset handles the conversation: collecting order info, return reason, and item details.
1

Add Ask a Person node

  • Name: “Returns Assistant”
  • Key: returns_conv
2

Configure the skillset

{
  "agentId": "returns-assistant",
  "name": "Returns Assistant",
  "description": "Help customers initiate product returns",

  "persona": {
    "agentName": "Returns Assistant",
    "organization": "{{store_name}}",
    "tone": "Helpful, empathetic, and efficient. Understand returns can be frustrating. Be apologetic if the product didn't meet expectations but stay positive."
  },

  "inputVariables": [
    {
      "name": "store_name",
      "defaultValue": "Our Store"
    },
    {
      "name": "customer_name",
      "description": "Customer's name"
    },
    {
      "name": "return_policy_days",
      "defaultValue": "30",
      "description": "Number of days for return eligibility"
    }
  ],

  "settings": {
    "maxFieldAttempts": 3,
    "requireConfirmation": true
  },

  "formFieldsMapping": {
    "order_number": {
      "template": {
        "id": "order_number",
        "name": "Order Number",
        "description": "The order number, usually starts with # or found in their confirmation email",
        "type": "text",
        "required": true
      }
    },
    "item_to_return": {
      "template": {
        "id": "item_to_return",
        "name": "Item to Return",
        "description": "Which item(s) from the order they want to return",
        "type": "text",
        "required": true
      }
    },
    "return_reason": {
      "template": {
        "id": "return_reason",
        "name": "Return Reason",
        "description": "Why they want to return the item",
        "type": "selection",
        "options": [
          "Doesn't fit",
          "Not as described",
          "Arrived damaged",
          "Changed my mind",
          "Received wrong item",
          "Quality not as expected",
          "Other"
        ],
        "required": true
      }
    },
    "item_condition": {
      "template": {
        "id": "item_condition",
        "name": "Item Condition",
        "description": "Current condition of the item being returned",
        "type": "selection",
        "options": [
          "Unopened/sealed",
          "Opened but unused",
          "Used once",
          "Used multiple times",
          "Damaged"
        ],
        "required": true
      }
    },
    "additional_details": {
      "template": {
        "id": "additional_details",
        "name": "Additional Details",
        "description": "Any other information about the return, like specific damage or issues",
        "type": "text",
        "required": false
      }
    },
    "preferred_resolution": {
      "template": {
        "id": "preferred_resolution",
        "name": "Preferred Resolution",
        "description": "How they'd like us to resolve this - refund or exchange",
        "type": "selection",
        "options": ["Full refund", "Exchange for different size/color", "Store credit"],
        "required": true
      }
    }
  },

  "knowledgeBaseId": "kb_return_policy"
}
3

Map input variables

{
  "customer_name": "{{start_1.customerName}}",
  "store_name": "Your Store Name"
}

Sample Conversation

AI: Hi Sarah! I’m here to help with your return. I’m sorry the product didn’t work out. Can you tell me your order number? You’ll find it in your confirmation email — it usually starts with #. Customer: It’s #12345 AI: Got it, order #12345. Which item from that order would you like to return? Customer: The blue sweater AI: The blue sweater — no problem. What’s the reason for the return? Customer: It doesn’t fit right AI: I understand — fit issues are frustrating! What condition is the sweater in? Customer: I tried it on once but it still has tags AI: Would you prefer a full refund, an exchange for a different size, or store credit? Customer: Exchange for a larger size AI: Perfect! Let me confirm: You’d like to exchange the blue sweater from order #12345 for a larger size because it doesn’t fit. The item is opened but unused. Is that correct? Customer: Yes AI: Great! I’m processing your exchange now…

Step 4: Look Up the Order

After collecting the order number, verify it exists and get order details.
1

Add App Action node

After the Ask a Person event handle, add:
  • App: Shopify
  • Action: Get Order
2

Configure the lookup

{
  "orderNumber": "{{returns_conv.collectedData.order_number}}"
}
3

Add error handling

Add a Condition node to check if the order was found:
{{shopify_order.success}} == true
If not found, send a reply asking them to double-check the order number.

Step 5: Validate Return Eligibility

Use AI to check if the return meets your policy.
1

Add Ask AI node

  • Name: “Validate Return”
  • Key: return_validation
2

Configure the validation prompt

You are a returns policy validator. Determine if this return request is eligible.

RETURN POLICY:
- Returns accepted within 30 days of delivery
- Items must be in original condition with tags (except for defective items)
- Sale items are final sale (no returns)
- Swimwear and underwear cannot be returned if opened
- Damaged items can be returned regardless of condition

ORDER DETAILS:
- Order Date: {{shopify_order.response.created_at}}
- Delivery Date: {{shopify_order.response.fulfilled_at}}
- Item: {{returns_conv.collectedData.item_to_return}}
- Item Category: {{shopify_order.response.line_items[0].product_type}}
- Was on Sale: {{shopify_order.response.line_items[0].discount_allocations.length > 0}}

RETURN REQUEST:
- Reason: {{returns_conv.collectedData.return_reason}}
- Item Condition: {{returns_conv.collectedData.item_condition}}
- Preferred Resolution: {{returns_conv.collectedData.preferred_resolution}}
- Days Since Delivery: <calculate from dates>

Respond in JSON:
{
  "eligible": true/false,
  "reason": "Brief explanation",
  "exceptions": ["any policy exceptions that apply"],
  "suggested_resolution": "What we should offer",
  "requires_human_review": true/false
}

Step 6: Route by Eligibility

1

Add Condition node

Check eligibility:
{{return_validation.response.eligible}} == true
2

Create two branches

  • Eligible → Process the return
  • Not Eligible → Explain and offer alternatives

Step 7: Process Eligible Returns

For eligible returns, generate a shipping label and update the order.

Generate Return Label

1

Add HTTP Request node

If you use a shipping API (ShipStation, EasyPost, etc.):
  • Method: POST
  • URL: https://api.easypost.com/v2/shipments
2

Configure the request

{
  "shipment": {
    "to_address": {
      "name": "Returns Department",
      "street1": "123 Warehouse St",
      "city": "Your City",
      "state": "ST",
      "zip": "12345"
    },
    "from_address": {
      "name": "{{start_1.customerName}}",
      "street1": "{{shopify_order.response.shipping_address.address1}}",
      "city": "{{shopify_order.response.shipping_address.city}}",
      "state": "{{shopify_order.response.shipping_address.province_code}}",
      "zip": "{{shopify_order.response.shipping_address.zip}}"
    },
    "parcel": {
      "weight": 16
    }
  }
}

Update Order in Shopify

1

Add App Action node

  • App: Shopify
  • Action: Add Order Note or Add Order Tag
2

Configure the update

{
  "orderId": "{{shopify_order.response.id}}",
  "note": "Return initiated: {{returns_conv.collectedData.item_to_return}} - {{returns_conv.collectedData.return_reason}}. Label: {{shipping_label.response.tracking_code}}",
  "tags": ["return-initiated", "{{returns_conv.collectedData.preferred_resolution}}"]
}

Send Confirmation to Customer

1

Add Send Reply node

Great news! Your return has been approved. Here's what happens next:

📦 **Return Label**
I've emailed your prepaid return label to {{start_1.customerEmail}}.

📋 **Instructions**
1. Pack the blue sweater securely
2. Attach the return label to the outside
3. Drop off at any UPS location

🔄 **Your Exchange**
Once we receive your return (usually 5-7 business days), we'll ship your new size right away.

**Tracking:** {{shipping_label.response.tracking_code}}

Anything else I can help with?

Notify Fulfillment Team

1

Add App Action (Slack)

📦 *Return Incoming*

Order: #{{returns_conv.collectedData.order_number}}
Customer: {{start_1.customerName}}
Item: {{returns_conv.collectedData.item_to_return}}
Reason: {{returns_conv.collectedData.return_reason}}
Resolution: {{returns_conv.collectedData.preferred_resolution}}
Tracking: {{shipping_label.response.tracking_code}}

Expected arrival: ~5-7 days

Step 8: Handle Ineligible Returns

For returns that don’t meet policy, explain why and offer alternatives.
1

Check if human review needed

Add a condition:
{{return_validation.response.requires_human_review}} == true
2

For human review

Transfer to human:
I want to make sure you get the best resolution. Let me connect you with our customer service team who can review your specific situation. They'll reach out within 24 hours.

In the meantime, is there anything else I can help with?
Then notify your CS team via Slack.
3

For clear policy violations

Send explanation:
I'm sorry, but I'm not able to process this return. {{return_validation.response.reason}}

Here are some alternatives:
{{#if return_validation.response.suggested_resolution}}
- {{return_validation.response.suggested_resolution}}
{{/if}}
- Contact our customer service team for special consideration
- Check if the item qualifies for our warranty program

Is there anything else I can help with?

Complete Workflow


Adding Email Support

Let customers initiate returns by email too.
1

Add parallel trigger

Create another workflow with an App Trigger (Gmail):
  • Filter: Subject contains “return” or “exchange”
2

Extract customer info

Use Ask AI to extract order number and intent from the email body.
3

Route to same skillset

Pass extracted data to the same returns skillset, but via email channel.

Testing Scenarios

Test these scenarios to ensure robustness:
ScenarioExpected Behavior
Valid return within 30 daysApproved, label generated
Return after 30 daysRejected with explanation
Damaged item (any age)Approved under damage exception
Sale itemRejected - final sale
Wrong order numberAsked to verify
Customer wants exchange + refundClarify which one
Unclear item descriptionAI asks for clarification

Metrics to Track

MetricTargetWhy It Matters
Self-service completion rate>80%Fewer tickets for your team
Average conversation length<5 minutesCustomer satisfaction
Return approval rateMonitorPolicy effectiveness
Human escalation rate<10%AI handling most cases
Customer satisfaction (post-return)>4/5Overall experience

Customization Ideas

Add Photo Upload

For damaged items, let customers upload photos:
{
  "id": "damage_photo",
  "name": "Damage Photo",
  "description": "Photo showing the damage for our records",
  "type": "file",
  "required": true,
  "condition": "return_reason == 'Arrived damaged'"
}

Multi-Item Returns

Handle returns with multiple items by making item_to_return a loop:
{
  "id": "items_to_return",
  "name": "Items to Return",
  "description": "All items they want to return from this order",
  "type": "array",
  "required": true
}

Proactive Return Offers

For very dissatisfied customers, proactively offer returns before they ask.

Troubleshooting

Check if the order number format matches what Shopify expects. Some stores use prefixes like “ORD-” that customers might not include.
Adjust the AI prompt with more specific rules. Be explicit about edge cases and exceptions.
Verify address formatting. EasyPost and ShipStation have specific requirements for address fields.
Consider sending an email follow-up if they don’t complete within 30 minutes. Add a timeout handler.

Next Steps

Lead Qualification

See how skillsets work for sales use cases.

Integrations

Connect to more e-commerce platforms.

Knowledge Base

Add your return policy to the knowledge base.

Channels

Enable more communication channels.