HaulProof

Integration guide

For engineers connecting a TMS, load board, factoring or insurance platform to HaulProof. Everything here works today against https://haulproof.ca. OpenAPI 3.1 · Live status · support@haulproof.ca

1. Keys

Send the key on every call as Authorization: Bearer <key>. Keys are shown once, stored only as a SHA-256 hash, can carry an end date and can be revoked one by one. Scopes: read, search, watchlists, alerts. Errors are JSON {"error": {"code", "message"}}; a 429 comes with Retry-After.

curl -H "Authorization: Bearer hp_test_…" "https://haulproof.ca/v1/tiers?ids=99990007,MC123456"

2. The nightly tier file (to show a tier next to every carrier)

GET /v1/tier-files returns download links valid for one hour: scope "all" is every active US carrier and every Canadian provincial profile (about 2.2 million rows, about 47 MB gzipped); scope "watchlist" is one of your watchlists. Gzipped CSV, UTF-8, header row. Columns: key, usdot, docket, nsc, cvor, nir, name, jurisdiction, status, tier, hard_rules, reasons, as_of. Rebuilt after the nightly refresh, done by 07:00 Toronto time.

3. Tiers for up to 100 carriers per call

GET /v1/tiers?ids=... takes a USDOT, MC123456, an NSC (MB9002108, AB123-4567), an Ontario CVOR (9 digits), a Quebec NIR (R-123456-7) or a key, and returns per id: key, name, dot_number, provinces, tier, hard_rules, reasons [{signal, weight, label}] and as_of, or error: not_found. Add lang=fr for French labels. Not metered.

4. Signed webhooks for changes

  1. POST /v1/watchlists, then POST /v1/watchlists/{id}/items/bulk (up to 10,000 identifiers per call; unknown ones are listed back).
  2. POST /v1/webhooks {"url", "min_severity"} returns the endpoint's signing secret once.
  3. POST /v1/webhooks/{id}/test sends one signed sample alert right away.

Each alert is POSTed as JSON {"event": "alert.created", "data": {...}} with X-HaulProof-Timestamp and X-HaulProof-Signature: sha256=<HMAC-SHA256(secret, "<timestamp>.<raw body>")>. Answer 2xx within 10 seconds; failed deliveries are retried after 1, 5 and 30 minutes, 2 hours and 12 hours. Types include authority.revoked, insurance.bipd_dropped, safety.placed_oos, safety.risk_elevated and canada.tier_changed. Polling instead: GET /v1/alerts?since_id=.

5. The full record on demand

GET /v1/carriers/{id}: the merged US and Canadian record (status, authority and its history, insurance and cancellations, 24 months of inspections and crashes, equipment, linked carriers, provincial ratings, the tier with its reasons). One call is one metered lookup; answers are cached until the next nightly refresh and carry as_of.

6. A badge to embed

GET /v1/badges/{id}.svg?lang=en returns a 230×44 SVG with the carrier's tier and "Checked with HaulProof" ("Verified by HaulProof" when the carrier verified its profile). Fetch it server-side with your key and cache it until the next refresh.

7. Sample code

All read the key from HP_KEY (and the webhook secret from HP_WEBHOOK_SECRET). Try them with a sandbox key first.

8. Limits

For platforms: how a pilot works Book a call