OnTime Trucking · Developer Platform

Build freight workflows without leaving your system.

Quote, book, retrieve, and track OTT shipments through a scoped REST API with predictable JSON, Bearer-token auth, and traceable RFC 7807 errors. Read it here, grab the machine-readable spec, and integrate in minutes.

View as Markdown ↗
Protocol
REST · JSON · HTTPS
Authentication
Bearer API key

Start here

Overview

The OTT API follows the shipment lifecycle: create a quote, book an eligible option, then retrieve and track the resulting shipment. Every response is tenant-scoped, so your key can only read records associated with your account.

Base URL
https://ontimetrucking.com/api/v1
Machine-readable contract
/api/openapi.json

Step 1

Authenticate every request

Send your API key as a Bearer token over HTTPS. Mint one in the portal under API Access. Keys are prefixed ott_live_, shown once at creation (copy it immediately), and you can keep 2 active keys at a time so you can rotate with zero downtime.

HTTP header
Authorization: Bearer $OTT_KEY
ScopeGrants
quote:readCreate and retrieve your own rate quotes (runs the live carrier rate-shop).
shipment:readRetrieve shipment details by PRO.
shipment:writeBook an eligible saved quote and request pickup (live carrier booking).
tracking:readRetrieve live tracking status and events by PRO.

A key inherits your account's scopes — you don't choose them at mint time. Scope changes (granting or removing) apply to your existing keys instantly, on the very next call, and a key can never exceed what OTT has granted your account. Calling an endpoint you aren't granted returns 403 insufficient_scope and names the missing scope.

Step 2

Follow the integration flow

  1. 01

    Quote

    Send the lane and freight details.

  2. 02

    Book

    Turn an eligible quote into a shipment.

  3. 03

    Retrieve

    Read the shipment using its PRO.

  4. 04

    Track

    Poll the live event timeline.

Your first quote
curl -X POST https://ontimetrucking.com/api/v1/quotes \
  -H "Authorization: Bearer $OTT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "originZip": "11735",
    "destZip": "10001",
    "weightLbs": 500,
    "pieces": 1,
    "freightClass": "100",
    "accessorials": ["LIFD", "RESD"]
  }'

Reference

Endpoint directory

There is no quote-list endpoint in v1. To retrieve a quote later, retain the quoteId returned by POST /quotes.

POST/quotes

Create a rate quote

Price a shipment and get transit days for every eligible carrier option.

Required scope quote:read

FieldTypeDescription
originZipstring · requiredOrigin postal code (US, Canada, or Mexico).
destZipstring · requiredDestination postal code (US, Canada, or Mexico).
originCountry / destCountryUS · CA · MXOptional; each defaults to US.
weightLbsnumber · 1–30,000Total weight for the flat single-commodity path. Legacy: the flat body can't carry dimensions — prefer commodities[].
piecesinteger · 1–1,000Handling-unit or pallet count; defaults to 1.
freightClassstringNMFC freight class used for rating; defaults to 100.
nmfcstring · max 30Optional single-commodity item number. Prints on the BOL; does not affect price.
commodities[]array · max 30 · recommendedPer-line items (see below) — the canonical, recommended request shape. When present, becomes the rating source of truth.
commodities[].dimsInobject · REQUIREDPer-line dimensions in inches: { length, width, height }. Now required for accurate rating (carriers re-rate on measured size). Compatibility aliases dims and dimensions are accepted. All three values are required together; any side over 336" (28 ft) is refused (422). A request missing dimensions is refused with 422.
ratingModeSTANDARD · VOLUMEOptional; defaults to STANDARD (class-based LTL). Use VOLUME to force spot rating for a large load — priced off linear feet, not freight class. You don't have to set it: OTT auto-runs a spot quote per carrier when a load trips that carrier's cubic-capacity rule (TForce Item 575: 750+ cu ft and under 6 lb/cu ft).
linearFeetnumber · 8–28Required when ratingMode is VOLUME: the trailer floor space the freight occupies, in linear feet. Ignored for STANDARD.
accessorials[]string[] · max 20Optional OTT service codes or documented friendly labels (see Accessorial codes). Unknown, blank, or malformed values return 422.
Request · flat single commodity
curl -X POST https://ontimetrucking.com/api/v1/quotes \
  -H "Authorization: Bearer $OTT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "originZip": "11735",
    "destZip": "10001",
    "weightLbs": 500,
    "pieces": 1,
    "freightClass": "100",
    "accessorials": ["LIFD", "RESD"]
  }'
