Skip to content

workflows-api

Status: Current | Last reviewed: 2026-10-13

workflows-api is the public API for workflow event ingest, direct workflow execution, execution inspection, human-in-the-loop actions, and execution event streaming. The service implementation is named async-agent in repo and deployment internals, but integration teams should refer to the external API as workflows-api.

Quick reference

Detail Value
Base URL https://events.vanguard.dev.trueserve.deloitte.com
Authentication Bearer tsf_* API token (tenant-scoped)
Required scopes Event ingestion, saved workflow execution and execution inspection/control require agents:run; agents:manage includes it

Per-workflow OpenAPI specs served by ai-manager at /api/workflows/<workflow_id>/openapi.json are also tenant-scoped. Fetch them with an ai-manager session or a tenant Bearer tsf_* token carrying agents:run; a token for one tenant cannot read another tenant's workflow contract.

What it covers

Capability Endpoint
Generic event ingest POST /api/v1/events
Direct workflow execution POST /api/v1/workflows/{workflow_config_id}/execute
Poll a workflow receipt or run GET /api/v1/workflow-runs/{run_id}
List and inspect executions GET /api/v1/executions, GET /api/v1/executions/{execution_id}
Read the execution event log GET /api/v1/executions/{execution_id}/events
Stream live execution updates GET /sse/executions/{execution_id}
Resume human/tool input gates POST /api/v1/executions/{execution_id}/approve, /override, /tool-input

Execution list/detail/event/SSE and human-in-the-loop routes are tenant-scoped. A token for one tenant receives 404 for another tenant's execution id rather than cross-tenant execution data.

The two ingest patterns

Direct execution is also available when the workflow is already selected. POST {"execution_mode":"async","inputs":{...}} to /api/v1/workflows/{numeric_id}/execute. A 200 response with status: "submitted" and execution_id means the execution and dispatch intent are durable. Publication may still be pending during a broker outage. The admitted root configuration/version is retained for execution and recovery.

Send an optional Idempotency-Key header (1–128 characters). Reusing it in the same tenant/workflow with identical inputs, caller chain and execution overrides returns the same execution. Changed arguments return 409. Use a new key for new work. This contract applies to asynchronous direct execution; it does not add idempotency to synchronous calls or generic events.

Poll /api/v1/workflow-runs/{execution_id} with the same tenant credential. The result contains execution_id, workflow_config_id, nullable run_id, status, nullable timestamps, run metadata and an execution SSE progress_stream path. The route also accepts a specific run UUID. A queued receipt has no run yet; a newly allocated run remains pending with no start time until its first useful node begins. metadata.startup contains trusted startup timestamps once recorded. Another tenant's receipt returns 404.

workflows-api takes in events through two distinct paths:

Generic events: POST /api/v1/events

For partner systems, custom scripts, and backend services. Authenticate with a tenant-scoped Bearer tsf_* token carrying the agents:run scope. The body is lean: supply event_type, source, and a payload. Routing to a workflow happens server-side by matching event_type against the tenant's configured trigger rules.

curl -X POST https://events.vanguard.dev.trueserve.deloitte.com/api/v1/events \
  -H "Authorization: Bearer tsf_..." \
  -H "Content-Type: application/json" \
  -d '{
    "event_type": "ticket.escalated",
    "source": "partner-helpdesk",
    "payload": {
      "ticket_id": "5003X00001abcd",
      "priority": "high"
    }
  }'

The full request schema (CreateEventRequest):

Field Required Notes
event_type yes Matched against trigger rules, e.g. ticket.escalated.
source yes Origin label, e.g. partner-helpdesk.
payload no Event body; addressed by workflows as {{trigger.<field>}}. Defaults to {}.
metadata no Optional extras. tenant_id is injected server-side from the token.

event_id and timestamp are generated server-side — you don't send them. The response is 202 Accepted with {"status": "accepted", "event_id": "..."} returning the assigned id (or "duplicate" if that id was seen in the last 24h — relevant for adapter-sourced events that carry a stable id). The endpoint does not return an execution_id — accepting an event is decoupled from whether (and how many) workflows it triggers. To observe the resulting run, list or stream executions: GET /api/v1/executions?status=... then GET /sse/executions/{execution_id}.

The token's tenant is authoritative. If you also set metadata.tenant_id it must match the token, or the request is rejected with 403.

Resuming a Wait node with an event

A workflow Wait node can pause a running execution until a matching event arrives. The event is sent to the same generic endpoint, but its payload must identify the running workflow execution to resume. Put the target execution id in payload.workflow_execution_id or payload.execution_id.

