๐Ÿ”ฅ 0
โญ 0
Lesson 5 of 10 22 min +175 XP

Shipping & Fulfillment Tools

Shipping is where e-commerce gets physical. Your AI agent needs to calculate rates, generate labels, and track packages across multiple carriers. Let's build the tools to make this seamless.

Easyship & ShipStation MCP Servers

Both Easyship and ShipStation offer official MCP servers with access to 550+ carriers, real-time rates, and automated label generation. You can use these directly or build custom tools on their APIs.

Shipping Tool Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                     AI AGENT CONVERSATION                        โ”‚
โ”‚  "What shipping options do I have for this order?"              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                  โ”‚
                                  โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                   SHIPPING MCP TOOLS                             โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ calculate_ratesโ”‚ create_label  โ”‚ track_shipmentโ”‚ validate_addr  โ”‚
โ”‚ get_carriers   โ”‚ void_label    โ”‚ schedule_pickupโ”‚ get_duties    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                  โ”‚
                                  โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚               MULTI-CARRIER API LAYER                            โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”            โ”‚
โ”‚  โ”‚  USPS   โ”‚  โ”‚  UPS    โ”‚  โ”‚  FedEx  โ”‚  โ”‚  DHL    โ”‚            โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜            โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Core Shipping Tools

1. Calculate Shipping Rates

Get real-time rates from multiple carriers:

from mcp.server import Server
from mcp import types
import json
from datetime import datetime, timedelta

app = Server("shipping-tools")

@app.list_tools()
async def list_tools() -> list[types.Tool]:
    return [
        types.Tool(
            name="calculate_shipping_rates",
            description="""Calculates shipping rates from multiple carriers for a package.
            Use when: Customer is checking out, comparing shipping options, or asking about delivery.
            Returns: Array of shipping options with prices, carriers, and estimated delivery dates.
            Note: Rates are live and may change - quote is valid for 30 minutes.""",
            inputSchema={
                "type": "object",
                "properties": {
                    "origin": {
                        "type": "object",
                        "properties": {
                            "zip": {"type": "string", "pattern": "^[0-9]{5}(-[0-9]{4})?$"},
                            "country": {"type": "string", "default": "US"}
                        },
                        "required": ["zip"],
                        "description": "Ship-from address. Defaults to nearest warehouse if omitted."
                    },
                    "destination": {
                        "type": "object",
                        "properties": {
                            "street": {"type": "string"},
                            "city": {"type": "string"},
                            "state": {"type": "string"},
                            "zip": {"type": "string"},
                            "country": {"type": "string", "default": "US"}
                        },
                        "required": ["zip", "country"],
                        "description": "Ship-to address"
                    },
                    "package": {
                        "type": "object",
                        "properties": {
                            "weight_oz": {
                                "type": "number",
                                "minimum": 0.1,
                                "description": "Total weight in ounces"
                            },
                            "length_in": {"type": "number", "description": "Length in inches"},
                            "width_in": {"type": "number", "description": "Width in inches"},
                            "height_in": {"type": "number", "description": "Height in inches"}
                        },
                        "required": ["weight_oz"]
                    },
                    "service_types": {
                        "type": "array",
                        "items": {
                            "type": "string",
                            "enum": ["economy", "standard", "express", "overnight"]
                        },
                        "description": "Filter to specific service levels. Omit for all options."
                    },
                    "carriers": {
                        "type": "array",
                        "items": {
                            "type": "string",
                            "enum": ["usps", "ups", "fedex", "dhl"]
                        },
                        "description": "Filter to specific carriers. Omit for all carriers."
                    },
                    "ship_date": {
                        "type": "string",
                        "format": "date",
                        "description": "Date to ship (YYYY-MM-DD). Defaults to today."
                    }
                },
                "required": ["destination", "package"]
            }
        )
    ]

