> ## 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.

# DPDLocal on Vortex IQ

> Monitor DPDLocal 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 DPDLocal 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=dpdlocal)

<CapabilityPage data={{"name": "DPDLocal", "reads": 6, "writes": 3, "stats": [["51", "performance signals"], ["8", "automated checks"], ["0", "prepared fixes"], ["0", "proven workflows"], ["9", "API operations"]], "resRows": [{"n": "shippingclaims", "r": 1, "w": 1}, {"n": "shippingcollections", "r": 1, "w": 1}, {"n": "shippingshipments", "r": 1, "w": 1}, {"n": "shippingservices", "r": 1, "w": 0}, {"n": "shippingtrackings", "r": 1, "w": 0}, {"n": "users", "r": 1, "w": 0}], "opsPhrase": "over 13,000", "connPhrase": "more than 200", "monitor": [{"n": "3PL vs Carrier Delay Attribution", "o": "Protect revenue", "a": "Merchant rule", "d": "For every late shipment - was the delay at the warehouse (ShipBob picked late) or on the carrier (DPDLocal in transit)? Hero.", "nc": false}, {"n": "Carrier OTD by Sales Channel", "o": "Protect revenue", "a": "95 / 90", "d": "Joins shipment timing to commerce-sibling orders by order_ref - which sales channel is suffering most from carrier delays. Hero.", "nc": false}, {"n": "Late-Delivery Revenue at Risk", "o": "Protect revenue", "a": "Merchant rule", "d": "Estimated revenue exposed to refund / chargeback / churn from late deliveries this week. Hero - the finance-CFO wake-up call.", "nc": false}, {"n": "Open Claims Without Jira Ticket", "o": "Protect revenue", "a": "Merchant rule", "d": "Open DPDLocal claims that don't have a corresponding Jira ticket - direct CS coverage gap. Each row = a customer waiting and nobody is on it.", "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": "Ageing Claim Watchlist", "o": "Run operations", "a": "Merchant rule", "d": "Open claims ageing past 7 days, sorted by value. Each row is cash trapped + a customer not chased.", "nc": false}, {"n": "Claim Resolution Time (median days)", "o": "Run operations", "a": "Merchant rule", "d": "Median days from claim opened to settled / denied. Above 14 days = the carrier is ageing your cash.", "nc": false}, {"n": "Claim Value as % of DPDLocal Revenue", "o": "Protect revenue", "a": "Merchant rule", "d": "Claim value as a fraction of DPDLocal-fulfilled revenue. \u003e2% = the carrier is materially eroding margin; carrier-renegotiation trigger.", "nc": false}, {"n": "Collections Booked", "o": "Run operations", "a": "Watch only", "d": "Trend of collections booked - sets capacity-planning context for the warehouse.", "nc": false}, {"n": "Cost by Service Code", "o": "Catalogue quality", "a": "Watch only", "d": "Spend split by DPDLocal service tier (Predict, NextDay, Sunday, EU, etc.) - feeds finance carrier-mix analysis.", "nc": false}, {"n": "Cost by Zone", "o": "Run operations", "a": "Watch only", "d": "Cost by Zone.", "nc": false}, {"n": "DPDLocal Health Score", "o": "Run operations", "a": "90 / 70", "d": "Composite - OTD x first-attempt x inverse exception x inverse open-claim age. The single number an ops manager checks at 9am Monday.", "nc": false}, {"n": "Delivery Experience Score", "o": "Customer experience", "a": "90 / 70", "d": "Composite from DPD app interactions (rate-your-driver feedback). 5-point scale; below 4.0 = flag the route.", "nc": false}, {"n": "Exception Rate Spike", "o": "Run operations", "a": "0 / 10", "d": "Exception count spike vs trailing 30-day baseline. Catches sudden carrier-side breakdowns (depot fire, weather, IT outage).", "nc": false}, {"n": "Exception Reasons (top 10)", "o": "Run operations", "a": "Watch only", "d": "Top 10 exception reasons by volume - feeds operational triage (refused vs damaged vs missing). Shifts in the mix surface emerging issues.", "nc": false}, {"n": "Failed Pickup Alerts", "o": "Protect revenue", "a": "Merchant rule", "d": "Today's failed collections - each row is a missed-cutoff parcel that will arrive a day late.", "nc": false}, {"n": "Failed Pickup Rate", "o": "Protect revenue", "a": "Merchant rule", "d": "% of scheduled collections where the driver failed to pick up. \u003e3% = the carrier-side relationship is decaying; renegotiate or switch carriers on the route.", "nc": false}, {"n": "GeoSession Auth Risk", "o": "Protect revenue", "a": "30 / 7", "d": "GeoSession JWTs expire ~1h - count of /user/ re-auth failures in the last 24h. Persistent failures signal credential rotation needed.", "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": "Late Shipments by Route", "o": "Customer experience", "a": "Merchant rule", "d": "Top routes by late-count this week - feeds the second 9am-Monday question (which route is dropping the ball).", "nc": false}, {"n": "OTD SLA Breach", "o": "Run operations", "a": "Merchant rule", "d": "Live SLA-breach indicator on the Nerve Centre - immediate ops trigger; archetype hero dpd_otd_rate covers the 30D rollup.", "nc": false}, {"n": "OTD Today", "o": "Run operations", "a": "95 / 90", "d": "Today's on-time delivery rate vs DPDLocal's ~98% contracted SLA. Drives the Monday-9am question; archetype dpd_otd_rate is the canonical hero on the 30D view.", "nc": false}, {"n": "OTD by Route", "o": "Run operations", "a": "Watch only", "d": "OTD by Route.", "nc": false}, {"n": "OTD by UK Region", "o": "Run operations", "a": "95 / 90", "d": "OTD broken down by UK postcode area (London, North-West, Scotland, NI, etc.). Identifies regional carrier weakness.", "nc": false}, {"n": "Open Claim Value", "o": "Run operations", "a": "100 / 1000", "d": "Total monetary value of unsettled claims. Direct cash-flow signal for finance.", "nc": false}, {"n": "Open Claims by Age", "o": "Protect revenue", "a": "Merchant rule", "d": "Histogram of open claims by days-since-opened. Anything in the \u003e14d bin = abandoned cash + customer goodwill at risk.", "nc": false}, {"n": "Parcels In Flight", "o": "Run operations", "a": "Watch only", "d": "Live count of shipments not yet delivered or returned. Sets context for every delay alert.", "nc": false}, {"n": "Predict Slot Accuracy (30-min / 1-hour)", "o": "Customer experience", "a": "90 / 75", "d": "DPD's flagship 'Predict' promise - did the parcel arrive in the customer-notified 30-min / 1-hour window? Below 92% means the brand promise is breaking.", "nc": false}, {"n": "Premium-Service Uplift vs Standard", "o": "Run operations", "a": "Merchant rule", "d": "Marginal cost of paying for Predict / Sunday / EU vs standard NextDay. \u003e40% uplift may not be justified by the OTD lift; finance trigger.", "nc": false}, {"n": "Route Degradation Alerts", "o": "Run operations", "a": "Merchant rule", "d": "UK postcode-area routes whose OTD dropped \u003e5 percentage points week-over-week. Early warning of carrier-side regional issues.", "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": "Shipments by Service Code", "o": "Run operations", "a": "Watch only", "d": "How merchant volume splits across DPDLocal service codes (NextDay, Predict, Sunday, EU). Drives carrier negotiation when imbalance emerges.", "nc": false}, {"n": "Sunday Delivery Success Rate", "o": "Protect revenue", "a": "95 / 85", "d": "Sunday delivery is a paid premium - misses double-hurt (refund + customer trust).", "nc": false}, {"n": "UK Postcode Delivery Heatmap", "o": "Run operations", "a": "Watch only", "d": "UK choropleth (postcode-area level) of shipment volume + median transit time. Surfaces hard-to-serve regions (Highlands, NI, IoM).", "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": "Candidate remediation", "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": "Candidate remediation", "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}} />
