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.

Node Types

Every workflow is a series of steps connected in a flow. Each step has a node type that determines what it does. This page covers all 32 built-in node types.

In a Recipe, a step's action is the part after the dot (http, condition); triggers use trigger.type. In the tables below, required marks a field you must set and — means optional with no default. Defaults are the engine's; the canvas editor may prefill different values. Config objects are strict: an unknown key fails the deploy.

Triggers

Triggers define how a workflow starts. Every workflow needs exactly one trigger. See Triggers for authentication, timing and full examples.

trigger.webhook

Start a workflow when an HTTP request hits a specific path.

ConfigTypeDefaultDescription
pathstringrequiredURL path, e.g. /new-lead. Unique across the install.
method"GET" | "POST"POSTStored with the trigger; the endpoint accepts both GET and POST.
Output:{ body, headers, query, method, path, receivedAt }
Invoke URL: https://s6s.ai/api/webhooks{path} — callers authenticate with the webhook secret from the deploy response (header, ?token=, HMAC signature or bearer token).
Recipe format
"trigger": { "type": "webhook", "path": "/new-lead", "method": "POST" }

trigger.schedule

Run a workflow on a recurring schedule using cron expressions.

ConfigTypeDefaultDescription
cronstringrequiredFive-field cron expression (minute, hour, day, month, weekday). Stored in the IR as cronExpression.
timezonestringUTCIANA timezone name
Output:{ scheduledAt, fired_at }

Both fields hold the same ISO timestamp, set when the scheduled run starts.

Common cron patterns:
  • */5 * * * * — every 5 minutes
  • 0 9 * * 1-5 — weekdays at 9 AM
  • 0 0 * * * — daily at midnight
  • 0 0 1 * * — first of every month
Recipe format
"trigger": { "type": "schedule", "cron": "0 9 * * 1-5", "timezone": "Europe/London" }

trigger.manual

Start a workflow on demand: "Run Now" in the app, or POST /api/v1/workflows/{id}/run with an API key. No configuration needed.

Output:{ payload, triggeredAt, triggeredBy }

payload — the input object from the run request body (or {} if none)

triggeredAt — ISO timestamp set when the run's trigger step executes

triggeredBy — always "api"

Recipe format
"trigger": { "type": "manual" }

trigger.telegram

Start a workflow when a Telegram chat linked to your S6S account sends a text message to the S6S Telegram bot.

ConfigTypeDefaultDescription
credentialstring—Optional label stored on the trigger. Message routing does not depend on it.
Output:{ chatId, text, from, chat, messageId, date, receivedAt }

Each message starts a run of every enabled workflow you own with a telegram trigger. Bot commands such as /start and /help are handled by the bot instead. Deploying starts one run with empty trigger data unless you send "autoRun": false.

Recipe format
"trigger": { "type": "telegram" }

Actions

Actions do work — call APIs, send messages, transform data, run code. A step that needs a credential uses the connected account named by its credential field, or any connected account for the provider when it is "default" or omitted.

action.http

Make an HTTP request to a public URL.

ConfigTypeDefaultDescription
urlstringrequiredFull URL. Private and internal addresses are blocked.
methodstringPOSTGET, POST, PUT, PATCH or DELETE
headersobject—Request headers (string values). No Content-Type is added for you.
bodystring | object—Request body; objects are sent as JSON text. Ignored for GET.
timeoutMsnumber30000Request timeout, 100–300000 ms
Output:{ status, statusCode, statusText, body }

JSON responses are parsed into body; other text is cut at 4096 characters. Binary responses (images, video, audio, PDF, archives) are stored as a temporary file and return fileUrl, fileName, mimeType, sizeBytes and expiresAt instead of body. A non-2xx response fails the step with HTTP_<status>. An optional credential is injected as authentication.

Example step
{
  "ref": "create_contact",
  "action": "http",
  "config": {
    "url": "https://api.example.com/contacts",
    "method": "POST",
    "headers": { "Content-Type": "application/json" },
    "body": { "email": "{{trigger.output.body.email}}" },
    "timeoutMs": 10000
  }
}

action.transform

Reshape data between steps using a JSON template with expressions.

ConfigTypeDefaultDescription
templateobjectrequiredJSON template with {{expression}} placeholders

Output: The template with every expression resolved. An expression that points at an object or array is inserted as JSON text.

