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

# Notification Campaign Lifecycle

> Campaign statuses (Editing / Dev / Live / Offline / Archived), runnable filter, versioning, transactional priority — everything that happens after an event matches.

# Campaigns

A campaign is a dashboard-defined reaction to an event. It owns the orchestrator code that builds recipients, the channel configurations that render messages, and a status that controls when it runs. This page covers the full lifecycle.

## TL;DR

* **Five statuses**: `Editing`, `Dev`, `Live`, `Offline`, `Archived`. The first four are runnable; `Archived` is terminal.
* **`Dev` is gated to dev environments** — never runs on prod.
* **Each save creates a new version**; in-flight workflow instances run against the version they started on.
* **Two categories**: `transactional` campaigns jump the queue ahead of `promotional` ones.

## Statuses

```mermaid theme={null}
stateDiagram-v2
    [*] --> Editing
    Editing --> Dev
    Dev --> Live
    Live --> Offline
    Offline --> Live
    Dev --> Editing
    Editing --> Archived
    Dev --> Archived
    Live --> Archived
    Offline --> Archived
    Archived --> [*]
```

The five statuses:

| Status     | Meaning                                                                                                        |
| ---------- | -------------------------------------------------------------------------------------------------------------- |
| `Editing`  | Campaign exists but the orchestrator code is unfinished or unreviewed. Dev-side iteration territory.           |
| `Dev`      | Orchestrator is staged for review on dev. **Runs on dev only**; explicitly skipped on production environments. |
| `Live`     | Approved for production. Receives every matching event in every environment.                                   |
| `Offline`  | Paused. The campaign is not removed; restart by promoting back to `Live`.                                      |
| `Archived` | Terminal. The campaign no longer creates workflow instances; existing in-flight instances finish.              |

The `Live ↔ Offline` cascade is built in — demoting a campaign cascades to dependents (e.g. archiving the upstream event).

## Runnable filter

When an event arrives, Notifizz looks up campaigns matching the event name and filters to a **runnable subset** — `Editing`, `Dev`, `Live`, `Offline`. `Archived` is the only status that's hard-excluded at instance creation.

A `Dev` campaign is then explicitly skipped on production environments — orchestrators staged for review can never accidentally fire on prod traffic. Whether `Editing` and `Offline` proceed to actual delivery depends on downstream step processing.

## Versioning

Each save publishes a new campaign version. The version number is monotonic per campaign and stamped on the workflow instance at creation time. In-flight instances run against the version they started on, even if a newer version has shipped since — there's no mid-flight surprise.

The  Practical implications:

* Editing a `Live` campaign is safe for in-flight messages.
* Rolling back to a previous version means re-publishing the older orchestrator code (the dashboard exposes a "rollback to version N" UI).
* Two campaigns at different versions targeting the same event each create independent workflow instances on the matching version.

## Transactional vs promotional

Campaigns carry a `category` :

| Category        | Examples                                         | Queue priority                                |
| --------------- | ------------------------------------------------ | --------------------------------------------- |
| `Transactional` | Password reset, order confirmation, invoice paid | High — popped first from `the dispatch stage` |
| `Promotional`   | Marketing, lifecycle, "we miss you"              | Standard                                      |

The split is enforced at the queue layer. If you have many promotional campaigns and a transactional one fires, the transactional message overtakes the queue.

The `category` field is part of the campaign's dashboard config; legacy campaigns without it default to `Promotional` (`DEFAULT_CAMPAIGN_CATEGORY`).

## Binding events to campaigns

A campaign listens on **one** event. Wiring is a dashboard step (or via `PUT /v1/events/:workflowId/event`):

1. Create or pick an event in the events catalogue.
2. Create the campaign with its orchestrator code.
3. Bind the campaign to the event.

To send to two distinct audiences from one product action, model **two events** (or one event with a property the campaign branches on) — not two campaigns on the same event with different recipient logic in code. The "one event, many campaigns" pattern is for unrelated reactions (e.g. customer email + ops Slack).

## FAQ

<AccordionGroup>
  <Accordion title="`Dev` vs `Live` — when to use which?">
    `Dev` is for orchestrators that are wired but haven't been reviewed for production. They run on dev environments so you can fire test events and verify the output without polluting prod. Promote to `Live` once the dev tasks are resolved and the orchestrator is reviewed.
  </Accordion>

  <Accordion title="A campaign worked in Dev but failed once promoted to Live — why?">
    Most common: the prod environment is missing a dependency the dev environment had — usually an enricher URL or a connector source. Compare the dashboard's enricher / connector sections between dev and prod. Less common: a property your test events sent isn't actually present in real production traffic.
  </Accordion>

  <Accordion title="Can I edit a Live campaign without breaking in-flight messages?">
    Yes — the new version applies only to events that arrive after the save. In-flight workflow instances run against the version they started on. The dashboard's version history shows what's currently `Live` and what's been published.
  </Accordion>

  <Accordion title="What happens to in-flight messages on archive?">
    They keep running until completion. `Archived` blocks **new** workflow instances; existing ones finish on the version they started on. If you need to stop in-flight delivery, archive the campaign and then cancel the queue jobs from the dashboard's job-monitoring view.
  </Accordion>

  <Accordion title="Can I roll back a campaign?">
    Yes. The dashboard's version history exposes a "republish version N" action — it duplicates version N as a new version (N+M, where M is the next monotonic step) and sets it `Live`. Rollback by republish, not by editing the version number directly.
  </Accordion>

  <Accordion title="Two campaigns on the same event — both fire?">
    Yes. Each match creates its own workflow instance with its own orchestrator. They share nothing beyond the inbound event payload, and they can be in different states (one `Live`, one `Dev`) without interfering.
  </Accordion>

  <Accordion title="How do I make a campaign transactional?">
    Set `category: 'transactional'` in the campaign config. The split affects queue priority, not delivery semantics — your campaign code is the same; only the queue popping order changes. The category field is per-campaign and per-version (you can change a campaign's priority across versions).
  </Accordion>
</AccordionGroup>

## See also

<CardGroup cols={2}>
  <Card title="Events" icon="bolt" href="/docs/concepts/events">
    Event grammar, properties, idempotency.
  </Card>

  <Card title="Recipients" icon="user" href="/docs/concepts/recipients">
    How the orchestrator builds the audience list.
  </Card>

  <Card title="Orchestrator" icon="robot" href="/docs/concepts/orchestrator">
    The campaign code that runs after match.
  </Card>

  <Card title="Activity log" icon="clock-rotate-left" href="/docs/concepts/activity-log">
    Audit trail of campaign edits and reviews.
  </Card>
</CardGroup>
