> ## Documentation Index
> Fetch the complete documentation index at: https://terminal49.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Terminal49 Developer Documentation

> Developer documentation for the Terminal49 container tracking API, DataSync data pipelines, TypeScript SDK, and MCP server for AI integrations.

export const capabilityCategories = [{
  id: "coverage",
  label: "Carrier & Terminal Coverage",
  items: [{
    id: "ocean-carriers",
    title: "Ocean Carriers",
    desc: "100+ carrier integrations covering over 98% of global container volume with standardized data",
    icon: "ship",
    href: "/api-docs/useful-info/api-data-sources-availability",
    detailLabel: "Coverage",
    detailPoints: ["Bill of Lading details, booking data, and vessel ETAs", "Container milestones from origin to destination", "Standardized across all carriers into a single data model"]
  }, {
    id: "terminals",
    title: "Port Terminals",
    desc: "Direct integrations with 150+ terminal operators for container availability, holds, and fees",
    icon: "warehouse",
    href: "/api-docs/useful-info/api-data-sources-availability",
    detailLabel: "Terminal Data",
    detailPoints: ["Container availability and pickup readiness", "Active holds and fee breakdowns by source", "Last Free Day from both terminal and shipping line"]
  }, {
    id: "ports",
    title: "Global Ports",
    desc: "Coverage across North America, Europe, and major global trade lanes",
    icon: "anchor",
    href: "/api-docs/useful-info/api-data-sources-availability",
    detailLabel: "Port Coverage",
    detailPoints: ["All major US ports including LA/LB, NY/NJ, Savannah, Houston", "Canadian ports: Vancouver, Prince Rupert, Halifax, Montreal", "European ports: Southampton, London Gateway, and expanding"]
  }, {
    id: "number-types",
    title: "Track by Any Number",
    desc: "Track by Bill of Lading, container number, or booking number — with automatic SCAC detection",
    icon: "hashtag",
    href: "/api-docs/in-depth-guides/auto-detect-carrier",
    detailLabel: "Flexible Tracking",
    detailPoints: ["Bill of Lading (Master or House)", "Container number", "Booking number", "Auto-detect the carrier SCAC from any tracking number"]
  }]
}, {
  id: "imports",
  label: "Import Tracking",
  items: [{
    id: "import-lifecycle",
    title: "Full Import Lifecycle",
    desc: "Track an import container from vessel loading at origin through discharge, rail, and final delivery",
    icon: "route",
    href: "/api-docs/in-depth-guides/tracking-request-lifecycle",
    detailLabel: "Milestones",
    detailPoints: ["Vessel loaded, departed, arrived, berthed, discharged", "Rail loaded, departed, arrived, unloaded (North America)", "Container available, picked up, and empty returned"]
  }, {
    id: "lfd-demurrage",
    title: "Last Free Day & Demurrage",
    desc: "Terminal and shipping line LFD with per-source breakdown so you know exactly when fees start",
    icon: "calendar-check",
    href: "/api-docs/in-depth-guides/holds-and-fees",
    detailLabel: "LFD Data",
    detailPoints: ["Terminal Last Free Day (demurrage deadline)", "Shipping line Last Free Day (per diem deadline)", "Per-source LFD breakdown when multiple sources report"]
  }, {
    id: "availability",
    title: "Container Availability",
    desc: "Know exactly when a container clears holds and is ready for pickup at the terminal",
    icon: "circle-check",
    href: "/api-docs/in-depth-guides/holds-and-fees",
    detailLabel: "Availability Data",
    detailPoints: ["Pickup availability status from the terminal", "Active holds with type and source (customs, freight, TMF)", "Fee details including amount, type, and status"]
  }, {
    id: "rail",
    title: "Inland Rail Tracking",
    desc: "Complete rail milestones for containers moving inland from port to final destination",
    icon: "train",
    href: "/api-docs/in-depth-guides/rail-integration-guide",
    detailLabel: "Rail Data",
    detailPoints: ["Rail loaded, departed, arrived, and unloaded events", "Inland destination ETA with source transparency", "Arrival at final inland destination confirmation"]
  }]
}, {
  id: "exports",
  label: "Export & Bookings",
  items: [{
    id: "export-lifecycle",
    title: "Export Tracking",
    badge: "Coming Soon",
    desc: "Track export containers from empty pickup through gate-in, vessel loading, and departure",
    icon: "arrow-right-from-bracket",
    href: "/api-docs/in-depth-guides/tracking-request-lifecycle",
    detailLabel: "Export Milestones",
    detailPoints: ["Empty out, full in, vessel loaded, vessel departed", "Transshipment events if the container transfers vessels", "Arrival and discharge at the destination port"]
  }, {
    id: "bookings",
    title: "Booking Management",
    badge: "Coming Soon",
    desc: "Track bookings before containers are assigned — see new containers as they appear on the booking",
    icon: "file-lines",
    href: "/api-docs/webhooks/event-catalog",
    detailLabel: "Booking Data",
    detailPoints: ["Track a booking number before containers are assigned", "Receive container.created events as containers appear", "Monitor for rollovers when bookings shift to a new vessel"]
  }, {
    id: "erd-cutoffs",
    title: "ERD & Cutoffs",
    badge: "Coming Soon",
    desc: "Earliest Return Date and vessel cutoff times so you know your export window",
    icon: "clock",
    href: "/api-docs/in-depth-guides/container-statuses",
    detailLabel: "Cutoff Data",
    detailPoints: ["Earliest Return Date (ERD) for empty container return", "Vessel cutoff dates for cargo and documentation", "Port cutoff times for gate-in deadlines"]
  }, {
    id: "export-lfd",
    title: "Export Per Diem",
    badge: "Coming Soon",
    desc: "Shipping line Last Free Day for export containers so you return empties before per diem charges",
    icon: "calendar-xmark",
    href: "/api-docs/in-depth-guides/holds-and-fees",
    detailLabel: "Per Diem Data",
    detailPoints: ["Shipping line LFD for empty container return deadline", "Per diem fee tracking for overdue empty returns", "Webhook alerts when export LFD changes"]
  }]
}, {
  id: "vessels",
  label: "Vessels & Routing",
  items: [{
    id: "vessel-tracking",
    title: "Vessel Tracking",
    desc: "Every container vessel tracked globally with position data and voyage details",
    icon: "location-crosshairs",
    href: "/api-docs/api-reference/vessels/get-a-vessel-using-the-id",
    detailLabel: "Vessel Data",
    detailPoints: ["Vessel name, IMO number, and current position", "Voyage number and service route details", "Vessel ETA at each port of call"]
  }, {
    id: "routing-data",
    title: "Route Data & GeoJSON",
    desc: "Full container route with every port call, vessel, and voyage — plus GeoJSON for map rendering",
    icon: "map-location-dot",
    href: "/api-docs/in-depth-guides/routing",
    detailLabel: "Route Data",
    detailPoints: ["Complete port-to-port route with vessel and voyage", "GeoJSON endpoints for rendering routes on a map", "Forecasted vessel positions with coordinates"]
  }, {
    id: "vessel-schedules",
    title: "Vessel Schedules",
    desc: "Future vessel positions and port call schedules for voyage planning and ETA forecasting",
    icon: "calendar-days",
    href: "/api-docs/api-reference/vessels/get-vessel-future-positions",
    detailLabel: "Schedule Data",
    detailPoints: ["Future port calls with estimated arrival and departure", "Position forecasts with latitude and longitude", "Use for ETA validation and route planning"]
  }, {
    id: "maps",
    title: "Embeddable Maps",
    desc: "Build interactive maps showing vessel positions, routes, and container journeys",
    icon: "map",
    href: "/api-docs/in-depth-guides/terminal49-map",
    detailLabel: "Map Capabilities",
    detailPoints: ["Embed a live vessel map with a single code snippet", "Container-level GeoJSON for custom map rendering", "Vessel position history and forecasted routes"]
  }]
}, {
  id: "custom",
  label: "Custom Data",
  items: [{
    id: "custom-fields",
    title: "Custom Attributes",
    desc: "Attach your own data to shipments and containers — like an Airtable for your supply chain",
    icon: "table-columns",
    href: "/api-docs/api-reference/custom-fields/create-a-custom-field",
    detailLabel: "Custom Fields",
    detailPoints: ["Define custom field schemas (text, number, date, dropdown)", "Attach values to individual shipments or containers", "Filter and query shipments by your custom fields", "Build your own data model on top of Terminal49 tracking"]
  }, {
    id: "custom-definitions",
    title: "Field Definitions",
    desc: "Create typed field definitions with validation rules and dropdown options",
    icon: "sliders",
    href: "/api-docs/api-reference/custom-fields/create-a-custom-field-definition",
    detailLabel: "Definition Types",
    detailPoints: ["Text, number, date, and single-select field types", "Dropdown options with predefined values", "Field definitions apply across all shipments or containers"]
  }, {
    id: "parties",
    title: "Parties & Contacts",
    desc: "Associate customers, consignees, and other parties with tracking requests for multi-tenant workflows",
    icon: "users",
    href: "/api-docs/api-reference/parties/list-parties",
    detailLabel: "Party Management",
    detailPoints: ["Create parties representing customers or business entities", "Link parties to tracking requests for organization", "Filter shipments by party for multi-tenant use cases"]
  }, {
    id: "ref-numbers",
    title: "Reference Numbers",
    desc: "Tag shipments with your internal reference numbers for easy cross-referencing",
    icon: "tags",
    href: "/api-docs/api-reference/shipments/edit-a-shipment",
    detailLabel: "Reference Data",
    detailPoints: ["Attach multiple reference numbers to any shipment", "Use for PO numbers, internal IDs, or customer references", "Search and filter shipments by reference number"]
  }]
}];

