Send device data over an HTTPS webhook

Webhook ingest lets a device (or any script or server) push telemetry to Synacl over plain HTTPS, instead of connecting to our MQTT broker. It's handy when a device already speaks HTTP, sits behind a firewall that only allows outbound HTTPS, or is driven by a cron job or cloud function you already run.

Data that arrives this way flows through the exact same pipeline as MQTT — live dashboards, stored history, threshold alert rules, actions, macros and egress all work the same.

Availability. Webhook ingest is a paid-plan feature enabled per account. If it isn't available on your plan, the endpoint returns HTTP 403 — see plans and limits.

The endpoint

POST https://api.synacl.com/ingest/webhook/<deviceId>
Content-Type: application/json

Use your device's own id (copy it from the device's detail page). Every request must be authenticated (below) and carry a JSON body.

Create a webhook device

The quickest path is to make webhook the device's protocol from the start:

  1. Go to Devices → Add Device and pick Webhook (HTTP push) as the protocol. No gateway or connection fields are needed.
  2. Define your tags — the keys you'll send in the JSON payload must match these names letter-for-letter.
  3. Save. You land on the device's page with the Webhook Ingest panel already live: secret minted, ingest enabled, endpoint URL and ready-to-paste curl examples on screen.

A webhook device's protocol is fixed at creation (as is mqtt-direct's) — to move an existing device to webhook push, create a new webhook device instead.

Get your webhook secret

Each device has its own secret — a string that looks like whsk_1a2b3c…. Webhook-protocol devices get one automatically at creation. You can also enable webhook push on any existing device (say, an mqtt-direct device that should fall back to HTTPS):

  1. Open the device from Devices and find the Webhook Ingest panel on its detail page.
  2. Click Generate to create a secret (or Rotate to replace an existing one).
  3. Copy it somewhere safe — treat it like a password.

Rotating invalidates the old secret immediately. Any device still using the previous secret will start getting rejected, so update it everywhere before (or right after) you rotate.

Authenticate the request

Include one of these two headers — either one is accepted:

Header What to send
Authorization: Bearer <secret> The per-device secret verbatim (whsk_…). Simplest option.
X-Synacl-Signature: sha256=<hmac> An HMAC-SHA256 of the exact raw JSON body, keyed by the secret. Nothing secret travels on the wire.

Use the signature style when you'd rather not send the raw secret with every request. If both headers are present, either one satisfies auth.

The body: two shapes

Flat — just the tag/value pairs. The server timestamps it on arrival:

{ "temperature": 22.5, "humidity": 60 }

In flat mode the keys ts, q and seq are reserved control keys — don't use them as tag names.

Native — wrap your readings in values, and set your own timestamp and quality:

{
  "ts": 1720000000000,
  "values": { "temperature": 22.5, "humidity": 60 },
  "q": "good"
}

Rules for the payload

Example: Bearer token

curl -X POST https://api.synacl.com/ingest/webhook/<deviceId> \
  -H "Authorization: Bearer whsk_1a2b3c4d5e6f7890" \
  -H "Content-Type: application/json" \
  -d '{"temperature": 22.5, "humidity": 60}'

Native shape works the same way — just change the body:

curl -X POST https://api.synacl.com/ingest/webhook/<deviceId> \
  -H "Authorization: Bearer whsk_1a2b3c4d5e6f7890" \
  -H "Content-Type: application/json" \
  -d '{"ts": 1720000000000, "values": {"temperature": 22.5}, "q": "good"}'

Example: HMAC signature

Sign the exact raw bytes you're about to send, then send those same bytes. If you re-format or re-serialize the JSON after signing, the hash won't match.

SECRET="whsk_1a2b3c4d5e6f7890"
BODY='{"temperature": 22.5, "humidity": 60}'

# HMAC-SHA256 of the raw body, keyed by the secret, as hex
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $2}')

curl -X POST https://api.synacl.com/ingest/webhook/<deviceId> \
  -H "X-Synacl-Signature: sha256=$SIG" \
  -H "Content-Type: application/json" \
  -d "$BODY"

This is the same signature scheme Synacl uses for outbound webhooks — see verifying webhook signatures for the details.

What to expect back

Once a reading lands, open the device or a dashboard bound to it — you should see the value appear live within a second or two, just as if it had come in over MQTT.

When something's wrong, check Events

Your device gets the HTTP error, but you might not be watching it. Rejected pushes also raise a warning on the Events page, so a broken integration is visible from inside Synacl:

Event What it means
Ingest Auth Failed The secret was wrong or missing. Usually a rotation that never made it to the device.
Ingest Bad Payload The body didn't match either accepted shape — often a nested object where a number belongs.
Ingest Unknown Tag The push succeeded, but a key matched none of the device's tags.

That last one is the quiet killer. A typo like voltag_battery instead of voltage_battery is still accepted with a 202 — the reading is simply filed under a name nothing is bound to, so your dashboard stays empty while the API keeps reporting success. The response body also names the offending keys:

{ "accepted": true, "tags": 1, "unknownTags": ["voltag_battery"] }

To keep the event log readable, each kind of failure is recorded at most once a minute per device — a device retrying in a loop produces one warning, not thousands.