Skip to main content

HTTP, Files & Storage

Generic connectivity and I/O nodes: arbitrary HTTP/REST and gRPC calls, the universal connector node for third-party integrations, SFTP file transfer, per-tenant key-value storage, file/encoding utilities, and Cypher queries against Neo4j.

http

Makes an HTTP request to any URL and returns the parsed response. Supports JSON, form, multipart, text, XML, GraphQL, and binary request bodies.

{
"id": "fetch_user",
"type": "http",
"config": {
"method": "POST",
"url": "https://api.example.com/users",
"body_type": "json",
"body": { "email": "{{trigger.body.email}}" },
"headers": { "X-Api-Version": "2024-01-01" },
"auth_bearer": "{{secret.API_TOKEN}}",
"timeout_seconds": 30
}
}
FieldTypeDefaultDescription
methodstring"GET"HTTP method, case-insensitive (normalized to uppercase).
urlstringRequired. Request URL. Supports {{ }} expressions.
body_typestringautoRequest body encoding — see table below. If unset, defaults to "none" for GET/DELETE/HEAD and "json" otherwise.
bodyanyRequest body. Used by json, text, xml, graphql (fallback), and binary body types.
form_fieldsobjectField map for form and multipart body types.
filesarrayFor multipart: list of { field_name, file_name, content_base64, content_type } objects to attach as file parts.
graphql_querystringGraphQL query string (used when body_type: "graphql"). Falls back to body if unset.
graphql_variablesobjectGraphQL variables object.
query_paramsobjectKey/value pairs appended to the URL's query string (merged with any existing query string).
headersobjectRequest headers. Accepts a JSON object. Overrides the auto-set Content-Type.
auth_username / auth_passwordstringIf auth_username is set, sends HTTP Basic auth.
auth_bearerstringIf set (and resolves to a non-empty value), sends Authorization: Bearer <value>.
content_typestring"application/octet-stream"Content-Type used for body_type: "binary".
timeout_secondsnumber60Per-request timeout override (the node's default HTTP client uses a 60s timeout).
fail_on_errorstring"true"If not "false", the step fails (returns an error) when the response status is >= 400. The parsed output is still returned alongside the error.

body_type values

ValueContent-Type sentBody source
noneNo body (used for GET/DELETE/HEAD by default).
json (default for non-GET)application/jsonbody, JSON-encoded. If body is already a valid JSON string, it's sent as-is.
formapplication/x-www-form-urlencodedform_fields (or body as a fallback object).
multipartmultipart/form-dataform_fields for regular fields, files for file parts.
texttext/plain; charset=utf-8body, stringified.
xmlapplication/xml; charset=utf-8body, stringified.
graphqlapplication/json{ "query": graphql_query (or body), "variables": graphql_variables }.
binarycontent_type (default application/octet-stream)body, base64-decoded into raw bytes.

Output:

FieldTypeDescription
status / status_codenumberHTTP response status code.
okbooleantrue if status is in the 200-299 range.
headersobjectResponse headers, flattened to { "Header-Name": "comma, joined, values" }.
body_rawstringRaw response body as a string.
bodyanyParsed response body — a JSON value if Content-Type contains application/json, a string if text/*, otherwise the raw text (binary responses also fall through here).
body_base64stringPresent only for non-text/non-JSON responses — the body base64-encoded.

A response with status >= 400 returns this output and an error (unless fail_on_error: "false"), so continue_on: "error" steps can still inspect steps.<id>.output.status and body.

connector

Executes one action against a connector registered through the Connector SDK (connector-sdk/) — the plugin mechanism for custom/marketplace connectors that ship a manifest plus action handlers (sdk.NewFromManifest). These are managed via GET/POST /api/v1/connectors.

Note: The 66 built-in integrations (GitHub, Slack, Stripe, databases, ad platforms, etc. — see the Connector Reference) are a separate library (internal/connectors) exposed only as AI agent tools via an agent node's tools array (see AI Agents — Connector tools), not through this connector node.

{
"id": "post_message",
"type": "connector",
"config": {
"connector": "slack",
"action": "send_message",
"auth": {
"type": "api_key",
"fields": { "token": "{{secret.SLACK_TOKEN}}" }
},
"input": {
"channel": "#general",
"text": "Deployment finished: {{steps.deploy.output.version}}"
}
}
}
FieldTypeDefaultDescription
connectorstringRequired. Connector identifier as registered in internal/connectors/registry.go (e.g. "slack", "tool-github").
actionstringRequired. One of the actions the connector exposes.
authobject{ type, fields }. type is "none", "api_key", "oauth2", "basic", or "custom", matching the connector's auth schema. fields is a flat string map (e.g. { "token": "...", "access_token": "..." }), typically populated from {{secret.NAME}} or the tenant's stored connector credentials.
inputobjectAction-specific input parameters. If omitted, the step's resolved inputs map (upstream step outputs) is passed through as-is.

Resolution path: the node looks up the connector by name in the global connector registry, builds an Auth{Type, Fields} from config.auth, builds the input map from config.input (or falls back to the step's inputs), and calls connector.Execute(ctx, action, auth, input).

Output: action-specific — the map returned by the connector's Execute implementation. See the Connector Reference for the full list of connectors, their actions, auth types, and per-action input/output shapes.

grpc-action

Calls any method on an external gRPC service using server-side reflection — no .proto files need to be bundled with the workflow.

{
"id": "say_hello",
"type": "grpc-action",
"config": {
"address": "api.example.com:443",
"method": "helloworld.Greeter/SayHello",
"payload": { "name": "{{trigger.body.name}}" },
"metadata": { "authorization": "Bearer {{secret.API_TOKEN}}" }
}
}
FieldTypeDefaultDescription
addressstringRequired. host:port of the gRPC server.
methodstringRequired. package.ServiceName/MethodName (e.g. helloworld.Greeter/SayHello). The part before the last / is the fully-qualified service name; the part after is the method name.
payloadobject{}Request message fields, as JSON. Converted to the request proto via protojson after the schema is fetched through reflection.
tlsstring"auto""true", "false", or "auto" — auto enables TLS when the address ends in :443.
timeout_msnumber (string)30000Request timeout in milliseconds.
metadataobject{}Outgoing gRPC metadata headers, e.g. { "authorization": "Bearer ..." }.

How it works: the node dials the address, opens a gRPC server reflection (v1alpha) stream to fetch the FileDescriptorProto for the service, locates the method descriptor, builds a dynamic request message from payload via protojson.Unmarshal, invokes the method, and marshals the dynamic response message back to JSON. The target server must have gRPC reflection enabled.

Output:

FieldTypeDescription
responseobjectThe decoded response message as a JSON object (with unpopulated fields emitted).
methodstringThe package.Service/MethodName that was called.
addressstringThe server address that was called.

sftp

Performs file and directory operations against a remote server over SFTP/SSH.

{
"id": "upload_report",
"type": "sftp",
"config": {
"operation": "upload_file",
"host": "files.example.com",
"port": "22",
"username": "deploy",
"private_key": "{{secret.SFTP_PRIVATE_KEY}}",
"path": "/incoming/report.csv",
"content": "{{steps.build_csv.output.csv}}",
"encoding": "text"
}
}

Connection fields (all operations)

FieldTypeDefaultDescription
hoststringRequired. Remote host.
portstring"22"SSH port.
usernamestringSSH username.
passwordstringPassword auth. Either password or private_key (or both) must be set.
private_keystringPEM-encoded private key for public-key auth (e.g. {{secret.SFTP_PRIVATE_KEY}}).
operationstring"list_files"One of the operations below.

Host key verification is not performed (InsecureIgnoreHostKey). Connection timeout is fixed at 30 seconds.

Operations

OperationExtra fieldsOutput
list_filespath (default .)files: array of { name, path, size, is_dir, modified, mode }; count.
read_filepathcontent (string), base64, size, path, name.
upload_filepath, content, encoding ("text" or "base64", default "text")path, bytes_written, name. Parent directories are created automatically.
delete_filepathpath, deleted: true.
renamefrom, tofrom, to, renamed: true.
create_folderpathpath, created: true. Creates intermediate directories as needed.
delete_folderpathpath, deleted: true. Directory must be empty.

store

Durable per-tenant key-value storage backed by the workflow_kv_store table (see Multi-Tenancy). Reads always go to the database, so values are correct across Temporal workflow replays.

{
"id": "remember_count",
"type": "store",
"config": {
"operation": "put",
"scope": "execution",
"key": "processed_count",
"value": "{{steps.count_items.output.count}}"
}
}
FieldTypeDefaultDescription
operationstring"get"One of the operations below.
scopestring"execution""execution" — isolated to the current workflow run (keyed by execution_id); "global" — shared across all runs for the tenant.
keystringThe KV key. Supports {{ }} expressions.
valueanyValue to write (put, append, add_to_list, remove_from_list).
default_valueanyReturned by get when the key doesn't exist.
separatorstring""Separator inserted between existing and new value for append.
itemanyItem to add/remove for add_to_list / remove_from_list.

Operations

OperationDescriptionOutput
getRead a key. Returns default_value if not found.value, found (boolean).
putUpsert a key's value (JSON-encoded).key, value, operation: "put".
deleteRemove a key.key, deleted: true.
appendString-concatenate value onto the existing string value, joined by separator.value (the new string), key.
add_to_listAppend item to a JSON array stored at key (creates it if absent).list, count, key.
remove_from_listRemove all elements equal to item (compared as strings) from the array.list, count, key.
list_keysList all keys for the current tenant + scope.keys (array of strings), count, scope.
clearDelete all keys for the current tenant + scope.cleared: true, scope.

file-helper

Encoding, decoding, and metadata utilities for in-workflow file content (base64 strings, MIME types, filenames). Operates purely on values passed through config/inputs — it does not touch the sandbox filesystem.

{
"id": "encode_attachment",
"type": "file-helper",
"config": {
"operation": "to_base64",
"content": "{{steps.fetch_doc.output.body}}"
}
}
FieldTypeDefaultDescription
operationstring"to_base64"One of the operations below.
contentstringSource content (text or already-encoded), depending on operation.
namestringFilename, used for extension/MIME detection.
pathstringPath string for get_name.
encodingstring"text"For create: "text" or "base64" — whether content is already base64.
from_encoding / to_encodingstring"utf8" / "base64"For change_encoding: source/target encodings ("utf8" or "base64").
base64stringInput for from_base64.

Operations

OperationOutput
to_base64base64, size (bytes of content), encoding: "base64".
from_base64content (decoded string, tries standard/raw/URL base64), size.
createname, content, base64, mime_type, extension, size. Builds a "virtual file" object from content + name.
get_namename, extension, dir, stem — derived from path.
check_typemime_type, extension, is_text, is_image, is_pdf, is_binary. MIME is detected from name's extension, falling back to content-sniffing (PDF/JPEG/PNG/GIF/WebP magic bytes).
get_extensionextension, name, mime_type — derived from name.
change_encodingresult (re-encoded content), size.

neo4j

Runs a Cypher query against a Neo4j graph database. Works for both reads (MATCH ... RETURN) and writes (CREATE / MERGE / SET) — Neo4j's auto-commit transaction picks the access mode based on the query.

{
"id": "find_related",
"type": "neo4j",
"config": {
"uri": "neo4j+s://my-instance.databases.neo4j.io",
"username": "neo4j",
"password": "{{secret.NEO4J_PASSWORD}}",
"database": "neo4j",
"query": "MATCH (n:Person)-[:KNOWS]->(m) WHERE n.name = $name RETURN m.name AS name",
"params": { "name": "{{trigger.body.name}}" },
"timeout_ms": 15000
}
}
FieldTypeDefaultDescription
uristringRequired. e.g. neo4j://localhost:7687 or neo4j+s://<host>.
usernamestring"neo4j"Database username.
passwordstring""Database password. Supports {{ }} expressions, e.g. {{secret.NEO4J_PASSWORD}}.
querystringRequired. Cypher query. Supports {{ }} expressions.
databasestringserver defaultOptional database name (Neo4j multi-database).
paramsobject{}Cypher $parameters, as a JSON object. Each value is independently resolved for {{ }} expressions.
timeout_msnumber15000Query timeout in milliseconds.

Output:

FieldTypeDescription
recordsarray of objectsEach record from the result, converted via record.AsMap() (column name -> value).
keysarray of stringsThe result's column names.
countnumberNumber of records returned.
countersobjectWrite statistics: nodes_created, nodes_deleted, relationships_created, relationships_deleted, properties_set, labels_added.

Next