Monitoring AI Check Calls: Wrong ETAs and Load Numbers

On this page
A check call looks simple. The agent asks the driver where they are, when they'll arrive, and whether anything is wrong. It writes the answers into the TMS. A tracking update goes to the shipper minutes later.
That last step is the problem. Nobody hears the call except the driver. A wrong load number puts the update on someone else's freight. A "3 PM" in the wrong time zone sets a dock plan around an impossible arrival. No exception is raised.
This post is for product and engineering teams running AI check calls trucking fleets and brokers depend on. It is a narrow companion to our complete QA guide for freight voice agents, which covers pre-launch testing. This one covers live calls, field by field.
What an AI check call writes into the TMS
Check call: a short status call between a carrier or broker and a driver during a load. It captures where the truck is, when it will arrive, and anything that changes the plan.
Dispatchers once made these calls by hand, dozens a shift. AI check call software now places them, or answers when drivers call in. Behind the voice sits a workflow: capture, a TMS write, a tracking event, and sometimes a detention bill.
Each driver check call produces four fields. Each field has its own way of breaking.
| Field | What the driver says | What the TMS needs | Who reads it downstream |
|---|---|---|---|
| Location | "Just past the Flying J at mile marker 142" | City, state, lat/long, timestamp | Shipper tracking page, ETA model |
| ETA | "Tomorrow morning, probably by six" | Absolute time with time zone | Receiver dock schedule, late alerts |
| Load reference | "Four four seven one oh nine three" | Exact load, PRO number or bill of lading | Which shipment the update attaches to |
| Exception | "Been sitting here since six" | Coded reason, start time, value | Detention billing, claims, escalations |