@app.call_tool()
async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
    if name == "calculate_shipping_rates":
        destination = arguments["destination"]
        package = arguments["package"]
        ship_date = arguments.get("ship_date", datetime.now().strftime("%Y-%m-%d"))

        # Determine origin (use warehouse closest to destination if not specified)
        if "origin" in arguments:
            origin = arguments["origin"]
        else:
            origin = await select_nearest_warehouse(destination["zip"])

        # Get rates from shipping API (e.g., EasyPost, Shippo, ShipStation)
        rates = await shipping_api.get_rates(
            from_zip=origin["zip"],
            from_country=origin.get("country", "US"),
            to_zip=destination["zip"],
            to_country=destination.get("country", "US"),
            weight_oz=package["weight_oz"],
            length=package.get("length_in"),
            width=package.get("width_in"),
            height=package.get("height_in"),
            ship_date=ship_date
        )

        # Filter by requested carriers/services
        if "carriers" in arguments:
            rates = [r for r in rates if r["carrier"].lower() in arguments["carriers"]]
        if "service_types" in arguments:
            rates = [r for r in rates if r["service_type"] in arguments["service_types"]]

        # Format response
        shipping_options = []
        for rate in sorted(rates, key=lambda x: x["total_cost"]):
            shipping_options.append({
                "carrier": rate["carrier"],
                "service": rate["service_name"],
                "service_type": rate["service_type"],
                "price": rate["total_cost"],
                "currency": "USD",
                "estimated_days": rate["transit_days"],
                "estimated_delivery": rate["delivery_date"],
                "rate_id": rate["rate_id"],  # For purchasing this rate
                "tracking_included": True
            })

        return [types.TextContent(
            type="text",
            text=json.dumps({
                "success": True,
                "origin_zip": origin["zip"],
                "destination_zip": destination["zip"],
                "ship_date": ship_date,
                "quote_expires": (datetime.now() + timedelta(minutes=30)).isoformat(),
                "options": shipping_options
            })
        )]

2. Create Shipping Label

Generate a shipping label after checkout:

types.Tool(
    name="create_shipping_label",
    description="""Purchases a shipping label from the selected carrier.
    Use when: Order is paid and ready to ship, or customer service needs to reship an item.
    Returns: Label URL (PDF), tracking number, and carrier details.
    Note: This charges the shipping account - use rate_id from calculate_shipping_rates.""",
    inputSchema={
        "type": "object",
        "properties": {
            "rate_id": {
                "type": "string",
                "description": "Rate ID from calculate_shipping_rates to purchase"
            },
            "order_id": {
                "type": "string",
                "description": "Order ID to associate with this shipment"
            },
            "from_address": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "company": {"type": "string"},
                    "street1": {"type": "string"},
                    "street2": {"type": "string"},
                    "city": {"type": "string"},
                    "state": {"type": "string"},
                    "zip": {"type": "string"},
                    "country": {"type": "string", "default": "US"},
                    "phone": {"type": "string"}
                },
                "required": ["name", "street1", "city", "state", "zip"]
            },
            "to_address": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "company": {"type": "string"},
                    "street1": {"type": "string"},
                    "street2": {"type": "string"},
                    "city": {"type": "string"},
                    "state": {"type": "string"},
                    "zip": {"type": "string"},
                    "country": {"type": "string", "default": "US"},
                    "phone": {"type": "string"},
                    "email": {"type": "string"}
                },
                "required": ["name", "street1", "city", "state", "zip"]
            },
            "package_details": {
                "type": "object",
                "properties": {
                    "weight_oz": {"type": "number"},
                    "length_in": {"type": "number"},
                    "width_in": {"type": "number"},
                    "height_in": {"type": "number"}
                },
                "required": ["weight_oz"]
            },
            "label_format": {
                "type": "string",
                "enum": ["pdf", "png", "zpl"],
                "default": "pdf",
                "description": "Label file format"
            },
            "signature_required": {
                "type": "boolean",
                "default": False,
                "description": "Require signature on delivery"
            }
        },
        "required": ["rate_id", "order_id", "to_address", "package_details"]
    }
)
Implementation:
elif name == "create_shipping_label":
    try:
        # Create the shipment and purchase the label
        shipment = await shipping_api.create_shipment(
            rate_id=arguments["rate_id"],
            from_address=arguments.get("from_address", default_warehouse_address),
            to_address=arguments["to_address"],
            parcel={
                "weight": arguments["package_details"]["weight_oz"],
                "length": arguments["package_details"].get("length_in"),
                "width": arguments["package_details"].get("width_in"),
                "height": arguments["package_details"].get("height_in")
            },
            options={
                "label_format": arguments.get("label_format", "pdf"),
                "signature_required": arguments.get("signature_required", False)
            }
        )

        # Store shipment info with order
        await orders_db.add_shipment(
            order_id=arguments["order_id"],
            shipment_id=shipment["id"],
            tracking_number=shipment["tracking_number"],
            carrier=shipment["carrier"],
            label_url=shipment["label_url"]
        )

        return [types.TextContent(
            type="text",
            text=json.dumps({
                "success": True,
                "shipment_id": shipment["id"],
                "order_id": arguments["order_id"],
                "tracking_number": shipment["tracking_number"],
                "carrier": shipment["carrier"],
                "service": shipment["service"],
                "label_url": shipment["label_url"],
                "cost": shipment["cost"],
                "estimated_delivery": shipment["estimated_delivery"]
            })
        )]

    except ShippingAPIError as e:
        return [types.TextContent(
            type="text",
            text=json.dumps({
                "success": False,
                "error": str(e),
                "error_code": e.code
            })
        )]

