You can keep a complete, readable copy of your SendOps configuration in your own
git repository — templates, segments, lists, topics, attributes and workflows —
and push changes back whenever you like. Nothing about this makes the repository
authoritative. It is a copy you own, and a door you can push through.

This is the answer to three different questions people ask:

- *"Can I review template changes in a pull request?"* Yes.
- *"Can I see what changed last Thursday and put it back?"* Yes, though the
  version history in SendOps answers that one without git.
- *"If we stop using SendOps tomorrow, do we still have our templates?"* Yes.
  Export whenever you want; the format is files.

## Export what you have

**Settings → Export** downloads your organization as a zip. Unzip it into a
repository and you have this:

```
sendops.json
templates/welcome.html
templates/receipt.html
audience/all-contacts.sendql
audience/lists.json
audience/topics.json
audience/attributes.json
audience/workflows/onboarding.flow
```

`sendops.json` is the index: it names every template, segment, list, topic and
workflow, and where each one's file lives. Everything else is the content, in the
format it was authored in — HTML for templates, SendQL for segments, the `.flow`
language for workflows.

Commit that, and you have a copy that diffs. When something changes in SendOps,
export again and the diff shows you what moved.

## Push changes back

The same format goes the other way. **Settings → Import** takes a zip and applies
it, and it always shows you a plan first:

> `welcome` — update · `receipt` — unchanged · `winback` — create
>
> **2 changes**

Nothing is written until you confirm, and an import that finds a problem anywhere
writes nothing at all — not even the objects that were fine. A bundle describes
one intended state, so applying half of it would leave you somewhere nobody
chose.

Re-importing a bundle you have not changed does nothing and says so. That is
worth knowing: it means importing is never a risky thing to try.

## Doing it automatically

If your team builds emails in a repository — with [React Email](https://react.email), MJML, or anything else that renders to HTML — your
pipeline can push straight to SendOps when a pull request merges. Add one step:

```yaml
- uses: AltaCoda/sendops-push@v1
  with:
    dir: ./sendops
    api_key: ${{ secrets.SENDOPS_API_KEY }}
```

Point `dir` at whatever your build writes. On a pull request, set `dry_run: true`
and the check shows the reviewer exactly what merging would do — including any
error, with the file and the line it is on. On merge, the same step applies it.

Create the API key under **Settings → API keys**. It needs the *manage*
permission for each kind you push: templates, segments, lists, topics,
attributes, activity properties, workflows, images. A key that can deploy
templates and nothing else is a good key.

The full setup, including the pull-request recipe, is in the developer
documentation under [Push templates and definitions from
CI](https://developers.sendops.dev/api-reference/push-from-ci).

## What this is not

**It is not a two-way sync.** SendOps does not watch your repository and your
repository does not watch SendOps. You export when you want a copy, and you push
when you want your changes applied. Anything you change in the dashboard simply
becomes what the next export says.

**It does not lock you out of the dashboard.** People can keep authoring in
SendOps while a pipeline pushes templates. The two only collide if you turn on
**prune**, which archives things your bundle omits — leave it off while anyone
still authors outside the repository.

**It is not your history.** SendOps keeps its own version history for every
template, segment, list, topic, attribute and workflow, with who changed it and
what changed, and a restore button. You get that whether or not you keep a copy
in git.