A wrong field rarely crashes anything. The TMS accepts a valid-looking string. That is why load tracking calls need monitoring on the values, not just the call outcome. Our guide to silent tool failures covers the general pattern.
How each field gets misheard or mis-resolved
Location
Drivers rarely give an address. They give landmarks, exits and mile markers. "Just past the Flying J" needs a geocoder and a route to resolve. There are many truck stops with that name. Without the route, the geocoder picks the most popular one. That might be 100 miles away.
Mile markers have their own trap. They restart at each state line. "Mile marker 142 on I-80" exists in several states. The agent must attach a state, or ask for one.
Speech errors make this worse. "Fifteen" and "fifty" differ by a short unstressed ending. "Exit 40" and "exit 14" sound close on a noisy line.
ETA
ETA is the field that breaks most quietly. It is a relative time expression that the agent has to turn into an absolute timestamp.
"Tomorrow morning" needs an anchor date and a guess at what "morning" means. "By six" needs AM or PM. Most of all, it needs a time zone. A driver in Gary, Indiana, is on Central time. A receiver in Columbus, Ohio, is on Eastern. "I'll be there by three" could mean either. Arizona mostly skips daylight saving time, so its offset to the rest of the country moves twice a year.
There's also a meaning gap. Drivers often answer with their appointment time, not their predicted arrival. "My appointment's at eight" is not an ETA. If the agent writes 8:00 as the ETA, freight ETA accuracy reports show perfect on-time performance until the truck misses the dock.
NLP researchers have studied this for two decades. The TimeML standard's TIMEX3 tag stores a relative expression like "Monday" as an underspecified value (`XXXX-WXX-1`). It then resolves it against an anchor time, such as when the document was written. In the TempEval-3 shared task, the top English system, HeidelTime, reached 77.61 value F1 on normalization. That was on clean news text. A phone transcript with a missing time zone is harder. The lesson for your agent is simple: store the raw phrase, the anchor and the resolved value as three separate fields. Then you can audit the resolution step later.
Load reference number
Load numbers, PRO numbers and BOL numbers are digit strings with no language model to help. Every digit counts. "Oh" can mean zero or the letter O. "Double seven" is two digits from one word. Drivers carrying multi-stop or team loads may read the wrong one. Some read only the last four digits.
Research on spoken identifiers shows why per-digit accuracy misleads. In the SNuC corpus paper (LREC 2022), a baseline Kaldi model got 96.6% of words right on real factory data. Yet only 77% of full identifiers were correct. That's almost one in four strings with an error. Adapting the model to the domain raised string accuracy to 91.7%. The authors also found that speakers misread about 6% of numbers themselves. Most of those slips went unnoticed by the speaker.
So score load numbers at the string level, never the digit level. The same advice applies to any entity field, as covered in our guide to STT accuracy for names and entities.
Exceptions
Exceptions carry the money. Detention starts a billing clock. A breakdown triggers a recovery plan. A reefer temperature out of range can mean a rejected load.
The common failure is a missed exception, not a wrong one. "Yeah, I've been sitting here a while" may never map to a detention code. "It's running at thirty-four" may get written without a sign or unit. "Minus ten" may lose the minus. A Spanish answer like "voy a llegar tarde" may be transcribed but never tagged as a delay. Each of these leaves the TMS saying "on time, no issues."
Why driver audio is hard for speech recognition
Truck cab audio stacks bad conditions on one call. There's engine idle, highway road noise, wind, a CB radio, and a Bluetooth headset. The headset compresses the voice before the phone network does it again. Word error rate climbs with each layer.
Research on in-vehicle speech backs this up. The ICMC-ASR challenge at ICASSP 2024 released over 100 hours of in-car speech. It was recorded across 60 scenarios that varied road type, speed, air conditioning, music and window opening. The baseline system's character error rate was 26.24%. The winning team cut that to 13.16%. That is a passenger car, not a Class 8 truck, and the speech is Mandarin. Still, even the winning system got more than one character in eight wrong.
OpenAI's Whisper paper found a similar pattern with added noise. Models trained on clean audio did well at 40 dB SNR. All models "quickly degrade as the noise becomes more intensive." Below 10 dB of pub-style noise, Whisper beat every clean-trained model. Pick your STT based on tests at the noise levels your drivers actually call from.
Spanish-speaking drivers add another layer. Many switch between English and Spanish within one answer. They might say numbers in Spanish and street names in English. Test both languages and the mix, as covered in our guide to multilingual accuracy. Our background noise test guide shows how to build an SNR ladder for this.
Cross-checks your system already has data for
The AI check calls trucking fleets run are unusual among voice tasks. You often hold independent truth for the very fields the driver is reporting. Telematics knows where the truck is. The ELD knows how much driving time is left. The TMS knows which loads this driver has. Use them.
Spoken location vs GPS and ELD position
Geocode the spoken location. Compare it to the nearest GPS ping using haversine distance. Flag it if the gap is larger than a tolerance.
Set the tolerance with care. FMCSA's ELD guidance says ELDs record location "at 60-minute intervals when the vehicle is in motion." On-duty location accuracy is "approximately within a 1-mile radius." During personal conveyance it widens to about 10 miles. So an ELD record can be an hour stale. A truck at 60 mph covers 60 miles in that time. Use your telematics feed's live ping where you have it. Grow the tolerance with ping age.
ETA vs distance and hours of service
An ETA must be physically and legally possible. The federal hours-of-service rules set the legal part. Under 49 CFR 395.3, a property-carrying driver:
1. Needs 10 consecutive hours off duty before driving.
2. May not drive after 14 consecutive hours from coming on duty.
3. May drive at most 11 hours in that window.
4. Must take a 30-minute break after 8 hours of driving. The break can be on-duty, not-driving time.
5. Stops driving after 60 hours on duty in 7 days, or 70 hours in 8 days.
The 2020 final rule also lets drivers extend the driving window by up to 2 hours in adverse driving conditions. It also allows split sleeper-berth periods. Treat both as reasons to widen the check, not break it. Short-haul exceptions also exist.
Here is the feasibility test. Take routed miles left and divide by a planning speed. Add a 30-minute break when driving crosses 8 hours. Add a 10-hour reset when the driver runs out of drive time. That gives an earliest legal arrival. If the spoken ETA is earlier than that, the ETA is wrong, the hours data is wrong, or the driver is planning to break the rules. All three deserve a flag.

