CarrierVet
通过MC或USDOT审核美国汽车承运人:PASS/REVIEW/FAIL判定、风险信号、历史记录、回执。
托管 MCP 服务器
npx add-mcp 'https://carriervet.dev/mcp'可安装到 Claude Code、Codex、Cursor 等客户端
文档
API reference
Beta: CarrierVet is in active testing. Verify critical decisions against FMCSA SAFER, and report anything that looks wrong to hello@carriervet.dev.
Base URL: https://carriervet.dev. Send Authorization: Bearer cv_live_... on every /v1 route except signup, login, and the Stripe webhook.
POST/v1/signup
Create a free account. Requires accept_terms: true, meaning you accept the Terms of Service; without it the call returns 400 terms_not_accepted. Returns the API key once. The key works for 5 lookups until you click the link emailed to you; GET /v1/verify-email?token=… confirms it and POST /v1/verify-email/resend sends a new link.
curl -s -X POST https://carriervet.dev/v1/signup \
-H 'content-type: application/json' \
-d '{"email":"desk@example.com","password":"a-long-password","accept_terms":true}'
POST/v1/login
Mint another key from email and password. The previous key cannot be retrieved; only its hash is stored. An account holds at most 10 active keys; at the cap, login revokes the oldest key a login created.
curl -s -X POST https://carriervet.dev/v1/login \
-H 'content-type: application/json' \
-d '{"email":"broker@example.com","password":"local-demo-password"}'
GET/v1/account
Account, plan, webhook signing secret, and key prefixes.
curl -s https://carriervet.dev/v1/account -H "authorization: Bearer $KEY"
POST/v1/keys
Create a named key. The secret is returned once. Maximum 10 active keys.
curl -s -X POST https://carriervet.dev/v1/keys \
-H "authorization: Bearer $KEY" -H 'content-type: application/json' \
-d '{"name":"tms-prod"}'
POST/v1/keys/{id}/rotate
Revoke the named key and return a replacement.
curl -s -X POST https://carriervet.dev/v1/keys/key_demo_business/rotate -H "authorization: Bearer $KEY"
DELETE/v1/keys/{id}
Revoke a key. The last active key cannot be revoked.
curl -s -X DELETE https://carriervet.dev/v1/keys/key_demo_business -H "authorization: Bearer $KEY"
GET/v1/carriers/{dot}
Overall verdict, then the full profile. Counts as one lookup, including a not-found response.
curl -s https://carriervet.dev/v1/carriers/53467 -H "authorization: Bearer $KEY"
Example response shape · 200 · application/json (illustrative values from a fictional sample carrier)
{
"verdict": "PASS",
"verdict_reasons": [],
"verdict_basis": ["authority", "insurance", "out_of_service", "operating_status", "safety_rating"],
"carrier": {
"dot_number": "9900001",
"legal_name": "Northline Freight LLC",
"authority": { "status": "active", "grant_date": "2014-06-01", ... },
"insurance": { "status": "on_file", ... },
"safety": { "out_of_service": false, ... },
...
},
"receipt_id": "rcpt_0123456789abcdef01234567",
"usage": { "used": 3, "limit": 50, "remaining": 47, "warning": null }
}
GET/v1/carriers/mc/{mc}
Verdict and profile by MC, FF, or MX number. Authority status, and the verdict, use the matched docket's motor-carrier authority; a broker-only or forwarder-only docket FAILs as not_a_carrier.
curl -s https://carriervet.dev/v1/carriers/mc/MC138328 -H "authorization: Bearer $KEY"
GET/v1/carriers/{dot}/risk
Overall verdict, then a score from 0 to 100 plus reason codes. The verdict here also uses the contact check and the risk level. A hard failure is listed in gates and keeps the score at 50 or more, so a carrier that fails a check is never scored low. The x-data-freshness header and snapshot_date show how current the record is. Weights live in the risk config.
curl -s https://carriervet.dev/v1/carriers/53467/risk -H "authorization: Bearer $KEY"
Example response shape · 200 · application/json (illustrative values from a fictional sample carrier)
{
"verdict": "FAIL",
"verdict_reasons": [
{ "code": "revoked_authority", "check": "authority", "result": "FAIL",
"message": "Operating authority is revoked or suspended." },
{ "code": "insurance_missing", "check": "insurance", "result": "FAIL",
"message": "Required insurance is not on file with FMCSA." },
{ "code": "out_of_service", "check": "out_of_service", "result": "FAIL",
"message": "Carrier is under an out-of-service order." },
{ "code": "risk_level_severe", "check": "risk_level", "result": "FLAG",
"message": "Risk level is severe." }
],
"verdict_basis": ["authority", "insurance", "out_of_service", "operating_status", "safety_rating", "contact", "risk_level"],
"dot_number": "9900003",
"score": 100,
"level": "severe",
"gates": ["insurance_missing", "revoked_authority", "out_of_service"],
"reasons": [
{ "code": "revoked_authority", "points": 45,
"message": "Operating authority is revoked or suspended.",
"details": { "authority_status": "revoked" } },
{ "code": "out_of_service", "points": 40,
"message": "Carrier is under an out-of-service order.",
"details": { "oos_status": "out_of_service" } },
{ "code": "insurance_missing", "points": 25,
"message": "Required insurance is not on file with FMCSA.",
"details": { "insurance_status": "missing" } }
],
"rules_version": "2026.10.27",
"snapshot_date": "2026-10-27",
"receipt_id": "rcpt_0123456789abcdef01234567",
"meta": { "disclaimer": "Carrier data is derived from records maintained by the Federal Motor Carrier Safety Administration (FMCSA). It is provided as-is, ..." }
}
GET/v1/carriers/mc/{mc}/risk
The same risk response by MC, FF, or MX number. The authority status used is that docket's own, as on the MC profile lookup.
curl -s https://carriervet.dev/v1/carriers/mc/MC138328/risk -H "authorization: Bearer $KEY"
GET/v1/carriers/{dot}/history
Two lists, newest first. changes: differences between CarrierVet's stored copies. fmcsa_history: dated changes from FMCSA's daily authority, insurance, and revocation files and from census rows with a new MCS-150 date. Each row has fmcsa_date (the date FMCSA recorded it; fmcsa_date_basis names the column), observed_at (when CarrierVet saw it), and old_value and new_value. Company officer name changes show both values as withheld. Rows are only added, never edited. Recording started on 2026-10-27, so older changes are not included.
curl -s https://carriervet.dev/v1/carriers/53467/history -H "authorization: Bearer $KEY"
GET/v1/receipts/{id}
Every charged lookup returns receipt_id (also in the x-receipt-id header). This returns the saved copy of that response: time, endpoint, identifier, the body as sent, and its SHA-256. Any API key on the account that made the lookup can read it. It appears a few seconds after the lookup. It records what CarrierVet returned then; it is not a new check. Free.
curl -s https://carriervet.dev/v1/receipts/rcpt_0123456789abcdef01234567 -H "authorization: Bearer $KEY"
POST/v1/carriers/batch
Up to 500 DOT or MC numbers. Pro and Business. Duplicate ids are billed once. Carriers not stored yet are fetched from FMCSA (a few at a time, up to about 25 seconds per call). Each result has status: ok (with verdict, verdict_reasons, carrier, freshness), not_found, or not_checked (FMCSA slow or the time budget ran out; retry it). Only ok and not_found are charged; summary gives the counts.
curl -s -X POST https://carriervet.dev/v1/carriers/batch \
-H "authorization: Bearer $KEY" -H 'content-type: application/json' \
-d '{"identifiers":["53467","MC133655"]}'
GET/v1/search?name=
Name search over the indexed snapshot. Minimum 2 characters.
curl -s "https://carriervet.dev/v1/search?name=Werner" -H "authorization: Bearer $KEY"
POST/v1/monitors
Watch a carrier. Free cannot monitor. Starter is email only. Pro and Business can set a webhook.
curl -s -X POST https://carriervet.dev/v1/monitors \
-H "authorization: Bearer $KEY" -H 'content-type: application/json' \
-d '{"dot_number":"53467","alert_email":"ops@example.com","webhook_url":"https://example.com/hooks/carriervet"}'
GET/v1/monitors
List monitors for the calling account.
curl -s https://carriervet.dev/v1/monitors -H "authorization: Bearer $KEY"
DELETE/v1/monitors/{dot}
Stop monitoring a USDOT number.
curl -s -X DELETE https://carriervet.dev/v1/monitors/53467 -H "authorization: Bearer $KEY"
GET/v1/export/monitors.csv
Business plan. One row per monitored carrier, plus a final disclaimer column.
curl -s https://carriervet.dev/v1/export/monitors.csv -H "authorization: Bearer $KEY"
GET/v1/usage
Lookups used this UTC month, monitor count, and plan limits.
curl -s https://carriervet.dev/v1/usage -H "authorization: Bearer $KEY"
POST/v1/billing/checkout
Paid plans open after beta. Prices: Starter $49/mo, Pro $149/mo, Business $399/mo; yearly is 10× monthly. Until then this returns 403 paid_signups_paused. The free plan (50 lookups/month, no card) is available now through POST /v1/signup.
curl -s -X POST https://carriervet.dev/v1/billing/checkout \
-H "authorization: Bearer $KEY" -H 'content-type: application/json' \
-d '{"plan":"starter","interval":"month"}'
POST/v1/billing/portal
Stripe Customer Portal: switch plan or billing interval (prorated) or cancel at the end of the period. Requires a completed checkout. Checkout returns 409 already_subscribed if the account already has a plan.
curl -s -X POST https://carriervet.dev/v1/billing/portal -H "authorization: Bearer $KEY"
POST/v1/stripe/webhook
Stripe subscription webhook. Rejects requests without a valid Stripe-Signature.
curl -s -X POST https://carriervet.dev/v1/stripe/webhook \
-H 'content-type: application/json' \
-d '{"id":"evt_demo","type":"checkout.session.completed"}'
Webhook signatures
Alert posts include X-CarrierVet-Signature: t=<unix>,v1=<hex>. The hex is HMAC-SHA256 of t + "." + rawBody using the account webhook secret from GET /v1/account.
Alert payloads (carrier.changed) include a disclaimer field, alert emails end with the same notice, and CSV exports carry it in a final disclaimer column: informational only, not a guarantee, derived from FMCSA records and provided as-is.
Carrier corrections
Carriers who think a record or flag is wrong can request a review by email. See /corrections.
Verdict
Carrier profile, risk, and batch responses start with verdict: PASS, REVIEW, or FAIL. Existing fields are unchanged.
FAILif any check is FAIL: motor-carrier authority revoked, inactive, or none; a broker-only, freight-forwarder-only, or intrastate-only entity (not_a_carrier,intrastate_only); insurance missing or lapsed; an out-of-service order; an inactive USDOT number or not allowed to operate; or an Unsatisfactory safety rating.REVIEWif any check is FLAG: authority pending or under 90 days old (counted from the start of the current authority period; administrative record corrections do not reset it), insurance status unknown, a Conditional safety rating, or incomplete or old data (data_incomplete: an FMCSA source did not answer for this lookup;data_stale: an older stored copy was served because FMCSA did not answer a refresh in time). On/v1/carriers/{dot}/risk, also a recent or shared phone, email, or address, or a risk level of elevated, high, or severe.PASSotherwise.
verdict_reasons lists {"code","check","result","message"}, FAIL reasons first, and is empty on PASS. Codes match the risk reason codes where one exists, plus no_authority, not_a_carrier, intrastate_only, insurance_unknown, data_incomplete, data_stale, and risk_level_elevated / _high / _severe. verdict_basis lists the checks used: profile and batch lookups use authority, insurance, out_of_service, operating_status, safety_rating (plus data_quality when a source did not answer); the risk endpoint adds contact and risk_level. Profile responses also include checks (PASS/FLAG/FAIL per check). The verdict is informational and not a guarantee.
Entity type and data quality
carrier.entity_type is motor_carrier, broker_only, freight_forwarder_only, intrastate_only, no_carrier_authority, or unknown. authority.status is motor-carrier authority only; broker and freight-forwarder authority are in authority.broker_status and authority.freight_forwarder_status. authority.grant_date starts the current authority period and authority.original_grant_date is the first grant on record.
carrier.data_quality has completeness (complete or partial), missing (checks a failed source would have backed), and the status of each FMCSA source for this copy. A partial copy is rechecked after 10 minutes and is never labeled fresh or live.
Risk reason codes
authority_under_90_days, recent_address_change, recent_phone_change, recent_email_change, multiple_contact_changes, shared_phone, shared_email, shared_address, insurance_lapsed, insurance_missing, revoked_authority, inactive_authority, pending_authority, no_authority, out_of_service, usdot_inactive, not_allowed_to_operate, unsatisfactory_rating, conditional_rating, prior_revocation, undeliverable_mail.
Hard failures (revoked_authority, inactive_authority, no_authority, out_of_service, insurance_lapsed, insurance_missing, usdot_inactive, not_allowed_to_operate, unsatisfactory_rating) are listed in gates and keep the score at 50 or more. Placeholder phone numbers such as 000-000-0000 are ignored for shared-phone checks.
Set RISK_CONFIG_JSON to override points, windows, and shared-contact thresholds. Unknown JSON is ignored and the built-in config is used. With an override, rules_version ends in +custom.<hash>, and shared-contact thresholds are at least 1.
Errors and rate limits
Every error is JSON: {"error":{"code","message","docs_url","retry_after"}}. retry_after (seconds) and the Retry-After header are set on 429, 202, and 503. Wait that long before retrying.
400 invalid_request · 400 terms_not_accepted · 401 unauthorized · 402 quota_exceeded · 403 plan_forbidden · 403 turnstile_failed · 404 not_found · 403 email_unverified (confirm your email to go past 5 lookups) · 409 email_taken · 409 key_limit · 409 already_subscribed (use the billing portal to switch plans) · 429 rate_limited · 202 fetching_from_fmcsa (new carrier being fetched; retry, not charged) · 503 fmcsa_unavailable / fmcsa_throttled (FMCSA down and carrier not cached; not charged) · 403 paid_signups_paused (paid plans open after beta) · 500 internal.
Limits: per-account requests per minute by plan, per-IP limits on signup, login, and public pages, and 3 tokenless API signups per IP per hour. Cached carriers keep working when FMCSA is down; the x-data-freshness header says whether a profile is fresh (stored, under a day old, complete), live (just fetched, complete), live-partial or cached-partial (an FMCSA source did not answer), stale-revalidating, or stale-upstream-down.
AI agents and MCP
Plain-language guides: /llms.txt, /llms-full.txt. OpenAPI: /openapi.json. MCP server (Streamable HTTP): https://carriervet.dev/mcp with Authorization: Bearer <key>.