Guides & API documentation

Build with carrier evidence

Retrieve public carrier records, insurance policies and matched UCC history. Keep source dates and availability with the data so your users can see what it supports.

Updated September 28, 2026

1. Create an API key

  1. Create an account or sign in, then open API Keys.
  2. Select Create Key, name and create the key, and copy it when shown. The full key will not be displayed again.
  3. Store it as a server-side secret named VERIFYCARRIER_API_KEY. Send Authorization: Bearer YOUR_API_KEY. Never put your key in a URL, public repository or browser bundle.

Free API accounts include 100 calls/month. Carrier watch is $49/month for 50 carriers and 1,000 API calls/month. Your keys share the account allowance; each evidence page consumes a request.

A machine-readable OpenAPI 3.1 description of these endpoints, including authentication and the 402 quota response, is at https://verifycarrier.com/openapi.json. No SDK packages are published; generate a client from the spec if you need one.

The evidence API does not require each carrier on a watchlist. Dashboard reviews separately require monitoring access and that carrier on your watchlist. Browser sessions also authenticate dashboard requests; integrations should use a key.

To rotate a key, create a new one, update and test your application, then delete the old key. If a key is exposed, delete it in API Keys and replace it. Deletion revokes that key.

Fuel benchmarks & published surcharges

Your active paid plan or seven-day trial includes GET /api/fuel-surcharges. Send your VerifyCarrier API key; browser session cookies do not authenticate this integration endpoint.

curl https://verifycarrier.com/api/fuel-surcharges   -H "Authorization: Bearer $VERIFYCARRIER_API_KEY"

The JSON response contains diesel (US EIA retail USD/gallon), regionalDiesel (East Coast, Midwest, Gulf Coast, Rocky Mountain, West Coast, California), surcharges (LTL), and parcelSurcharges (UPS, FedEx, DHL by service).

LTL coverage: Old Dominion, Saia, Estes, XPO, ABF, TForce, Averitt and Southeastern Freight Lines. These are fuel surcharge schedules, not full freight tariffs or negotiated lane rates. FedEx Freight LTL is not covered.

Each schedule includes carrier, name, percent, effectiveDate, retrievedAt, source and state; parcel rows also include serviceLevel. Benchmarks include price, asOf, source and stale. Keep these fields with every displayed value. Regional averages do not estimate a specific route’s pump prices.

status is available, partial or unavailable. A 200 partial response can contain old or upcoming schedules: check every row’s state (recent, stale, upcoming), not just HTTP success. The display freshness window is ten days, not a statement about contract validity. checkedAt is response time; observation and retrieval dates are separate. Invalid schedules are omitted and counted in rejectedSchedules.

Data is cached upstream for up to an hour. Each successful API response consumes one shared account request, including partial responses. Carrier watch includes 1,000 calls/month; the trial allows up to 1,000 calls across its seven days. Dashboard fuel views do not consume this API allowance.

Errors: 401 missing/invalid/revoked key; 403 plan or trial expired; 402 quota_exhausted allowance used up; 503 provider, configuration or account verification unavailable. Never treat an absent benchmark as zero. See Fuel tools for calculations using your agreed base price, MPG and mileage.

2. Request carrier evidence

GET https://verifycarrier.com/api/carrier/:dot/evidence

Use a positive USDOT number of 1–8 digits, without a DOT or MC prefix. The response includes the normalized FMCSA carrier record, active/pending insurance, matched UCC/state-lien history, and public review/contact evidence. Private customer notes and decisions are not included.

curl --fail-with-body --max-time 45 \
  -H "Authorization: Bearer $VERIFYCARRIER_API_KEY" \
  'https://verifycarrier.com/api/carrier/594/evidence'

DOT 594 (Duffy Crane) and DOT 23907 (Severance Trucking) are populated examples in the September 28, 2026 UCC batch, with 39 and 3 matched historical filings respectively. These are snapshot facts, not risk findings. Responses may differ later.

HTTP 200 does not mean every source is available. A partial response can contain useful filings while a carrier field is unavailable. Missing crash data is not a zero-crash result. The original DOT/MC lookup endpoints keep their response format and do not include UCC; use this endpoint for combined evidence.

3. Read the response correctly

FieldMeaning
dot_numberRequested USDOT as a string.
statusavailable or partial. Inspect each source and field status; available is not carrier approval.
response_generated_atWhen this response was assembled, not a government update time.
carrierStatus: available, not_found or unavailable. Contains normalized data, source URL, and field_availability for BASICs, authority details, inspections and crash summaries.
insuranceStatus: ok, empty or unavailable. Contains policies, retrieval time and pagination when available. Empty means no rows returned by this source, not a coverage determination.
uccStatus: available, no_match or unavailable. Contains a page of filings, source metadata and pagination. total is null when unavailable.
public_review_evidencePublic FMCSA facts and census contact overlaps with both source attributions. Its status can be available while data.contacts.available is false. At most five contact matches are returned; truncated=true means additional matches exist.