Load number format and ownership
Each shipper or broker uses its own reference formats. One uses seven digits. Another uses a prefix and six digits. Some include a check digit. Keep a format rule per customer and validate every write. Then do the stronger check: is this load assigned to this driver today? A valid-format number that belongs to another truck is the worst case. It passes the format rule and corrupts two shipments.
Duplicate and stale updates
Retries and drivers calling in twice create duplicates. Flag same-load, same-place updates within 15 minutes. Also flag a location that sits behind the last one on the route.
The check-call field-accuracy monitor
This is a copyable framework. Each field gets an error definition, an automatic check that runs on every call, and an alert threshold. The thresholds are starting points. Tune them on your own baseline, as described in our guide to setting production thresholds.
| Field | Counts as an error when | Automatic check (every call) | Starting alert threshold |
|---|---|---|---|
| Location | Resolved point is outside tolerance of GPS truth, or state is missing | Haversine vs ping, tolerance = 10 mi + speed × ping age | Daily rate above 2× trailing 14-day mean |
| ETA | Earlier than earliest legal arrival, wrong time zone, or appointment written as ETA | HOS feasibility; ETA zone vs receiver zone; ETA equals appointment exactly | Any infeasible ETA on a shipper-visible load |
| Load reference | String differs from truth, or load not assigned to driver | Per-customer regex plus assignment lookup | Any write to an unassigned load |
| Exception | Spoken exception not coded, or coded value wrong (sign, unit, start time) | Keyword and intent scan of transcript vs coded fields; reefer reading vs setpoint | Human sample error rate above baseline (see sampling math) |
| Duplicate | Same load, same place, within 15 min | Dedupe on load ID, time and position | More than 1% of updates |
Two rules make this work. Score at the field level, not the call level. A polite "drive safe" ending can hide three corrupted fields. And keep raw spoken values next to resolved ones, so you can tell a speech error from a resolution error.
Python: scoring a batch of check calls against GPS and HOS truth
This is simplified. It uses a fixed planning speed, ignores the 60/70-hour limits and the sleeper split, and the data is illustrative. It runs as-is on Python 3.9 or later.
# Simplified check-call field-accuracy scorer. Illustrative data only.
import math, re
from dataclasses import dataclass
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
EARTH_MI = 3958.8
def haversine_mi(lat1, lon1, lat2, lon2):
p1, p2 = math.radians(lat1), math.radians(lat2)
dp, dl = p2 - p1, math.radians(lon2 - lon1)
a = math.sin(dp / 2) ** 2 + math.cos(p1) * math.cos(p2) * math.sin(dl / 2) ** 2
return 2 * EARTH_MI * math.asin(math.sqrt(a))
@dataclass
class CheckCall:
call_id: str
load_ref: str # what the agent wrote
customer: str
said_lat: float # geocoded spoken location
said_lon: float
gps_lat: float # telematics ping nearest the call
gps_lon: float
gps_age_min: float # ping age at call time
called_at: datetime # tz-aware
eta: datetime # tz-aware, as written to the TMS
miles_left: float # routed miles from GPS ping to receiver
drive_left_h: float # HOS driving time left (11-hour rule)
window_left_h: float # time left in the 14-hour window
since_break_h: float # driving since last 30-min break
appt: datetime # receiver appointment, facility local time
LOAD_FORMATS = {"acme": r"^\d{7}$", "bolt": r"^BL-\d{6}$"}
PLAN_MPH = 50 # planning speed, illustrative
LOC_TOL_MI = 10 # base tolerance, covers geocoding and ELD-grade fixes
ETA_SLACK_MIN = 30
def earliest_arrival(c: CheckCall) -> datetime:
"""Earliest legal arrival under a simplified 11/14/8-hour model."""
need_h = c.miles_left / PLAN_MPH
t = 0.0
drive_left = min(c.drive_left_h, c.window_left_h)
since_break = c.since_break_h
while need_h > 1e-9:
if drive_left <= 1e-9:
t += 10.0 # 10 consecutive hours off duty
drive_left, since_break = 11.0, 0.0
continue
until_break = 8.0 - since_break
if until_break <= 1e-9:
t += 0.5 # 30-minute interruption
since_break = 0.0
continue
leg = min(need_h, drive_left, until_break)
t += leg; need_h -= leg; drive_left -= leg; since_break += leg
return c.called_at + timedelta(hours=t)
def score(c: CheckCall):
flags = []
dist = haversine_mi(c.said_lat, c.said_lon, c.gps_lat, c.gps_lon)
tol = LOC_TOL_MI + PLAN_MPH * c.gps_age_min / 60
if dist > tol:
flags.append(f"location: {dist:.0f} mi from GPS (tol {tol:.0f})")
earliest = earliest_arrival(c)
if c.eta < earliest - timedelta(minutes=ETA_SLACK_MIN):
flags.append(f"eta: infeasible, earliest legal {earliest:%a %H:%M %Z}")
elif earliest > c.appt and c.eta <= c.appt:
flags.append("eta: on-time ETA but appointment is unreachable")
pat = LOAD_FORMATS.get(c.customer)
if pat and not re.match(pat, c.load_ref):
flags.append(f"load_ref: '{c.load_ref}' fails {c.customer} format")
return dist, earliest, flags
CT, ET = ZoneInfo("America/Chicago"), ZoneInfo("America/New_York")
now = datetime(2026, 10, 15, 13, 0, tzinfo=CT)
calls = [
# Accurate call: Joliet IL, 290 routed miles to Columbus OH.
CheckCall("c1", "4471093", "acme", 41.525, -88.082, 41.530, -88.070, 5,
now, datetime(2026, 10, 15, 20, 45, tzinfo=ET), 290, 7.5, 9.0, 2.0,
datetime(2026, 10, 15, 21, 0, tzinfo=ET)),
# ETA said "by six" and written as 18:00 Central, but HOS forces a reset.
CheckCall("c2", "4471094", "acme", 41.593, -87.346, 41.590, -87.350, 3,
now, datetime(2026, 10, 15, 18, 0, tzinfo=CT), 300, 2.0, 3.0, 6.0,
datetime(2026, 10, 16, 8, 0, tzinfo=ET)),
# Driver said "just past the Flying J"; geocoder picked one in another state.
CheckCall("c3", "BL-209318", "bolt", 39.768, -86.158, 41.080, -85.139, 4,
now, datetime(2026, 10, 15, 19, 30, tzinfo=ET), 160, 8.0, 10.0, 1.0,
datetime(2026, 10, 16, 7, 0, tzinfo=ET)),
# Load number lost a digit ("four four seven one oh nine").
CheckCall("c4", "447109", "acme", 40.440, -86.910, 40.445, -86.900, 10,
now, datetime(2026, 10, 15, 18, 15, tzinfo=ET), 180, 9.0, 11.0, 3.0,
datetime(2026, 10, 15, 21, 0, tzinfo=ET)),
]
for c in calls:
d, e, f = score(c)
print(f"{c.call_id}: {d:6.1f} mi | earliest {e.astimezone(ET):%a %H:%M %Z} | "
+ ("; ".join(f) if f else "OK"))Output:
c1: 0.7 mi | earliest Thu 19:48 EDT | OK
c2: 0.3 mi | earliest Fri 06:00 EDT | eta: infeasible, earliest legal Fri 05:00 CDT
c3: 105.3 mi | earliest Thu 17:12 EDT | location: 105 mi from GPS (tol 13)
c4: 0.6 mi | earliest Thu 17:36 EDT | load_ref: '447109' fails acme formatCall c2 is the classic silent failure. The driver had 2 hours of drive time left and 300 miles to go. The spoken "by six" was written as 6 PM the same day. The earliest legal arrival is 6 AM Eastern the next morning. Call c3 is a landmark resolved to the wrong state. Call c4 dropped one digit. Each of these would have reached the shipper as a clean update.
In production, add the assignment lookup and the dedupe check. Store `earliest` on the record too. If your agent passes these values through tool calls, our guide to tool-argument accuracy from speech covers how to score the arguments themselves.
Sampling math: how many check calls to review each day
Automatic checks cover every one of the AI check calls trucking customers see, but not every error. A missed detention or a reefer reading with the wrong sign needs a human or an audio judge. So you also review a fixed daily sample.
This is a worked example with illustrative numbers. Say your baseline exception-field error rate is 2%. You want to catch a jump to 5% within one day. You want a 5% false-alarm rate and 80% power. The one-sample formula for a proportion is:
n = [z_α · √(p₀(1−p₀)) + z_β · √(p₁(1−p₁))]² / (p₁ − p₀)²
With z_α = 1.645 (one-sided 5%), z_β = 0.842 (80% power), p₀ = 0.02 and p₁ = 0.05, you get n ≈ 191 calls.
The normal approximation is a little optimistic at rates this low. An exact binomial check is better. Review 200 calls and alert at 8 or more errors. The false-alarm rate is then 4.9%, and the chance of catching a true 5% rate is 78.7%.

