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

# NetDispatch on Vortex IQ

> Monitor NetDispatch delivery performance, SLA risk and cost per order, and catch carrier problems before customers feel them.

export const CapabilityPage = ({data}) => {
  const d = data || ({});
  const [tab, setTab] = useState('overview');
  const [sel, setSel] = useState(null);
  const [q, setQ] = useState('');
  const [outcome, setOutcome] = useState('');
  const [status, setStatus] = useState('');
  const [limit, setLimit] = useState(8);
  const monitor = d.monitor || [];
  const audits = d.audits || [];
  const autos = d.autos || [];
  const outcomes = useMemo(() => {
    const s = new Set();
    monitor.forEach(m => s.add(m.o));
    audits.forEach(a => s.add(a.o));
    return [...s].sort();
  }, [monitor, audits]);
  const rows = useMemo(() => {
    const t = q.trim().toLowerCase();
    if (tab === 'monitor') {
      return monitor.filter(m => (!t || (m.n + ' ' + (m.d || '')).toLowerCase().includes(t)) && (!outcome || m.o === outcome));
    }
    if (tab === 'audit') {
      return audits.filter(a => (!t || (a.n + ' ' + (a.why || '')).toLowerCase().includes(t)) && (!outcome || a.o === outcome) && (!status || a.s === status));
    }
    if (tab === 'automate') {
      return autos.filter(w => !t || (w.n + ' ' + (w.d || '')).toLowerCase().includes(t));
    }
    return [];
  }, [tab, q, outcome, status, monitor, audits, autos]);
  const pill = (text, kind) => {
    const tone = kind === 'good' ? {
      color: '#1f9e54',
      borderColor: '#1f9e54',
      background: '#ecf8f110'
    } : kind === 'warn' ? {
      color: '#c07a17',
      borderColor: '#c07a17',
      background: '#fdf6e910'
    } : kind === 'bad' ? {
      color: '#c53527',
      borderColor: '#c53527',
      background: '#fdf0ee10'
    } : kind === 'brand' ? {
      color: '#5529d6',
      borderColor: '#5529d6'
    } : {
      color: 'inherit',
      borderColor: 'currentColor',
      opacity: 0.65
    };
    return <span key={text} style={{
      fontSize: '10.5px',
      fontFamily: 'ui-monospace, monospace',
      border: '1px solid',
      borderRadius: '999px',
      padding: '2px 8px',
      whiteSpace: 'nowrap',
      ...tone
    }}>
        {text}
      </span>;
  };
  const sevKind = s => s === 'critical' ? 'bad' : s === 'high' ? 'warn' : 'muted';
  const fixKind = s => s === 'Prepared fix' ? 'good' : s === 'Candidate remediation' ? 'warn' : 'muted';
  const card = (item, kind) => {
    const title = item.n;
    const badges = kind === 'monitor' ? [pill(item.o, 'brand'), pill(item.a === 'Watch only' || item.a === 'Merchant rule' ? item.a : `Alert ${item.a}`, 'muted')] : kind === 'audit' ? [pill(item.sev, sevKind(item.sev)), pill(item.s, fixKind(item.s))] : [pill(item.role, 'brand'), pill(item.ready, 'good')];
    const body = kind === 'monitor' ? item.nc ? 'Description pending editorial review; the signal is live.' : item.d : kind === 'audit' ? item.why : item.d;
    return <button key={title} onClick={() => setSel({
      kind,
      item
    })} style={{
      display: 'block',
      width: '100%',
      textAlign: 'left',
      border: '1px solid rgba(128,128,128,.28)',
      borderRadius: '10px',
      padding: '12px 14px',
      marginBottom: '8px',
      background: 'transparent',
      cursor: 'pointer',
      font: 'inherit',
      color: 'inherit'
    }}>
        <div style={{
      display: 'flex',
      gap: '10px',
      justifyContent: 'space-between',
      alignItems: 'flex-start',
      flexWrap: 'wrap'
    }}>
          <strong style={{
      fontSize: '14px'
    }}>{title}</strong>
          <span style={{
      display: 'flex',
      gap: '5px',
      flexWrap: 'wrap'
    }}>{badges}</span>
        </div>
        {body ? <div style={{
      fontSize: '12.5px',
      opacity: 0.72,
      marginTop: '4px'
    }}>{body}</div> : null}
      </button>;
  };
  const tabBtn = (id, label) => <button key={id} onClick={() => {
    setTab(id);
    setLimit(8);
    setQ('');
  }} style={{
    border: 0,
    background: 'none',
    font: 'inherit',
    fontWeight: 600,
    fontSize: '14px',
    padding: '9px 14px',
    cursor: 'pointer',
    color: tab === id ? '#5529d6' : 'inherit',
    opacity: tab === id ? 1 : 0.65,
    borderBottom: tab === id ? '2px solid #5529d6' : '2px solid transparent'
  }}>
      {label}
    </button>;
  const inputStyle = {
    border: '1px solid rgba(128,128,128,.3)',
    borderRadius: '999px',
    padding: '7px 13px',
    font: 'inherit',
    fontSize: '13px',
    background: 'transparent',
    color: 'inherit'
  };
  return <div style={{
    position: 'relative'
  }}>
      {}
      <div style={{
    display: 'grid',
    gridTemplateColumns: 'repeat(auto-fit,minmax(120px,1fr))',
    gap: '10px',
    margin: '18px 0'
  }}>
        {(d.stats || []).map(([v, l]) => <div key={l} style={{
    border: '1px solid rgba(128,128,128,.28)',
    borderRadius: '10px',
    padding: '11px 13px'
  }}>
            <div style={{
    fontSize: v.length > 6 ? '15px' : '21px',
    fontWeight: 700,
    letterSpacing: '-.02em',
    color: v.length > 6 ? '#5529d6' : 'inherit'
  }}>{v}</div>
            <div style={{
    fontSize: '11px',
    opacity: 0.66
  }}>{l}</div>
          </div>)}
      </div>

      <div style={{
    display: 'flex',
    gap: '4px',
    borderBottom: '1px solid rgba(128,128,128,.25)',
    marginBottom: '16px',
    flexWrap: 'wrap'
  }}>
        {tabBtn('overview', 'Overview')}
        {tabBtn('monitor', `Monitor (${monitor.length})`)}
        {tabBtn('audit', `Audit (${audits.length})`)}
        {tabBtn('automate', 'Automate')}
      </div>

      {tab === 'overview' && <div>
          <div style={{
    display: 'grid',
    gridTemplateColumns: 'repeat(auto-fit,minmax(240px,1fr))',
    gap: '10px'
  }}>
            {outcomes.map(o => <div key={o} style={{
    border: '1px solid rgba(128,128,128,.28)',
    borderLeft: '3px solid #5529d6',
    borderRadius: '10px',
    padding: '11px 14px'
  }}>
                <strong style={{
    fontSize: '13.5px'
  }}>{o}</strong>
              </div>)}
          </div>
          <p style={{
    fontSize: '13px',
    opacity: 0.75,
    marginTop: '16px'
  }}>
            Every capability follows the same controlled sequence: connect, monitor, detect, recommend,
            approve, execute, verify. Nothing changes a connected system without the approval step.
          </p>
        </div>}

      {tab !== 'overview' && <div>
          <div style={{
    display: 'flex',
    gap: '8px',
    marginBottom: '12px',
    flexWrap: 'wrap'
  }}>
            <input style={{
    ...inputStyle,
    flex: 1,
    minWidth: '170px'
  }} placeholder={`Search ${tab === 'monitor' ? 'signals' : tab === 'audit' ? 'checks' : 'workflows'}...`} value={q} onChange={e => {
    setQ(e.target.value);
    setLimit(8);
  }} />
            {tab !== 'automate' && <select style={inputStyle} value={outcome} onChange={e => {
    setOutcome(e.target.value);
    setLimit(8);
  }}>
                <option value="">All outcomes</option>
                {outcomes.map(o => <option key={o} value={o}>{o}</option>)}
              </select>}
            {tab === 'audit' && <select style={inputStyle} value={status} onChange={e => {
    setStatus(e.target.value);
    setLimit(8);
  }}>
                <option value="">All fix statuses</option>
                <option>Prepared fix</option>
                <option>Candidate remediation</option>
                <option>Report only</option>
              </select>}
          </div>

          {rows.length === 0 && tab === 'automate' && <div style={{
    border: '1px dashed #5529d6',
    borderRadius: '10px',
    padding: '15px'
  }}>
              <strong style={{
    fontSize: '14px'
  }}>Ready to build your first {d.name} workflow</strong>
              <p style={{
    fontSize: '12.5px',
    opacity: 0.75,
    margin: '6px 0 0'
  }}>
                Vortex IQ is integrated with {d.reads} read and {d.writes} write operations on {d.name}.
                Pick a trigger, add them as steps, and every step that changes data pauses for approval.
              </p>
            </div>}
          {rows.length === 0 && tab !== 'automate' && <div style={{
    opacity: 0.6,
    fontSize: '13px'
  }}>Nothing matches this search or filter.</div>}

          {rows.slice(0, limit).map(r => card(r, tab))}

          {rows.length > limit && <button onClick={() => setLimit(rows.length)} style={{
    ...inputStyle,
    display: 'block',
    margin: '10px auto 0',
    cursor: 'pointer'
  }}>
              View all {rows.length}
            </button>}
        </div>}

      {}
      {sel && <>
          <div onClick={() => setSel(null)} style={{
    position: 'fixed',
    inset: 0,
    background: 'rgba(10,6,26,.45)',
    zIndex: 40
  }} />
          <aside style={{
    position: 'fixed',
    top: 0,
    right: 0,
    width: 'min(430px, 94vw)',
    height: '100vh',
    overflowY: 'auto',
    background: 'var(--background, #fff)',
    backgroundColor: 'light-dark(#fff, #0c061f)',
    borderLeft: '1px solid rgba(128,128,128,.3)',
    padding: '20px 22px',
    zIndex: 50
  }}>
            <button onClick={() => setSel(null)} style={{
    float: 'right',
    border: '1px solid rgba(128,128,128,.3)',
    background: 'transparent',
    color: 'inherit',
    borderRadius: '999px',
    width: '30px',
    height: '30px',
    cursor: 'pointer'
  }}>
              ×
            </button>
            <DetailBody sel={sel} d={d} pill={pill} sevKind={sevKind} fixKind={fixKind} />
          </aside>
        </>}
    </div>;
};

