Skip to Content
FR8 Factory Docs

Events

The two event types, and the payload envelope they share.

load.created

Fired once, when a load record is first created. Not on update, not on status change — those are out of scope for this version.

webhook.ping

A no-op you can send at any time to test the connection. We verify the signature, store it, and acknowledge it without any processing.

It exists because testing with a real load.created is awkward for both of us: a real load id triggers a real fetch and ingest on our side, and a fake one fails as a lookup error that looks like a bug. The ping gives you signing and connectivity validation on demand, in production, with no side effects. Send it with "data": {}.

The envelope

{
  "eventId": "9f2c1a84-3d7e-4b19-a0f5-1c2e6b8d4a30",
  "eventType": "load.created",
  "occurredAt": "2026-09-23T14:31:02Z",
  "apiVersion": 1,
  "data": { "loadId": 2129858 }
}
FieldTypeNotes
eventIdUUIDUnique per event, and stable across retries — this is our idempotency key.
eventTypestringload.created or webhook.ping.
occurredAtISO 8601When the event happened, not when the request was sent. Must carry a zone.
apiVersioninteger1. Lets either side add fields later without ambiguity.
data.loadIdintegerFor load.created: the same identifier getLoadById accepts.

occurredAt must carry a zone designator

2026-09-23T14:31:02Z or 2026-09-23T10:31:02-04:00. A value with no zone — 2026-09-23T14:31:02 — is rejected with 400.

This is not pedantry. We have already had a naive timestamp from LDI shift by a full day depending on where the interpreting code ran, and the resulting wrong date looked entirely plausible in the UI. A zone designator makes that failure impossible rather than unlikely.

Why we want the id and not the whole load

We deliberately do not want the full load record in the payload, even though it would save us a call.

getLoadById is already the single definition of a load on our side, with a mapper hardened over a year of edge cases. A second representation of the same entity would be a second thing to keep correct, and any divergence between the two would be silent — the worst kind.

Fetching by id also means your schema can evolve freely: a new column appears in getLoadById and we pick it up with no change to this webhook and no conversation.

Adding event types later

You can ship a new eventType, or bump apiVersion, without coordinating a release with us. We accept anything we do not recognise with 202, store it, and ignore it.

So the sequence is: you ship, we notice, we add handling, and nothing is rejected or lost in between.

On this page

Help

How do I get API access?

API keys are issued per customer by the FR8 Factory team. Ask your account contact — or send us a request through the Help desk tab with your company name and use case.

How do I authenticate requests?

Send your API key in the Authorization header on every request. Keys are secret — never ship them in browser code or mobile apps.

Open the guide — How do I authenticate requests?

How do I keep my copy of the data in sync?

Use delta polling: request only records changed since your last sync cursor instead of re-downloading everything. The guide covers cursors, ordering, and replay safety.

Open the guide — How do I keep my copy of the data in sync?

What are the rate limits?

Limits are per API key and documented on the rate-limits page, along with the response headers that tell you where you stand and how to back off.

Open the guide — What are the rate limits?

What does each load field mean?

The load field dictionary defines every field the API returns — types, nullability, and freight-domain meaning (pick vs drop dates, AR, equipment types).

Open the guide — What does each load field mean?

Found a bug or missing data?

Send it through the Help desk tab with the request you made and what you expected back. You'll get a reference code, and we'll email you when it's resolved.