> For the complete documentation index, see [llms.txt](https://docs.kiloiot.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kiloiot.io/devices/commands/verification.md).

# Confirming Commands

How Kilo IoT Server confirms a command took effect — no verification, next-uplink check, or query after the ack.

Command verification helps you follow a request through to device feedback. After sending a saved command, Kilo can compare a reported reading with the state you expected, such as a valve's reported position. That gives operators more information than a delivery receipt alone.

Verification is optional: choose **No verification**, **Wait for next uplink** (the next incoming message), or **Query after acknowledgement**, according to the command and device. Sending or accepting a command does not by itself prove physical execution.

Emulated devices offer **No verification** only. Their generated values can exercise dashboards and rules, but do not verify delivery to physical hardware.

Configure the check per command in **section 4** of the [command editor](/devices/commands/creating-commands.md). The strategies below explain what each result can tell you.

## No verification

Fire-and-forget. The command is sent and the platform does not check the result.

With this strategy, an execution is marked **Delivered as soon as the downlink is accepted for delivery — not when the device acts on it.** (The green **Delivered** status means exactly that: sent, but unverified — distinct from **Confirmed**, which only a verification strategy can produce. The warning the editor shows under this option says the execution is marked *Confirmed*; in the execution list the status you will see is **Delivered**.) There is no guarantee the action had any effect. This is appropriate for non-critical, idempotent actions where a missed command is harmless and will be re-sent anyway, but never rely on it as proof that something physically changed.

## Wait for next uplink

After the command is sent, the platform waits for the device's next regular uplink and checks it against the **expected sensor states** you define. When the reported values match, the execution is confirmed.

This suits devices that report on a schedule and reflect their state in normal telemetry — for example, a controller that includes its current setpoint or relay position in every uplink.

## Query after ack

The most thorough option. After the device acknowledges the command, the platform sends a **query command** — a small read that pokes the device for its current state — and matches that query's uplink response against the expected states.

On a LoRaWAN device, turn **Confirmed downlink** on in section 2 (Routing) before choosing this strategy. The query is sent once the device acknowledges the command, so there has to be an acknowledgment to wait for — the command will not save otherwise. If you would rather not use a confirmed downlink, choose *Wait for next uplink*.

* **Query command** — Select an existing query command, or **create a new one** inline. A query command is a dedicated, lightweight command type: a **state-polling read with no operator parameters**, so there is nothing to fill in at execute time. It is always itself set to **No verification** — the query *is* the verification step, and its uplink is what gets checked, so it carries no verification block of its own. Any command that takes no parameters and uses No verification can serve as a query command and appears in this list. Once saved it appears in the Commands list, flagged as suitable as a query, and can be reused by any other command's *Query after ack*.
* In the **New query command** dialog you define the payload that polls the device. For MQTT devices, choose whether to **Send as-is** (deliver the payload exactly as written) or **Process with encoder** (run it through the device's encoder first).
* The query runs after the device acks, and its response is evaluated against the expected states below.

Use this when a device does not volunteer its state in routine uplinks but will answer a direct read.

## Expected sensor states

<figure><img src="https://2057878315-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtNQh1wBSHSaknslMdOXm%2Fuploads%2Fgit-blob-790ad766b881ec2bfe4167b00af37dd8014e79b3%2Fkilo-command-verification-expected-states.jpg?alt=media" alt="Section 4 Verification of the command editor with Wait for next uplink selected: the Expected sensor states list with the Add State button and the message Add at least one expected state to verify the result, and the Convergence timeout field"><figcaption></figcaption></figure>

Both *Wait for next uplink* and *Query after ack* check the device's reported telemetry against the states you declare here. Click **Add State** to add a row, and fill in the two fields below. Add at least one row — the command will not save without it, and a row only counts when both its **Metric** and its **Expected value** are filled in. The editor flags the incomplete field in place (*Select a metric* or *Expected value is required*) and keeps **Save** disabled, so a half-filled row can no longer be dropped silently and leave the command saved without the check you thought you had.

### Metric

Select the sensor that the command changes. A command that switches a relay is checked against the sensor reporting the relay's state, not against battery level or signal strength.

The dropdown lists the device's sensors under the names you gave them when mapping — the same names you see on dashboards and in rules. Those names are not the field names inside your decoder: a decoder that outputs `socket_status` may appear here as *Socket status*. To see which sensor carries which decoded field, open the device's Mapping section — see [Payload Decoding and Connector Keys](/devices/payload-decoding.md).

Choose a sensor that is already mapped and receiving readings. Unmapped sensors also appear in this list, and a command checked against one never receives a value to compare, so verification cannot confirm the expected state. If the device has no sensors mapped yet, the editor links you to the Mapping section to set them up first.

### Expected value

Enter the value the sensor should report once the command has taken effect. Write it exactly as the device reports it — open the device's Mapping section and read the sensor's current value to see the form to copy.

**For a text state**, type it directly. Match the reported spelling, for example `ON` for a device reporting `ON`.

**For a number or a true/false state**, reference a command parameter instead of typing the value: enter `{{ parameterName }}` and declare that parameter as Integer, Float, or Boolean in the payload section. A value you type is always treated as text, so a typed `1` looks for the text `1` and will not match a device reporting the number 1.

**To follow the operator's input**, use the same `{{ parameterName }}` reference — a "set brightness" command can check that the device now reports whatever brightness was requested. The name must match a parameter defined in the payload section; the editor flags it if it does not.

| The sensor reports  | Enter                                          |
| ------------------- | ---------------------------------------------- |
| `ON`                | `ON`                                           |
| `open`              | `open`                                         |
| `60` (a number)     | `{{ level }}`, with **level** declared Integer |
| `true` (true/false) | `{{ state }}`, with **state** declared Boolean |

If a command keeps finishing as *Soft warning* even though the device clearly responded, check this field first: compare what you entered against the value the sensor is actually reporting in the Mapping section.

## Convergence timeout

The **Convergence timeout** is how long the platform waits for the reported state to match before it gives up.

* Leave it empty to use the platform default of **1.5 × the device's data sending interval**. Set that interval accurately on the device first, because the default follows it.
* Or enter a positive whole number of seconds, up to **86400** (24 hours). The editor does not flag a value it cannot use: an empty box, zero, a negative number or text silently falls back to the default above, and the server rejects anything over 86400 when you save.
* If the window passes without a match, the execution is marked **Soft warning** rather than Failed — the platform could not confirm the expected result within the window. Check Details to distinguish missing acknowledgement from missing state feedback. This distinction matters operationally: a soft warning is "we couldn't confirm," not "it definitely failed."
* Review the execution details before sending the action again, especially if repeating it could have another effect.

## Choosing a strategy

| Strategy             | Confirms                                        | Best for                                            |
| -------------------- | ----------------------------------------------- | --------------------------------------------------- |
| No verification      | Dispatch status, without a reported-state check | Low-stakes, repeatable actions                      |
| Wait for next uplink | Reported state on the next scheduled message    | Devices that report their state routinely           |
| Query after ack      | Reported state from a direct query              | Devices that answer reads but don't volunteer state |

Once verification is set, move on to [Executing Commands](/devices/commands/executing-commands.md) to dispatch the command and watch the result. For the whole sequence on one device — payload, verification and execution — see [Example: Smart Socket](/devices/commands/smart-socket-example.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.kiloiot.io/devices/commands/verification.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
