04. Integration Catalog¶
The complete list of things a CALL node can do.
Put one of the ids below in integration:, then fill input: with the values that integration asks for.
- id: node-id
name: Node name
type: CALL
integration: llm_chat # ← here
input: # ← every integration asks for different fields
...
The full list¶
| id | Name | Category | Connection needed | What it does |
|---|---|---|---|---|
http_request |
HTTP request | HTTP | None | Call any HTTP API directly |
llm_chat |
LLM Chat | AI | None (API key) | Have AI summarize, classify or write |
transform_jmespath |
Transform (JMESPath) | DATA | None | Shape and filter JSON data |
dataset |
Dataset | DATA | None | Read and write workspace datasets |
slack_post_message |
Send Slack message | MESSAGING | Slack connection | Post a message to a Slack channel |
httpbin_get |
HTTPBin GET | HTTP | None | A test call for checking things work |
Start with the ones that need no connection. With just
http_request·llm_chat·transform_jmespathyou can build most automations end to end. Set up OAuth connections only when you really need that service.Checking the current list: this catalog grows. To see what is available in your workspace right now, look at the node palette in the visual editor, or — if you have connected an AI assistant — just ask it "what integrations can I use?".
http_request¶
Calls any HTTP API directly. The most flexible integration, and the one you will use most.
Input¶
| Field | Required | Description |
|---|---|---|
uri |
✅ | The address to call. Expressions allowed |
method |
✅ | GET · POST · PUT · DELETE · PATCH |
mediaType |
Content-Type. Defaults to application/json |
|
queryParams |
Query string (?a=1&b=2) |
|
body |
Request body | |
authenticate |
A bundle of auth headers (see below) |
Example — reading¶
- id: fetch-orders
name: Fetch orders
type: CALL
integration: http_request
timeout: 10s
input:
uri: "https://api.example.com/v1/orders"
method: GET
queryParams:
status: "PAID"
from: "${nodes.trigger.response.body.windowStart}"
authenticate:
authMethod: HEADERS
data:
Authorization: "Bearer ${secrets.EXAMPLE_API_TOKEN}"
Example — sending¶
- id: post-hook
name: Notify an external system
type: CALL
integration: http_request
input:
uri: "https://hooks.example.com/notify"
method: POST
body:
orderId: "${nodes.trigger.response.body.orderId}"
status: "confirmed"
Output¶
The response body is the output, as-is.
${nodes.fetch-orders.response.body.data} # the data field of the response body
${nodes.fetch-orders.response.body.items.0.name} # the name of the first array element
API keys always go through
${secrets.*}. If you write a token straight into YAML, it leaks along with the workflow whenever you copy or share it. → 08. Variables and Secrets
llm_chat¶
Calls AI. Use it for summarizing, classifying, changing tone, drafting and so on.
It is not tied to a specific vendor — you pick an API shape (contract) instead. Any provider that matches the shape works.
Input¶
| Field | Required | Description |
|---|---|---|
apiContract |
✅ | OPENAI_CHAT or ANTHROPIC_MESSAGES |
model |
✅ | The model id. For example: gpt-4o-mini, claude-sonnet-4-6 |
apiKey |
✅ | The API key. Pass it via ${secrets.*} |
userPrompt |
✅ | What you are asking the AI to do |
systemPrompt |
Sets the role and the rules | |
endpoint |
If omitted, the default address for the contract | |
maxTokens |
Maximum response length. ANTHROPIC_MESSAGES sends 4096 when omitted |
|
temperature |
0–2. Only sent when you set it |
If you omit endpoint, this is where the call goes.
apiContract |
Default address |
|---|---|
OPENAI_CHAT |
https://api.openai.com/v1/chat/completions |
ANTHROPIC_MESSAGES |
https://api.anthropic.com/v1/messages |
Anywhere else works too as long as the contract is compatible (Fireworks, Together, your own vLLM instance, and so on). Just put the address in endpoint.
Example¶
- id: summarize
name: Sales summary
type: CALL
integration: llm_chat
timeout: 30s
input:
apiContract: OPENAI_CHAT
model: gpt-4o-mini
apiKey: "${secrets.OPENAI_API_KEY}"
systemPrompt: "You are an e-commerce operations lead. Do not exaggerate numbers; report facts concisely."
userPrompt: |
Summarize the order data below in three lines.
Always include total revenue and order count, and add one line if anything stands out.
Data: ${nodes.aggregate.response.body.summary}
Output¶
| Field | Description |
|---|---|
${nodes.summarize.response.body.content} |
The text the AI wrote |
${nodes.summarize.response.body.tokenUsage.totalTokens} |
Tokens used |
${nodes.summarize.response.body.tokenUsage.promptTokens} |
Input tokens |
${nodes.summarize.response.body.tokenUsage.completionTokens} |
Output tokens |
Careful with
temperature: some models, including recent Claude models, reject this value with a 400 error. If you do not need it, leave it out entirely.You pay for usage. eeumsae only makes the call on your behalf with your API key; the bill comes from OpenAI, Anthropic and the rest directly. If tokens worry you, cap them with
maxTokens.Want to branch on the AI's answer? → the
containsoperator in 06. Flow Control
transform_jmespath¶
Reshapes JSON data. Pull out only the fields you need, keep only what matches a condition, count things, and so on.
It uses JMESPath syntax.
Input¶
| Field | Required | Description |
|---|---|---|
expression |
✅ | A JMESPath expression |
data |
What to transform. If omitted, everything in input except expression |
⚠️ The result must be an object¶
A CALL node's output has to be a JSON object. Emitting a bare array or number fails. Wrap it in braces.
expression: "items[*].id" # ❌ array → fails
expression: "{ids: items[*].id}" # ✅ object → works
expression: "length(items)" # ❌ number → fails
expression: "{count: length(items)}" # ✅ works
Common patterns¶
# pull specific fields into an array
expression: "{ids: data[*].orderId}"
# filter by a condition (mind the backticks)
expression: "{active: items[?status == `active`]}"
# count and sum
expression: "{count: length(orders), total: sum(orders[*].amount)}"
# rename fields
expression: "{name: customer.name, amount: payment.total}"
# several at once
expression: "{count: length(orders), revenue: sum(orders[*].amount), firstOrder: orders[0]}"
Example¶
- id: aggregate
name: Aggregate orders
type: CALL
integration: transform_jmespath
input:
expression: "{count: length(@), totalRevenue: sum([*].amount)}"
data: "${nodes.fetch-orders.response.body.data | raw}"
Do not forget
| raw. Without that marker, an array or object passed to another node gets converted into a string. → 05. Connecting Data with Expressions
Output¶
The result of evaluating expression, as-is.
dataset¶
Reads and writes rows in a workspace dataset. Use it when you need to remember a value between executions (for example: order numbers you already processed, or a running total).
The dataset has to exist first. → 09. Datasets
Input¶
| Field | Required | Description |
|---|---|---|
datasetTitle |
✅ | The title of the target dataset (unique within the workspace) |
operation |
✅ | QUERY · INSERT · UPDATE · DELETE |
data |
INSERT/UPDATE | The values to store. Keys that are not dataset columns are dropped |
rowId |
UPDATE/DELETE | The id of the target row |
limit |
Maximum rows for QUERY. Default 100, maximum 1000 | |
offset |
Where QUERY starts |
Example¶
# read
- id: load-log
type: CALL
integration: dataset
input:
datasetTitle: "processing-log"
operation: QUERY
limit: 50
# write
- id: save-log
type: CALL
integration: dataset
input:
datasetTitle: "processing-log"
operation: INSERT
data:
orderId: "${nodes.trigger.response.body.orderId}"
processedAt: "${nodes.trigger.response.body.windowEnd}"
Output¶
| operation | Output shape | Reference example |
|---|---|---|
QUERY |
{ rows: [ {id, ...columns}, ... ] } |
${nodes.load-log.response.body.rows \| raw} |
INSERT / UPDATE |
{ id, ...columns } |
${nodes.save-log.response.body.id} |
DELETE |
{ deleted: true, id } |
${nodes.del.response.body.deleted} |
slack_post_message¶
Posts a message to a channel in a connected Slack workspace.
Before you start¶
- Connect Slack on the Connections screen. → 07. Managing Connections
- Invite the eeumsae bot into the channel you want to post to. In that channel, run
/invite @eeumsae. Skip this step and you get anot_in_channelerror.
Input¶
| Field | Required | Description |
|---|---|---|
channel |
✅ | Channel ID (for example C0123ABCDEF) or channel name |
text |
✅ | The message body |
In the visual editor you can pick channel from the channel list of the connected Slack.
Example¶
- id: notify
name: Send to Slack
type: CALL
integration: slack_post_message
input:
channel: "C0123ABCDEF"
text: |
📊 Today's sales summary
${nodes.summarize.response.body.content}
Output¶
| Field | Description |
|---|---|
${nodes.notify.response.body.ok} |
Whether it succeeded |
${nodes.notify.response.body.channel} |
The channel it was sent to |
${nodes.notify.response.body.ts} |
The message timestamp |
⚠️ This integration really does send¶
slack_post_message is marked as an integration with a side effect.
When you run it from an AI assistant over MCP, a workflow like this does not run straight away — it asks for approval once.
That safeguard exists so an AI cannot accidentally blast messages at your customers.
httpbin_get¶
A test integration for checking things work. It calls httpbin.org, which echoes back what you send. Since it needs no authentication, it is handy for quickly confirming "does this workflow run at all?".
| Field | Required | Description |
|---|---|---|
query |
✅ | The value to get echoed back. URL-safe characters only (letters, digits, _ . ~ -) |
Output: ${nodes.ping.response.body.args} · ${nodes.ping.response.body.url} · ${nodes.ping.response.body.origin}
Non-ASCII characters or spaces cause the save to be rejected. It is for testing only, so keep it out of real automations.
Options every CALL node can use¶
These can be attached to any CALL node, whatever its integration.
- id: fetch
type: CALL
integration: http_request
timeout: 10s # over this and it counts as a failure
retry-policy: # try again on failure
max-attempts: 3
backoff:
type: EXPONENTIAL
initial-delay: 500ms
retry-on: ["429", "5xx"]
input:
...
For the details → 10. Executions and Monitoring