curl -X POST https://events.vanguard.dev.trueserve.deloitte.com/api/v1/events \
  -H "Authorization: Bearer tsf_..." \
  -H "Content-Type: application/json" \
  -d '{
    "event_type": "ticket.updated",
    "source": "partner-helpdesk",
    "payload": {
      "workflow_execution_id": "8f3f06a2-6fd7-44b8-8ac6-1f421b9fca8d",
      "ticket_id": "5003X00001abcd",
      "status": "resolved",
      "notes": "Customer replied"
    }
  }'

event_type must match the Wait node's Event type. source remains an origin label for observability; Wait-node matching does not require authors to choose a source in the editor. The optional Event filter matches dot paths inside payload, so a filter key of status with value resolved only resumes the wait for payloads with "status": "resolved".

When the workflow resumes, the Wait node output includes the payload both flattened and under payload. If the Wait node id is wait_for_ticket, downstream blocks can reference {{wait_for_ticket.ticket_id}}, {{wait_for_ticket.status}}, or the full nested form {{wait_for_ticket.payload.ticket_id}}.

Provider events: push adapters (no inbound webhook)

Provider integrations — Salesforce Pub/Sub, AWS EventBridge, Google Pub/Sub — do not post to a workflow webhook URL. The platform runs a background subscriber that pulls from the provider's stream, normalizes each provider event into the same InboundEvent envelope, and hands it to the identical trigger-matching path the generic endpoint uses. There is no /api/v1/webhooks/* route — provider auth is the subscription's own credential, configured on the integration, not a bearer token on a request.

Internal normalized envelope

Both paths normalize to an internal InboundEvent before trigger evaluation. Callers don't construct this — it's what the generic request and provider adapters both produce:

{
  "event_id": "<server-generated-uuid>",
  "event_type": "ticket.escalated",
  "source": "partner-helpdesk",
  "source_integration_id": null,
  "timestamp": "2026-05-28T13:18:00Z",
  "payload": { "ticket_id": "5003X00001abcd", "priority": "high" },
  "metadata": { "tenant_id": "..." },
  "raw_event": null
}

source_integration_id and raw_event are populated only by provider adapters (they record which integration emitted the event and the untouched provider payload); the generic HTTP path leaves them null. Workflows address the body as {{trigger.<field>}} in their nodes — e.g. {{trigger.ticket_id}} once trigger field-mappings project payload.ticket_id into the workflow input.

Execution SSE events

GET /sse/executions/{execution_id} streams workflow execution progress. Each SSE frame uses the Redis stream id as id:, the event kind as event:, and a JSON object as data:.

Common event: values:

Event When it appears Important data
execution_created A workflow run is created execution_id, workflow metadata
node_completed A node finishes node id/type, output summary, timing
workflow_completed The run reaches End final outputs
workflow_error The run fails error message and context
waiting A Wait node suspends the run awaited event/duration details
workflow_waiting_human / human_review_requested Human approval is required review prompt and action options
workflow_waiting_input / tool_input_requested A tool-input gate is waiting requested fields
tool_use An LLM/tool node invokes a tool tool name, arguments/result summary
doom_loop Loop protection fires loop diagnostic details
human_approved, human_rejected, human_override A reviewer resolves a gate reviewer action payload
tool_input_provided External input resumes a gate provided fields

Clients should ignore unknown event types and use Last-Event-ID when reconnecting.

Live OpenAPI

The block below renders the running service's /openapi.json, grouped into three tags:

  • Events — generic event ingest.
  • Workflows — direct workflow execution (sync or async).
  • Executions — introspection of an in-flight or completed run: status, event log, communications, human-in-the-loop approve/override, tool-input gates, and the SSE live stream.

If the live service is unavailable while the docs build, the generator keeps the last successful spec when one exists so this reference does not collapse to an empty OpenAPI page.

Idempotency

Asynchronous direct execution uses the Idempotency-Key contract above. Its deduplication lasts as long as the execution record is retained; it has no fixed 24-hour expiration.

The platform deduplicates by the normalized event's event_id for 24 hours. For the generic HTTP endpoint the server assigns a fresh event_id per request, so each accepted POST is a distinct event — retry only if you got no 202.

Provider adapters set a stable event_id derived from the upstream record (e.g. Salesforce Pub/Sub uses the platform event's replay ID), so adapter-sourced retries naturally dedupe and never double-trigger a workflow.

See also

Preview a Decision

POST /api/v1/decisions/test accepts {node, sample}. node contains the router id/type/config and optional node-level integration_id. sample accepts input, vars, node_results, trigger, and iterator objects. The response is the selected node result, including route_value and AI answers when applicable. This endpoint requires a tenant-scoped agents:run token; a supplied X-TrueServe-Tenant must match it. Invalid configuration returns 400, invalid request shape returns 422, and tenant mismatch returns 403.

Studio calls the rate-limited POST /api/workflows/decisions/test proxy with workflow-authoring permission. The browser never receives integration credentials. The preview executes no downstream nodes.