AI Knowledge & Logic

Order Tracking

Wire up order lookups for any backend by writing a small Python action that calls your existing order API. The bot uses it to answer 'Where's my order?', 'What's the status of #12345?', and similar questions.

If your store doesn't use a platform we integrate with directly (Shopify, WooCommerce, BigCommerce, Magento), you can still let the bot answer order questions like "Where's my order?", "What's the status of #12345?", or "What did I buy with this email?"

You don't need to expose a special endpoint or match any particular schema. Whatever API you already have for orders — REST, GraphQL, a partner-only feed, anything reachable over HTTPS — is enough. We just wrap a thin Python action around it that:

  1. Receives a lookup argument from the bot (email, order ID, phone)
  2. Calls your API however your API wants to be called (auth, headers, query params — your choice)
  3. Returns whatever fields you want the bot to know about

The bot uses the returned data however the conversation needs — composing a status update, summarizing items, sharing tracking links, and so on. You control the shape of what comes back, and you can iterate on it without touching your backend.


Instead of one mega-action with optional filters, we recommend a separate Python action per lookup type. This makes it obvious to the bot when each one applies, and keeps the code in each action simple.

ActionArgumentPriorityWhy
getOrdersByEmailemailMinimumMost customers can give you their email. Cover this and you can answer most order questions.
getOrderByIdorderIdBonusFaster, more specific lookup when the customer has their order number handy.
getOrdersByPhonephoneBonusUseful for phone-channel conversations or when customers can't remember the email used.

Each action returns the same shape of data — just looked up a different way. The bot will pick the right one based on what the customer provides.


Suggested return shape (for inspiration)

You can return any fields you find useful. Below is a reasonable starting point — feel free to add, remove, or rename fields to match your business.

# Example return from getOrdersByEmail / getOrderById / getOrdersByPhone
[
  {
    "id": "ORD-12345",
    "status": "shipped",                 # pending | processing | shipped | delivered | cancelled
    "created_at": "2024-10-10T14:21:00Z",
    "updated_at": "2024-10-11T09:00:00Z",
    "customer": {
      "email": "[email protected]",
      "phone": "+14151234567",
      "name": "Jane Doe",
    },
    "shipping_address": {
      "line1": "123 Main Street",
      "city": "San Francisco",
      "postal_code": "94103",
      "country": "US",
    },
    "items": [
      {
        "sku": "ABC123",
        "name": "Wireless Earbuds",
        "quantity": 1,
        "price": 59.99,
      },
    ],
    "total": 59.99,
    "currency": "USD",
    "tracking_number": "1Z999999",
    "tracking_url": "https://www.ups.com/track?tracknum=1Z999999",
  },
]

Minimum useful fields: id, status, customer email or phone, items, total, currency. High-value extras: tracking_number / tracking_url (for "where is it?"), shipping_address (for delivery questions), updated_at (for status timelines).

Always return a list of orders, even for a single-result lookup like getOrderById. It keeps the action's downstream consumers (the bot, your workflows) consistent.


Phone number normalization

If you support phone lookups, normalize both sides (the customer's input and the stored value) by stripping non-digits and comparing the last 7 digits. This avoids country-code and formatting mismatches.

Raw inputNormalized (last 7 digits)
+1 (415) 867-53098675309
+49 151 2345 67893456789
41512345671234567

Skeleton: getOrdersByEmail

import urllib.request, urllib.parse, json

def execute_action(context):
    email = context["args"]["email"]

    url = "https://api.your-store.com/orders?" + urllib.parse.urlencode({"email": email})
    req = urllib.request.Request(url, headers={
        "Authorization": "Bearer YOUR_API_KEY",
        "Accept": "application/json",
    })

    with urllib.request.urlopen(req, timeout=10) as resp:
        raw_orders = json.loads(resp.read())

    # Reshape into whatever you want the bot to see.
    return [
        {
            "id": o["order_number"],
            "status": o["fulfillment_status"],
            "created_at": o["created_at"],
            "customer": {"email": o["email"], "name": o.get("customer_name")},
            "items": [
                {"name": li["title"], "quantity": li["qty"], "price": li["price"]}
                for li in o["line_items"]
            ],
            "total": o["total_price"],
            "currency": o["currency"],
            "tracking_number": o.get("tracking_number"),
            "tracking_url": o.get("tracking_url"),
        }
        for o in raw_orders
    ]

getOrderById and getOrdersByPhone follow the same pattern — just a different filter, and (in the phone case) the normalization step from above.

For the full details on how Python actions work, hook into workflows, declare arguments, and handle errors, see Custom Actions.


Need help?

If your order API needs more involved logic (multi-step lookups, OAuth refresh, paginated results) or you'd like us to review your schema, reach out — we're happy to validate a sample and help you wire it up.

Contact support →

On this page