export const appCategories = [{
  id: "tracking",
  label: "Automated Tracking",
  items: [{
    id: "start-here",
    title: "Get Started",
    desc: "Get your API key, create your first tracking request, and see shipment data in minutes",
    icon: "rocket",
    href: "/api-docs/getting-started/start-here",
    detailLabel: "Quick Start",
    detailPoints: ["Track by Bill of Lading, container number, or booking number", "Automatic carrier detection when you don't know the SCAC", "100+ integrations covering over 98% of global container volume"]
  }, {
    id: "lifecycle",
    title: "Container Lifecycle",
    desc: "Track a container from empty-out at origin to empty-return at destination with standardized milestones",
    icon: "route",
    href: "/api-docs/in-depth-guides/tracking-request-lifecycle",
    detailLabel: "Data Sources",
    detailPoints: ["Ocean carriers, rail terminals, and port terminals", "Vessel positions and route data", "Holds, fees, and availability from 150+ terminal sources"]
  }, {
    id: "container-statuses",
    title: "Container Statuses",
    desc: "Understand the standardized status model that normalizes data across all carriers",
    icon: "list-check",
    href: "/api-docs/in-depth-guides/container-statuses",
    detailLabel: "What You Get",
    detailPoints: ["Consistent status model regardless of carrier", "ETA at port of discharge and inland destination", "Last Free Day, holds, fees, and pickup availability"]
  }, {
    id: "auto-detect",
    title: "Auto-Detect Carrier",
    desc: "Identify the shipping line from a tracking number when you don't know the carrier SCAC",
    icon: "magnifying-glass",
    href: "/api-docs/in-depth-guides/auto-detect-carrier",
    detailLabel: "How It Works",
    detailPoints: ["Pass a Bill of Lading or container number", "Terminal49 identifies the carrier automatically", "Use the result to create a tracking request"]
  }]
}, {
  id: "events",
  label: "Real-Time Events",
  items: [{
    id: "why-webhooks",
    title: "Why Webhooks",
    desc: "Terminal49 is event-driven — receive updates the moment data changes instead of polling",
    icon: "webhook",
    href: "/api-docs/webhooks/overview",
    detailLabel: "Event-Driven Architecture",
    detailPoints: ["30+ events covering the full container lifecycle", "Updates delivered within minutes of carrier reporting", "No polling required — no wasted API calls"]
  }, {
    id: "eta-monitoring",
    title: "ETA Monitoring",
    desc: "Get notified when a shipment's estimated arrival changes so you can adjust plans immediately",
    icon: "clock",
    href: "/api-docs/webhooks/use-cases/eta-monitoring",
    detailLabel: "Key Events",
    detailPoints: ["Alert when ETA shifts by more than your threshold", "Track both port of discharge and inland destination ETAs"],
    events: ["shipment.estimated.arrival", "container.transport.estimated.arrived_at_inland_destination"]
  }, {
    id: "lfd-alerts",
    title: "LFD & Availability",
    desc: "Monitor Last Free Day changes and container holds to dispatch pickups before demurrage or per diem",
    icon: "calendar-check",
    href: "/api-docs/webhooks/use-cases/lfd-alerts",
    detailLabel: "Key Events",
    detailPoints: ["Get alerted when LFD changes at the terminal or shipping line", "Trigger dispatch when containers clear holds"],
    events: ["container.pickup_lfd.changed", "container.transport.available"]
  }, {
    id: "milestone-tracking",
    title: "Milestone Tracking",
    desc: "Build a container journey timeline from empty-out at origin to empty-return at destination",
    icon: "timeline-arrow",
    href: "/api-docs/webhooks/use-cases/milestone-tracking",
    detailLabel: "Key Events",
    detailPoints: ["Origin, transshipment, destination, and rail milestones", "Measure transit times and dwell times automatically"],
    events: ["container.transport.vessel_departed", "container.transport.vessel_arrived", "container.transport.full_out"]
  }]
}, {
  id: "data",
  label: "Data Integration",
  items: [{
    id: "datasync",
    title: "DataSync",
    desc: "Deliver fresh tracking data directly into your warehouse, database, or spreadsheet — no code required",
    icon: "database",
    href: "/datasync/overview",
    detailLabel: "Supported Destinations",
    detailPoints: ["Snowflake, BigQuery, PostgreSQL, Google Sheets, and more", "Automatic syncing — no data pipeline to build or maintain", "Pre-built table schemas for shipments, containers, and events"]
  }, {
    id: "typescript-sdk",
    title: "TypeScript SDK",
    desc: "Type-safe client for Node.js with built-in pagination, filtering, and error handling",
    icon: "rectangle-terminal",
    href: "/sdk/introduction",
    detailLabel: "Features",
    detailPoints: ["Full TypeScript types for all API resources", "Built-in retry logic and pagination helpers", "Install with npm — get started in 5 lines of code"]
  }, {
    id: "mcp-server",
    title: "MCP Server",
    desc: "Connect Terminal49 to Claude, Cursor, or any MCP-compatible AI assistant",
    icon: "plug",
    href: "/mcp/home",
    detailLabel: "How It Works",
    detailPoints: ["Install the MCP server and connect to your AI tool", "Ask natural language questions about your shipments", "Get live tracking data back in the conversation"]
  }, {
    id: "api-reference",
    title: "API Reference",
    desc: "Complete endpoint documentation for tracking requests, shipments, containers, and more",
    icon: "code",
    href: "/api-docs/api-reference/introduction",
    detailLabel: "Includes",
    detailPoints: ["JSON:API compliant REST endpoints", "Tracking requests, shipments, containers, webhooks", "Documents, custom fields, vessels, ports, parties"]
  }]
}, {
  id: "embeds",
  label: "Embeds & Widgets",
  items: [{
    id: "map-embed",
    title: "Map Embed",
    desc: "Embed an interactive vessel tracking map into your application with a single snippet",
    icon: "map-location-dot",
    href: "/api-docs/in-depth-guides/terminal49-map",
    detailLabel: "Capabilities",
    detailPoints: ["Real-time vessel positions and route visualization", "Embed with a single code snippet", "Shows ETAs and port call sequences for your shipments"]
  }, {
    id: "widget-embed",
    title: "Tracking Widget",
    desc: "Drop a shipment tracking widget into any web page for customer-facing visibility",
    icon: "window-restore",
    href: "/api-docs/in-depth-guides/terminal49-widget",
    detailLabel: "Capabilities",
    detailPoints: ["Show shipment status, milestones, and ETAs", "Customize the look and feel to match your brand", "Embed in customer portals, internal tools, or websites"]
  }, {
    id: "deep-links",
    title: "Dashboard Deep Links",
    desc: "Link directly to shipments and containers in the Terminal49 dashboard",
    icon: "arrow-up-right-from-square",
    href: "/api-docs/in-depth-guides/dashboard-deep-linking",
    detailLabel: "Use Cases",
    detailPoints: ["Link from internal tools, Slack alerts, or emails", "Open specific shipments or containers in one click", "No authentication flow — links work for logged-in users"]
  }, {
    id: "routing",
    title: "Route Data",
    desc: "Access vessel and container route data including port sequences and voyage details",
    icon: "route",
    href: "/api-docs/in-depth-guides/routing",
    detailLabel: "What You Get",
    detailPoints: ["Full route with every port call, vessel, and voyage number", "GeoJSON endpoints for map rendering", "Vessel future positions with coordinates"]
  }]
}];

