> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trylath.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Every Lath operation is POST https://platform.trylath.com/<operation name with dots replaced by slashes>, with a JSON body and `Authorization: Bearer <key>`. `email.send` is POST /email/send.
> Branch on `error.code`, never on `error.message`. Every refusal also carries `error.fix`, which names the next step.
> Send an `Idempotency-Key` header on any operation that is not retry-safe, so a retry cannot run it twice.
> A `lath_test_` key emails only the account's own members and sends no SMS; a `lath_live_` key reaches real recipients and is billed.
> The OpenAPI document, generated from the same registry as the routes, is at https://platform.trylath.com/openapi.json.

# Automations

> A tree of steps a contact walks through, one step at a time, because an event enrolled them. Nothing runs until you activate it, and nothing activates while a send inside it cannot go out.

## An event enrols, a tree decides

An automation is a trigger and a list of steps. The trigger names one event type — matched exactly, with no wildcards — and the event's payload names the contact through its `contactId`. An optional filter narrows it further: the event enrols only if its payload contains the keys and values you give.

Enrolment happens in the database as the event is written, not in a worker polling for new ones, so an event either enrols a contact or it does not, at the moment it is raised.

An automation cannot be triggered by its own product's events — a trigger starting with `email.automation.` is refused, because that is how loops start.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://platform.trylath.com/email/automation/create \
    -H "Authorization: Bearer $LATH_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"name":"Welcome","trigger":{"event":"audience.contact.created"},"steps":[{"type":"wait","seconds":3600},{"type":"send","channel":"email","template":"welcome","topic":"onboarding","from":"hello@example.com"}]}'
  ```

  ```ts TypeScript theme={null}
  import { createLath } from "@trylath/sdk";

  const lath = createLath({ key: process.env.LATH_API_KEY });

  const { result } = await lath.email.automation.create({
    name: "Welcome",
    trigger: { event: "audience.contact.created" },
    steps: [
      { type: "wait", seconds: 3600 },
      {
        type: "send",
        channel: "email",
        template: "welcome",
        topic: "onboarding",
        from: "hello@example.com",
      },
    ],
  });
  ```
</CodeGroup>

## The four kinds of step

**wait** holds the run and wakes it later — up to ninety days. **send** sends one template on a channel, against a consent topic the contact must have granted on that channel; email needs a `from` on a verified domain, SMS sends from the deployment's number and takes neither `from` nor a subject. **property.set** writes one value onto the contact. **branch** tests a condition and descends into one arm.

A branch reads three things: a property on the contact, a field from the event that enrolled them, or whether a consent topic is granted. Consent is per channel, so the same topic can be true for email and false for text.

A tree may hold fifty steps and nest four branches deep. A single execution will take a hundred steps before it gives up, which is what stops a malformed tree running forever.

## Draft, active, paused, archived

Creating an automation leaves it a draft and returns its readiness — every reason a send inside it could not go out, such as a sender that is not verified, a topic or template that does not exist, or a missing legal address. Activating is refused while any of those stand, so the failure arrives when you are building rather than halfway through somebody's journey.

Pausing stops new enrolments and freezes the runs in progress where they are; activating again resumes them. Archiving retires the automation and cancels every run still in flight, telling you how many, while the definition and the history stay readable.

## Editing something that is already running

Steps are stored as one tree and read fresh each time a run is picked up, so a run already under way continues against the **current** tree from the position it had reached. Change the shape underneath it and that position can stop pointing at anything, which fails the run rather than guessing where it meant to be.

This is the one genuinely sharp edge here. Pause before you reshape a live tree, and let the runs drain or cancel them deliberately.

## Watching runs

A run is `running`, `waiting`, `completed`, `failed` or `cancelled`. `email.automation.run.list` pages them newest first and can be narrowed to one automation, one contact or one status; each run carries its position in the tree and the log of every step it took with the outcome.

Cancelling one run stops that contact where they are. Messages earlier steps already queued are not recalled — queued means handed over, and pretending otherwise would be the one lie this documentation cannot afford.

A contact enrols once by default: an earlier run blocks a new one whatever became of it, completed, failed or cancelled alike. Set `reenter` when a journey is genuinely meant to run again.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://platform.trylath.com/email/automation/run/list \
    -H "Authorization: Bearer $LATH_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"limit":50}'
  ```

  ```ts TypeScript theme={null}
  import { createLath } from "@trylath/sdk";

  const lath = createLath({ key: process.env.LATH_API_KEY });

  const { result } = await lath.email.automation.run.list({ limit: 50 });
  ```

  ```bash CLI theme={null}
  lath email automation run list --limit 50
  ```
</CodeGroup>