Request · per-commodity line items with dimensions
curl -X POST https://ontimetrucking.com/api/v1/quotes \
  -H "Authorization: Bearer $OTT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "originZip": "11735",
    "destZip": "10001",
    "commodities": [
      {
        "freightClass": "70",
        "weightLbs": 800,
        "pieces": 2,
        "nmfc": "156600",
        "dimsIn": { "length": 48, "width": 40, "height": 48 }
      },
      {
        "freightClass": "125",
        "weightLbs": 300,
        "pieces": 1,
        "nmfc": "049880"
      }
    ]
  }'
Request · volume / spot (large low-density load)
curl -X POST https://ontimetrucking.com/api/v1/quotes \\
  -H "Authorization: Bearer ***" \\
  -H "Content-Type: application/json" \\
  -d '{
    "originZip": "91764",
    "destZip": "75069",
    "ratingMode": "VOLUME",
    "linearFeet": 14,
    "commodities": [
      {
        "freightClass": "100",
        "weightLbs": 6200,
        "pieces": 6,
        "dimsIn": { "length": 48, "width": 40, "height": 60 }
      }
    ]
  }'
Example 201 response
{
  "quoteId": "qt_3Fa9c2",
  "options": [
    { "carrierOptionId": "v1.9VLCDygJZ8Z9WxAdpD4hGfaS3pHG9HOeODuBejZI9FQ", "carrierName": "TForce Freight", "totalUSD": 312.40, "transitDays": 2 },
    { "carrierOptionId": "v1.EYiAHNfjMugZqAbVW_tVF0SAjGPiyVmt5FXvyrk6psM", "carrierName": "Saia LTL Freight", "totalUSD": 318.75, "transitDays": 2 }
  ],
  "expiresAt": "2026-07-24T20:14:00Z"
}

Each totalUSD is your final all-in price — nothing to add on top. expiresAt tells you how long OTT stands behind the displayed rate. The saved quote stays retrievable past it, but booking an expired quote is refused with 409 conflict (quotes are valid for 3 days by default) — request a fresh quote to book at current pricing.

GET/quotes/{id}

Retrieve a quote

Fetch one saved quote by its API quote ID or visible carrier quote number.

Required scope quote:read

Use the API quoteId returned by quote creation. The visible carrier “Quote #” is also accepted for convenience; the API id is matched first.

Request
curl https://ontimetrucking.com/api/v1/quotes/qt_3Fa9c2 \
  -H "Authorization: Bearer $OTT_KEY"
Example 200 response
{
  "id": "qt_3Fa9c2",
  "originZip": "11735",
  "destZip": "10001",
  "weightLbs": 500,
  "pro": null,
  "createdAt": "2026-07-21T18:42:00Z"
}
POST/quotes/{id}/book

Book a quote

Create the BOL, assign a PRO, and request pickup in one idempotent call.

Required scope shipment:write

