# Definitions API

Everything you author, as files, and the safety-railed way to apply an edited copy of it back. The three endpoints the [CLI](/content/docs/cli/index.html) is a thin client of.

| Method & path | What it does |
| --- | --- |
| `GET /api/v1/definitions` | The whole surface as `{ files: { path: contents } }`. |
| `POST /api/v1/definitions/diff` | What applying these files would change. Changes nothing. |
| `POST /api/v1/definitions/apply` | Diff, validate, rehearse, apply — all or nothing. |

The file formats are documented at [definition files reference](/content/docs/reference/definitions-repo.html). Authoring artifacts only: people, events, runs, sends and money are runtime and never appear, and neither do credentials.

## Pull

```bash
GET /api/v1/definitions

{ "files": {
    "flows/trial_journey.json": "{ … }",
    "emails/0042-welcome-aboard.md": "---\nid: 42\n…",
    "settings.yml": "tunables:\n  …" } }
```

Canonically formatted — one key order, one indent, one trailing newline — so a pull straight after a pull is byte-identical, and an unrelated push doesn't churn every file in the repo with reordered keys.

## Diff and apply

```bash
POST /api/v1/definitions/apply
{ "files": { "flows/trial_journey.json": "…", … },
  "prune": false,
  "force": false }
```

Send the **whole managed tree**, not a subset — absences are how removals are expressed, and a partial tree would read as a mass deletion. (With `prune: false`, the default, absences are only reported.)

### The response

```json
{ "changes": [\
    { "path": "flows/trial_journey.json", "kind": "update", "type": "flow",\
      "label": "trial_journey",\
      "summary": ["added 12-send-recap (id 12 minted)"],\
      "errors": [], "warnings": [] } ],
  "changed": 1,
  "dry_runs": [ { "flow": "trial_journey", "triggered": true, "steps": 6, "problems": [] } ],
  "notices": [],
  "parse_errors": [],
  "blocked": false,
  "ok": true,
  "applied": 1 }
```

| Field | Meaning |
| --- | --- |
| `kind` | `create`, `update`, `unchanged`, or `absent` (on your Mimeo, no file in the tree). |
| `summary` | Human-readable lines. Steps are named by handle; an email re-point is described in the chooser's terms. |
| `dry_runs` | One per changed flow, rehearsed against a real person with details that satisfy that flow's own trigger. |
| `notices` | Definitions already on your Mimeo that don't validate. Not caused by this push, and not blocking it. |
| `parse_errors` | Files that couldn't be read at all. Always blocking, never forcible. |
| `blocked` | Whether apply would refuse. |

### Matching, not filenames

Records match by identity — a key, or the `id` in a file's frontmatter — never by filename. Renaming an email changes its filename, and a rename is not a delete.

### What blocks

- **Any error** in something this push changes. Never forcible.
- **A file that can't be parsed.** Never forcible.
- **`node_id_freed` or `node_id_repurposed`** — a step wearing an id that belonged to a different step. Warnings in the validator, blocking here, because the failure is silent: whoever is parked on that id moves with it. `force: true` overrides these and only these.

A definition already broken on your Mimeo appears in `notices` and doesn't block — you can't fix it by not pushing, and one broken record shouldn't wall off every unrelated change from then on.

### Order of operations

Templates, fields and products first; then emails; then segments, guards and sequences; then flows; then settings. So a commit that adds an email and the step using it lands in one push. Everything happens in one transaction — a push that half-landed would leave your Mimeo in a state no file describes.

### Pruning

`prune: true` also removes what's on your Mimeo but not in the tree. Emails are **archived** rather than destroyed — an email that has been sent is part of the record of what went out — and a flow people have run through refuses regardless, because their history is theirs.

## Live updates

A successful apply pings every surface an admin page watches, so changes appear on an open page without a refresh.
