---
title: "Run every step over the same rows (read once) → one batch job per form; ?dry=1 reports each step's mapping without filling. A refused step stops the later ones."
method: POST
path: "/api/v1/workflows/{id}/run"
tags: ["Automation"]
---

# Run every step over the same rows (read once) → one batch job per form; ?dry=1 reports each step's mapping without filling. A refused step stops the later ones.

`POST /api/v1/workflows/{id}/run`

## Request

- Base URL: `https://philforms.com`
- URL: `https://philforms.com/api/v1/workflows/{id}/run`
- Auth: HTTP bearer

## Path parameters

- `id` string, required

## Query parameters

- `dry` '1'

## Request body

- object
  - `row` object[]
  - `csv` string
  - `source` object: A source: { type: csv, text } · { type: xlsx, data (base64) } · { type: url, url, header? } · { type: sheet, url (a Google Sheets link shared "anyone with the link") } · { type: airtable, base_id, table, view?, token } · { type: supabase, url (https://<ref>.supabase.co), table, select?, key (a read-only role) } · { type: static, row }. Tokens, keys and auth headers are sealed on save and never returned.
  - `as_of` string

## Response `200`

Dry run: { workflow_id, row_count, header, step: [{ form_id, mapping, mapped_column, unmapped_column, unfed_parameter, … }] }

## Other responses

- `202`: { workflow_id, row_count, step: [{ form_id, job, poll, … }] }
- `402`: A form needs a paid plan
- `404`: No such workflow

---

[API](https://skmtc.dev/philforms/apis/philforms-api.md) · [All operations](https://skmtc.dev/philforms/apis/philforms-api/llms.txt) · [OpenAPI document](https://skmtc.dev/philforms/apis/philforms-api/revisions/a43bf313729c?raw)
