Article type: How-to guide (one task: check a US motor carrier's registration, operating authority and safety rating by USDOT or MC number)
Prerequisites: Python 3 with
requests, or justcurl. No API key or account is needed for the open data. An Apify account only if you use the hosted version at the end.Tested on: 14 November 2026
Before you tender a load or add a carrier to your system, you usually want three answers: is the USDOT number active, does the company hold the operating authority it needs, and what safety rating has FMCSA given it?
All the data in this post comes from the Federal Motor Carrier Safety Administration (FMCSA), part of the U.S. Department of Transportation. FMCSA publishes its carrier files as public US government data on data.transportation.gov, and two of them answer those three questions:
| File | What it holds |
|---|---|
Company Census File (az4n-8mr2) | One row per USDOT number: legal and DBA name, status, interstate or intrastate, fleet size, safety rating. 4,530,952 rows on 14 November 2026, refreshed that day |
Motus Carrier, all with history (inys-ebih) | One row per operating authority: docket number (MC, FF or MX), authority type and status. 190,351 rows, refreshed the same day |
FMCSA also has an official QCMobile API, but it needs a WebKey. The open data files need nothing: one GET request, no key.
How do I look up one carrier with curl?
Filter the census on dot_number, then the authority file on usdot_number:
curl -sG https://data.transportation.gov/resource/az4n-8mr2.json \ --data-urlencode '$where=dot_number=90849' \ --data-urlencode '$select=dot_number,legal_name,status_code,carrier_operation,phy_state,power_units,safety_rating,safety_rating_date' curl -sG https://data.transportation.gov/resource/inys-ebih.json \ --data-urlencode "\$where=usdot_number='90849'" \ --data-urlencode '$select=docket_number,op_auth_type,op_auth_status' [{"dot_number":"90849","legal_name":"OLD DOMINION FREIGHT LINE INC","status_code":"A","carrier_operation":"A","phy_state":"NC","power_units":"10313","safety_rating":"S","safety_rating_date":"19950929"}] [{"docket_number":"MC107478","op_auth_type":"Motor Carrier of Property (Except Household Goods)","op_auth_status":"Active"} ,{"docket_number":"MC107478","op_auth_type":"Broker of Property (Except Household Goods)","op_auth_status":"Active"}] Note the quotes: dot_number is a number column in the census, while usdot_number is a text column in the authority file.
The codes come from FMCSA's data dictionary (attached to the census dataset):
| Column | Codes |
|---|---|
status_code | A = Active, I = Inactive, P = Pending (a Mexico-domiciled company whose application is still under review) |
carrier_operation | A = interstate, B = intrastate hazardous materials, C = intrastate non-hazardous |
safety_rating | S = Satisfactory, C = Conditional, U = Unsatisfactory, blank = no safety or compliance review has been conducted |
safety_rating_date | The date the review that produced the rating was entered (YYYYMMDD) |
So Old Dominion Freight Line: active, interstate, rated Satisfactory, with active property-carrier and property-broker authority under MC107478.
How do I check a carrier in Python?
This script asks for company columns only (the census also has phone, email and officer-name columns, which you don't need for a carrier check), turns the codes into words and accepts an MC number as well as a USDOT number. pip install requests, then save as fmcsa_lookup.py:
import time import requests BASE = "https://data.transportation.gov/resource" CENSUS = f"{BASE}/az4n-8mr2.json" # FMCSA Company Census File AUTHORITY = f"{BASE}/inys-ebih.json" # FMCSA operating authority (Motus Carrier, all with history) HEADERS = {"User-Agent": "carrier-check-script"} # add your own contact details here # Company-level columns only. The census also has phone, email and officer columns; we don't ask for them. CENSUS_COLS = ("dot_number,legal_name,dba_name,status_code,carrier_operation,phy_city,phy_state," "power_units,total_drivers,safety_rating,safety_rating_date") STATUS = {"A": "Active", "I": "Inactive", "P": "Pending"} OPERATION = {"A": "Interstate", "B": "Intrastate (hazmat)", "C": "Intrastate (non-hazmat)"} RATING = {"S": "Satisfactory", "C": "Conditional", "U": "Unsatisfactory"} # blank = never rated def get(url, **params): r = requests.get(url, params=params, headers=HEADERS, timeout=60) r.raise_for_status() time.sleep(1.1) # robots.txt asks for Crawl-delay: 1 return r.json() def usdot_for_mc(mc): """MC-135797, MC135797 or 135797 -> USDOT number (or None).""" digits = "".join(ch for ch in mc if ch.isdigit()) rows = get(AUTHORITY, **{"$select": "usdot_number", "$where": f"docket_number='MC{digits}'", "$limit": 1}) return rows[0]["usdot_number"] if rows else None def carrier(usdot): usdot = "".join(ch for ch in str(usdot) if ch.isdigit()) rows = get(CENSUS, **{"$select": CENSUS_COLS, "$where": f"dot_number={usdot}"}) if not rows: return {"usdot": usdot, "found": False} c = rows[0] auth = get(AUTHORITY, **{"$select": "docket_number,op_auth_type,op_auth_status", "$where": f"usdot_number='{usdot}'", "$order": "docket_number,op_auth_type"}) rated = c.get("safety_rating_date", "") return { "usdot": usdot, "found": True, "name": c["legal_name"], "dba": c.get("dba_name", ""), "usdot_status": STATUS.get(c.get("status_code"), c.get("status_code")), "operation": OPERATION.get(c.get("carrier_operation"), "unknown"), "where": f'{c.get("phy_city", "").title()}, {c.get("phy_state", "")}', "power_units": int(c.get("power_units") or 0), "drivers": int(c.get("total_drivers") or 0), "safety_rating": RATING.get(c.get("safety_rating"), "Not rated"), "rated_on": f"{rated[:4]}-{rated[4:6]}-{rated[6:]}" if rated else None, "authority": [(a["docket_number"], a["op_auth_type"], a["op_auth_status"]) for a in auth], } def show(r): if not r["found"]: print(f'USDOT {r["usdot"]}: not in the census file\n') return print(f'USDOT {r["usdot"]} {r["name"]} ({r["where"]})') print(f' USDOT status: {r["usdot_status"]}, {r["operation"]}, ' f'{r["power_units"]:,} power units, {r["drivers"]:,} drivers') print(f' Safety rating: {r["safety_rating"]}' + (f' (since {r["rated_on"]})' if r["rated_on"] else "")) if not r["authority"]: print(" Operating authority: none on file") for docket, kind, status in r["authority"]: print(f" {docket} {kind}: {status}") print() if __name__ == "__main__": for usdot in ["80806", "90849"]: show(carrier(usdot)) mc = "MC-133655" usdot = usdot_for_mc(mc) print(f"{mc} -> USDOT {usdot}") show(carrier(usdot)) show(carrier("999999999")) Output on 14 November 2026:
USDOT 80806 J B HUNT TRANSPORT INC (Lowell, AR) USDOT status: Active, Interstate, 25,280 power units, 24,116 drivers Safety rating: Satisfactory (since 1992-05-08) MC135797 Broker of Household Goods: Active MC135797 Broker of Property (Except Household Goods): Active MC135797 Motor Carrier of Household Goods: Active MC135797 Motor Carrier of Property (Except Household Goods): Active USDOT 90849 OLD DOMINION FREIGHT LINE INC (Thomasville, NC) USDOT status: Active, Interstate, 10,313 power units, 10,341 drivers Safety rating: Satisfactory (since 1995-09-29) MC107478 Broker of Property (Except Household Goods): Active MC107478 Motor Carrier of Property (Except Household Goods): Active MC-133655 -> USDOT 264184 USDOT 264184 SCHNEIDER NATIONAL CARRIERS INC (Green Bay, WI) USDOT status: Active, Interstate, 9,866 power units, 11,335 drivers Safety rating: Satisfactory (since 2003-02-20) MC133655 Broker of Household Goods: Active MC133655 Broker of Property (Except Household Goods): Active MC133655 Motor Carrier of Household Goods: Active MC133655 Motor Carrier of Property (Except Household Goods): Active USDOT 999999999: not in the census file Why it's built this way:
- Two requests per carrier, one per file. The census has the registration and the rating; the authority file has the dockets and their status. They join on the USDOT number.
- MC numbers go through the authority file. It stores dockets as one string (
MC133655), so the function strips the input to digits and matches the whole docket exactly. - IDs are reduced to digits before they go into the query. That handles
USDOT 80806orMC-133655and keeps anything else out of the$whereclause. - A pause between requests. The portal's
robots.txtasks for a 1-second crawl delay.
What should I check before I trust the result?
- Most carriers have no safety rating. Of the 2,246,971 active USDOT numbers on 14 November 2026, 2,194,063 (97.6%) had a blank rating, meaning no review has been conducted. Only 41,061 were Satisfactory, 11,086 Conditional and 761 Unsatisfactory. Treat "Not rated" as "no review on file", not as a pass or a fail.
- A rating can be decades old. All three carriers above are Satisfactory, from reviews entered in 1992, 1995 and 2003. Show the date next to the rating.
- No operating authority isn't always a problem. FMCSA says authority is generally needed to carry passengers, or other people's federally regulated cargo, for hire across state lines. Private carriers hauling their own goods, carriers of exempt commodities and some commercial-zone carriers don't need it. 1,536,062 active USDOT numbers are intrastate non-hazardous, while only 139,035 USDOT numbers hold an active authority. Decide what "OK" means for the kind of company you're checking.
- "Pending" is not granted. 25,806 authority rows were Pending, plus 16,295 Inactive and 5,481 Withdrawn. Check
op_auth_status, not just whether a docket exists. - Use the authority file for authority. The census has its own docket columns (
docket1prefix,docket1,docket1_status_codeand so on). For J B Hunt it lists an FF docket as active that has no row in the authority file. The authority file is the one with the authority type and status, so read authority from there. - Match dockets exactly. A prefix search such as
docket_number like 'FF51075%'returned a different company's docket. Always compare the whole docket. - Numbers are often stored as text.
power_unitsis a text column, so$order=power_units DESCsorts it as text and puts blanks first. Cast it ($order=power_units::number DESC). Fleet sizes are self-reported on the MCS-150 form: the largest value in the file was 2,099,979 power units, which is not a real fleet. Sanity-check before you rank or filter on it.
Rate limits and freshness
You don't need a token, but without one the portal throttles requests by IP address. For more than a handful of checks, register a free app token on data.transportation.gov, send it in the X-App-Token header, and keep to about one request a second.
Both files were refreshed on 14 November 2026. Before you act on a single result, such as turning a carrier away, confirm it on FMCSA's SAFER Company Snapshot, which looks up one carrier at a time by USDOT number, MC/MX number or name, free.
The hosted version (Disclosure: we built this)
We built an Apify Actor, FMCSA Carrier Lookup: USDOT Lookup & Broker Authority, that does this join for you. Give it up to 1,000 USDOT and MC numbers (80806, USDOT 80806, DOT#80806, MC-135797 and MC135797 all work) and you get one row per company: the census record, the safety rating (not_rated when there's none), and every operating authority with its status. Numbers that aren't valid or aren't in the files get a free status row. Monitor mode re-checks a list on a schedule and returns only companies whose status, authority, rating or suspensions changed. It reads the same public FMCSA files on data.transportation.gov, with no key, and exports CSV, JSON or Excel. For example (not run for this post):
{ "usdotNumbers": ["80806", "90849"], "mcNumbers": ["MC-133655"] } It's pay per event: $0.002 per carrier record, $0.01 per monitor run that returns at least one new or changed company, and Apify's $0.00005 Actor start per run (per GB of memory; a default run counts once). Status rows are free. The three carriers above would cost 3 × $0.002 + $0.00005 = $0.00605, and 1,000 carriers $2.00005. Set Maximum cost per run and the run stops there. The Python above is all you need if you'd rather run it yourself.
Data: Federal Motor Carrier Safety Administration (FMCSA), U.S. Department of Transportation: Company Census File and Motus Carrier operating authority file (data.transportation.gov). This post and the Actor are not affiliated with or endorsed by FMCSA or the U.S. Department of Transportation.
Your Evenings