Catching small jumps takes huge samples. A jump from 2% to 3% needs about 1,400 reviewed calls a day. Two practical moves help:
1. Pool days. Review 200 a day, but test the trailing 7 days for small shifts.
2. Stratify. Sample more from risky slices: Spanish calls, calls with high noise, new customer formats, and calls right after a prompt change.
Our post on sampling live calls for evaluation covers stratified designs in more depth.
How to monitor AI check calls in production
1. Log raw and resolved values. For every field, store the spoken phrase, the resolved value, the anchor time and time zone, and the call recording link. Our guide to monitoring voice agents in production lists the rest of the per-call schema.
2. Join each call to truth. Pull the nearest GPS ping, its age, HOS clocks from the ELD, routed miles left, and the driver's assigned loads.
3. Run the field checks on every call. Use location tolerance, ETA feasibility, time zone match, appointment-as-ETA, load format and assignment, and dedupe.
4. Block or hold risky writes. An infeasible ETA or an unassigned load number should not reach the shipper. Hold it and send it to a dispatcher.
5. Review a fixed daily sample. Use the sampling math above. Score exceptions and Spanish calls from the audio, not only the transcript.
6. Alert on rates, not single calls. Use per-field daily rates against a trailing baseline. Break them out by customer, language and agent version.
7. Turn failures into tests. Every confirmed error becomes a replayable test case before the next prompt change ships. See turning production failures into tests.
Evalgent can carry steps 5 to 7 for teams that don't have an eval function. Teams push their call recordings. Evalgent transcribes them, maps each call to a scenario and judges it from the audio. It flags tool-call failures, latency spikes and policy failures, with fix suggestions. Custom metrics run on every call, so a "load number matches assignment" check can sit next to the built-in ones.
Before a change ships, the same scenarios can be replayed. Evalgent's caller profiles set accent, pace, interruptions, background noise and language, including Spanish. Simulated calls reach the agent over phone, SIP or WebRTC. That covers the cab-noise and code-switching cases above without a driver on the line.
If your agent places outbound calls to drivers, consent rules also apply. The FCC's February 2024 declaratory ruling holds that AI-generated voices are "artificial" under the TCPA. Our outbound voice agent testing guide covers what to test there. This is not legal advice; check with counsel for your use case.
Frequently asked questions
What is an AI check call in trucking?
An AI check call in trucking is a status call between a voice agent and a driver during a load. The agent asks for location, ETA, load reference and any exceptions. It then writes those values into the TMS, which sends tracking updates to the shipper or broker. Agents may place the call or answer when drivers call in.
How accurate are automated check calls?
Automated check call accuracy has no published industry benchmark. It depends on cab noise, the STT model, and how the agent resolves times and landmarks. Research on spoken identifiers found only 77% of full strings correct for a baseline model on real data. Measure your own per-field error rate against GPS, ELD and assignment data.
How do you verify a driver's location on a check call?
Verify a driver's location by geocoding the spoken landmark and comparing it to the nearest GPS ping with haversine distance. Allow for ping age, because FMCSA says ELDs record location every 60 minutes while moving, at about 1-mile accuracy. Flag gaps beyond the tolerance and calls that give a mile marker without a state.
How do you check if a driver's ETA is realistic?
Check an ETA by computing the earliest legal arrival. Divide routed miles left by a planning speed. Then add a 30-minute break after 8 hours of driving and a 10-hour reset when the 11-hour or 14-hour limit runs out. Flag any spoken ETA earlier than that result, and any ETA that exactly matches the appointment time.
Why does AI get load numbers wrong?
AI gets load numbers wrong because digit strings have no context to help recognition. One wrong digit makes the whole string wrong. "Oh" versus zero, "double seven," dropped digits and drivers reading the wrong load all cause errors. Validate each number against the customer's format and confirm the load is assigned to that driver.
How many check calls should you review each day?
The number of check calls to review depends on the jump you need to detect. In an illustrative example, catching a rise from 2% to 5% error rate takes about 200 reviewed calls a day. Alert at 8 or more errors. Catching a rise from 2% to 3% needs about 1,400 calls, so pool days or stratify instead.
Can AI check calls handle Spanish-speaking drivers?
AI check calls can handle Spanish-speaking drivers if the STT and agent are tested in Spanish and in mixed English-Spanish speech. Drivers often say numbers in one language and place names in another. Monitor field error rates by language. A delay said in Spanish, like "voy a llegar tarde," must still map to an exception code.
Do AI check calls need driver consent?
Outbound AI check calls fall under TCPA rules on artificial voices. The FCC's February 2024 declaratory ruling says AI-generated voices count as "artificial," so such calls generally need prior express consent unless an exemption applies. Inbound calls that drivers place are a different case. This is not legal advice; confirm your consent flow with counsel.
The bottom line
The AI check calls trucking teams rely on are only as good as the four fields they write, and none of those fields fail loudly. Check every call against GPS, ELD hours and load assignment, then hand-review a fixed sample so wrong ETAs and load numbers never reach the shipper.
Related Articles

How to automate voice agent testing: synthetic callers vs manual QA
Learn how ai test automation replaces manual QA for voice agents. Compare synthetic callers vs human testers, with a 5-step framework to scale without hiring.
Read more
AI Agent Testing vs Voice Agent Testing: What General Tools Miss for Voice
AI agent testing measures text outputs. Voice agent testing measures behaviour through an acoustic pipeline. Five failure categories general tools miss.
Read more