TruckTabs API · v1

TruckTabs API

Send a route, a vehicle and a load. Get back the permits each state needs, what they cost, and a link your carrier can pay from. The same engine as trucktabs.com, over HTTP.

Getting started

The API is for businesses whose own software handles oversize and permitted freight: brokers, carriers with a dispatch system, TMS vendors. Keys are issued by our team. Request access below and we reply by email, usually within a business day.

Every request goes to one base URL, and every body in both directions is JSON:

Base URL
https://trucktabs.com/api/v1

Once you have a key, call GET /me first. It proves the key works and shows what it can do.

curl
curl https://trucktabs.com/api/v1/me \
  -H "Authorization: Bearer $TRUCKTABS_API_KEY"
200 OK
{
  "client": { "id": "3f6c2b8e-5d1a-4f7e-9c2b-8a1d4e6f7b90", "name": "Example Logistics" },
  "key": {
    "id": "9a4e1c7d-2b3f-4d5e-8f6a-1b2c3d4e5f60",
    "name": "Production",
    "prefix": "tt_live_Ab3x",
    "scopes": ["read", "write"],
    "expires_at": null
  },
  "limits": {
    "read_requests_per_minute": 100,
    "write_requests_per_minute": 30,
    "quotes_per_minute": 30,
    "quotes_per_day": 500
  }
}

Then read Quotes to price your first route. Places, state limits, the vehicle and trailer codes, and every error code are in the Reference.

Authentication

Send your key in the Authorization header on every request. Keys start with tt_live_. Never put a key in a URL, where it ends up in logs.

Header
Authorization: Bearer tt_live_…
  • Call from your servers only. The API sends no CORS headers, so a browser can't call it. A key in a web page or a mobile app is a key anyone can copy.
  • We never email a key. You get a one-time link that shows the key once, and it expires after 24 hours. We store only a fingerprint of the key, so we can't look it up for you later. If it's lost, we issue a new one.
  • Scopes. A read key can look things up. A write key can also create quotes.
  • Rotating a key. Ask us for a second key, move your systems to it, then tell us to revoke the old one. Both work in the meantime.

A missing, unknown, revoked or expired key gets 401 UNAUTHORIZED. A suspended account gets 403 CLIENT_SUSPENDED, and a read key creating a quote gets 403 FORBIDDEN_SCOPE.

Requests and responses

  • Send request bodies with Content-Type: application/json, at most 32 KB. Unknown fields are refused rather than ignored, so a misspelled field name is an error you see, not a dimension that silently goes unpriced.
  • Money is a JSON number in dollars with cents, alongside "currency": "USD". Times are ISO 8601 in UTC.
  • Dimensions take an explicit unit: { "value": 13.5, "unit": "ft" } or "unit": "in".
  • Every response carries an X-Request-Id header. Include it when you contact us about a request and we can find it straight away.
  • Status codes mean what they say. A failed request never comes back as 200.
  • An unsupported method, such as PUT /quotes, gets 405 with an empty body.
  • US states only, for now.

Errors

Every error has the same shape. Branch on code, which never changes meaning. message is a sentence you can show a person.

422 Unprocessable Content
{
  "error": {
    "code": "INVALID_INPUT",
    "message": "The request is missing 2 required fields.",
    "details": {
      "missing": [
        { "field": "vehicle.trailer_axles", "message": "Axles on the trailer." },
        { "field": "load.gross_weight_lbs", "message": "The gross weight in pounds, including the load." }
      ]
    }
  },
  "request_id": "req_7Kq2mX9vB4nT1pR8sL3w"
}

A quote request reports every problem at once, in details.invalid for values that are wrong and details.missing for values we need. The full list of codes is in the Reference.

Rate limits

WhatLimitCounted per
Read requests (GET)100 a minutekey
Write requests (POST)30 a minutekey
Quotes created30 a minutekey
Place lookups60 a minutekey
Quotes createdYour daily allowance, shown by GET /me. Every quote that reaches pricing countsaccount, midnight to midnight UTC

Over a per-key limit you get 429 RATE_LIMITED with a Retry-After header in seconds, plus X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. Over the daily allowance you get 429 QUOTE_LIMIT_REACHED; ask us if you need more. If quoting is briefly unavailable on our side you get 503 UNAVAILABLE, also with Retry-After.

A 429 with an HTML body instead of JSON is our firewall, not the API. It happens when a request reaches us without an Authorization header.

Retrying safely

Creating a quote creates a real draft order. To retry after a timeout without creating a second one, send an Idempotency-Key header with a value you generate once per quote, such as a UUID: 8 to 128 letters, digits, _, ., : or -.

Header
Idempotency-Key: 6f1d8f0e-3c2a-4b7e-9d15-2a8c4e7b9f31
  • For 24 hours, the same key with the same body returns the quote it created, as it stands now, with the headers Idempotent-Replayed: true and Location. Nothing is priced or created again.
  • Only a success is kept. After an error, the same key runs the request again, so you can correct the body and resend it with the same key.
  • The same key with a different body is refused with 409 IDEMPOTENCY_MISMATCH, unless the earlier request failed.
  • While the first request is still running, a retry gets 409 IDEMPOTENCY_IN_PROGRESS and a Retry-After header. If it never finishes, a retry two minutes later picks up the same order: it returns the quote, or finishes pricing it.

Versioning

The version is in the path. Within v1 we only add things: new fields in responses, new optional fields in requests, new error codes for new situations. Build your client to ignore fields it doesn't know. Renaming or removing anything would be v2, running beside v1, and we would tell you well ahead.

Request access

Tell us who you are and what you're building. A person on our team reads every request. Use your work email address: we issue keys to businesses.