FieldTypeDescription
pickupDateYYYY-MM-DD · requiredCannot be in the past.
readyTimeHH:MM · requiredEarliest pickup time in 24-hour format.
closeTimeHH:MM · requiredDock close; must be later than readyTime.
shipFrom / shipToobject · optionalAddress override; saved quote/profile values are reused when omitted.
requesterobject · optionalPickup requester company, contact, email, and phone.
customerReferencestring · max 50Your PO or pickup reference; sent to the carrier and returned on shipment reads.
poNumberstring · max 30Purchase-order number. Prints on the OTT BOL and rides to the carrier — TForce as a structured PO reference; Saia, XPO, and Old Dominion in carrier/driver instructions.
pickupReferencestring · max 30Your pickup/warehouse reference. Prints on the OTT BOL and rides to the carrier — TForce in the native pickup Reference Number field; Saia, XPO, and Old Dominion in carrier/driver instructions.
notesstring · max 500Special handling or pickup instructions printed on the OTT BOL.
Request
curl -X POST https://ontimetrucking.com/api/v1/quotes/qt_3Fa9c2/book \
  -H "Authorization: Bearer $OTT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "pickupDate": "2026-07-23",
    "readyTime": "09:00",
    "closeTime": "17:00",
    "customerReference": "PO-88231",
    "poNumber": "PO-88231",
    "pickupReference": "WH-4471",
    "notes": "Call dock 30 minutes before arrival"
  }'
Example 201 response
{
  "quoteId": "qt_3Fa9c2",
  "status": "BOOKED",
  "pro": "773117166",
  "bolNumber": "BOL-260723-3FA9C2",
  "pickupConfirmation": "WBU68949302",
  "carrierName": "TForce",
  "customerReference": "PO-88231"
}
GET/shipments/{pro}

Retrieve a shipment

Read shipment details using its carrier PRO number.

Required scope shipment:read

Request
curl https://ontimetrucking.com/api/v1/shipments/773117166 \
  -H "Authorization: Bearer $OTT_KEY"
Example 200 response
{
  "pro": "773117166",
  "status": "IN_TRANSIT",
  "originZip": "11735",
  "destZip": "10001",
  "weightLbs": 500,
  "freightClass": "100",
  "dims": { "lengthIn": 48, "widthIn": 40, "heightIn": 48 },
  "pieces": 1,
  "nmfc": "156600",
  "customerReference": "PO-88231",
  "accessorials": ["LIFD"],
  "commodities": []
}

Note the response returns dimensions as dims.lengthIn (and null when none were captured) — the read shape, not the dimsIn.length request shape.

GET/shipments/{pro}/tracking

Track a shipment

Read the current status and carrier event timeline.

Required scope tracking:read

Request
curl https://ontimetrucking.com/api/v1/shipments/773117166/tracking \
  -H "Authorization: Bearer $OTT_KEY"
Example 200 response
{
  "pro": "773117166",
  "status": { "code": "IN_TRANSIT", "description": "In transit" },
  "pickup": { "date": "2026-07-23T14:02:00Z" },
  "delivery": null,
  "events": [
    {
      "date": "2026-07-24T09:14:00Z",
      "description": "Departed service center",
      "serviceCenter": "Edison, NJ"
    },
    {
      "date": "2026-07-23T14:02:00Z",
      "description": "Picked up",
      "serviceCenter": "Farmingdale, NY"
    }
  ]
}

Live tracking is TForce-backed in v1. Carrier brownouts return 503 with a Retry-After header; OTT self-dispatch shipments return an honest OTT dispatch status rather than a fabricated carrier timeline.

GET/shipments/{pro}/documents/{type}

Retrieve a shipment document

Download your shipment's Bill of Lading (HTML), Proof of Delivery (PDF), or Invoice (PDF) by PRO.

Required scope shipment:read

Request — Bill of Lading (HTML)
curl https://ontimetrucking.com/api/v1/shipments/773117166/documents/bol \\
  -H "Authorization: Bearer ***"
Request — Bill of Lading (PDF)
curl https://ontimetrucking.com/api/v1/shipments/773117166/documents/bol?format=pdf \\
  -H "Authorization: Bearer ***" -o bol.pdf
Request — Proof of Delivery (PDF)
curl https://ontimetrucking.com/api/v1/shipments/773117166/documents/pod \\
  -H "Authorization: Bearer ***" -o pod.pdf
