Freight Risk Scoring API
Check a shipment's freight cost and goods value against what is normal for its lane and commodity.
What it checks
Freight Risk Scoring compares what a shipment declares with U.S. Census import data for the same origin country, U.S. port area, mode and commodity. It checks three measures: freight per kilogram, freight as a share of the goods' value, and goods value per kilogram. It returns a 0-100 score, a low, elevated or high level, and reason codes you can log. A freight or invoice value far from the normal range is a trade-based money laundering and invoicing-fraud signal. It is a prompt for review, not a finding.
- Three measures per shipment: freight per kg, freight as a share of goods value, goods value per kg
- A 0-100 score and a low, elevated or high level, with the measure that drove it
- Reason codes (TBML-F01 to V02, Q01, Q03) for your audit file
- Benchmarks from the last 24 months of U.S. Census monthly import data, with percentile bands (p5 to p95) you can read
- Reports which level the benchmark came from (customs district, country or region) and how confident it is
- Customs-district benchmarks, not port level: Census publishes freight charges by district, so a Shanghai to Los Angeles request is scored against China to the Los Angeles district
- Immutable benchmark versions, so a score can be replayed with as_of
- Idempotency-Key, problem+json errors and rate-limit headers on every call
Endpoints
| Method | Path | What it does | |
|---|---|---|---|
| POST | /freight-risk/score | Scores one shipment against its freight benchmark and returns a 0-99 score, the deviation and percentile behind it, reason codes, and the points it would add to a composite score. Authenticate with `Authorization: Bearer <API key>` or the `x-api-key` header. This release accepts USD only (convert first), does not post to a counterparty's composite score (`contribution.posted_to` is null), and serves the 24-month benchmark window. Errors use RFC 9457 problem details. | Docs |
| GET | /benchmarks/{lane}/{hs} | Returns the percentile bands for one lane and HS code, with no shipment and no score. Served from public-domain data (U.S. Census) whatever the caller's plan. The destination must be a U.S. port or US. Resolution falls back from customs district to country, region and HS4, and the response says which level it used and how confident it is. | Docs |
Request and response
const res = await fetch("https://api.compliancegrid.ai/freight-risk/score", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CG_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
origin: "CNSHA", // port of loading (UN/LOCODE)
destination: "USLAX", // U.S. port of discharge
mode: "ocean_container",
hs_code: "8471.30",
weight_kg: 12400,
goods_value: { amount: 1490000, currency: "USD" },
freight: { amount: 6300, currency: "USD" },
}),
});
const score = await res.json();
console.log(score.score, score.level, score.driving_measure);
console.log(score.benchmark.resolution, score.benchmark.confidence);
for (const r of score.reasons) console.log(r.code, r.message);{
"id": "frs_6e082e44f8ce4e3b",
"object": "freight_risk_score",
"score": 0,
"level": "low",
"driving_measure": "freight_pct_of_value",
"measures": {
"freight_per_kg": { "value": 0.5081, "unit": "USD/kg", "z": -0.02, "percentile": 47.3,
"band": { "p5": 0.422, "p25": 0.480, "p50": 0.511, "p75": 0.680, "p95": 0.781, "n_cells": 24 } },
"freight_pct_of_value": { "value": 0.423, "unit": "%", "z": -0.62, "percentile": 32.3 },
"value_per_kg": { "value": 120.1613, "unit": "USD/kg", "z": 0, "percentile": 50.1 }
},
"reasons": [
{ "code": "OK", "severity": "info", "message": "All measures are inside the expected range for this lane and commodity." },
{ "code": "Q01", "severity": "info", "message": "Confidence is medium: the benchmark used the customs-district benchmark, built from 24 cells." }
],
"benchmark": {
"id": "bm_2026-08_CN-US:27-ocean_container_847130",
"resolution": "country_district",
"district": { "code": "27", "name": "Los Angeles, CA" },
"window": { "from": "2024-09-01", "to": "2026-08-31" },
"confidence": "medium",
"sources": ["us_census_imports_hs"]
}
}Glossary
Regulatory acronyms and data sources referenced by this API.
Robust sigma
A spread measure from the 25th to 75th percentile (IQR divided by 1.349). It is not thrown off by a few extreme shipments, which is why scores use it, not the standard deviation.
z
How many robust sigmas a value is from the benchmark median. The first sigma adds nothing to the score; the score rises toward 100 beyond it.
Resolution
How specific the benchmark is: customs district, country, or region. A thin district falls back to the country when the country has far more data.
Confidence
High with at least 30 cells at the 6-digit HS code, medium with 12 to 29 (or a region), low below that or at the 4-digit heading. Below high adds reason Q01.
Good to know
- A high score means the numbers are unusual for this lane and commodity. It does not mean fraud: odd values have ordinary causes, such as a different incoterm or a mixed container.
- Census freight charges include insurance and stop at the first U.S. port. A declared freight figure without insurance reads slightly low, and a door-to-door figure reads high (the response flags door-to-door with Q03).
- Benchmarks are U.S. imports only, in USD, from the last 24 months. Other currencies are refused with a clear error, and a lane that does not end in a U.S. port returns 404.
- Every response carries its source and the list version, so the result can go in your audit file.
- The sandbox returns mock data and production returns live data. Build in the sandbox and switch your key to go live.