Company profiles and website observations

company_profile contains reviewed company descriptions, service areas, logo attribution, source links and dated website observations where identity could be matched. Its status is reviewed, not_reviewed or identity_unconfirmed. Unreviewed companies return null data, not an adverse signal.

data.website includes the URL, status (reachable or dns_error), HTTP status when available, check time and method. website_observation_stale becomes true after seven days. These checks are not continuous monitoring. A reachable website is not verification of business health; a failed check alone does not establish closure. Historical descriptions and company disclosures retain their dates and sources.

Carrier data

The evidence response uses normalized field names under carrier.data. Optional fields may be omitted or null; do not substitute zero. It does not add the basic lookup's computed risk object.

  • Identity/contact: dot_number, mc_number, legal_name, dba_name, physical_address, physical_city, physical_state, physical_zip, phone, email.
  • Fleet/filing: power_units, drivers, mcs_150_date, mcs_150_mileage, operation_classification, carrier_operation, cargo_carried.
  • Registration/authority: authority_status, allowed_to_operate, common_authority, contract_authority, broker_authority, authority_details, docket_numbers.
  • Safety/insurance: safety_rating, safety_rating_date, out_of_service_date, insurance_required, bonds_insurance_on_file, basics, basic_alerts, inspections_24mo, crashes_24mo.

Codes may be returned as published. Registration, authority and safety ratings are separate facts. Check carrier.field_availability and the returned values before using optional fields.

Crash-history limitation: the current integration does not populate inspections_24mo or crashes_24mo; these fields are null with unavailable status. Independent NHTSA/NTSB crash history is not integrated. BASIC indicators are not individual accident records.

Insurance policies

Each policy has form, type, insurer, policyNumber, effectiveDate, maxCoverage, sourceTransactionDate and sourceRecord. The last preserves the original published row, including fields beyond the display summary. maxCoverage is a formatted display string, not a numeric balance.

UCC filings and events

Each filing has state, fileNumber, sourceStatus, filedDate, lapseDate, securedParties, sourceUrl, events and match. State plus file number identifies a chain. Events contain id, date, type and sourceStatus.

The match object contains basis, debtorName, debtorAddress, debtorState, debtorZip and carrierRecordDate. The latter is the census MCS-150 filing date, usually YYYYMMDD; it is not an address-change date.

Provenance and dates

ucc.batchId identifies the imported match batch; ucc.censusAsOf dates its census snapshot. Each ucc.sources entry includes state, asOf, retrievedAt, history, cadence and staleAfterDays. Cadence describes the government source, not an enabled refresh schedule.

source_updated_at: null means the upstream update time is unknown. Retrieval and response times are not substitutes. Dates for policies/events describe individual records, not freshness of the entire source. See the date guide.

4. Retrieve every page

UCC: 25 filing chains per page

  1. Start with ucc_offset=0. Require ucc.status to be available or no_match before using its count. A gated status means filing details are not yet enabled on your account: ucc.total is the matched filing count and ucc.filings is empty.
  2. Save ucc.batchId and append that page's filings.
  3. While ucc.next_offset is not null, request that offset and pass the saved batch as ucc_batch.
  4. On HTTP 409, discard the partial UCC export and restart at offset 0. Never combine batches.
# Replace BATCH_ID with ucc.batchId from the first response.
curl --fail-with-body --max-time 45 \
  -H "Authorization: Bearer $VERIFYCARRIER_API_KEY" \
  'https://verifycarrier.com/api/carrier/594/evidence?ucc_offset=25&ucc_batch=BATCH_ID'

All retained events are nested inside each filing; they have no separate pages. Keep batch ID, source metadata and match evidence with your export. Out-of-range UCC offsets can reset to zero, so check that returned offsets advance.

Insurance: up to 100 policies per page

Start at insurance_offset=0. Follow insurance.nextOffset until null. Insurance is a live source and pages may change during retrieval; this is not a frozen snapshot or point-in-time proof of coverage.

Both offsets accept integers from 0 to 1,000,000. Keep pagination sequences separate: each response contains both sources, but only append the source whose offset you are advancing.

Runnable Node.js example

Download carrier-evidence.mjs. Use Node.js 20 or newer and a key in VERIFYCARRIER_API_KEY. The example checks source status, follows all pages, rejects non-advancing pages, and restarts a changed UCC batch at most twice. It stops on authentication/quota failures.

# Set VERIFYCARRIER_API_KEY securely in your environment first.
node carrier-evidence.mjs 594 ucc > duffy-ucc.json
node carrier-evidence.mjs 594 insurance > duffy-insurance.json

Results reach stdout only after collection succeeds. Check the command's exit status before reading the export: failed shell redirection can leave an empty file. The example does not automatically retry quota or transient failures; retries consume requests.

Basic DOT, MC and name lookups

