Developer section: these pages cover the S6S workflow engine for self-hosted installs and developers. On s6s.ai, API keys and MCP access are issued by S6S on request (contact us); on a self-hosted install, an admin creates them on the API Keys page. For the AI Visibility product, start at the AI Visibility docs.

Workflow Quick Start

Deploy and run your first workflow with the REST API. This is the developer-playground path — if you're here for brand monitoring and the AI Visibility Report, start at /docs/ai-visibility instead.

What this is

The S6S workflow engine runs persistent, multi-step workflows for AI agents and humans. You define workflows as JSON recipes, and S6S handles validation, compilation, credential binding, scheduling, and execution. Deploy via the REST API, MCP server, TypeScript SDK, or the chat UI. The API, MCP server and SDK all need an API key (Step 1).

The same engine powers AI Visibility fixes, discovery, and scheduled monitoring underneath the product surface — but you don't need to know any of that to use AI Visibility. It only matters when you want to build agents on top of S6S.

Choose your path

AI Agent (MCP)

Connect your AI agent via MCP server.

Learn more

API / SDK

Deploy workflows programmatically. Continue reading below.

You are here

Chat UI

Build workflows with Ali, the AI copilot.

Open chat

Step 1: Get an API Key

  • On s6s.ai: API keys are issued by S6S on request. Contact us to get one.
  • On a self-hosted install: an admin opens API Keys (/keys) in the app, clicks Create Key, and gives it a name.

The key starts with s6s_ and is shown only once, so copy it right away. Send it as Authorization: Bearer s6s_…. Keep it secure: store it in an environment variable rather than in code. See API Keys for best practices.

The examples below use https://s6s.ai. On a self-hosted install, use your install's URL instead.

Step 2: Deploy Your First Workflow

Deploy a workflow by sending a Recipe to the deploy endpoint. A Recipe is a JSON object that describes your workflow's trigger, steps, and execution flow.

Here is a minimal example — a manual-trigger workflow with a single transform step:

POST https://s6s.ai/api/v1/workflows/deploy
curl -X POST https://s6s.ai/api/v1/workflows/deploy \
  -H "Authorization: Bearer s6s_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Hello World",
    "trigger": { "type": "manual" },
    "steps": [
      {
        "ref": "greet",
        "action": "transform",
        "config": {
          "template": {
            "message": "Hello from S6S!",
            "run_id": "{{run.id}}"
          }
        }
      }
    ],
    "flow": ["greet"]
  }'

Recipe fields explained

FieldPurpose
nameA human-readable name for the workflow. The workflow's slug is derived from it.
triggerHow the workflow starts. A manual trigger runs once right after deploy.
stepsAn array of actions. Each step has a ref (unique name), action (what to do), and config (action-specific settings).
flowExecution order as an array of step refs. Every step must be listed. Refs in a nested array run in parallel.

Success response

{
  "ok": true,
  "workflowId": "6c33d112-7297-4f02-9092-2a22135ba56b",
  "versionId": "7680dc16-9169-48ad-a08d-c474b625c39f",
  "version": 1,
  "hash": "2d711642b726b04401627ca9fbac32f5c8530fb1903cc4db02258717921a4881",
  "runId": "7ed60fcc-f5ac-4306-a455-24bee407186c",
  "connectedProviders": [],
  "monitorUrl": "https://s6s.ai/runs/7ed60fcc-f5ac-4306-a455-24bee407186c",
  "refToId": {
    "greet": "4bdbdac7-7204-40bd-ac2e-8571bc6d4f74",
    "__trigger__": "76447542-e948-4916-9778-1c8ac50e5da6"
  }
}

The monitorUrl opens the run in the S6S app (when no run started, it opens the workflow). refToId maps each step ref to the node ID used in run results. If the recipe is invalid, the deploy returns 422 with a list of errors; if the account doesn't have enough credits for the run, it returns 402 and the workflow is saved without a run. See Recipe Format for the deploy options (autoRun, waitForCompletion, callback_url, slug).

Step 3: Check the Run

Poll the run status with your API key, or open the monitorUrl in the app:

GET https://s6s.ai/api/v1/runs/:runId
curl https://s6s.ai/api/v1/runs/7ed60fcc-f5ac-4306-a455-24bee407186c \
  -H "Authorization: Bearer s6s_your_api_key"

Response fields

FieldMeaning
runId, workflowIdIDs of the run and its workflow
statusRun status (see below)
startedAt, finishedAt, durationMsTiming
errorCode, failureReasonWhy a failed run failed
stepsOne entry per step that has started or been skipped, including the trigger: nodeId, nodeType, status, durationMs, errorCode, output. Match nodeId to a ref with refToId.
The greet entry in steps
{
  "nodeId": "4bdbdac7-7204-40bd-ac2e-8571bc6d4f74",
  "nodeType": "action.transform",
  "status": "succeeded",
  "durationMs": 4,
  "errorCode": null,
  "output": {
    "message": "Hello from S6S!",
    "run_id": "7ed60fcc-f5ac-4306-a455-24bee407186c"
  }
}