3. Track Shipment

Get real-time tracking information:

types.Tool(
    name="track_shipment",
    description="""Gets current tracking status for a shipment.
    Use when: Customer asks "where is my order?" or needs delivery status.
    Returns: Current status, location, and tracking history timeline.""",
    inputSchema={
        "type": "object",
        "properties": {
            "tracking_number": {
                "type": "string",
                "description": "Carrier tracking number"
            },
            "carrier": {
                "type": "string",
                "enum": ["usps", "ups", "fedex", "dhl", "auto"],
                "default": "auto",
                "description": "Carrier name. Use 'auto' to detect from tracking number."
            },
            "order_id": {
                "type": "string",
                "description": "Alternative: Look up tracking by order ID"
            }
        },
        "oneOf": [
            {"required": ["tracking_number"]},
            {"required": ["order_id"]}
        ]
    }
)
Implementation:
elif name == "track_shipment":
    # Get tracking number from order if not provided directly
    if "order_id" in arguments:
        shipment = await orders_db.get_shipment(arguments["order_id"])
        tracking_number = shipment["tracking_number"]
        carrier = shipment["carrier"]
    else:
        tracking_number = arguments["tracking_number"]
        carrier = arguments.get("carrier", "auto")

    # Fetch tracking info
    tracking = await shipping_api.track(
        tracking_number=tracking_number,
        carrier=carrier
    )

    # Format tracking events
    events = []
    for event in tracking["events"]:
        events.append({
            "timestamp": event["datetime"],
            "status": event["status"],
            "description": event["description"],
            "location": f"{event.get('city', '')}, {event.get('state', '')}".strip(", ")
        })

    return [types.TextContent(
        type="text",
        text=json.dumps({
            "tracking_number": tracking_number,
            "carrier": tracking["carrier"],
            "status": tracking["status"],
            "status_detail": tracking["status_detail"],
            "estimated_delivery": tracking.get("estimated_delivery"),
            "delivered_at": tracking.get("delivered_at"),
            "signed_by": tracking.get("signed_by"),
            "events": events
        })
    )]

4. Validate Address

Verify and correct shipping addresses:

types.Tool(
    name="validate_address",
    description="""Validates and standardizes a shipping address.
    Use when: Before calculating rates or creating labels to prevent delivery issues.
    Returns: Validated address with corrections, or error if invalid.""",
    inputSchema={
        "type": "object",
        "properties": {
            "street1": {"type": "string"},
            "street2": {"type": "string"},
            "city": {"type": "string"},
            "state": {"type": "string"},
            "zip": {"type": "string"},
            "country": {"type": "string", "default": "US"}
        },
        "required": ["street1", "city", "state", "zip"]
    }
)

TypeScript Implementation

import { Server } from "@modelcontextprotocol/sdk/server";

const server = new Server({ name: "shipping-tools", version: "1.0.0" });

