AI Agents
Stateway is designed to be consumed directly by AI agents via REST. An agent can start a process, query its state, complete human tasks, and send events — all through straightforward HTTP calls.
This page covers the complete integration pattern with ready-to-use JSON payloads suitable for LLM tool calls.
Authentication
Every request requires an API Key in the X-API-Key header. The key resolves the tenant automatically — you never pass a tenant_id.
X-API-Key: sw_live_<key>
Core Operations
1. Start a Process
Instantiate a process definition by its key. Pass any initial variables the process needs.
POST /v1/instances
Content-Type: application/json
X-API-Key: sw_live_<key>
{
"definition_key": "loan-approval",
"variables": {
"applicantId": "usr_123",
"amount": 5000,
"currency": "BRL"
}
}
Response:
{
"data": {
"id": "inst_abc123",
"tenantId": "ten_abc123",
"definitionId": "def_abc123",
"definitionHash": "a3f1c2d4e5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2",
"correlationId": null,
"status": "running",
"variables": {
"applicantId": "usr_123",
"amount": 5000,
"currency": "BRL"
},
"startedAt": "2026-04-01T10:00:00Z",
"endedAt": null,
"error": null,
"metadata": {}
}
}
Save data.id — you'll use it for all subsequent calls on this instance.
2. Query Instance State
Check whether the process is still running and what the current variable values are.
GET /v1/instances/{instance_id}
X-API-Key: sw_live_<key>
Response:
{
"data": {
"id": "inst_abc123",
"status": "running",
"variables": {
"applicantId": "usr_123",
"amount": 5000,
"decision": null
},
"startedAt": "2026-04-01T10:00:00Z",
"endedAt": null
}
}
status is one of: pending, running, suspended, completed, terminated, error.
To find out which element the process is currently waiting on, query its tokens:
GET /v1/instances/{instance_id}/tokens
X-API-Key: sw_live_<key>
{
"data": [
{ "id": "tok_1", "elementId": "start", "elementType": "startEvent", "status": "completed" },
{ "id": "tok_2", "elementId": "approve-loan-task", "elementType": "userTask", "status": "waiting" }
]
}
A token with status: "waiting" is where the process is currently paused.
3. List Pending Tasks
Retrieve human tasks that are waiting for action — filtered by instance, status, assignee, or candidate group.
GET /v1/tasks?instance_id=inst_abc123&status=pending
X-API-Key: sw_live_<key>
Response:
{
"data": [
{
"id": "task_xyz789",
"instanceId": "inst_abc123",
"elementId": "approve-loan-task",
"name": "Approve Loan",
"status": "pending",
"assignee": null,
"candidateGroups": ["credit-team"],
"candidateUsers": [],
"variables": {
"amount": 5000
},
"createdAt": "2026-04-01T10:00:05Z",
"claimedAt": null,
"completedAt": null
}
]
}
4. Complete a Task
Submit the outcome of a human task. The variables object is merged into the existing instance variables — you only need to send what you're setting.
POST /v1/tasks/{task_id}/complete
Content-Type: application/json
X-API-Key: sw_live_<key>
{
"variables": {
"decision": "approved",
"reviewedBy": "agent-gpt4o",
"reviewNotes": "Income verified. Risk score within acceptable range."
}
}
Response:
{
"data": {
"id": "task_xyz789",
"status": "completed"
}
}
Completing an already-completed task returns 404 NOT_FOUND ("Task already completed") — check status first if you're not sure.
5. Send an Event to an Instance
Deliver an external signal to a specific instance — a payment confirmation, a webhook callback result, an async service response. The event resolves only the waiting tokens that declare the event_type as their name (a named intermediateCatchEvent, a message boundary event, or an async service task's callbackEvent). It never completes a user task; without event_type, nothing advances — see the Events and Signals guide for the exact rules.
POST /v1/instances/{instance_id}/events
Content-Type: application/json
X-API-Key: sw_live_<key>
{
"event_type": "payment_confirmed",
"variables": {
"transactionId": "txn_9981",
"paidAt": "2026-04-01T10:10:00Z"
}
}
Response:
{
"data": {
"event_type": "payment_confirmed",
"processed": true
}
}
Full error conditions (instance not found, no waiting or active token, instance already finished) are covered in the Events and Signals guide.
6. Broadcast a Signal
Broadcast a signal to every waiting token across the tenant's running instances — this is a different endpoint from instance events, and does not take an instance ID. The signal_name is echoed back but not matched against any element (name-based matching is planned, not yet supported), so every waiting token is completed regardless of what it is waiting for.
POST /v1/events/signal/{signal_name}
Content-Type: application/json
X-API-Key: sw_live_<key>
{
"variables": {
"productId": "prod-001",
"newPrice": 99.99
}
}
Response:
{
"data": {
"signal_name": "price_update",
"processed": 3,
"failed": 0,
"errors": []
}
}
See the Events and Signals guide for how partial failures are reported.
Tool Definitions for LLMs
The examples below are ready to paste into your LLM's tool schema. They follow the JSON Schema format used by the OpenAI/Anthropic tool call APIs, with parameter names matching the REST API's own field names one-to-one — no translation layer needed. If you use the Stateway MCP server instead, its tools have their own parameter names; see the MCP guide.
start_process
{
"name": "start_process",
"description": "Start a new instance of a Stateway process definition. Returns the instance ID needed for all subsequent operations.",
"parameters": {
"type": "object",
"properties": {
"definition_key": {
"type": "string",
"description": "The process definition key (e.g. 'loan-approval', 'onboarding')"
},
"variables": {
"type": "object",
"description": "Initial process variables as key-value pairs",
"additionalProperties": true
}
},
"required": ["definition_key"]
}
}
get_instance
{
"name": "get_instance",
"description": "Query the current state of a process instance: status and variable values.",
"parameters": {
"type": "object",
"properties": {
"instance_id": {
"type": "string",
"description": "The instance ID returned by start_process"
}
},
"required": ["instance_id"]
}
}
list_tasks
{
"name": "list_tasks",
"description": "List human tasks for a given process instance.",
"parameters": {
"type": "object",
"properties": {
"instance_id": {
"type": "string",
"description": "Filter tasks by instance ID"
},
"status": {
"type": "string",
"enum": ["pending", "claimed", "completed", "cancelled"],
"description": "Task status filter (default: pending)"
}
},
"required": []
}
}
complete_task
{
"name": "complete_task",
"description": "Complete a pending human task and supply output variables that will be merged into the process.",
"parameters": {
"type": "object",
"properties": {
"task_id": {
"type": "string",
"description": "The task ID from list_tasks"
},
"variables": {
"type": "object",
"description": "Output variables to merge into the process after task completion",
"additionalProperties": true
}
},
"required": ["task_id"]
}
}
send_event
{
"name": "send_event",
"description": "Send a named event to a specific process instance. It resolves the waiting tokens that declare event_type as their name (a named intermediateCatchEvent, a message boundary event, or an async service task whose callbackEvent matches). If none declares it, the event is recorded for a later catch and nothing advances. It never completes a user task.",
"parameters": {
"type": "object",
"properties": {
"instance_id": {
"type": "string",
"description": "Target instance ID"
},
"event_type": {
"type": "string",
"description": "Event name (e.g. 'payment_confirmed'), matched against the event names declared by waiting elements in the instance. Without it, nothing advances"
},
"variables": {
"type": "object",
"description": "Variables to merge into the instance",
"additionalProperties": true
}
},
"required": ["instance_id"]
}
}
send_signal
{
"name": "send_signal",
"description": "Broadcast a signal to every waiting token of every running instance in the tenant. The signal name is not matched against any element: all waiting tokens are completed.",
"parameters": {
"type": "object",
"properties": {
"signal_name": {
"type": "string",
"description": "Signal name; echoed in the response but not matched against any element"
},
"variables": {
"type": "object",
"description": "Variables to attach to the broadcast",
"additionalProperties": true
}
},
"required": ["signal_name"]
}
}
Complete Agent Loop Example
A typical agent loop for a process that requires an external decision:
import httpx
BASE_URL = "https://api.stateway.io/v1"
HEADERS = {"X-API-Key": "sw_live_<key>", "Content-Type": "application/json"}
# 1. Start the process
resp = httpx.post(f"{BASE_URL}/instances", headers=HEADERS, json={
"definition_key": "credit-analysis",
"variables": {"customerId": "cust_001", "requestedLimit": 10000}
})
instance_id = resp.json()["data"]["id"]
# 2. Poll until a task appears
import time
while True:
tasks = httpx.get(f"{BASE_URL}/tasks", headers=HEADERS,
params={"instance_id": instance_id, "status": "pending"}).json()
if tasks["data"]:
break
time.sleep(2)
task = tasks["data"][0]
# 3. Agent makes a decision and completes the task
decision = run_agent_analysis(task["variables"]) # your LLM call
httpx.post(f"{BASE_URL}/tasks/{task['id']}/complete", headers=HEADERS, json={
"variables": {"decision": decision["result"], "score": decision["score"]}
})
# 4. Wait for the process to finish
while True:
instance = httpx.get(f"{BASE_URL}/instances/{instance_id}", headers=HEADERS).json()["data"]
if instance["status"] in ("completed", "terminated", "error"):
break
time.sleep(2)
print(instance["variables"])
Tips for Agent Implementations
- Poll with backoff. Processes can wait for minutes or hours at a human task or timer. Use exponential backoff instead of tight loops — this is the reliable integration pattern today for instance and task state.
- Webhooks cover a narrower set of events today. Service task completion/failure and a few instance-management operations dispatch webhooks (see the Webhooks guide); general instance and human-task lifecycle changes are not yet dispatched as webhooks, so poll for those.
- Idempotency. Completing a task twice returns
404 NOT_FOUND. Checkstatusbefore callingcomplete_task. - Variables are merged. Sending
variablesin a task completion or an event merges them into the existing instance variables — you don't need to send every variable, only the ones you're setting. - Use MCP for richer integrations. If your agent framework supports MCP, the MCP guide describes the Stateway MCP server which exposes these operations as native tools with typed schemas.