Run statuses

StatusMeaning
runningThe workflow is currently executing.
succeededThe run finished. Steps skipped by run_if or a branch don't fail it.
failedA step failed. Check errorCode and failureReason.
cancelledThe run was cancelled by the user or via API.

To follow a run live instead of polling, open the server-sent event stream GET /api/runs/{runId}/stream (API key or app session). It sends status and step events as the run progresses, then done when it finishes (or error), and closes after at most 5 minutes.

Step 4: Deploy a Real Workflow

Now let's deploy something more realistic: a webhook-triggered workflow that fetches data from an API, reshapes it, and sends a Slack notification — with a retry policy for the API call.

POST https://s6s.ai/api/v1/workflows/deploy
curl -X POST https://s6s.ai/api/v1/workflows/deploy \
  -H "Authorization: Bearer s6s_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Order Processor",
    "trigger": {
      "type": "webhook",
      "path": "/orders/new",
      "method": "POST"
    },
    "steps": [
      {
        "ref": "fetch_order",
        "action": "http",
        "config": {
          "method": "GET",
          "url": "https://api.example.com/orders/{{trigger.output.body.order_id}}"
        }
      },
      {
        "ref": "enrich",
        "action": "transform",
        "config": {
          "template": {
            "summary": "New order #{{fetch_order.output.body.id}} — ${{fetch_order.output.body.total}}",
            "customer": "{{fetch_order.output.body.customer_name}}"
          }
        }
      },
      {
        "ref": "notify_slack",
        "action": "slack",
        "config": {
          "channel": "#orders",
          "textTemplate": "{{enrich.output.summary}}"
        },
        "credential": "default"
      }
    ],
    "flow": ["fetch_order", "enrich", "notify_slack"],
    "on_error": {
      "fetch_order": { "action": "retry", "retry": { "max_attempts": 3 } }
    }
  }'

Key concepts in this example

  • Webhook trigger — Deploying it doesn't start a run. The response's webhookTrigger object holds the invoke URL (https://s6s.ai/api/webhooks/orders/new) and, on the first deploy only, the secret. Each request must carry that secret, for example in an X-Webhook-Token header; the request body is available as {{trigger.output.body.*}}. See Triggers for all authentication options.
  • Expressions — Double-brace expressions like {{fetch_order.output.body.id}} reference outputs from previous steps by their ref name. An http step's response data is under .body.
  • Error handling — on_error is a top-level map keyed by step ref. Here fetch_order gets up to 3 attempts when the API returns a temporary error (5xx, 429 or a timeout). Steps without an entry use stop, the default: a failure ends the run. continue moves on to the next flow item instead.
  • Parallel flow — Refs in a nested array run in parallel, e.g. ["fetch_order", ["notify_slack", "log_order"]]. A step can only use outputs of steps from earlier flow items, so enrich and notify_slack can't run in parallel here: notify_slack reads enrich's output.
Send an order to the webhook
curl -X POST https://s6s.ai/api/webhooks/orders/new \
  -H "X-Webhook-Token: $WEBHOOK_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "order_id": "1042" }'

The webhook replies at once with the new runId; check it as in Step 3.

Missing credentials

If your workflow uses an integration (like Slack) that you haven't connected yet, the workflow is saved but no run starts. The deploy response has "runId": null and a missing_credentials array with a connect_url for each provider:

{
  "ok": true,
  "workflowId": "6c33d112-7297-4f02-9092-2a22135ba56b",
  "versionId": "7680dc16-9169-48ad-a08d-c474b625c39f",
  "version": 1,
  "hash": "2d711642b726b04401627ca9fbac32f5c8530fb1903cc4db02258717921a4881",
  "runId": null,
  "connectedProviders": [],
  "monitorUrl": "https://s6s.ai/workflows/6c33d112-7297-4f02-9092-2a22135ba56b",
  "dashboard_url": "https://s6s.ai/credentials",
  "missing_credentials": [
    {
      "provider": "slack",
      "ref": "default",
      "node_name": "Slack: notify slack",
      "connect_url": "https://s6s.ai/credentials/connect/slack"
    }
  ],
  "message": "Workflow saved but cannot run — missing credentials for: slack. Connect them at https://s6s.ai/credentials then re-deploy or trigger the workflow.",
  "refToId": {
    "fetch_order": "4bdbdac7-7204-40bd-ac2e-8571bc6d4f74",
    "enrich": "0e4a7c52-1d3b-4f6e-9a8c-2b5d7e9f1a3c",
    "notify_slack": "9b1f3e6d-5c2a-4d8b-8e7f-3a6c9d2e5b14",
    "__trigger__": "76447542-e948-4916-9778-1c8ac50e5da6"
  }
}

Visit the connect_url to authorize S6S with the provider, then deploy again. For a webhook-triggered workflow like this one, that next deploy is also the one that returns the webhook secret. Steps with "credential": "default" use any connected account for that provider.

Next Steps

Ready to build?

Run S6S on your own infrastructure, or ask us for API access on s6s.ai.