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

# Trigger with records

> Fan one trigger out into an execution per record — load a whole contact list in a single API call

A trigger doesn't have to carry a single input. Pass a `records` array — one object per row — and GetDialed fans the flow out: **one job** for the trigger, and **one execution per record**, all running concurrently. It's the natural fit for anything row-shaped: a parsed CSV, a CRM export, a nightly batch of leads.

## How fan-out works

When you `POST /definitions/{id}/trigger` with `records`:

1. One **job** is created with `record_count` equal to the number of records.
2. One **execution** is created per record. Each record becomes that execution's `input_data`, so your definition's expressions read its fields via `{{input.<column>}}` — exactly as they would for a single trigger.
3. All executions run concurrently. Each succeeds or fails independently.
4. When every execution finishes, the job gets an aggregate status.

| Job status         | Meaning                                |
| ------------------ | -------------------------------------- |
| `completed`        | Every execution succeeded              |
| `partially_failed` | Some executions succeeded, some failed |
| `failed`           | Every execution failed                 |

<Note>
  A single trigger accepts up to 15,000,000 records. Beyond that, the request is rejected with `422`.
</Note>

## Example: load a contact list

Say you have a contact CSV:

```csv theme={null}
first_name,last_name,phone
Alice,Nguyen,5551234567
Bob,Marsh,5559876543
Carla,Diaz,5555550123
```

Your flow reads each row's columns through `{{input.first_name}}`, `{{input.last_name}}`, and `{{input.phone}}`. Parse the file into one dict per row and send the rows as `records`:

```bash theme={null}
curl -X POST "$BASE_URL/definitions/def_a1b2c3d4/trigger" \
  -H "X-API-Key: $GETDIALED_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "source": "csv_upload",
    "metadata": {
      "filename": "july-leads.csv",
      "uploaded_by": "alice@example.com"
    },
    "records": [
      {"first_name": "Alice", "last_name": "Nguyen", "phone": "5551234567"},
      {"first_name": "Bob",   "last_name": "Marsh",  "phone": "5559876543"},
      {"first_name": "Carla", "last_name": "Diaz",   "phone": "5555550123"}
    ]
  }'
```

```json theme={null}
{
  "job_id": "job_55667788",
  "definition_id": "def_a1b2c3d4",
  "status": "pending"
}
```

<Tip>
  The definition can't tell the difference between a single trigger and a fan-out — each execution sees one record as its `input_data`. Build the flow once, trigger it with 1 record or 100,000.
</Tip>

## Track the job and its executions

Fetch the job to see the aggregate picture — `record_count` confirms how many executions were fanned out:

```bash theme={null}
curl "$BASE_URL/jobs/job_55667788" \
  -H "X-API-Key: $GETDIALED_API_KEY"
```

```json theme={null}
{
  "id": "job_55667788",
  "definition_id": "def_a1b2c3d4",
  "source": "csv_upload",
  "metadata": {"filename": "july-leads.csv", "uploaded_by": "alice@example.com"},
  "status": "partially_failed",
  "record_count": 3,
  "started_at": "2026-07-06T14:00:01Z",
  "completed_at": "2026-07-06T14:00:09Z"
}
```

A `partially_failed` job means some rows made it and some didn't. List just the failures to find out which:

```bash theme={null}
curl "$BASE_URL/jobs/job_55667788/executions?status=failed" \
  -H "X-API-Key: $GETDIALED_API_KEY"
```

Each failed execution carries its own `input_data` (the original record) and an `error` message — everything you need to fix the row and re-trigger just the failures as a new, smaller `records` array.

## Defer the start with scheduled\_at

To load records now but run them later — say, at the start of the calling window — add `scheduled_at` (ISO 8601):

```bash theme={null}
curl -X POST "$BASE_URL/definitions/def_a1b2c3d4/trigger" \
  -H "X-API-Key: $GETDIALED_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "source": "csv_upload",
    "records": [
      {"first_name": "Alice", "last_name": "Nguyen", "phone": "5551234567"}
    ],
    "scheduled_at": "2026-07-07T09:00:00Z"
  }'
```

The trigger response comes back with `"status": "scheduled"` instead of `"pending"`, and the executions start at the given time. Until then the job can still be cancelled with `DELETE /jobs/{job_id}` — only `pending` and `scheduled` jobs are cancellable.

## Record provenance with source and metadata

Both fields are free-form and stored on the job, so you can answer "where did this run come from?" weeks later:

| Field      | Type   | Default | Use it for                                                                           |
| ---------- | ------ | ------- | ------------------------------------------------------------------------------------ |
| `source`   | string | `"api"` | The trigger origin — e.g. `csv_upload`, `crm_sync`, `nightly_batch`                  |
| `metadata` | object | `{}`    | Anything worth keeping with the job — filename, uploader, batch IDs, correlation IDs |

Neither affects execution; they exist purely for auditing and filtering on your side.

## Trigger request reference

| Field          | Type              | Required | Description                                                                |
| -------------- | ----------------- | -------- | -------------------------------------------------------------------------- |
| `source`       | string            | no       | Trigger origin label. Default `"api"`                                      |
| `metadata`     | object            | no       | Arbitrary provenance data stored on the job. Default `{}`                  |
| `input_data`   | object            | no       | Input for a single-execution trigger. Default `{}`                         |
| `records`      | array of objects  | no       | One object per row; if non-empty, one execution per record. Max 15,000,000 |
| `scheduled_at` | string (ISO 8601) | no       | Defer the start; job status becomes `scheduled`                            |

<Warning>
  The definition must be `active` — triggering a `draft` or `archived` definition returns `400`. See [Build your first flow](/guides/build-your-first-flow) for the create-and-activate walkthrough.
</Warning>

## Next steps

<CardGroup cols={2}>
  <Card title="Jobs and executions" icon="diagram-project" href="/concepts/jobs-and-executions">
    The full lifecycle and every status in detail.
  </Card>

  <Card title="Batching" icon="layer-group" href="/concepts/batching">
    Aggregate records across executions into efficient platform calls.
  </Card>
</CardGroup>
