Workflows
GET/POST /v1/workflows, GET/PATCH/DELETE /v1/workflows/{workflowIdOrKey}, plus toggle, deploy, webhook secret rotate, run, and run history — multi-step automations via API key.
Multi-step automations via API key — chains of intents, agent runs, tool calls, and conditions. This is the same resource as the dashboard's Workflow Builder and the same underlying service — creating or deploying a workflow here shows up in the dashboard immediately, and vice versa.
Every {workflowIdOrKey} below accepts either the database id or the human-readable workflow_key.
List workflows
GET https://api.liyaengine.ai/v1/workflows
Authorization: Bearer liya_xxxxxxxxxxxxReturns only this tenant's deployed and active workflows, each with its callable endpoint. Drafts and toggled-off workflows stay dashboard-only.
{
"success": true,
"data": [
{
"id": "wf_01HZ...",
"name": "Lead Intake",
"workflow_key": "lead-intake",
"status": "active",
"is_active": true,
"trigger_type": "webhook",
"trigger_config": { "slug": "a1b2c3...", "has_secret": true },
"steps": [ "..." ],
"endpoint": "/v1/workflows/lead-intake/run",
"method": "POST"
}
]
}Create a workflow
POST https://api.liyaengine.ai/v1/workflows
Authorization: Bearer liya_xxxxxxxxxxxx
Content-Type: application/json
{
"name": "Lead Intake",
"steps": [
{ "step_type": "trigger", "config": { "trigger_subtype": "webhook" } },
{ "step_type": "ai_intent", "config": { "intent_id": "intent_01HZ..." } }
]
}Created in draft status with an auto-generated workflow_key — use the deploy endpoint below to publish it. Returns 201 with { "data": { "workflow": {...} } }.
step_type is one of trigger, action, condition, switch, delay, loop, ai_intent, ai_agent, approval, end. Give a step an id (any client-chosen string) and reference it from another step's on_success_ref/on_failure_ref to wire up branching — both get resolved to real step ids server-side.
Get a workflow
GET https://api.liyaengine.ai/v1/workflows/{workflowIdOrKey}
Authorization: Bearer liya_xxxxxxxxxxxxReturns the full workflow definition and its steps. Only a deployed, active workflow is visible here — a draft 404s until you deploy it.
Update a workflow
PATCH https://api.liyaengine.ai/v1/workflows/{workflowIdOrKey}
Authorization: Bearer liya_xxxxxxxxxxxx
Content-Type: application/json
{
"name": "Lead Intake v2",
"steps": [ "..." ]
}All fields optional — only what you pass gets changed. steps is upsert-by-id: include a step's existing id to edit it in place, omit id for a new step, and leave out an existing step's id entirely to delete it. workflow_key can be changed here too (409 WORKFLOW_KEY_TAKEN if already in use).
Toggle a workflow
PATCH https://api.liyaengine.ai/v1/workflows/{workflowIdOrKey}/toggle
Authorization: Bearer liya_xxxxxxxxxxxxFlips is_active on an already-deployed workflow — a pure runtime on/off switch that doesn't touch its definition. Returns 409 DEPLOY_REQUIRED on a draft; deploy it first.
Deploy a workflow
POST https://api.liyaengine.ai/v1/workflows/{workflowIdOrKey}/deploy
Authorization: Bearer liya_xxxxxxxxxxxxThe draft → active transition — a deliberate, separately audited step distinct from toggle. For a webhook-triggered workflow, the first deploy also mints the webhook endpoint and signing secret:
{
"success": true,
"data": {
"workflow": { "...": "..." },
"webhook_url": "https://api.liyaengine.ai/webhooks/workflows/a1b2c3...",
"webhook_secret": "8f3e9c2a1b7d4f0e..."
}
}webhook_url/webhook_secret are only present when a webhook is newly minted (the first deploy of a webhook-triggered workflow). webhook_secret is shown here exactly once — store it immediately. Every later GET/list response only ever exposes trigger_config.has_secret: true, never the plaintext secret. Redeploying an already-deployed workflow does not regenerate it.
Rotate the webhook secret
POST https://api.liyaengine.ai/v1/workflows/{workflowIdOrKey}/webhook-secret/rotate
Authorization: Bearer liya_xxxxxxxxxxxx
Content-Type: application/json
{ "grace_period_seconds": 300 }Only valid for a deployed, webhook-triggered workflow (409 NOT_A_WEBHOOK_WORKFLOW otherwise). The previous secret stays valid for grace_period_seconds (0–3600, default 300) so in-flight senders don't break mid-rollover; pass 0 for an immediate hard cutover.
{
"success": true,
"data": {
"webhook_url": "https://api.liyaengine.ai/webhooks/workflows/a1b2c3...",
"webhook_secret": "1a2b3c4d5e6f7g8h...",
"previous_secret_valid_until": "2026-09-18T23:25:09.618Z"
}
}The new webhook_secret is returned exactly once here too — same rule as deploy.
Delete a workflow
DELETE https://api.liyaengine.ai/v1/workflows/{workflowIdOrKey}
Authorization: Bearer liya_xxxxxxxxxxxxA hard delete — unlike Collections and Agents, there's no soft-delete/inactive state to recover from. Returns { "success": true } with no data.
Run a workflow
POST https://api.liyaengine.ai/v1/workflows/{workflowIdOrKey}/run
Authorization: Bearer liya_xxxxxxxxxxxx
Content-Type: application/json
{ "input": { "email": "[email protected]" } }{
"success": true,
"data": {
"run_id": "run_01HZ...",
"conversation_id": "convo_01HZ...",
"status": "completed",
"trace": [ "..." ]
}
}A synchronous, authenticated counterpart to the async webhook trigger — same execution engine, request/response instead of fire-and-forget. Only an active workflow can be run. Pass a previously-returned conversation_id to resume a paused (needs_input) run instead of starting fresh.
Run history
GET https://api.liyaengine.ai/v1/workflows/{workflowIdOrKey}/runs
GET https://api.liyaengine.ai/v1/workflows/{workflowIdOrKey}/runs/{runId}runs is a paginated list (page, pageSize, status query params); runs/{runId} returns one run's full step-by-step trace.
Using an SDK
import { LiyaEngine } from '@liyaengine/sdk';
const client = new LiyaEngine({ apiKey: process.env.LIYA_API_KEY! });
const workflow = await client.workflows.create({
name: 'Lead Intake',
steps: [{ step_type: 'trigger', config: { trigger_subtype: 'webhook' } }],
});
// Capture webhook_secret immediately — it's never returned again.
const { webhook_url, webhook_secret } = await client.workflows.deploy(workflow.workflow_key);
const result = await client.workflows.run(workflow.workflow_key, {
input: { email: '[email protected]' },
});Related
Agents
GET/POST /v1/agents, GET/PATCH/DELETE /v1/agents/{agentKey}, plus deploy, run, and run/session history — standalone Agents via API key.
Evaluations
Full Datasets/Cases/Suites/Runs/Reviews CRUD, real suite execution, cancel/resume, statistical + LLM-judge pairwise comparison, and standalone scoring — all via API key.