LiyaEngine Docs
API Reference

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.

Dashboard

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_xxxxxxxxxxxx

Returns 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_xxxxxxxxxxxx

Returns 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_xxxxxxxxxxxx

Flips 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_xxxxxxxxxxxx

The 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_xxxxxxxxxxxx

A 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]' },
});

On this page