interface ShippingRate {
  carrier: string;
  service: string;
  service_type: string;
  price: number;
  transit_days: number;
  delivery_date: string;
  rate_id: string;
}

interface TrackingEvent {
  timestamp: string;
  status: string;
  description: string;
  location: string;
}

const shippingTools = [
  {
    name: "calculate_shipping_rates",
    description: "Calculates real-time shipping rates from multiple carriers",
    inputSchema: {
      type: "object" as const,
      properties: {
        destination: {
          type: "object",
          properties: {
            zip: { type: "string" },
            country: { type: "string", default: "US" }
          },
          required: ["zip"]
        },
        package: {
          type: "object",
          properties: {
            weight_oz: { type: "number", minimum: 0.1 },
            length_in: { type: "number" },
            width_in: { type: "number" },
            height_in: { type: "number" }
          },
          required: ["weight_oz"]
        },
        service_types: {
          type: "array",
          items: { type: "string", enum: ["economy", "standard", "express", "overnight"] }
        }
      },
      required: ["destination", "package"]
    }
  },
  {
    name: "create_shipping_label",
    description: "Purchases a shipping label from the selected carrier",
    inputSchema: {
      type: "object" as const,
      properties: {
        rate_id: { type: "string" },
        order_id: { type: "string" },
        to_address: {
          type: "object",
          properties: {
            name: { type: "string" },
            street1: { type: "string" },
            city: { type: "string" },
            state: { type: "string" },
            zip: { type: "string" },
            country: { type: "string", default: "US" }
          },
          required: ["name", "street1", "city", "state", "zip"]
        },
        package_details: {
          type: "object",
          properties: { weight_oz: { type: "number" } },
          required: ["weight_oz"]
        }
      },
      required: ["rate_id", "order_id", "to_address", "package_details"]
    }
  },
  {
    name: "track_shipment",
    description: "Gets current tracking status and history for a shipment",
    inputSchema: {
      type: "object" as const,
      properties: {
        tracking_number: { type: "string" },
        carrier: { type: "string", enum: ["usps", "ups", "fedex", "dhl", "auto"], default: "auto" },
        order_id: { type: "string" }
      }
    }
  }
];

server.setRequestHandler("tools/list", async () => ({ tools: shippingTools }));

server.setRequestHandler("tools/call", async (request) => {
  const { name, arguments: args } = request.params;

  switch (name) {
    case "calculate_shipping_rates": {
      const rates = await shippingAPI.getRates({
        toZip: args.destination.zip,
        toCountry: args.destination.country || "US",
        weightOz: args.package.weight_oz,
        length: args.package.length_in,
        width: args.package.width_in,
        height: args.package.height_in
      });

      let filteredRates = rates;
      if (args.service_types) {
        filteredRates = rates.filter(
          (r: ShippingRate) => args.service_types.includes(r.service_type)
        );
      }

      const options = filteredRates
        .sort((a: ShippingRate, b: ShippingRate) => a.price - b.price)
        .map((rate: ShippingRate) => ({
          carrier: rate.carrier,
          service: rate.service,
          service_type: rate.service_type,
          price: rate.price,
          currency: "USD",
          estimated_days: rate.transit_days,
          estimated_delivery: rate.delivery_date,
          rate_id: rate.rate_id
        }));

      return {
        content: [{
          type: "text",
          text: JSON.stringify({
            success: true,
            destination_zip: args.destination.zip,
            options
          })
        }]
      };
    }

    case "create_shipping_label": {
      const shipment = await shippingAPI.purchaseLabel({
        rateId: args.rate_id,
        toAddress: args.to_address,
        parcel: args.package_details
      });

      await ordersDB.addShipment(args.order_id, {
        shipmentId: shipment.id,
        trackingNumber: shipment.tracking_number,
        carrier: shipment.carrier,
        labelUrl: shipment.label_url
      });

      return {
        content: [{
          type: "text",
          text: JSON.stringify({
            success: true,
            shipment_id: shipment.id,
            tracking_number: shipment.tracking_number,
            carrier: shipment.carrier,
            label_url: shipment.label_url,
            cost: shipment.cost
          })
        }]
      };
    }

    case "track_shipment": {
      let trackingNumber = args.tracking_number;
      let carrier = args.carrier || "auto";

      if (args.order_id && !trackingNumber) {
        const shipment = await ordersDB.getShipment(args.order_id);
        trackingNumber = shipment.trackingNumber;
        carrier = shipment.carrier;
      }

      const tracking = await shippingAPI.track(trackingNumber, carrier);

      return {
        content: [{
          type: "text",
          text: JSON.stringify({
            tracking_number: trackingNumber,
            carrier: tracking.carrier,
            status: tracking.status,
            estimated_delivery: tracking.estimatedDelivery,
            events: tracking.events.map((e: TrackingEvent) => ({
              timestamp: e.timestamp,
              status: e.status,
              description: e.description,
              location: e.location
            }))
          })
        }]
      };
    }

    default:
      throw new Error(`Unknown tool: ${name}`);
  }
});