export const ProductTiles = ({categories, hideButtons = false}) => {
  const [activeCategory, setActiveCategory] = useState(categories[0].id);
  const [activeSubTab, setActiveSubTab] = useState(categories[0].items[0]?.id ?? null);
  const currentCategory = categories.find(cat => cat.id === activeCategory);
  const currentSub = currentCategory?.items.find(item => item.id === activeSubTab);
  return <div className="not-prose space-y-6">
      {!hideButtons && <div className="flex flex-wrap gap-2">
          {categories.map(cat => <button key={cat.id} onClick={() => {
    setActiveCategory(cat.id);
    setActiveSubTab(cat.items[0]?.id ?? null);
  }} className={`px-4 py-2 text-sm rounded-full font-medium transition-colors ${activeCategory === cat.id ? 'bg-[#0A0B0D] text-white dark:bg-white dark:text-[#0A0B0D]' : 'bg-gray-100 dark:bg-white/10 text-black dark:text-white'}`}>
              {cat.label}
            </button>)}
        </div>}

      <div>
        {currentCategory?.items?.length ? <div className="flex flex-col lg:flex-row gap-6 bg-gray-50 dark:bg-[#141414] rounded-2xl">
            <div className="flex flex-col w-full lg:w-1/2 space-y-1 p-4">
              {currentCategory.items.map(item => <a key={item.id} href={item.href} onMouseOver={() => setActiveSubTab(item.id)} className={`flex items-start gap-3 text-left px-5 py-4 rounded-2xl transition-all no-underline ${activeSubTab === item.id ? 'bg-white dark:bg-white/5 shadow-sm' : 'hover:bg-white/50 dark:hover:bg-white/[0.02]'}`}>
                  <div className="mt-0.5 min-w-[28px] flex items-center justify-center">
                    <Icon icon={item.icon} size={18} className={activeSubTab === item.id ? 'text-primary' : 'text-gray-400 dark:text-gray-500'} />
                  </div>
                  <div className="flex-1">
                    <h3 className="font-medium text-[15px] text-black dark:text-white m-0 flex items-center gap-2">
                      {item.title}
                      {item.badge && <span className="text-[10px] font-semibold uppercase tracking-wider px-1.5 py-0.5 rounded-full bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400">{item.badge}</span>}
                    </h3>
                    <p className="text-sm text-gray-500 dark:text-gray-400 m-0 mt-1 leading-snug">
                      {item.desc}
                    </p>
                  </div>
                  <div className={`flex items-center justify-center min-w-[20px] self-center transition-opacity ${activeSubTab === item.id ? 'opacity-100' : 'opacity-0'}`}>
                    <div className="hidden dark:block">
                      <Icon icon="chevron-right" size="12" color="#FFF" />
                    </div>
                    <div className="block dark:hidden">
                      <Icon icon="chevron-right" size="12" color="#0A0B0D" />
                    </div>
                  </div>
                </a>)}
            </div>
            <div className="w-full lg:w-1/2 rounded-2xl flex items-stretch overflow-hidden min-h-[380px] p-4 pl-0">
              {currentSub && <div className="w-full bg-white dark:bg-white/5 rounded-xl p-8 flex flex-col">
                  <div className="flex items-center gap-4 mb-6">
                    <div className="w-12 h-12 rounded-xl bg-primary/10 dark:bg-primary/20 flex items-center justify-center">
                      <Icon icon={currentSub.icon} size={22} className="text-primary dark:text-primary-light" />
                    </div>
                    <span className="text-sm font-semibold tracking-wide uppercase text-primary dark:text-primary-light">
                      {currentSub.detailLabel}
                    </span>
                  </div>
                  {currentSub.detailPoints && <ul className="space-y-4 mb-5 flex-1">
                      {currentSub.detailPoints.map((point, i) => <li key={i} className="flex items-start gap-3 text-[15px] text-gray-700 dark:text-gray-300 leading-relaxed">
                          <div className="mt-1 min-w-[18px]">
                            <Icon icon="check" size={13} className="text-primary dark:text-primary-light" />
                          </div>
                          <span>{point}</span>
                        </li>)}
                    </ul>}
                  {currentSub.events && <div className="pt-4 border-t border-gray-100 dark:border-white/10">
                      <p className="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-3 m-0">Events</p>
                      <div className="flex flex-wrap gap-2">
                        {currentSub.events.map((evt, i) => <code key={i} className="text-xs bg-gray-50 dark:bg-white/10 border border-gray-200 dark:border-white/10 px-2.5 py-1 rounded-md text-gray-700 dark:text-gray-300 font-mono">{evt}</code>)}
                      </div>
                    </div>}
                  <div className="mt-auto pt-5">
                    <a href={currentSub.href} className="inline-flex items-center gap-2 text-[15px] font-semibold text-primary dark:text-primary-light hover:underline no-underline">
                      Learn more
                      <Icon icon="arrow-right" size={13} />
                    </a>
                  </div>
                </div>}
            </div>
          </div> : <p className="text-sm text-gray-500 dark:text-gray-400">
            No features available for this category.
          </p>}
      </div>
    </div>;
};