Request — Invoice (PDF)
curl https://ontimetrucking.com/api/v1/shipments/773117166/documents/invoice \\
  -H "Authorization: Bearer ***" -o invoice.pdf

bol returns your shipment's OnTime Trucking Bill of Lading as a printable text/html document by default; add ?format=pdf to get it as application/pdf.pod returns the carrier Proof of Delivery as application/pdf once the shipment has been delivered; before then it returns 404. invoice returns your OnTime Trucking invoice as application/pdf once the shipment is booked. All are for shipments on your own account, looked up by their carrier PRO, and contain customer-facing information only — never carrier cost or margin.

Reference

Accessorial codes

Pass accessorial services on POST /quotes as an accessorials array. Canonical codes are recommended — for example ["LIFD", "RESD"] — and are case-insensitive. Friendly accessorial labels such as liftgate, residential, appointment, limitedAccess, inside, tradeShow, and hazmat are normalized to the matching code. Add pickup or delivery to choose the side; a directionless label defaults to delivery.

CodeServiceApplies to
INPUInside pickupPickup
LIFOLiftgate pickupPickup
LAPULimited-access pickupPickup
TRPUTradeshow pickupPickup
RESPResidential pickupPickup
IBFDIn-bond freight pickupPickup
INDEInside deliveryDelivery
LIFDLiftgate deliveryDelivery
LADLLimited-access deliveryDelivery
NTFNCall before deliveryDelivery
TRDSTradeshow deliveryDelivery
RESDResidential deliveryDelivery
GWHDGrocery warehouse deliveryDelivery
HAZDHazardous materialsShipment

Reference

Errors use RFC 7807

Switch on the stable code, not the human-readable title or detail. Every error echoes the requestId too.

Validation responses may also include an errors[] array. Each item has a machine-readable path, code, message, and optional expected value so an integration can correct the exact field.

Example problem response
{
  "type": "https://ontimetrucking.com/technology/api#errors",
  "title": "Resource not found",
  "status": 404,
  "detail": "Shipment not found.",
  "code": "not_found",
  "requestId": "0be4c35a-0f05-4905-97da-d3367748eaa4"
}
HTTPCodeMeaning
401missing_key · invalid_key · revoked_key · expired_keyAuthentication failed.
403insufficient_scope · no_tenant_scopeThe key cannot perform this operation.
404not_foundNot found, or the record does not belong to your account (no existence leak).
409conflictA concurrent booking claim is already in progress on this quote.
422validation_failedBad input — e.g. a field out of range, a side over 336", or a lane OTT dispatches itself.
429rate_limitedSlow down; wait for the Retry-After interval before retrying.
503upstream_unavailable · upstream_errorA carrier service is temporarily unavailable; see Retry-After.

Reference

Rate limits and retries

Per-client caps, shared across our servers. On exceed you get 429 with a Retry-After header (seconds) — wait, then retry.

PolicyApplies toLimit
api_defaultMost calls — quote reads, booking, shipment reads, tracking60 / minute
api_rateQuote creation (POST /quotes) — the live carrier rate-shop20 / 10 minutes

Limits are per client and shared across OTT servers. On a 429 or a retryable 503, respect the Retry-After header before trying again.

Reference

Changelog

The OTT API is versioned in the OpenAPI spec (info.version). Changes are additive and backward-compatible within v1 — new optional fields and endpoints may appear; existing request and response shapes are not broken.

v1.5.0September 2026 · current

Item dimensions are now required on POST /quotes. Carriers re-rate every shipment on measured size and weight and bill the difference (extreme-length, cube, reweigh). A class-only quote can't price those adjustments, so we now rate on real dimensions to keep your quotes accurate and avoid surprise re-rates.

  • Required now — a quote missing any line item's length, width, or height is refused with 422 validation_failed. Send each commodity with dimsIn: { length, width, height } in inches.
  • Canonical shape — use the commodities[] array (each line with dimsIn, weightLbs,pieces, freightClass). The legacy flat weightLbs/freightClass body can't carry dimensions and is no longer accepted for rating.
  • Commodity description field — each commodity line now accepts an optional plain-text description (e.g. "machine parts"). Prints on the BOL; does not affect the rate.