Monitor NetDispatch delivery performance, SLA risk and cost per order, and catch carrier problems before customers feel them.

No changes are made without the configured approval policy. Read-only operations do not modify the connected system; schedules, access scopes, API usage and data handling remain governed by Vortex IQ controls.

[Connect or manage this source](https://app.vortexiq.ai/workbench/settings/sources) · [How connecting works](/integrations/connector-catalogue) · [Create a workflow](https://app.vortexiq.ai/workbench/flows/create?connector=net-dispatch)

<CapabilityPage data={{"name": "NetDispatch", "reads": 2, "writes": 0, "stats": [["24", "performance signals"], ["8", "automated checks"], ["0", "prepared fixes"], ["0", "proven workflows"], ["2", "API operations"]], "resRows": [{"n": "tbds", "r": 2, "w": 0}], "opsPhrase": "over 13,000", "connPhrase": "more than 200", "monitor": [{"n": "Dispatch-to-Collection Lag", "o": "Run operations", "a": "Merchant rule", "d": "Hours from NetDispatch dispatch event to carrier-side collection scan. The core NetDispatch SLA - \u003e24h lag means warehouse cutoff missed or carrier-side delay.", "nc": false}, {"n": "NetDispatch OTD by Sales Channel", "o": "Protect revenue", "a": "95 / 90", "d": "Per-channel NetDispatch OTD.", "nc": false}, {"n": "Avg Shipping Cost", "o": "Run operations", "a": "Merchant rule", "d": "Avg Shipping Cost for the selected period.", "nc": true}, {"n": "Days to Token Expiry", "o": "Run operations", "a": "Watch only", "d": "Days to Token Expiry for the selected period.", "nc": true}, {"n": "Exception Rate", "o": "Run operations", "a": "2 / 5", "d": "Exception Rate for the selected period.", "nc": true}, {"n": "Late Shipments", "o": "Customer experience", "a": "Watch only", "d": "Late Shipments for the selected period.", "nc": true}, {"n": "On-Time Delivery Rate", "o": "Customer experience", "a": "95 / 90", "d": "On-Time Delivery Rate for the selected period.", "nc": true}, {"n": "Open Claims", "o": "Run operations", "a": "Watch only", "d": "Open Claims for the selected period.", "nc": true}, {"n": "Cost by Zone", "o": "Run operations", "a": "Watch only", "d": "Cost by Zone.", "nc": false}, {"n": "High-Cost Shipment Outliers", "o": "Run operations", "a": "Watch only", "d": "High-Cost Shipment Outliers, broken down by row.", "nc": false}, {"n": "OTD by Route", "o": "Run operations", "a": "Watch only", "d": "OTD by Route.", "nc": false}, {"n": "Route Volume Concentration", "o": "Run operations", "a": "Merchant rule", "d": "Route Volume Concentration, compared across items.", "nc": false}, {"n": "Shipments by Service", "o": "Run operations", "a": "Watch only", "d": "Shipments by Service.", "nc": false}, {"n": "API Error Rate", "o": "Run operations", "a": "Watch only", "d": "API Error Rate for the selected period.", "nc": true}, {"n": "Avg Transit (days)", "o": "Customer experience", "a": "Watch only", "d": "Avg Transit (days) for the selected period.", "nc": true}, {"n": "Claim Value (open)", "o": "Run operations", "a": "Watch only", "d": "Claim Value (open) for the selected period.", "nc": true}, {"n": "Cost Per Shipment Trend", "o": "Run operations", "a": "Watch only", "d": "Cost Per Shipment Trend for the selected period.", "nc": true}, {"n": "Failed Deliveries", "o": "Protect revenue", "a": "Merchant rule", "d": "Failed Deliveries for the selected period.", "nc": true}, {"n": "First-Attempt Delivery Rate", "o": "Customer experience", "a": "Watch only", "d": "First-Attempt Delivery Rate for the selected period.", "nc": true}, {"n": "Label Generation Success", "o": "Run operations", "a": "Watch only", "d": "Label Generation Success for the selected period.", "nc": true}, {"n": "Returned to Sender", "o": "Run operations", "a": "Watch only", "d": "Returned to Sender for the selected period.", "nc": true}, {"n": "Shipments", "o": "Run operations", "a": "Merchant rule", "d": "Shipments for the selected period.", "nc": true}, {"n": "Shipments Over Time", "o": "Run operations", "a": "Watch only", "d": "Shipments Over Time for the selected period.", "nc": true}, {"n": "Shipments by Destination", "o": "Run operations", "a": "Watch only", "d": "Shipments by Destination for the selected period.", "nc": true}], "audits": [{"n": "API token expired or about to expire (\u003c14 days)", "o": "Run operations", "sev": "critical", "s": "Report only", "why": "Once this token expires, VortexIQ stops receiving tracking and delivery data from this carrier entirely, and every finding in this report that depends on courier data goes stale from that moment, silently, until someone notices shipments look wrong.", "codes": ["COURIER-AUTH-001"]}, {"n": "Exception rate above 3%", "o": "Protect revenue", "sev": "high", "s": "Report only", "why": "More than 3% of shipments with this carrier are hitting an exception, a failed delivery attempt, damage, an address problem, a lost parcel, each of which usually turns into a support ticket and, often, a refund or reshipment cost the store absorbs.", "codes": ["COURIER-EXCEPTION-001"]}, {"n": "On-time delivery rate below 90%", "o": "Protect revenue", "sev": "high", "s": "Report only", "why": "More than 1 in 10 shipments with this carrier is arriving late. Late delivery is one of the most common drivers of customer support contacts, refund requests and negative reviews, and it lands on the store's reputation even though the carrier caused it.", "codes": ["COURIER-OTD-001"]}, {"n": "Open claims unresolved \u003e 7 days", "o": "Run operations", "sev": "high", "s": "Report only", "why": "Courier claims open beyond 7 days are money owed sitting unclaimed; carriers rely on claimants giving up.", "codes": ["COURIER-CLAIM-001"]}, {"n": "Avg cost per shipment up \u003e 10% vs prior period", "o": "Run operations", "sev": "medium", "s": "Report only", "why": "Average cost per shipment with this carrier rose more than 10% compared to the prior period. Shipping is rarely re-priced into the product on the same timeline it changes, so a jump this size quietly erodes margin on every order this carrier touches until pricing or carrier choice is revisited.", "codes": ["COURIER-COST-001"]}, {"n": "Failed-delivery rate above 2%", "o": "Protect revenue", "sev": "medium", "s": "Report only", "why": "Failed deliveries above 2 percent create support contacts, redelivery costs and refunds; address validation and carrier choice are the usual levers.", "codes": ["COURIER-FAIL-001"]}, {"n": "OTD trending down \u003e5pp WoW", "o": "Run operations", "sev": "medium", "s": "Report only", "why": "On-time delivery dropped more than 5 percentage points in a single week. A move this fast usually has a specific, recent cause (a service disruption, a capacity issue at the carrier, a seasonal volume spike), which is worth catching now, before it settles into a new, worse normal that customers star", "codes": ["COURIER-OTD-002"]}, {"n": "Single-carrier dependency on a route (\u003e80% volume)", "o": "Run operations", "sev": "medium", "s": "Report only", "why": "Over 80% of shipping volume on one route runs through a single carrier. If that carrier has an outage, a rate hike, or a capacity problem on that route, there is no fallback already in place, and the store finds out at the worst possible time, mid-disruption, rather than in advance.", "codes": ["COURIER-DEPENDENCY-001"]}], "autos": [], "inValidation": 0}} />
