Working with Webhooks
Have Surfact push readings to your systems as they arrive, instead of polling the API.
Webhooks
Surfact can push data to your systems the moment it arrives. Instead of polling GET /variables/{id}/values/ on a timer, you give us an endpoint and we POST each new reading to it — the pattern we recommend for integration partners feeding a fleet management or transport management system.
Two ways to receive data
| You want | Use |
|---|---|
| Every reading from your devices as it lands — a live feed into your own system | A streaming webhook, set up by the Surfact team (this page) |
| Only readings that cross a threshold — an alert, not a feed | A web-hook action on an event, which you configure yourself |
The rest of this page covers streaming webhooks.
How it works
Whenever one of your devices reports, Surfact sends an HTTP POST to your endpoint. Delivery is per variable: a tracker that reports temperature, humidity and battery in one packet produces three requests, one for each reading. You receive every variable the device reports — filter for the ones you need when you receive them.
Your endpoint should respond with a 2xx to acknowledge receipt.
Example: temperature into a transport management system
A reefer trailer reports a new temperature sample. Your TMS receives:
{
"device": {
"name": "Reefer Trailer 21",
"id": "6a7c777c1da2efbc51f62ba9",
"label": "reefer-trailer-21",
"properties": {
"device-serial": "18e-9e1-242",
"destination": "Bergen Cold Hub",
"max-temp-threshold": "-15",
"min-temp-threshold": "-22"
},
"data": {
"temperature": {
"value": "-18.4",
"context": {},
"timestamp": "1788377538000"
}
}
}
}| Field | Description |
|---|---|
device.label | The device's API label — the same key you use on /devices/~{label} |
device.properties | The device's properties as they stand when the reading arrives. device-serial is the serial printed on the tracker, usually the key you already hold in your TMS |
device.data | Exactly one key — the label of the variable that just reported: temperature, humidity, battery, position, … |
data.<label>.value | The reading, as a string — parse it as a number on your side |
data.<label>.timestamp | When the device took the sample, POSIX milliseconds, as a string. Order on this — a device that was out of coverage delivers its backlog late |
data.<label>.context | Extra keys on the reading. For position this carries lat and lng; see Device Position |
Match on device.properties["device-serial"], read the single key under device.data, and write its value against its timestamp. That is a live temperature trace per shipment with no polling.
Numbers arrive as strings
valueandtimestampare JSON strings, not numbers. A typed deserialiser expecting a float will reject the payload — coerce them explicitly.
The payload shape is fixedEvery webhook delivers this structure. If your system needs a different one, transform it on receipt.
Limits
- 4 requests per second per webhook. If your devices produce more than four readings in the same second, the excess is dropped, not queued.
- Every variable fires. A webhook is scoped to devices, not variables — when a device in scope reports, you receive one request for each variable in that packet, and there is no way to subscribe to only some of them. An Emma tracker typically reports ten or more variables per packet, so two trackers reporting in the same second already exceed the limit. Tell us the size of the fleet and what you need the data for, and we will advise on how to scope the webhook — for example, one webhook per device group — so it stays within the limit. Filter to the variables you need on your side.
- Don't treat the webhook as your only copy. Every reading also remains available through the API, so a periodic reconciliation pull is good practice for anything you depend on — it covers a dropped request or a period when your endpoint was unreachable.
Setting one up
Webhooks are configured by the Surfact team. Send [email protected]:
- Endpoint URL — HTTPS, reachable from the public internet.
- HTTP method — normally
POST. - Headers we should send — typically an
Authorizationheader or API key your endpoint expects. - Which devices — all of your devices, or a named organization or device group. This is the only scoping available; all variables on those devices will be delivered.
We configure it, send a test reading to your endpoint with you on the line, and switch it live once you confirm it landed.
Updated about 2 months ago