TurfAI Developer Docs

Quickstart

Trigger your first TurfAI workflow over HTTP, from webhook to result.

Trigger a workflow and read its result in four HTTP calls: create a webhook, trigger it, poll with the returned token, and read the output. You'll need a TurfAI account, a JWT (see Authentication), and the ID of a workflow (an "activity") to trigger.

Base URLs: staging is https://apisandbox.turfai.in/api, local development is http://localhost:1338/api. All examples below use staging.

The flow

1. Create a webhook for your workflow

A webhook binds a public trigger URL to one workflow (activity). This call needs your JWT.

curl -X POST https://apisandbox.turfai.in/api/webhooks \
  -H "Authorization: Bearer $TURFAI_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "activity": 123,
    "name": "Quickstart Webhook"
  }'
{
  "success": true,
  "data": {
    "id": 1,
    "name": "Quickstart Webhook",
    "url": "https://apisandbox.turfai.in/api/webhooks/trigger/1",
    "secret_key": "a1b2c3d4...64_char_hex...",
    "active": true,
    "trigger_count": 0
  }
}

Save the url and secret_key. The secret is shown in full only on create and regenerate — store it like a password.

2. Trigger the workflow

The trigger endpoint is public — it authenticates with the X-Webhook-Secret header, not your JWT. Any JSON body becomes the workflow's inputs.

curl -X POST https://apisandbox.turfai.in/api/webhooks/trigger/1 \
  -H "X-Webhook-Secret: $WEBHOOK_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "candidate_name": "Jane Smith",
    "email": "[email protected]",
    "resume_file_id": "1ABC123xyz"
  }'
{
  "success": true,
  "execution_id": 456,
  "message": "Workflow execution started",
  "polling_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

You get back an execution_id and a short-lived polling_token (a JWT, ~1 hour) scoped to polling this one execution.

To send files, use multipart/form-data instead of JSON. Each uploaded file is stored as a document and injected into the workflow as inputs.<field>_file_url and inputs.<field>_document_id. See Event-driven automation and Build a chatbot.

3. Poll for the result

Use the polling_token as a Bearer token to check status. Poll every 2–5 seconds and stop on a terminal status (completed or failed).

curl https://apisandbox.turfai.in/api/workflow-executions/456 \
  -H "Authorization: Bearer $POLLING_TOKEN"
{
  "data": {
    "id": 456,
    "status": "completed",
    "inputs": { "candidate_name": "Jane Smith" },
    "outputs": {
      "Classify resume-classify-1": { "type": "resume", "confidence": 0.95 },
      "Extract fields-extract-1": { "name": "Jane Smith", "skills": ["Python", "ML"] }
    },
    "started_at": "2025-11-24T10:00:00.000Z",
    "completed_at": "2025-11-24T10:00:45.000Z"
  }
}

Status values: queued (waiting), running (executing), completed (success), failed (check the error field). A long-running workflow with a human step can also report awaiting_user_input — see the HITL guide.

4. Read the output

The data.outputs object holds each node's output, keyed by "<node label>-<node id>". Pull the field you need with JSONPath in your own code, or chain another task in the workflow that emails or POSTs the result somewhere.

A complete poller

import os, time, requests

BASE = "https://apisandbox.turfai.in/api"

def trigger(payload):
    r = requests.post(
        os.environ["WEBHOOK_URL"], json=payload,
        headers={"X-Webhook-Secret": os.environ["WEBHOOK_SECRET"]},
    )
    r.raise_for_status()
    return r.json()

def poll(execution_id, token, attempts=30):
    for _ in range(attempts):
        r = requests.get(f"{BASE}/workflow-executions/{execution_id}",
                         headers={"Authorization": f"Bearer {token}"})
        r.raise_for_status()
        data = r.json()["data"]
        if data["status"] == "completed":
            return data["outputs"]
        if data["status"] == "failed":
            raise RuntimeError(data.get("error"))
        time.sleep(2)
    raise TimeoutError("polling timed out")

started = trigger({"candidate_name": "Jane Smith", "resume_file_id": "1ABC123xyz"})
print(poll(started["execution_id"], started["polling_token"]))

Next steps

On this page