GET endpointUse
/api/lookup/dot/198USDOT lookup. Returns success and data.
/api/lookup/mc/147039Resolve an MC number; use its returned DOT for evidence.
/api/search?q=trucking&limit=10Name search. q: at least three characters. limit: 1–50, default 10. Returns query, count, results (best match first, each with status and active), total and truncated.

These endpoints allow limited anonymous access. Use a key for your account allowance and evidence requests. /api/carrier/:dot and /api/lookup/:dot are aliases for basic DOT lookup, not the evidence endpoint.

// Server-side JavaScript; this limited basic lookup permits anonymous access.
const response = await fetch('https://verifycarrier.com/api/lookup/dot/198', {
  signal: AbortSignal.timeout(30000)
});
if (!response.ok) throw new Error('Lookup failed: HTTP ' + response.status);
const { data } = await response.json();
console.log(data.legal_name);
console.log(data.risk?.tier ?? 'Assessment unavailable');
# Python (requires requests).
import requests
response = requests.get('https://verifycarrier.com/api/lookup/dot/198', timeout=30)
response.raise_for_status()
data = response.json()['data']
print(data['legal_name'])
print((data.get('risk') or {}).get('tier', 'Assessment unavailable'))

Basic lookup groups fields under address, fleet, safety, registration, authority and metadata. Its risk object uses score and tier, not level. It is not a prediction of fraud or automatic approval.

Risk tiers (methodology 2.2.0)

Tiers are anchored to FMCSA's own facts. Extreme: an active out-of-service order or an Unsatisfactory rating. High: any BASIC at or above its FMCSA intervention threshold (65 for Unsafe Driving, Hours of Service and Crash Indicator, 80 for the others; FMCSA's lower passenger and hazmat thresholds apply when it reports them), a pending FMCSA suspension of the operating authority, or a pending insurance cancellation with no replacement on file. Moderate: a BASIC within 10 points of its threshold, a Conditional rating, an acute/critical flag in FMCSA's current SMS results, or a vehicle or driver out-of-service rate above FMCSA's national average (10 or more inspections). Low: none of these. Scores run 0–24.9 Low, 25–49.9 Moderate, 50–79.9 High and 80–100 Extreme.

FMCSA does not publish BASIC percentiles for most property carriers. Without a percentile, without 10 or more current vehicle or driver inspections to compare and without another fact above to decide the tier, tier is Insufficient data and score is null. No percentile is ever derived from a measure. enrichment carries the current FMCSA facts behind these rules, each with its source and as-of date: pending suspensions and insurance cancellations (flags), out-of-service rates and acute/critical flags (inspections, FMCSA SMS, monthly), authority and insurance on file vs required and BOC-3 (authority, FMCSA Motus, daily) and the MCS-150 date (registration). A source that could not be read is unavailable, never a clean record. factors lists each reason, such as “Vehicle Maintenance 51 — below 80 threshold”. basic_measures carries FMCSA measure values, which are not percentiles, and basics_as_of is the date of FMCSA's BASIC snapshot. When that snapshot is more than 24 months old, basics_stale is true and basics, basic_alerts and basic_measures are null or empty: the percentiles are not current and are not scored. Current percentiles are on the FMCSA SMS site.

Legacy metadata.last_updated is the lookup response time, not a confirmed government update time. Use the evidence endpoint's explicit provenance fields when tracking freshness. Empty search results are not proof that a company has no records.

Errors, quotas and recovery

ResultRecovery
200 + partial/unavailableKeep source failures visible; use only available evidence. Retry failed sources later. Never convert unknown counts to zero.
400Correct the identifier, search query or offset.
401Check the Bearer key, whether it was deleted, and service status. Do not log your key.
403 in a dashboard reviewCheck monitoring access and your active watchlist. This is separate from API allowance.
404 in basic lookupCheck the identifier and source. Evidence instead reports per-source not_found/unavailable states.
409 + ucc_batch_changedDiscard partial UCC pages and restart with the new batch.
402 + quota_exhaustedYour daily (anonymous) or monthly (account) allowance is used up. Retrying will not help before the reset: follow offer.url (a free API key for anonymous calls, a plan upgrade for account keys) or wait for resetDate.
429Too many requests in a short window. Back off and retry with a bounded delay; avoid immediate retry loops.
5xx / timeoutKeep the operation unconfirmed, check service status, and retry with a bounded delay.

Metered responses include X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix seconds). A 402 quota_exhausted body includes limit, used, ISO resetDate and an offer naming the plan, price and allowance. Account allowances reset at the next calendar month; anonymous limits use a daily window. Read the returned reset time, not your subscription anniversary.

Each page/retry can count, including authenticated requests that reach validation and return an error. Preserve source dates in any cached export. The evidence endpoint sends private, no-store HTTP cache headers.

For support, send the route, USDOT, timestamp and HTTP/source status to karl@verifycarrier.com. Exclude API keys, Authorization headers, passwords and private notes.