Start runs from your systems
A pipeline trigger is a secret URL that starts a run with your inputs and returns the exact rows that run produced. Up to four runs at once, a test dialog, and ready-made code.
A pipeline trigger gives one pipeline a secret URL. POST JSON to it and a run starts with the inputs you sent. The answer carries a status URL for that run alone, and once the run completes, result URLs that return exactly the rows it produced. Use it from a scheduler you already have, a deploy step, a Zapier zap, or your own application.
- Start
POST /api/ingest/<trigger>, answers 202- Follow
status_urlfor that run- Read
result_url, 100 rows a page- At once
- Up to four runs per pipeline; 429 beyond that
- POST inputsthe pipeline's inputs as JSON
- 202 + status_urlone run per request
- Poll statusuntil completed
- Page the resultsthe exact version this run wrote
The URL is the secret. There is no separate key, header or signature. Anyone who has the trigger URL, or a status or result URL built from it, can use it until the trigger is deleted. Keep it server-side, and if it leaks, delete the trigger and create a new one.
Create a trigger
- Ask for one. Open Integrations → Inputs → Connect Input, choose Webhooks, and pick the suggestion “Start a pipeline run when my system calls a URL”, or say which pipeline. From a pipeline’s Integrations tab, Add input does the same with the pipeline already named.
- Open it. Jason creates the trigger and links to it. The card and the page header show the pipeline’s icon.
- Copy the URL. It is on the Settings tab.
The pipeline’s own Run dialog shows a banner, “Pipeline Trigger attached”, with a link to the trigger (“2 triggers attached” when there are several), so anyone running it by hand knows it can also be started from outside.
Trigger settings
The Settings tab reads, top to bottom:
- Trigger endpoint. “POST JSON to start a run. Up to four can run at once (429 if full). The response includes
run_idand a secretstatus_urlfor exact results.” - Pipeline to run. A pipeline with an active version. Required. A workspace with none shows “No pipelines with an active revision in this workspace yet.”
- URL. The trigger URL, with Copy.
- Pipeline inputs. One row per input the pipeline accepts: its id, its type (
string,int,list[url]and so on), “Default:” with its default value when it has one, and its description. These are the fields you may send in the body. - Save. Stores a change of pipeline.
The tabs after Settings are Code (see Code samples), Activity (every request, accepted or refused, with the run it started) and Delete. Deleting the trigger stops its URL, and every status and result URL built from it, immediately.
Start a run
An empty body starts the pipeline with its defaults and its default row cap, exactly as pressing Run would:
curl -X POST https://factory.jsonify.com/api/ingest/marketint009
To pass inputs, send them as top-level JSON fields. Two optional run controls sit alongside them:
| Field | Values | Default | What it does |
|---|---|---|---|
| each input id | As its type | The input’s default | One field per pipeline input, as listed on the Settings tab |
row_limit |
0 or a positive number |
The pipeline’s default row cap | The row cap for this run. 0 runs all rows |
pipeline_version |
A version number | The active version | Run a specific version instead |
curl -X POST https://factory.jsonify.com/api/ingest/marketint009 \
-H 'Content-Type: application/json' \
-d '{"region": "uk", "include_out_of_stock": false, "row_limit": 0}'
The nested form {"params": {"region": "uk"}, "row_limit": 0} is also accepted. Do not send the same input both ways; the request is refused. Inputs are checked as in the Run dialog: a wrong type or an unknown name is a 400 with the reason.
The answer is HTTP 202 Accepted as soon as the run is queued:
{
"ok": true,
"run_id": "mrun00000361",
"pipeline": "marketpipe03",
"status": "queued",
"status_url": "https://factory.jsonify.com/api/ingest/marketint009/runs/mrun00000361"
}
Runs started this way show the trigger webhook on the runs list, and the run’s Integrations tab names the trigger under In. They count rows like any other run, and a failing one is eligible for automatic repair in the same way as a scheduled run.
Up to four runs at once
Each pipeline can have up to four runs queued or running at the same time, whether they came from the trigger, the Run button or another tool. Every accepted request gets its own run, even when two requests send identical inputs.
A fifth request, while four are still outstanding, is refused with HTTP 429:
{"error": "Pipeline has 4 outstanding runs; retry after one finishes"}
Nothing is queued behind it. Wait a moment and send it again; the code samples do this for you. The same limit applies to the Run button in Jsonify, and the pipeline page shows one “Run 3f9a2c is active” banner per run in flight. A scheduled run is skipped while its pipeline has a run outstanding.
Runs of the same pipeline each publish their own dataset version. The one that finishes publishing last becomes the dataset’s active version. That is why you should always read results through the URLs a request returned, never through the dataset’s latest version: they point at the exact version your run wrote.
Check the status
status_url belongs to one run and to the trigger that started it. Fetch it until status is completed, failed or cancelled; every couple of seconds is plenty.
curl https://factory.jsonify.com/api/ingest/marketint009/runs/mrun00000361
{
"ok": true,
"run_id": "mrun00000361",
"pipeline": "marketpipe03",
"status": "completed",
"created_at": 1789452131,
"finished_at": 1789452498,
"results": [
{
"dataset": "marketdata02",
"dataset_name": "Price observations",
"version": 61,
"table": "main",
"row_count": 1184,
"result_url": "https://factory.jsonify.com/api/ingest/marketint009/runs/mrun00000361/results/marketdata02?table=main"
}
],
"results_truncated": false
}
Output results
A pipeline that publishes no dataset, and only produces run outputs, lists those instead. Each entry has output, description, row_count and a result_url ending in /results/output-<id>:
{
"output": "Weekly price summary",
"description": "One row per retailer",
"row_count": 24,
"result_url": "https://factory.jsonify.com/api/ingest/marketint009/runs/mrun00000361/results/output-8812"
}
Read the results
Each result_url returns a page of the exact version, or output, that the run produced. Pages hold up to 100 rows; add offset and limit to choose, and follow next_url while has_more is true.
curl 'https://factory.jsonify.com/api/ingest/marketint009/runs/mrun00000361/results/marketdata02?table=main&offset=0&limit=100'
{
"ok": true,
"run_id": "mrun00000361",
"pipeline": "marketpipe03",
"dataset": "marketdata02",
"dataset_name": "Price observations",
"version": 61,
"table": "main",
"row_count": 1184,
"offset": 0,
"limit": 100,
"rows": [ { "...": "..." } ],
"has_more": true,
"next_url": "https://factory.jsonify.com/api/ingest/marketint009/runs/mrun00000361/results/marketdata02?table=main&offset=100&limit=100"
}
An output result has the same shape, with output and description in place of dataset, dataset_name, version and table. Because the version is pinned, you can page through it at leisure; a later run does not change what this URL returns.
Errors
| Answer | Meaning |
|---|---|
400 “Invalid run config:” |
An input failed validation, was supplied both directly and inside params, or the body was not a JSON object |
400 “Integration is not live” |
The trigger is not Live. Open it and check its status |
404 “Integration not found” |
Wrong URL, or the trigger was deleted |
404 “Configured pipeline not found” |
The pipeline was deleted. Open the trigger and pick another |
409 “Pipeline has no active revision” |
The pipeline has never been activated; finish its first build in Jsonify |
429 “Pipeline has 4 outstanding runs; retry after one finishes” |
Four runs are already queued or running. Retry shortly |
404 “Trigger run not found” |
The run was not started by this trigger, or the identifier is wrong |
409 “Trigger run is not completed” |
Results were requested before the run finished |
400 “offset and limit must be integers” |
A paging parameter was not a whole number |
Every refused request is recorded on the trigger’s Activity tab as “Rejected a request”, with the reason.
Test a trigger from Jsonify
Test, in the trigger’s page header, opens the Test API request dialog. It sends real requests from your browser, so a test starts a real run that counts rows.
The dialog has two tabs.
Start run:
Get result:
Close leaves the dialog. Every request also appears on the Activity tab.
Code samples
The Code tab holds three samples built from the trigger’s real URL and the pipeline’s current inputs. Each is a collapsible card with Copy; Python comes first and starts open, followed by cURL and JavaScript (Node.js).
Every sample does the whole job:
- Sets your inputs as constants at the top, with each input’s default and, in Python, the other allowed values as a comment.
ROW_LIMIT = 0runs all rows;PIPELINE_VERSIONis empty for the latest. - Starts the run, and retries every two seconds while the pipeline is at its four-run limit (
429). - Polls the status URL every two seconds until the run completes, fails or is cancelled.
- Reads every result page, following
next_url, and prints the rows.
The Python and JavaScript samples stop after five minutes, and raise an error if the run failed or produced more than 100 results. The cURL sample needs jq.
The essential Python flow is:
started = requests.post(TRIGGER_URL, json={**inputs, "row_limit": 0}, timeout=30)
# 429 means four runs are outstanding: wait and post again.
status = requests.get(started.json()["status_url"], timeout=30).json()
# ...poll until status["status"] == "completed", then page each result_url.
A deployment step posts to the trigger after each catalogue import, waits on the status URL, then pages the result into the search index. Two imports that land at once each get their own run and their own rows. The row cap, inputs and version are all in the request, so the step needs nothing from the Jsonify UI.