API trigger
Start a workflow run with an API call, pass input in the request body, and read the run that the call creates through the Runs API.
The API trigger starts a run when your system calls POST /workflows/:id/run. Use it when your own application decides when the work should happen, for example after a month-end batch is ready.
Configuration
{ "trigger": { "type": "api" } }There are no other fields. In Studio, the API block in the Triggers group shows the run endpoint for the workflow. The request body's input reaches steps as {{input.<path>}}.
Start a run
POST /workflows/:id/run needs the workflows:execute scope and counts against the execute rate limit (500 requests per minute per key). The workflow must be active.
curl -X POST https://workflow.loopfour.ai/api/v1/workflows/$WORKFLOW_ID/run \
-H "x-api-key: $LOOPFOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": {
"customerId": "CUST-0042",
"period": "2026-10",
"amount": 12500
},
"idempotencyKey": "invoice-CUST-0042-2026-10"
}'Request body
| Field | Type | Default | Meaning |
|---|---|---|---|
input | object | {} | The run input. Checked against the workflow's inputSchema when one is set |
idempotencyKey | string | none | A key for this request. A second call with the same key for the same workflow returns the existing run instead of starting a new one |
mode | async or sync | async | sync waits for the run to finish before answering |
maxExecutionTimeMs | number, 1,000 to 300,000 | 30,000 | How long a sync call waits |
onTimeout | return_run_id or throw_error | return_run_id | What a sync call does when the wait runs out |
onFailure | throw_error or switch_to_async | throw_error | What the call returns when the run fails or cannot be queued |
Responses
| Situation | Status | data |
|---|---|---|
async run queued | 202 | run_id, status: "pending", workflow_id, mode: "async" |
Same idempotencyKey seen before | 200 | run_id and status of the existing run, workflow_id, message |
sync run finished | 200 | run_id, status, workflow_id, mode: "sync", output, duration_ms |
sync wait ran out (return_run_id) | 202 | run_id, status, mode: "async", timed_out: true |
Run failed, onFailure: "switch_to_async" | 202 | run_id, status: "failed", error, switched_to_async: true |
The response fields of this endpoint use snake case (run_id, workflow_id). The Runs API uses camel case.
Errors
| Status | Code | Cause |
|---|---|---|
400 | WORKFLOW_NOT_ACTIVE | The workflow is a draft, paused or archived |
400 | VALIDATION_ERROR | input failed the workflow's inputSchema; details.errors lists each problem, such as Missing required field: customerId |
404 | NOT_FOUND | No workflow with that id in your company |
408 | SYNC_TIMEOUT | A sync wait ran out and onTimeout was throw_error |
500 | TRIGGER_ERROR | The run was recorded but could not be queued. It is marked failed |
500 | the run's error code, or WORKFLOW_FAILED | A sync run failed and onFailure was throw_error. details.run_id names the run |
The input check covers the required list and the top-level type of each property. It does not look inside nested objects.
Follow the run
curl https://workflow.loopfour.ai/api/v1/runs/$RUN_ID \
-H "x-api-key: $LOOPFOUR_API_KEY"The response has status, input, output, stepResults, error, startedAt, completedAt and durationMs. Poll until status is completed, failed or cancelled; a few seconds between calls is enough for most workflows. GET /runs/:id/logs returns the step-by-step log. See the Runs API.
Run any workflow on demand
This endpoint starts any active workflow, whatever its trigger type. That makes it the simplest way to test a webhook, email or schedule workflow: post an input in the shape that trigger would produce. For a webhook workflow:
{
"input": {
"webhookEvent": {
"provider": "stripe",
"eventType": "invoice.paid",
"payload": { "data": { "object": { "id": "in_123", "amount_paid": 9900 } } }
}
}
}Studio's Run button calls the same endpoint. Those runs are recorded with trigger type manual instead of api.
Loopfour