# Commands and receipts

> Every write carries your own command_id, so retries are safe and a lost reply can always be reconciled.

Every operation that changes something is a **command**. You generate a UUID, send it as `command_id`, and Browlix applies the command at most once.

## Retrying safely

- The first time, the reply is `201` with `replayed: false`.
- Sending the **same `command_id` with the same body** again returns the stored result with `200` and `replayed: true`. Nothing is applied twice.
- Sending the same `command_id` with a **different body** is `CONFLICT`: one id names one intent.

So when a request times out or the connection drops, resend it with the same id. Never generate a new id for a retry — that would be a second command.

## After a lost reply

If you are not sure a command was received, ask for its receipt instead of writing again:

```bash
curl https://browlix.com/api/public/v1/receipts/$COMMAND_ID \
  -H "Authorization: Bearer $BROWLIX_API_KEY"
```

`NOT_FOUND` means the command never arrived, so sending it is safe. A receipt tells you how it ended.

## `OUTCOME_UNKNOWN`

Some effects happen outside Browlix — a page submitting a form, a webhook to your server. When a step's effect cannot be confirmed, Browlix says so with `OUTCOME_UNKNOWN` (HTTP 202) instead of guessing, and automation never repeats such a step on its own. Decide with `run_targets.resolve` (`happened` / `not_happened`) or look at the target system.

## In the SDK, CLI and MCP

- The SDK generates a `command_id` when you omit one and returns it as `reply.commandId`; its automatic retries reuse it.
- The CLI prints the id it used; pass `--command-id` to retry with the same one.
- MCP tools generate one when the agent omits it and return it in the result; after a disconnect the agent calls `receipts_get` with it.