International Shipping: Duties & Taxes

For cross-border shipments, calculate import duties and taxes:

types.Tool(
    name="calculate_duties_taxes",
    description="""Calculates import duties and taxes for international shipments.
    Use when: Shipping outside the origin country to show total landed cost.
    Returns: Duty amount, tax amount, and total de minimis threshold.""",
    inputSchema={
        "type": "object",
        "properties": {
            "destination_country": {
                "type": "string",
                "description": "ISO 2-letter country code (e.g., 'GB', 'DE', 'JP')"
            },
            "items": {
                "type": "array",
                "items": {
                    "type": "object",
                    "properties": {
                        "description": {"type": "string"},
                        "quantity": {"type": "integer"},
                        "value": {"type": "number", "description": "Unit value in USD"},
                        "hs_code": {"type": "string", "description": "Harmonized System code"}
                    },
                    "required": ["description", "quantity", "value"]
                }
            },
            "shipping_cost": {
                "type": "number",
                "description": "Shipping cost in USD"
            }
        },
        "required": ["destination_country", "items"]
    }
)

Real-World Conversation Flow

Customer: "How much is shipping to 90210?"

AI Agent: [Calls calculate_shipping_rates]
  calculate_shipping_rates(
    destination={"zip": "90210", "country": "US"},
    package={"weight_oz": 24, "length_in": 12, "width_in": 8, "height_in": 4}
  )

Tool Response:
{
  "success": true,
  "options": [
    {"carrier": "USPS", "service": "Ground Advantage", "price": 8.95, "estimated_days": 5},
    {"carrier": "UPS", "service": "Ground", "price": 12.50, "estimated_days": 4},
    {"carrier": "FedEx", "service": "Express Saver", "price": 24.99, "estimated_days": 2},
    {"carrier": "UPS", "service": "Next Day Air", "price": 45.00, "estimated_days": 1}
  ]
}

AI Agent: "Great news! Here are your shipping options to Beverly Hills:

โ€ข **USPS Ground Advantage** - $8.95 (5 days) - Best value
โ€ข **UPS Ground** - $12.50 (4 days)
โ€ข **FedEx Express** - $24.99 (2 days) - Fastest economy
โ€ข **UPS Next Day** - $45.00 (1 day) - Need it tomorrow?

Which would you prefer?"

Customer: "The FedEx 2-day please"

AI Agent: [Stores selection, proceeds to checkout]
"Perfect! I've selected FedEx Express ($24.99) for 2-day delivery.
Your order total is now $124.98. Ready to complete your purchase?"

Key Takeaways

  • Multi-carrier rates give customers choices on speed vs. cost
  • Validate addresses before label creation to prevent delivery issues
  • Return rate_id from quotes to purchase exact quoted rate
  • Track by order or tracking number for flexible lookups
  • Include duties/taxes for international to avoid surprises

Next up: CRM & Customer Data Tools - Building tools to look up customers, update records, and manage communications.

๐Ÿง  Quick Quiz

Test your understanding of this lesson.

1

What information is minimally required to calculate shipping rates?

2

Why should shipping tools return multiple carrier options?

3

What is the purpose of a tracking webhook?

Inventory Management Tools