Everything you author in SendOps is versioned. Change a template's wording, tighten
a segment rule, rename an attribute, edit a workflow — SendOps snapshots what was
there before and records **who** made the change. You can read the history, see
exactly what one edit changed, and put an earlier version back.

This covers all seven authored kinds:

| Kind | Where its history lives |
|---|---|
| **Templates** | `GET /v1/templates/{slug}/versions` |
| **Segments** | `GET /v1/segments/{id}/versions` |
| **Lists** | `GET /v1/lists/{id}/versions` |
| **Topics** | `GET /v1/topics/{name}/versions` |
| **Attributes** | `GET /v1/attributes/{id}/versions` |
| **Activity properties** | `GET /v1/activity-properties/{id}/versions` |
| **Drip Workflows** | `GET /v1/workflows/{id}/versions` |

## Reading the history

Open a definition in the dashboard and click **History**. A panel slides in with
every recorded edit, newest first. Each row gives you:

- **The version number** — the handle you use everywhere else. Numbers only mean
  something relative to that definition's own history.
- **Who made the edit** — a person's name, an API key's name, or the name of a
  connected app. An edit made by software is attributable even though no person
  made it.
- **When** it happened.
- **A one-line summary** of how that version differs from the one before it —
  `+3 −1 lines` for something with source text, `renamed` or
  `type string→number` for a schema definition. The oldest row reads
  *first recorded version*.



Select a version to see its full content, or compare it against the definition as
it stands now. A template, segment or workflow compares as a **unified diff** of
its source; an attribute, activity property, List or topic compares
**field by field**, because there is no text to diff.

The same three things are available over the API —
`GET …/versions/{version}` for one snapshot, `GET …/versions/{version}/diff` for
the comparison, `POST …/versions/{version}/restore` to put it back — and to an AI
agent through the [MCP server](/ai-agents/mcp-server)'s `definitions_history`
tool.


  A definition keeps its last fifty versions. If you need a permanent record of
  everything that ever changed, that's what [keeping a copy in
  git](/templates/keeping-a-copy-in-git) is for — and the [audit
  log](/team/audit-log) records the fact of every change indefinitely, even after
  a version falls off the end.


## A version is the state *before* the edit

This is the one thing worth getting straight before you restore anything.

A snapshot is written by the edit that **replaces** it. So version 4 is what the
definition looked like *until* edit 5 changed it — not what edit 4 produced. The
newest row is the state immediately before the most recent edit, and the state
you are looking at right now has no row of its own until somebody changes it
again.


  A workflow records the state **after** each edit. Its newest version row *is*
  its current definition, and its numbering therefore runs one ahead of every
  other kind's. If you are restoring a workflow, the version you want is usually
  one number different from the one you'd pick for a segment.


## Restoring

A restore is an ordinary edit whose content happens to be old.


  <Step title="Pick the version">
    Open **History**, find the version you want, and read it — or diff it against
    the current definition — before you commit to it.
  </Step>

  <Step title="Restore it">
    Click **Restore**, or call `POST /v1/{kind}/{id}/versions/{version}/restore`.
    You need the kind's *manage* permission; reading the history only needs
    *view*.
  </Step>

  <Step title="Review and save">
    The definition is now the old content. In an editor, the restored text is
    loaded for you to review — restore another version if you picked the wrong
    one.
  </Step>


### A restore does not delete history

Restoring version 4 does not throw away versions 5, 6 and 7. The restore
snapshots whatever it replaced in the same transaction, so:

- **The versions after the one you restored are still there.** Nothing is
  removed from the history, ever.
- **The restore itself appears in the history**, attributed to whoever ran it.
- **The restore is undoable** — restoring the version the restore created puts
  you back where you were.

That is why restoring is not treated as a dangerous operation. Nothing is lost,
so it is the right way to fix a bad edit rather than retyping what was
overwritten.

A restore also deliberately ignores the usual "has anyone changed this since you
loaded it?" check. *"Whatever is there now, make it this"* is not a statement
about what you last read.

### What a restore touches beyond the definition

Three kinds do something extra, because the definition alone isn't the whole
story:

**A restored template is redeployed to SES.** The restored body goes out to your
AWS account like any other save, so what sends matches what is stored. Its deploy
state reads *pending* until it lands — saved is not the same as sendable.

**A restored topic is re-pushed to your contact list.** What a subscriber sees on
the [unsubscribe page](/sending-email/unsubscribe-page) follows the restore. Every
contact's own stored preference for the topic is untouched.

**A restored workflow changes nothing about its runs.** Restoring a
[workflow](/workflows/overview) does **not** change its status — an active
workflow stays active, a draft stays a draft. It does not cancel, re-version or
touch journeys already in flight: each run keeps the definition version it
enrolled under. And it re-enrols nobody.


  Because the status doesn't change, restoring the source of an **active**
  workflow is exactly as consequential as editing it normally — the next contact
  to enrol gets the restored definition. Pause it first if you want to look
  before it takes effect.


## Who made the edit

Every version carries an actor, and it is one of:

- **A person** — someone signed in to the dashboard.
- **An API key** — the key's name, so you can tell which integration wrote it.
  See [API Keys](/api-integrations/api-keys).
- **A connected app** — an AI agent or third-party product acting on your behalf.
  See [Connected Apps](/api-integrations/connected-apps).

Older rows, written before SendOps recorded actors, read *unknown*. That's an
honest answer rather than a blank.

The label is resolved for you and never contains a key, a token or a secret. A
credential that has since been revoked falls back to a short form of its id
rather than rendering empty.


  **Version history** tells you *what the definition used to say* and lets you put
  it back. The [audit log](/team/audit-log) tells you *what happened in the
  organization*, across everything, whether or not it was versioned. Reach for
  history when you want content back; reach for the audit log when you want the
  record.


## What's next?

- [Template Management](/templates/template-management) — creating and deploying templates.
- [Export & import](/templates/export-and-import) — move whole sets of definitions in and out.
- [Keeping a copy in git](/templates/keeping-a-copy-in-git) — a permanent copy in a repository you own.
- [Audit Log](/team/audit-log) — the organization-wide record of changes.