export const Title = ({children}) => {
  return <div className="text-gray-900 dark:text-gray-200 text-2xl tracking-tight">
      {children}
    </div>;
};

export const Container = ({children}) => {
  return <div className="px-4 lg:px-10 py-14">
      {children}
    </div>;
};

<div className="px-5 divide-y divide-gray-100 dark:divide-white/10">
  <Container>
    <div className="w-full flex flex-col">
      <div className="flex flex-col items-start justify-center w-full max-w-4xl text-left">
        <div className="text-gray-900 dark:text-gray-200 text-4xl tracking-tight">
          Terminal49 Developer Docs
        </div>

        <p className="text-md text-gray-600 dark:text-gray-400 text-left mt-3 mb-4">
          Automated container tracking from empty-out at origin to empty-return at destination. 100+ integrations covering over 98% of global container volume.
        </p>

        <div className="flex flex-row gap-4 mt-5">
          <a href="/api-docs/getting-started/start-here">
            <button type="button" className="px-5 flex items-center font-medium text-sm rounded-full py-2 shadow-sm text-white dark:text-gray-900 bg-primary-dark dark:bg-primary-light hover:opacity-[0.9] hover:bg-primary justify-center">
              Get started

              <svg
                className="size-3 ml-2 bg-white dark:bg-gray-900"
                style={{
              maskImage: 'url("https://mintlify.b-cdn.net/solid/arrow-right-long.svg")',
              maskRepeat: 'no-repeat',
              maskPosition: 'center center'
            }}
              />
            </button>
          </a>
        </div>
      </div>
    </div>
  </Container>

  <Container>
    <div className="flex flex-col w-full mb-8">
      <Title>
        Build with Terminal49
      </Title>

      <p className="text-[#5B616E] dark:text-gray-300 text-md mb-1 mt-3">
        Track shipments by Bill of Lading, container number, or booking. Integrate data from ocean carriers, rail terminals, port terminals, and vessel positions into a single stream.
      </p>
    </div>

    <ProductTiles categories={appCategories} />
  </Container>

  <Container>
    <div className="flex flex-col w-full mb-8">
      <Title>
        Data Sources & Capabilities
      </Title>

      <p className="text-[#5B616E] dark:text-gray-300 text-md mb-1 mt-3">
        Integrated data from ocean carriers, port terminals, rail providers, and vessel positions — normalized into a single stream for every container.
      </p>
    </div>

    <ProductTiles categories={capabilityCategories} />
  </Container>
</div>
