Developers

SmartLoads Partner API and webhooks

Connect any TMS, spreadsheet or in-house tool to SmartLoads. Read an agency's loads, AI carrier leads and Cover Cards with an API key, and get signed webhooks the moment a lead comes in, matches a load or a load is booked.

In short

The SmartLoads Partner API is a REST API at https://api.smartloads.io/v1. An agency admin creates an API key in SmartLoads, and any tool can then read that agency's loads, AI carrier leads and Cover Cards as JSON. Webhooks push events such as lead.matched_load and load.booked to your URL within about 30 seconds, signed with HMAC-SHA256, or straight into a Slack channel.

Why SmartLoads has its own API

SmartLoads is an integration partner in its own right, not an add-on to one TMS. A brokerage, an agency or a TMS vendor connects to SmartLoads, so an agency's integrations don't depend on which TMS its parent brokerage runs. It's the same model TMS vendors use to connect to Truckstop.

What you can build with it:

  • Sync the live board into your TMS or a spreadsheet. SmartLoads has already turned shipper emails, PDFs and sheets into clean loads, so you read the finished loads.
  • Route AI carrier leads to your own tools. Every call the SmartLoads AI agents answer becomes a lead with the carrier, MC number, lane and the rate they asked for.
  • Pull Cover Cards. Customer paperwork forwarded to SmartLoads comes back as structured fields matched to a load.
  • React to events as they happen. Webhooks for new leads, lead-to-load matches, Cover Cards, bookings and loads leaving the board.

Authentication

Every request carries an agency API key:

Authorization: Bearer sl_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

X-API-Key: sl_live_… also works.

  • Agency admins create keys in Settings → Connectors → SmartLoads API. A key is shown once; SmartLoads stores only its SHA-256 hash.
  • Create one key per tool or partner so each can be revoked on its own. An agency can have 10 active keys.
  • A key belongs to one agency, and every response is that agency's data only.
  • Scopes: loads:read, leads:read, cover_cards:read.

Conventions

  • Base URL: https://api.smartloads.io/v1. JSON in and out.
  • Formats: timestamps are ISO 8601 UTC; dates such as board_date and ship_date are YYYY-MM-DD.
  • Pagination: lists return { "data": [...], "next_cursor": "…" | null }, oldest first. Pass next_cursor back as ?cursor=. limit defaults to 50, max 200.
  • Incremental sync: save the newest updated_at you've seen and ask for ?updated_since=<timestamp> next time.
  • Rate limit: 120 requests per minute per key. Authenticated responses carry X-RateLimit-Limit and X-RateLimit-Remaining; over the limit you get 429 with Retry-After: 60.
  • Errors: an HTTP status plus { "error": { "code": "…", "message": "…" } }.
StatusCodeMeaning
400invalid_status, invalid_cursor, invalid_updated_sinceBad parameter
401missing_api_key, invalid_api_keyNo key, wrong key, or revoked
403insufficient_scopeThe key lacks the scope for this endpoint
404not_foundUnknown endpoint, or no such record for this agency
429rate_limitedMore than 120 requests a minute
503rate_limit_unavailableThe limit couldn't be checked; retry shortly

Endpoints

GET /me

Checks a key and returns its agency and scopes.

curl https://api.smartloads.io/v1/me -H "Authorization: Bearer $SMARTLOADS_KEY"
{ "agency": { "id": "…", "name": "Example Brokerage" },
  "key": { "name": "TMS sync", "prefix": "sl_live_ab12", "scopes": ["loads:read", "leads:read", "cover_cards:read"] } }

GET /loads and /loads/{id}

Scope loads:read. Query parameters:

  • status: active (the default: on the board, not archived), open, booked, covered, archived or all
  • updated_since, limit, cursor
{
  "id": "3a2489ad-…",
  "load_number": "SL-TX-2025-0418",
  "status": "open",
  "board_date": "2026-09-14", "ship_date": "2026-09-14", "delivery_date": null,
  "customer": { "name": "Example Steel" },
  "source": "email_xlsx",
  "pickup": { "city": "JEWETT", "state": "TX" },
  "delivery": { "city": "WEIMAR", "state": "TX" },
  "equipment": { "type": "Flatbed", "length_ft": 20, "tarp_required": false },
  "freight": { "commodity": "Rebar", "weight_lbs": 48075 },
  "miles": 120,
  "rate": { "basis": "flat", "customer_total": 1000, "per_ton": null, "target_pay": 750, "max_pay": 850 },
  "posted": { "truckstop_at": "…", "dat_at": null },
  "updated_at": "…"
}