Example step
{
  "ref": "format",
  "action": "transform",
  "config": {
    "template": {
      "message": "Hello, {{trigger.output.body.name}}!",
      "received": "{{trigger.output.receivedAt}}"
    }
  }
}

action.code

Run JavaScript in a sandbox and return the result.

ConfigTypeDefaultDescription
expressionstringrequiredA single expression, or statements with return. await is allowed.
languagestringjavascriptOnly javascript

The code can read steps (earlier outputs by ref), trigger (the trigger output) and input (this step's config), and can call fetch on public addresses. It has no access to Node.js modules and times out after 30 seconds. Output: a returned object or array as-is; other values as { value }.

Example step
{
  "ref": "count_orders",
  "action": "code",
  "config": {
    "expression": "const orders = trigger.body.orders || []; return { count: orders.length };"
  }
}

action.filter

Filter, map, find or reduce an array.

ConfigTypeDefaultDescription
arrayExpressionstringrequiredExpression that resolves to an array, e.g. {{fetch.output.body.items}}
conditionstringrequiredJavaScript expression using item and index (and acc for reduce)
modestringfilterfilter, map, find or reduce
reduceInitialany—Starting value for reduce

Output: an array result as { result, count }; an object result as-is; any other result as { result }. Up to 100,000 items.

Example step
{
  "ref": "big_orders",
  "action": "filter",
  "config": {
    "arrayExpression": "{{trigger.output.body.orders}}",
    "condition": "item.total > 100",
    "mode": "filter"
  }
}

action.email

Send a plain-text email via SMTP, Resend, SendGrid or Postmark.

ConfigTypeDefaultDescription
tostringrequiredRecipient email
subjectstringrequiredEmail subject
bodyTemplatestringrequiredEmail body as plain text (supports expressions)
providerstring—smtp, resend, sendgrid or postmark. When omitted: SMTP if the credential has a host, Resend if it has an api_key.
fromstring—Sender address. Defaults to the credential's from, user or username field.
Output:{ messageId, accepted, rejected, provider }

That is the SMTP output; the other providers return { messageId, provider, status }.

Requires credential: smtp

action.slack

Post a message to a Slack channel.

ConfigTypeDefaultDescription
channelstringrequiredChannel name or ID
textTemplatestringrequiredMessage text (supports expressions)
Output:{ channel, ts }

Requires credential: slack

action.discord

Send a message to a Discord channel.

ConfigTypeDefaultDescription
actionstringsend_messageOnly send_message
channelIdstringrequiredDiscord channel ID
contentstringrequiredMessage content, up to 2000 characters
usernamestring—Passed to Discord as username
avatarUrlstring—A URL, passed to Discord as avatar_url
Output:{ messageId, channelId }

Requires credential: discord

action.telegram

Send messages, photos or documents, forward a message, or read updates with a Telegram bot.

ConfigTypeDefaultDescription
actionstringsend_messagesend_message, send_photo, send_document, get_updates, forward_message
chatIdstring—Target chat. Falls back to the chat_id stored on the credential.
textstring—Message text (required for send_message)
parseModestring—HTML, MarkdownV2 or Markdown
photoUrlstring—Photo to send (required for send_photo)
documentUrlstring—Document to send (send_document)
captionstring—Caption for a photo or document
offsetnumber—Update offset (get_updates)
limitnumber—Updates to fetch, 1–100 (get_updates)
fromChatIdstring—Source chat (forward_message)
messageIdnumber—Message to forward (forward_message)
Output:{ messageId, chatId, action, chunks }

That is the send_message output. send_photo, send_document and forward_message return { messageId, chatId, action } (forward_message adds fromChatId); get_updates returns { updates, updateCount, action }.

Requires credential: telegram

Auto-chunking: With send_message, text longer than 4096 characters is split, at a newline where possible, and sent as several messages.

action.imap

Fetch, search, or read mailbox content over IMAP.

ConfigTypeDefaultDescription
actionstringfetch_recentfetch_recent, search, read_message
querystring—Search query for search mode
messageIdstring—Message identifier (required for read_message)
maxResultsnumber20Maximum messages to return, 1–100
sincestring—Relative time filter like 1h or 7d
folderstringINBOXMailbox folder
markAsReadbooleanfalseMark fetched messages as read
Output:{ messages, resultCount } or { message }

Requires credential: imap

action.rss

Fetch and parse an RSS or Atom feed.

ConfigTypeDefaultDescription
feedUrlstringrequiredFeed URL
maxItemsnumber10Maximum items to return, 1–100
Output:{ feedTitle, itemCount, items: [{ title, link, description, pubDate }] }

action.twitter

Post a tweet or search tweets.

ConfigTypeDefaultDescription
actionstringpost_tweetpost_tweet or search
textstring—Tweet text, up to 280 characters (required for post_tweet)
querystring—Search query (required for search)
maxResultsnumber10Search results, 1–100
Output:{ tweetId, text } or { resultCount, tweets }

Requires credential: twitter

action.google_sheets

Append rows, read rows, or update cells in Google Sheets.

ConfigTypeDefaultDescription
actionstringappend_rowappend_row, read_rows, update_cell
spreadsheetIdstringrequiredSpreadsheet ID from the URL
rangestringrequiredA1 range, e.g. Sheet1!A:C
valuesarray—Rows as arrays of strings, numbers or booleans (required for append_row)
Output:{ rowCount, values } / { updatedRows, updatedRange } / { updatedRange, updatedCells }

For read_rows, append_row and update_cell respectively.

Requires credential: google

action.google_drive

List, upload, or download files in Google Drive.

ConfigTypeDefaultDescription
actionstringlistlist, upload, download, download_media
folderIdstring—Folder to list or upload into
fileNamestring—Name for upload (required for upload)
fileIdstring—File to download
contentstring—File content for upload
mimeTypestringapplication/octet-streamMIME type for upload
maxResultsnumber20Files to list, 1–100

Output: list { fileCount, files }; upload { fileId, name, mimeType }; download returns the file as text { contentLength, content, wasTruncated } (up to 65,536 characters); download_media stores binary content as a temporary file { fileUrl, fileName, mimeType, sizeBytes, expiresAt }.

Requires credential: google

action.gmail

Search, read, or send email via the Gmail API.

ConfigTypeDefaultDescription
actionstringsearch_messagessearch_messages, read_message, send_message
querystring—Gmail search query (required for search_messages)
messageIdstring—Message ID (required for read_message)
maxResultsnumber10Max results for search, 1–100
tostring—Recipient (required for send_message)
subjectstring—Email subject (required for send_message)
bodystring—Email body (required for send_message)
bodyTypestringtexttext or html
Output:{ messages, resultCount, account } / { message } / { messageId, threadId }

Requires credential: google

action.database

Run a SQL query against a connected PostgreSQL database.

ConfigTypeDefaultDescription
querystringrequiredSQL query; use $1, $2 … for parameters
paramsarray—Parameter values (string, number, boolean or null)
operationstringselectselect, insert, update, delete or raw. A label: select marks the step as a read; the SQL runs as written.
Output:{ rows, rowCount, operation }

Requires credential: database

action.ai

Send a prompt to the LLM configured for the install (OpenAI, Anthropic, Google or OpenRouter), optionally as a tool-using agent.

ConfigTypeDefaultDescription
promptstringrequiredThe prompt (supports expressions)
systemPromptstring—System instructions
responseFormatstringtexttext or json. With json, the reply is also parsed into json.
modelstring—Model name. Defaults to the install's model; a name that doesn't fit the configured provider is ignored.
temperaturenumber0.20–2. Defaults to the install setting, else 0.2.
maxTokensnumber40961–128000. Defaults to the install setting, else 4096.
outputSchemaobject—JSON Schema for structured output. Can't be combined with tools.
toolsarray—Up to 20 tools: { name, description, parameters }. A tool with no built-in handler returns its arguments as the result, which is useful for structured extraction.
agentModebooleanfalseAdds the http_request tool (public URLs only) and loops: the model calls tools until it answers or hits maxIterations.
maxIterationsnumber10Agent loop limit, 1–50. At the limit, one last call without tools produces the answer.
memoryEnabledbooleanfalseAdds memory_read, memory_write and memory_search tools. Memory belongs to the workflow and persists across runs.
skillsstring[]—Up to 5 skill slugs (yours or public). Each skill adds its instructions to the system prompt and its tools.
workflowToolsarray—Up to 5 { slug, name, description }. Each becomes a tool named s6s_wf_<slug> that runs that workflow with the tool call's arguments as input and waits up to 15 seconds for its result.
imagesstring[]—Up to 10 image URLs or data: URIs sent with the prompt
streamingbooleanfalseAccepted; it does not change the step output.
timeoutMsnumber120000Per-request timeout, 1000–300000 ms
Output:{ text, model, promptTokens, completionTokens }

Extra output fields: json (responseFormat json or outputSchema), schemaValid (with outputSchema), toolCalls (every tool call with its arguments and result), toolCall (outside agent mode, when there was exactly one call), and totalIterations (agent mode). The step needs no credential; it uses the install's LLM settings.

Agent step with memory
{
  "ref": "research",
  "action": "ai",
  "config": {
    "systemPrompt": "You are a careful research assistant.",
    "prompt": "Find the pricing page of {{trigger.output.payload.domain}} and list its plans as JSON.",
    "responseFormat": "json",
    "agentMode": true,
    "maxIterations": 8,
    "memoryEnabled": true
  }
}
Structured output step
{
  "ref": "classify",
  "action": "ai",
  "config": {
    "prompt": "Classify this support message: {{trigger.output.body.text}}",
    "outputSchema": {
      "type": "object",
      "properties": {
        "category": { "type": "string", "enum": ["billing", "bug", "other"] },
        "urgent": { "type": "boolean" }
      },
      "required": ["category", "urgent"]
    }
  }
}

action.mcp_tool

Call one tool on a remote MCP server.

ConfigTypeDefaultDescription
serverUrlstringrequiredMCP server URL. Private and internal addresses are blocked.
toolNamestringrequiredTool to call
argumentsobject—Tool arguments (supports expressions)
transportstringssestreamable-http: Streamable HTTP only. sse: tries Streamable HTTP first and uses the older HTTP+SSE transport when the server refuses that request with a 4xx.
timeoutMsnumber30000Request timeout, 1000–120000 ms
Output:{ toolName, result, isError, serverUrl, transport }

S6S sends initialize and then tools/call, without authentication headers. Replies may be JSON or an event stream. With the older transport, S6S opens the event stream at serverUrl and posts to the endpoint it names, which must be on the same origin. transport in the output says which one ran. result is the tool's text output, parsed as JSON when possible. A JSON-RPC error fails the step with MCP_TOOL_ERROR.

Example step
{
  "ref": "lookup_issue",
  "action": "mcp_tool",
  "config": {
    "serverUrl": "https://mcp.example.com/mcp",
    "toolName": "get_issue",
    "arguments": { "id": "{{trigger.output.payload.issue_id}}" },
    "timeoutMs": 20000
  }
}

action.rag

Search a knowledge base with a query embedding.

ConfigTypeDefaultDescription
querystringrequiredSearch text (supports expressions)
knowledgeBaseIdstringrequiredKnowledge base to search
topKnumber5Chunks to return, 1–50
minScorenumber0.5Minimum similarity, 0–1
includeMetadatabooleantrueInclude chunk metadata

Status: the schema and the deploy API accept this node, but no vector store is connected in this release. The step embeds the query with the install's LLM key and then fails with RAG_NO_VECTOR_STORE (or RAG_NO_API_KEY when no key is set).

action.buffer

Create, update, delete and publish posts through Buffer, and list channels, queued and sent posts.

ConfigTypeDefaultDescription
actionstringcreate_postcreate_post, list_channels, get_queue, get_sent, share_now, delete_post, update_post
textstring—Post text (required for create_post; also update_post)
mediaUrlstring—URL of an image or video to attach
channelIdsarray—Buffer channel IDs to publish to (create_post)
scheduledAtstring—ISO timestamp to schedule the post
shareModestring—queue, now or schedule. Without it: schedule when scheduledAt is set, else queue.
postTypestring—post, story or reel (Instagram and Facebook channels)
shortenbooleantrueShorten links in post text
profileIdstring—Profile/channel ID (get_queue, get_sent)
updateIdstring—Buffer update ID (share_now, delete_post, update_post)
countnumber—Results per page, 1–100 (get_queue, get_sent)
pagenumber—Page number for pagination
sincestring—Unix timestamp — only return updates after this time

Output: create_post { postIds, postId, count, scheduledAt, errors? }; list_channels { channels, channelCount }; get_queue and get_sent { updates, updateCount, total }; share_now { success, updateId }; delete_post { deleted, updateId }; update_post { postId, status, text, scheduledAt }.

Requires credential: buffer

action.youtube

Upload videos, list channel videos, get video details, and update video metadata via the YouTube Data API.

ConfigTypeDefaultDescription
actionstringupload_videoupload_video, list_videos, get_video, update_video
videoUrlstring—URL of the video to upload (required for upload_video)
titlestring—Video title (required for upload_video)
descriptionstring—Video description
tagsarray—Video tags
privacyStatusstringprivatepublic, unlisted, or private
categoryIdstring22YouTube video category ID
videoIdstring—Video ID (required for get_video / update_video)
maxResultsnumber10Max videos to return, 1–50 (list_videos)

Output: list_videos { videos, resultCount }; the other actions { videoId, url, status, title }, plus channelId for upload_video and get_video.

Requires credential: google

action.webhook_response

Record a status code, headers and body as the step output.

ConfigTypeDefaultDescription
statusCodenumber200HTTP status code, 100–599
headersobject—Header values (strings)
bodystring | object—Response body; objects are stored as JSON text
Output:{ statusCode, headers, body }

This does not change the HTTP reply to the webhook caller. That reply is sent as soon as the run is created and contains the run ID and trigger data.

action.execute_workflow

Start another S6S workflow by slug.

ConfigTypeDefaultDescription
slugstringrequiredTarget workflow slug
inputobject—Input for the child run (its trigger payload)
waitForCompletionbooleantrueWait for the child run to finish
maxWaitMsnumber300000How long to wait, 1000–600000 ms
Output:{ runId, status, workflowSlug, result }

result holds the child run and its steps. Without waiting, the output is { triggered, runId, workflowSlug }. A failed or cancelled child run fails this step; so does running out of wait time (EXECUTE_WORKFLOW_TIMEOUT).

Example step
{
  "ref": "run_child",
  "action": "execute_workflow",
  "config": {
    "slug": "enrich-lead",
    "input": { "email": "{{trigger.output.body.email}}" },
    "waitForCompletion": true,
    "maxWaitMs": 120000
  }
}

action.stop_and_error

Fail the step, and so the run, with a custom message. Useful for guardrails.

ConfigTypeDefaultDescription
messagestringrequiredError message; the step fails with STOP_AND_ERROR: <message>
Output:{ message }

Usually combined with run_if so it only fires when a check fails.

Logic

Logic nodes control execution flow — branching, routing, timing, and joining parallel steps.

logic.condition

Branch execution on a comparison. In a Recipe, place it first in a flow tuple: [condition, true_branch, false_branch].

ConfigTypeDefaultDescription
expressionstringrequiredLeft-hand value (supports expressions)
operatorstringrequiredComparison operator (see below)
valuestring | number | boolean | array—Right-hand value
Operators:
eqneqgtgteltltecontainsnot_containsexistsnot_existsmatchesin

eq, neq, contains and not_contains compare as text. gt, gte, lt and lte compare as numbers (an empty value counts as 0) and are false if either side isn't numeric. matches takes a regular expression; in takes an array or a comma-separated list. exists is true when the field the expression names is set (an empty string, 0 and false count as set) and false when it is missing or null; not_exists is the opposite. For a template that mixes text or several fields, exists means its text is not empty.

Output:{ conditionResult, resolvedValue, operator, compareValue, skippedNodeIds }

Raw IR also accepts a compound form, { logic: "and" | "or", conditions }: and needs every condition to hold, or any one, and a condition can itself be compound (up to 10 levels). Its output has logic in place of operator and compareValue, and resolvedValue reads compound(and) or compound(or). Recipes take one comparison per condition step.

Recipe example
{
  "name": "Check Order Size",
  "trigger": { "type": "manual" },
  "steps": [
    {
      "ref": "is_large",
      "action": "condition",
      "config": {
        "expression": "{{trigger.output.payload.total}}",
        "operator": "gt",
        "value": 1000
      }
    },
    {
      "ref": "large_order",
      "action": "transform",
      "config": { "template": { "size": "large" } }
    },
    {
      "ref": "small_order",
      "action": "transform",
      "config": { "template": { "size": "small" } }
    }
  ],
  "flow": [["is_large", "large_order", "small_order"]]
}

logic.switch

Route to one of several steps based on an expression's value.

ConfigTypeDefaultDescription
expressionstringrequiredValue to switch on
casesarrayrequiredAt least one { value, target_ref } in a Recipe ({ value, target } with a node ID in the IR)
defaultTargetstring—Step ref to run if no case matches
Output:{ resolvedValue, matchedTarget, skippedNodeIds }

Values are compared as text. The matching step runs; the other targets and the steps that only follow them are skipped. With no match and no default, all targets are skipped. Put the targets after the switch in the flow, usually as one parallel group.

Recipe example
{
  "name": "Route Ticket",
  "trigger": { "type": "manual" },
  "steps": [
    {
      "ref": "route",
      "action": "switch",
      "config": {
        "expression": "{{trigger.output.payload.priority}}",
        "cases": [
          { "value": "high", "target_ref": "page_oncall" },
          { "value": "low", "target_ref": "log_ticket" }
        ],
        "defaultTarget": "log_ticket"
      }
    },
    {
      "ref": "page_oncall",
      "action": "transform",
      "config": { "template": { "action": "page" } }
    },
    {
      "ref": "log_ticket",
      "action": "transform",
      "config": { "template": { "action": "log" } }
    }
  ],
  "flow": ["route", ["page_oncall", "log_ticket"]]
}

logic.loop

Turn an expression into an array of items, capped at maxIterations.

ConfigTypeDefaultDescription
arrayExpressionstringrequiredExpression resolving to an array, e.g. {{fetch.output.body.items}}. A non-array value becomes a one-item array.
itemVariablestringitemName returned in the output
maxIterationsnumber100Maximum items kept, 1–1000
Output:{ items, iterations, itemVariable }

The loop does not run later steps once per item. To process each item, use action.filter (map mode) or action.code.

logic.wait

Pause execution for a specified duration.

ConfigTypeDefaultDescription
secondsintegerrequiredWait time in seconds (1 or more)
Output:{ waited, seconds, actualMs }

logic.merge

Combine outputs from parallel steps into a single object. Place it right after a parallel group in the flow array.

ConfigTypeDefaultDescription
modestringwait_allMerge strategy; only wait_all exists, and Recipes always use it
Output:{ "<step_ref>": <that step's output>, ... }
Recipe example
{
  "name": "Fetch Two Sources",
  "trigger": { "type": "manual" },
  "steps": [
    {
      "ref": "branch_a",
      "action": "http",
      "config": { "url": "https://api.example.com/a", "method": "GET" }
    },
    {
      "ref": "branch_b",
      "action": "http",
      "config": { "url": "https://api.example.com/b", "method": "GET" }
    },
    {
      "ref": "combine",
      "action": "merge",
      "config": {}
    },
    {
      "ref": "send_result",
      "action": "transform",
      "config": {
        "template": {
          "a_status": "{{combine.output.branch_a.status}}",
          "b_status": "{{combine.output.branch_b.status}}"
        }
      }
    }
  ],
  "flow": [["branch_a", "branch_b"], "combine", "send_result"]
}

combine waits for both parallel steps and outputs their results keyed by ref.

Conditional Execution

Any step can include a run_if field next to its config (not inside it). The engine resolves it at runtime: a truthy result runs the step, a falsy one skips it with status skipped. Skipped steps do not fail the run. Put comparison operators outside the braces.

run_if example
{
  "ref": "send_alert",
  "action": "telegram",
  "config": {
    "action": "send_message",
    "chatId": "123456",
    "text": "Alert: amount is {{trigger.output.payload.amount}}"
  },
  "credential": "default",
  "run_if": "{{trigger.output.payload.amount}} > 1000"
}

See Recipe Format for the full comparison rules.

Dynamic Integrations

Beyond the built-in action types, S6S supports a provider.action syntax for other APIs, such as Notion, Pinterest, HubSpot or Stripe. These steps compile to action.http nodes.

ActionDescription
notion.create_pageCreate a page in Notion
pinterest.create_pinCreate a pin on Pinterest
hubspot.create_contactCreate a contact in HubSpot
stripe.create_invoiceCreate a Stripe invoice

S6S resolves the provider and action from its store of learned integrations (learning unknown ones at deploy time when the learning module and an LLM are available), builds the request, and injects the step's credential. Failed calls are retried only under the step's retry policy. Learn more about dynamic integrations.

Expressions

Use {{expression}} syntax in any config string to reference data from the trigger and earlier steps:

ExpressionDescription
{{trigger.output.body.name}}Webhook request body field
{{format.output.message}}An earlier step's output by ref ({{steps.format.output.message}} also works)
{{fetch.output.body.items.0}}Array element by index (dot notation; brackets are not supported)
{{run.id}}Current run ID

Expressions are resolved just before each step runs. See Expressions for every context and output shape.

Need help choosing node types?

The Recipe Format guide shows how steps, flow and error handling fit together.