> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.v2.rasen.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.v2.rasen.ai/_mcp/server.

# Revisions and ETags

Resources you can edit return an `ETag` header. An edit sends that value back in `If-Match`:

```bash
ETAG=$(curl -sS -D - -o /dev/null "$RASEN_API_BASE/agents/$AGENT_ID/draft" \
       -H "Authorization: Bearer $RASEN_API_KEY" | awk -F': ' 'tolower($1)=="etag"{print $2}' | tr -d '\r')
curl -sS -X PATCH "$RASEN_API_BASE/agents/$AGENT_ID/draft" \
  -H "Authorization: Bearer $RASEN_API_KEY" \
  -H "If-Match: $ETAG" -H "Idempotency-Key: $(uuidgen)" -H "Content-Type: application/json" \
  -d '{"prompt": "You are the support agent."}'
```

| Answer                                               | Meaning                                                                                                                                                                                                            |
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `428 revision_required`                              | The edit had no `If-Match`. `details.header` is `"If-Match"`.                                                                                                                                                      |
| `409 draft_conflict`                                 | A stale ETag on an agent, its draft, a variable, a tool, an MCP server or a publication token. `details` carries `expected_etag` (the value you sent) and `current_etag`, both opaque, and may carry `changed_at`. |
| `409 conflict` with `details.reason: stale_revision` | A stale ETag on a phone number, Knowledge source, campaign, share link or telephony connection.                                                                                                                    |

When an edit is refused as stale: read the resource again, apply your change to the new state, and
retry with the new ETag. Never resend an old body with a fresh ETag: that would overwrite the change
you did not see.

## Which ETag each edit uses

| Edit                                                  | `If-Match` value                                         |
| ----------------------------------------------------- | -------------------------------------------------------- |
| Agent identity (`updateAgent`)                        | The agent's identity ETag, from `GET /agents/{agent_id}` |
| Draft, variables, tools, draft validation and publish | The draft ETag, from `GET /agents/{agent_id}/draft`      |
| MCP server replacement or disable                     | The server's own ETag                                    |
| Phone-number assignments                              | The number's ETag; it equals the body's `revision`       |
| Knowledge source reingest                             | The source's ETag                                        |
| Campaign state commands                               | The campaign's current ETag                              |
| Hosted share-link enable, disable or rotate           | The share-link ETag                                      |
| Telephony connection replacement or disable           | The connection's ETag                                    |
| Imported number removal                               | The number's ETag                                        |

Rollback does not take `If-Match`. It takes `expected_live_version_id` in the body instead, and a
live version that moved answers `409 conflict` with `details.reason: live_version_changed`.

## The draft ETag is the publication token

The draft ETag covers everything a publish would freeze: the draft revision, the revision of each
bound tool, the revision of each MCP server the tools use, every pinned secret version, the direct agent
library membership and source state/revision and the default-tool policy. A change to any of them gives
a new ETag. Editing a shared MCP server therefore changes the draft ETag of every agent that uses
it. The body's `revision` field equals the ETag.

`POST /agents/{agent_id}/publish` requires this token in `If-Match`. The server recomputes it inside
the publish, and a mismatch answers `409 draft_conflict`: the version you reviewed is the version
that goes live, or nothing does. Two publishes sent with the same token make one version.

Adding or removing a source in the direct agent library changes the token. A source state or
revision change also changes it. An MCP server rediscovered with the same tool set does not move it.

`GET /agents/{agent_id}/draft/diff` returns the same token, so you can review the changes a publish
would make and publish exactly that.

## Replays and revisions

An idempotent replay returns its stored answer before the current revision is checked, and uses the
original `If-Match`. See [Idempotency and replay](/concepts/idempotency).