For per-ton loads, rate.basis is per_ton and rate.per_ton is the customer's rate per ton.

GET /leads and /leads/{id}

Scope leads:read. These are AI carrier leads: calls answered by the AI phone agents, plus carrier chat and board requests. Query parameters are updated_since (the default is the last 7 days), limit and cursor.

{
  "id": "…", "created_at": "…", "updated_at": "…",
  "status": "pending",
  "load_id": "…",
  "channel": "synthflow",
  "carrier": { "name": "Example Trucking", "mc": "1234567", "contact_name": "Dana", "phone": "+15125550100" },
  "lane": { "pickup": { "city": "Jewett", "state": "TX" }, "delivery": { "city": "Weimar", "state": "TX" } },
  "equipment": "Flatbed",
  "rate_asked": "900",
  "summary": "Has a 48' flatbed empty in Jewett tomorrow morning.",
  "high_intent": true
}

The AI quotes only the starting rate and never books; a person books every load.

GET /cover-cards and /cover-cards/{id}

Scope cover_cards:read. These are customer load documents forwarded to SmartLoads, read into fields and matched to a load. Query parameters:

  • status: matched (the default), possible, unmatched or all
  • since, limit, cursor

Webhooks

Agency admins add endpoints in Settings → Connectors → SmartLoads API → Webhooks: a URL, the events to send and an optional name. SmartLoads POSTs each event, usually within 30 seconds.

EventWhen it fires
lead.createdA carrier lead comes in: AI phone agents, carrier chat, Telegram or the public board
lead.matched_loadA lead is tied to a load on the board, at intake or when someone attaches it later
cover_card.readyForwarded paperwork has been read, and again when someone confirms its load
load.bookedA load is booked
load.coveredA booked load has its carrier
load.removedA load leaves the board: archived, cleared or deleted

Each request looks like this:

POST https://your-tms.example.com/smartloads
Content-Type: application/json
X-SmartLoads-Event: lead.matched_load
X-SmartLoads-Delivery: 0b8f…
X-SmartLoads-Signature: t=1790000000,v1=<hex HMAC-SHA256>

{ "id": "5c1f…", "type": "lead.matched_load", "created_at": "2026-09-26T18:04:11Z",
  "agency_id": "…", "data": { "lead": { … }, "load": { … } } }
  • id is the event id. The same event sent to two endpoints has the same id, so use it to drop duplicates.
  • data uses the same shapes as the read API and shows the record as it was when the event happened.

Verify the signature

Each endpoint has a signing secret (whsec_…), shown once when you add it. v1 is the hex HMAC-SHA256 of "<t>.<raw body>". Recompute it from the raw body, compare in constant time, and reject any t more than 5 minutes old.

import crypto from "node:crypto";

function isFromSmartLoads(rawBody, header, secret) {
  if (!header) return false;
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  if (!(Math.abs(Date.now() / 1000 - Number(parts.t)) <= 300)) return false;
  const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
  const given = Buffer.from(parts.v1 ?? "");
  const wanted = Buffer.from(expected);
  return given.length === wanted.length && crypto.timingSafeEqual(given, wanted);
}

Retries

  • Reply with any 2xx within 10 seconds; do slow work after you reply. Redirects aren't followed.
  • A failed delivery is retried after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours and 12 hours: 7 tries over about a day.
  • If every delivery to an endpoint fails for 3 days, SmartLoads switches it off and shows why. Switching it back on resumes delivery.
  • The URL must be public https. Private and internal addresses are refused.

Slack

Paste a Slack incoming-webhook URL as the endpoint and events arrive as readable Slack messages. A matched lead shows the carrier, MC number, contact and phone, the load and lane, the rate they asked for, the call summary and a link to the lead. It's the quickest way to ping a channel when an AI lead matches a load.

Frequently asked questions

Does SmartLoads replace our TMS?

No. Your TMS stays the system of record for settlements, carriers and accounting. SmartLoads runs the operational front end: load intake, the live board, posting and carrier calls. The API is how your TMS or tools read what SmartLoads produces.

Can the API book or cover loads?

Not in v1, which is read-only plus webhooks. Writing loads in from a TMS is next. Booked and covered status will only ever come from a person's action, never from AI.

How do we get access?

If your agency uses SmartLoads, an admin creates a key in Settings → Connectors → SmartLoads API. If you're a TMS vendor or developer building for broker agencies, contact us through the form on smartloads.io.

Is there a sandbox?

Not yet. A sandbox agency with sample loads and leads is on the roadmap alongside partner apps.

Already a SmartLoads agency? Create a key in Settings → Connectors → SmartLoads API. Building a TMS integration? Talk to us.

Contact us