v1.4.0Effective August 2026

Documentation accuracy update — no request or response shapes changed. Brings the published reference in line with current live behavior.

  • Extended dimension ceiling — the per-side limit is now 336" (28 ft), not 96". Loads up to the ceiling are rated online with per-carrier extreme-length handling; only a side over 336" is refused with 422.
  • Carrier selection with carrierOptionId POST /quotes returns a carrierOptionId on every option; pass it unchanged to POST /quotes/{id}/book to book that exact priced option. A stale or unknown id returns 409.
  • Quote-expiry booking gate clarified — booking an unbooked quote past its validity window (default 3 days) is refused with 409 conflict. (Previously documented as advisory-only or a 422; the live behavior is a 409.)
v1.3.0Effective August 2026

Invoice document retrieval on GET /shipments/{pro}/documents/{type}. Backward-compatible — bol and pod are unchanged.

  • Invoice PDF — request type=invoice to download your OnTime Trucking invoice as application/pdf once the shipment is booked (before booking it returns 404). It is the same invoice shown in the OTT portal, and contains customer-facing information only — never carrier cost or margin. No new scope: it uses the existing shipment:read.
  • Bill of Lading as PDF — add ?format=pdf to type=bol to receive the BOL as application/pdf. Backward-compatible: omit it and bol still returns HTML as before.
v1.2.0Effective August 2026

Volume / spot rating for large and multi-pallet loads on POST /quotes. Backward-compatible — standard LTL requests are unchanged.

  • Volume / spot quoting — send ratingMode: "VOLUME" with linearFeet (8–28) to rate a large load off linear feet instead of freight class. Omit both for standard class-based LTL.
  • Automatic cubic-capacity spot rating — OTT computes each load's cube and density and auto-runs a spot quote per carrier when it trips that carrier's cubic-capacity rule (TForce Item 575: 750+ cu ft and under 6 lb/cu ft), with no pallet-count threshold. Volume lanes that need a manual spot quote return a clear 422 pointing to OTT dispatch (not a retryable error).
  • Safer input compatibility — per-commodity dims and dimensions are accepted as aliases for dimsIn; common accessorial labels are normalized to OTT codes; malformed or conflicting values return structured field errors.
v1.1.0Effective August 2026

Backward-compatible additions and stricter request validation. The endpoint path is unchanged (/api/v1) — the path only changes for a breaking redesign.

  • Multi-commodity quoting — send commodities[] (max 30 lines) on POST /quotes; each line rates with its own freight class and the top-level weightLbs/pieces/freightClass become optional aggregates. When present, commodities[] is the rating source of truth.
  • Per-commodity NMFC — each line accepts an nmfc item number (also available as a single-commodity nmfc). Prints on the BOL; does not affect price.
  • commodities[].dimsIn validation — dimensions live only inside a per-line dimsIn object ({ length, width, height } in inches, all three required together). A side over 336" (28 ft), or dimensions sent at the wrong level, is now rejected with 422 naming the offending field — before any carrier call.
  • Booking notes and customerReference on POST /quotes/{id}/book customerReference (your PO, echoed on shipment reads) and notes (special-handling text printed on the OTT BOL).
v1.0.0July 2026 · initial release
  • Initial public v1: POST /quotes, GET /quotes/{id}, POST /quotes/{id}/book, GET /shipments/{pro}, and GET /shipments/{pro}/tracking.
  • Bearer API-key auth with account-inherited scopes, RFC 7807 errors with a stable code, per-client rate limits, and X-Request-Id on every response.

Ready to integrate?

Start with a scoped key and one test quote.

Grab a key in the portal, then point your tooling at the spec. For support, include the endpoint, timestamp, and X-Request-Id — and never email your API key. Questions? sales@ontimetrucking.com or call dispatch at (800) 248-4630.