Documentation Index
Fetch the complete documentation index at: https://docs.pinkfish.ai/llms.txt
Use this file to discover all available pages before exploring further.
Async Polling
When your workflow takes more than a few seconds to complete, use the async pattern: fire the trigger, then poll for status and retrieve results when done.
This is the recommended approach for integrations that need to programmatically retrieve workflow results.
How It Works
Trigger the workflow asynchronously
Call the trigger endpoint with x-api-wait: false (or omit the header entirely). The API returns immediately with an empty body. Two response headers contain the IDs you need for polling:
X-Pf-Run-Id: The unique identifier for this workflow run
X-Pf-Automation-Id: The automation/workflow ID
curl -s -i --location 'https://triggers.app.pinkfish.ai/ext/triggers/YOUR_TRIGGER_ID' \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: YOUR_API_KEY' \
--header 'x-api-wait: false' \
--data '{"user_request": "process this data"}'
Response headers:X-Pf-Run-Id: 1778786207851669420
X-Pf-Automation-Id: d831ue4rccbc73knbi80
Poll for status
Check the status endpoint until the workflow completes. Poll every 2-5 seconds for typical workflows.Polling endpoints always use the webhook-style URL format (/ext/webhook/{apiKey}/...) — even if you triggered the workflow using the API endpoint with X-API-KEY header authentication.
curl -s 'https://triggers.app.pinkfish.ai/ext/webhook/YOUR_API_KEY/runs/AUTOMATION_ID/RUN_ID/status'
Response:{
"automationId": "d831ue4rccbc73knbi80",
"runId": "1778786207851669420",
"status": "COMPLETE",
"stepStatus": {
"1": "COMPLETE"
},
"stepInfo": {
"1": {
"status": "COMPLETE",
"name": "Step 1",
"executionOrder": 1
}
}
}
Status values:| Status | Meaning |
|---|
PENDING | Workflow is queued but not yet started |
RUNNING | Workflow is currently executing |
COMPLETE | Workflow completed successfully |
FAILED | Workflow failed with an error |
TIMEOUT | Workflow exceeded execution time limit |
Fetch the results
Once the status is COMPLETE, retrieve the full results:curl -s 'https://triggers.app.pinkfish.ai/ext/webhook/YOUR_API_KEY/runs/AUTOMATION_ID/RUN_ID/results'
Response:{
"automationId": "d831ue4rccbc73knbi80",
"automationVersion": 3,
"automationName": "Hello World",
"id": "1778786207851669420",
"type": "TRIGGER",
"results": [
{
"stepIndex": 1,
"stepVersion": 3,
"resultUrls": {
"output.txt": {
"url": "https://run-files.app.pinkfish.ai/...",
"mimeType": "text/plain",
"size": 13
},
"stdout.txt": {
"url": "https://run-files.app.pinkfish.ai/...",
"mimeType": "text/plain",
"size": 419
}
},
"exitCode": 0,
"duration": 2264
}
],
"started": "2026-05-14T19:16:47Z",
"status": "COMPLETE"
}
Complete Examples
Bash
#!/bin/bash
API_KEY="YOUR_API_KEY"
TRIGGER_ID="YOUR_TRIGGER_ID"
# Step 1: Fire the trigger
RESPONSE=$(curl -s -i --location "https://triggers.app.pinkfish.ai/ext/triggers/$TRIGGER_ID" \
--header 'Content-Type: application/json' \
--header "X-API-KEY: $API_KEY" \
--header 'x-api-wait: false' \
--data '{"user_request": "process this data"}')
# Step 2: Extract IDs from response headers
RUN_ID=$(echo "$RESPONSE" | grep -i "X-Pf-Run-Id" | cut -d' ' -f2 | tr -d '\r')
AUTOMATION_ID=$(echo "$RESPONSE" | grep -i "X-Pf-Automation-Id" | cut -d' ' -f2 | tr -d '\r')
echo "Run ID: $RUN_ID"
echo "Automation ID: $AUTOMATION_ID"
# Step 3: Poll for status
while true; do
STATUS_RESPONSE=$(curl -s "https://triggers.app.pinkfish.ai/ext/webhook/$API_KEY/runs/$AUTOMATION_ID/$RUN_ID/status")
STATUS=$(echo "$STATUS_RESPONSE" | jq -r '.status')
if [ "$STATUS" = "COMPLETE" ]; then
echo "Workflow completed!"
break
elif [ "$STATUS" = "FAILED" ] || [ "$STATUS" = "TIMEOUT" ]; then
echo "Workflow ended with status: $STATUS"
exit 1
fi
echo "Status: $STATUS, waiting..."
sleep 3
done
# Step 4: Fetch results
RESULTS=$(curl -s "https://triggers.app.pinkfish.ai/ext/webhook/$API_KEY/runs/$AUTOMATION_ID/$RUN_ID/results")
echo "$RESULTS" | jq '.'
JavaScript / TypeScript
const API_KEY = "YOUR_API_KEY";
const TRIGGER_ID = "YOUR_TRIGGER_ID";
const BASE = "https://triggers.app.pinkfish.ai";
async function triggerAndPoll(payload) {
// Step 1: Fire the trigger
const res = await fetch(`${BASE}/ext/triggers/${TRIGGER_ID}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": API_KEY,
"x-api-wait": "false",
},
body: JSON.stringify(payload),
});
const runId = res.headers.get("X-Pf-Run-Id");
const automationId = res.headers.get("X-Pf-Automation-Id");
// Step 2: Poll for status
while (true) {
const statusRes = await fetch(
`${BASE}/ext/webhook/${API_KEY}/runs/${automationId}/${runId}/status`
);
const { status } = await statusRes.json();
if (status === "COMPLETE") break;
if (status === "FAILED" || status === "TIMEOUT") {
throw new Error(`Workflow ended with status: ${status}`);
}
await new Promise((r) => setTimeout(r, 3000));
}
// Step 3: Fetch results
const resultsRes = await fetch(
`${BASE}/ext/webhook/${API_KEY}/runs/${automationId}/${runId}/results`
);
return resultsRes.json();
}
const results = await triggerAndPoll({ user_request: "process this data" });
console.log(results);
Python
import requests
import time
API_KEY = "YOUR_API_KEY"
TRIGGER_ID = "YOUR_TRIGGER_ID"
BASE = "https://triggers.app.pinkfish.ai"
def trigger_and_poll(payload):
# Step 1: Fire the trigger
res = requests.post(
f"{BASE}/ext/triggers/{TRIGGER_ID}",
headers={
"Content-Type": "application/json",
"X-API-KEY": API_KEY,
"x-api-wait": "false",
},
json=payload,
)
run_id = res.headers["X-Pf-Run-Id"]
automation_id = res.headers["X-Pf-Automation-Id"]
# Step 2: Poll for status
while True:
status_res = requests.get(
f"{BASE}/ext/webhook/{API_KEY}/runs/{automation_id}/{run_id}/status"
)
status = status_res.json()["status"]
if status == "COMPLETE":
break
if status in ("FAILED", "TIMEOUT"):
raise Exception(f"Workflow ended with status: {status}")
time.sleep(3)
# Step 3: Fetch results
results_res = requests.get(
f"{BASE}/ext/webhook/{API_KEY}/runs/{automation_id}/{run_id}/results"
)
return results_res.json()
results = trigger_and_poll({"user_request": "process this data"})
print(results)
Designated Output
If your trigger has a designated output configured, the results response includes a top-level designatedOutput field with a direct link to the output file:
{
"id": "1773184744204578408",
"status": "COMPLETE",
"results": [ ... ],
"designatedOutput": {
"url": "https://run-files.app.pinkfish.ai/...",
"fileName": "retrieved-poem.txt",
"mimeType": "text/plain",
"size": 117
}
}
To download just the designated output:
RESULTS=$(curl -s "https://triggers.app.pinkfish.ai/ext/webhook/YOUR_API_KEY/runs/$AUTOMATION_ID/$RUN_ID/results")
DESIGNATED_URL=$(echo "$RESULTS" | jq -r '.designatedOutput.url // empty')
if [ -n "$DESIGNATED_URL" ]; then
curl -s "$DESIGNATED_URL"
fi
Best Practices
- Poll interval: Every 2-5 seconds for most workflows. For long-running workflows, poll every 10-30 seconds.
- Set a timeout: Add a maximum polling duration to avoid infinite loops in production.
- Handle errors: Always check for
FAILED and TIMEOUT statuses in your polling loop.
- Use step status: The
stepStatus field in the status response lets you track progress of multi-step workflows while they run.