Choose what the sink receives
The output structure decides the shape of the JSON posted to a sink. It is set per source → sink pair, in Flow → Routing, so each destination can get exactly what it wants.
The examples below are the same Sigfox message delivered five ways, so you can compare them directly.
Full message
Everything the Center knows, wrapped around the payload. The default, and the right answer unless you have a reason to pick another.
{
"provider": "SIGFOX",
"deviceIdentifier": "1A2B3C",
"messageType": "DATA_BIDIR",
"receivedAt": "2026-08-15T13:47:45.000Z",
"idempotencyKey": "SIGFOX:1A2B3C:DATA_BIDIR:18",
"payload": {
"device": "1A2B3C",
"data": "00018d460000300040e12402",
"seqNumber": 18,
"decoded": { "index": 18.061, "unit": "m3", "battery": 100 }
},
"raw": { "device": "1A2B3C", "data": "00018d46…", "seqNumber": 18 }
}
Note idempotencyKey — the Center delivers
at least once, and that is how your side
recognises a repeat.
Raw provider frame
Exactly what the provider POSTed, untouched:
{
"device": "1A2B3C",
"data": "00018d460000300040e12402",
"seqNumber": 18,
"time": 1755265665
}
Right when the receiving system already speaks the provider's format — you are using the Center for routing and retries, not translation.
Decoded telemetry only
The envelope, with payload replaced by what your decoder returned:
{
"provider": "SIGFOX",
"deviceIdentifier": "1A2B3C",
"idempotencyKey": "SIGFOX:1A2B3C:DATA_BIDIR:18",
"payload": { "index": 18.061, "unit": "m3", "battery": 100 },
"raw": { }
}
Two things surprise people:
- It falls back. No decoder, a decoder that threw, or a callback with no
payload — and
payloadstays the full message payload instead. The same sink can see two different shapes. Checkpayload.decodeError. - Only three Sigfox callbacks are decoded.
DATA_UPLINK,DATA_BIDIRandSERVICE_DATA_ADVANCEDcarry a payload frame; the other four have nothing to decode.
Everything decoded
Everything the decoder returned, with its two groups kept apart:
{
"provider": "SIGFOX",
"payload": {
"telemetry": { "index": 18.061, "unit": "m3", "battery": 100 },
"meta": { "seqNumber": 18, "rssi": -103.41 }
}
}
They stay separate on purpose: merged, a key your decoder puts in both would
silently lose one, and nothing downstream could tell a reading from a piece of
radio metadata. If your decoder returns only telemetry, only telemetry appears.
Custom
You compose the entire body. Nothing is wrapped around your fields — no
envelope, no payload:
{
"device": "1A2B3C",
"idempotencyKey": "SIGFOX:1A2B3C:DATA_BIDIR:988",
"reading": 18.061,
"tag": "maski"
}
It starts you with four fields — device, event type, timestamp and the de-duplication key — because an empty document looks broken and those are what a sink usually needs. Every one is removable.
You pick fields, you do not type paths
The Center remembers what your decoder returns — every field, including nested ones, with its type and last value — and lists them as buttons grouped From the message, telemetry and meta. Click to include; rename if you want a different key.
Until a source's decoder has run once there is nothing to list, and the editor says so. Send one message and the fields appear.
Four kinds of row
| Row | What it does |
|---|---|
| a picked field | copies it, under whatever name you type |
| a fixed value | the same constant on every message |
| text from fields | {device}-{seqNumber} → "1A2B3C-988" |
| a computed value | arithmetic or a condition |
Text rows need no quotes and no operators — write the field names in braces and everything else literally. A missing field renders as nothing, and the row still arrives.
Nested objects
Add a nested object creates a container you can put fields inside, to any depth:
device = deviceIdentifier
meter { }
battery = decoded.battery
reading { }
value = decoded.index
unit = "m3"
which delivers:
{
"device": "1A2B3C",
"meter": { "reading": { "value": 18.061, "unit": "m3" }, "battery": 100 }
}
Drag the handle beside a field to move it — onto an object to put it inside, onto
another field to reorder. A name containing a dot nests too: meter.reading is
the same as putting reading inside meter.
An object with nothing in it is not sent; there is no reason to deliver {}.
null. That
is not an error — and the editor tells you it happened, and why, so a field never
just disappears on you.Choosing
| Want | Pick |
|---|---|
| Everything, safest default | Full message |
| The receiver already parses the provider's format | Raw provider frame |
| Just the readings, with an envelope | Decoded telemetry only |
| Readings and radio metadata, kept apart | Everything decoded |
| An exact contract the receiver already defines | Custom |
When unsure, start with Full message. It is the only one that never loses information, and narrowing later is easy.
Where the default comes from
A sink can carry its own default output structure, used by any pair that has not set one. A pair's own setting always wins; clearing it falls back to the sink's default.