Your First Carrier Lookup
Look up a motor carrier by DOT number, parse 280+ fields of authority, safety, insurance, and fleet data, then search by company name. You'll have a working integration in under 5 minutes.
What you'll learn
- Look up any carrier by DOT number
- Parse identity, authority, and insurance fields
- Read ISS scores and BASIC percentiles
- Search carriers by company name
- Handle pagination with page and pageSize
- Implement error handling and retries
Look up a carrier by DOT number
The Carrier Profiles API returns a full profile for any of 4M+ FMCSA-registered carriers. The simplest lookup uses a DOT number — the unique identifier assigned to every motor carrier.
curl "https://api.carrierok.com/v2/profile?dot_number=568253" \
-H "Authorization: Bearer YOUR_API_KEY"{
"items": [
{
"dot_number": "568253",
"legal_name": "HANSEN & ADKINS AUTO TRANSPORT INC",
"docket": "MC277621",
"authority_common": "Active",
"authority_contract": "Active",
"authority_age_common": "7937",
"insurance_bipd_on_file": "1000000",
"insurance_bipd_required": "1000000",
"indicator_insurance": true,
"iss_value": "45",
"risk_score": "Low",
"total_power_units": "897",
"total_drivers": "897",
"safety_rating_desc": "Satisfactory",
"usdot_status": "Active"
}
],
"total_count": 1
}The response contains an items array and a total_count. A DOT lookup returns exactly one result.
Understand the response
Each carrier profile contains 280+ fields. Here are the categories you'll use most:
| Category | Key Fields |
|---|---|
| Identity | legal_name, dot_number, docket, ein |
| Authority | authority_common, authority_contract, authority_age_common |
| Insurance | insurance_bipd_on_file, insurance_bipd_required, indicator_insurance |
| Safety | iss_value, risk_score, basic_percentile_*, safety_rating_desc |
| Fleet | total_power_units, total_drivers, cargo_carried |
| Contact | telephone_number, email_address, physical_address |
All 7 BASICs
basic_percentile_* fields.See the complete field reference in the Carrier Profiles endpoint docs.
Search by company name
When you don't have a DOT number, search by company name. The API supports partial matching and returns paginated results.
curl "https://api.carrierok.com/v2/profile?company=hansen+adkins&pageSize=5" \
-H "Authorization: Bearer YOUR_API_KEY"{
"items": [
{
"dot_number": "568253",
"legal_name": "HANSEN & ADKINS AUTO TRANSPORT INC",
"physical_address_city": "LOS ALAMITOS",
"physical_address_state": "CA",
"authority_common": "Active",
"total_power_units": "897"
}
],
"total_count": 1
}You can also search by EIN, phone, email, address, VIN, or license plate. Each uses the same /v2/profile endpoint with different query parameters.
Paginate results
Company name searches can return many results. Use page and pageSize to page through them:
import requests
import math
API_KEY = "YOUR_API_KEY"
BASE = "https://api.carrierok.com/v2/profile"
def fetch_all(company: str, page_size: int = 100):
"""Fetch all carriers matching a company name."""
carriers = []
page = 1
while True:
resp = requests.get(
BASE,
params={
"company": company,
"page": page,
"pageSize": page_size,
},
headers={"Authorization": f"Bearer {API_KEY}"},
)
resp.raise_for_status()
data = resp.json()
carriers.extend(data["items"])
total_pages = math.ceil(data["total_count"] / page_size)
if page >= total_pages:
break
page += 1
return carriers
results = fetch_all("werner")
print(f"Fetched {len(results)} carriers")Default page size
total_count field so you can calculate remaining pages.Handle errors
The API returns standard HTTP status codes. Here's a production-ready error handler:
import time
import requests
def lookup_carrier(dot_number: str, api_key: str, retries: int = 3):
"""Look up a carrier with automatic retry on rate limits."""
url = "https://api.carrierok.com/v2/profile"
for attempt in range(retries):
resp = requests.get(
url,
params={"dot_number": dot_number},
headers={"Authorization": f"Bearer {api_key}"},
)
if resp.status_code == 200:
data = resp.json()
if data["items"]:
return data["items"][0]
return None # DOT not found
if resp.status_code == 429:
wait = min(2 ** attempt, 30)
print(f"Rate limited — retrying in {wait}s")
time.sleep(wait)
continue
if resp.status_code == 401:
raise ValueError("Invalid API key")
resp.raise_for_status()
raise TimeoutError("Max retries exceeded")| Status | Meaning | Action |
|---|---|---|
200 | Success | Parse items array |
400 | Missing parameters | Check query string |
401 | Invalid API key | Verify Authorization: Bearer header |
429 | Rate limited | Exponential backoff, then retry |
503 | Service unavailable | Retry after 5 seconds |
See Rate Limits & Errors for the full error reference and rate limits.
What's next
You now have a working API integration. Here are two ways to go deeper: