---
title: Trigger Step
description: The entry point for your notiflow
---

The trigger step is the starting point of every notiflow. When you run a notiflow via the API, execution begins at this step and flows through the subsequent steps.

## How It Works

When you call the run endpoint, you provide:

- **Recipients** — The users who will receive the notifications
- **Actor** (optional) — The user who caused the notification (e.g., the commenter, the follower)
- **Data** (optional) — Custom payload with dynamic content for templates
- **Topic** (alternative) — Send to all users subscribed to a topic instead of listing recipients

The trigger step receives this data and passes it to every subsequent step in the flow.

## Running via API

Use the Admin API to run a notiflow:

```bash
curl -X POST https://api.notiflows.com/admin/v1/notiflows/{notiflow_handle}/run \
  -H "x-notiflows-api-key: pk_your_api_key" \
  -H "x-notiflows-secret-key: sk_your_secret_key" \
  -H "Content-Type: application/json" \
  -d '{
    "recipients": [
      {
        "external_id": "user_123",
        "email": "jane@example.com",
        "first_name": "Jane"
      }
    ],
    "actor": {
      "external_id": "user_456",
      "first_name": "Alex"
    },
    "data": {
      "order_id": "ORD-789",
      "total": "$99.00"
    }
  }'
```

### Authentication

The Admin API requires two headers:

| Header | Description |
|--------|-------------|
| `x-notiflows-api-key` | Your project's public API key (starts with `pk_`) |
| `x-notiflows-secret-key` | Your project's secret key (starts with `sk_`) |

Find both keys in your Notiflows Dashboard under **Project Settings**.

<Callout>
Your secret key grants full access to your project. Never expose it in client-side code, commit it to version control, or share it publicly.
</Callout>

### Request Body

#### Recipients

The `recipients` field is an array of user objects. Each object must include an `external_id` — the user ID from your system. You can also include user attributes that will be stored and available in templates:

```json
{
  "recipients": [
    {
      "external_id": "user_123",
      "email": "jane@example.com",
      "first_name": "Jane",
      "last_name": "Doe",
      "phone": "+15551234567",
      "avatar": "https://example.com/avatars/jane.jpg",
      "locale": "en-US",
      "timezone": "America/New_York",
      "custom_fields": {
        "plan": "premium",
        "company": "Acme Inc"
      }
    }
  ]
}
```

| Field | Required | Description |
|-------|----------|-------------|
| `external_id` | Yes | Your system's user ID (string or integer) |
| `email` | No | User's email address |
| `first_name` | No | User's first name |
| `last_name` | No | User's last name |
| `phone` | No | Phone number in E.164 format (e.g., `+15551234567`) |
| `avatar` | No | URL to user's avatar image (must be `https://`) |
| `locale` | No | BCP 47 locale (e.g., `en-US`) |
| `timezone` | No | IANA timezone (e.g., `America/New_York`) |
| `custom_fields` | No | Arbitrary JSON object for additional user data |

If a recipient with the given `external_id` doesn't exist yet, Notiflows creates the user automatically with the provided attributes. If they already exist, their attributes are updated.

#### Actor

The `actor` field is optional and uses the same structure as a recipient object. The actor represents the user who triggered the notification — for example, the person who commented on a post or followed another user.

```json
{
  "actor": {
    "external_id": "user_456",
    "first_name": "Alex"
  }
}
```

#### Data

The `data` field is an optional JSON object containing any custom payload you want to use in templates:

```json
{
  "data": {
    "order_id": "ORD-789",
    "total": "$99.00",
    "items": [
      { "name": "Widget", "quantity": 2 }
    ]
  }
}
```

#### Topic (Alternative to Recipients)

Instead of listing individual recipients, you can send to all users subscribed to a topic:

```json
{
  "topic": "order-updates",
  "data": {
    "order_id": "ORD-789"
  }
}
```

You must provide either `recipients` or `topic`, but not both.

### Response

A successful request returns `201 Created`:

```json
{
  "notiflow_run_id": "01HQXYZ123456789ABCDEFGHIJ"
}
```

### Errors

| Status | Description |
|--------|-------------|
| 404 | Notiflow not found |
| 409 | Notiflow is not active or has no published version |
| 422 | Validation failed (missing or invalid fields) |

### Prerequisites

Before a notiflow can be run:

1. The notiflow must have a **published version** — see [Versioning](/docs/learn/building-notiflows/versioning)
2. The notiflow must be **active** (not deactivated)

## Data Context

The data you pass when running becomes available in templates throughout the flow:

| Context | Description |
|---------|-------------|
| `recipient.*` | Recipient user attributes (first_name, email, etc.) |
| `actor.*` | Actor user attributes |
| `data.*` | Custom payload you passed when running |

See [Templates](/docs/learn/building-notiflows/templates) for how to use these variables.

## Connected Steps

The trigger step connects to the first action step in your flow. This is typically a channel step, but could also be a control step like wait, digest, or a condition step for routing.
