Skip to content

I/O & Files

These connectors move bytes — files, objects, streams — and speak the wire protocols a flow needs to reach the outside world.

Connectorinvoke:What it does
Filesystemfilesystem.*Read, write, move, list local files.
SFTPsftp.*List, get, put, move, delete over SFTP. Write actions carry compensating deletes.
SSHssh.*Run remote commands over SSH.
S3s3.*Object get/put/list/delete on AWS S3 or S3-compatible stores.
Dropboxdropbox.*File operations against Dropbox.
Archivearchive.*Create/extract zip, tar.gz; bundle multiple inputs.
Binary Decoderbinary-decoder.*Decode binary payloads into structured data.
Kinesiskinesis.*Put/get records on AWS Kinesis streams.
Terminal window
using:
- environment/prod
- zenvara/sftp
output:
path: !str
steps:
- $upload:
create: sftp.file
on: drop
with:
Path: "/incidents/${= str(_run-id)}.json"
Input: "${= toJson(rows.rows)}"
- return:
path: "${upload.Path}"

Output field names are descriptive — path, content, files, etc. For a presigned-URL handoff, a flow can return: a _redirect:.

Connectorinvoke:What it does
HTTPhttp.*get, post, put, delete, … Generic HTTP with multiple auth modes; auto-discovers OpenAPI specs.
RESTrest.*Higher-level REST client over the HTTP core.
GraphQLgraphql.*Typed GraphQL queries and mutations.
SOAP / WSDL SOAPsoap.*SOAP requests; consumes a WSDL to type the operations.
Terminal window
using:
- zenvara/http
output:
temp: !any
steps:
- $weather:
invoke: http.get
with:
Url: "https://api.example.com/weather?city=${city}"
- return:
temp: "${weather.body.temp}"

Output: body, statusCode, headers. body auto-parses into a structured value when the response carries a JSON Content-Type — dotted access like ${weather.body.temp} works directly, same as any other connector output. Without a JSON Content-Type (XML, plain text, a missing header, or malformed JSON), body stays raw text and dotting into it fails ('body' is not an object); reach into it instead with path(): "${= path(weather.body, '$.temp')}". Full grammar in the Flow Language Reference.

Sibling connectors already return structured data regardless of Content-Type: rest.data, graphql.data, and soap.data are typed as objects and always parsed. http.*’s body is !any precisely because it can be either shape, depending on what the server sends back.

Every http.* request is checked against an allow-list of permitted origins before it leaves the box. It is an SSRF guard: it stops a flow from being steered into your internal network or a cloud metadata endpoint.

You only have to write it when the host is not compile-time constant. Above, the host is pinned by the literal https://api.example.com in Url, so the allow-list is derived automatically. But when the host itself comes from a variable, there is nothing to derive from — declare it explicitly:

Terminal window
using:
- zenvara/http
output:
body: !any
steps:
- $fetch:
invoke: http.get
with:
Hosts: ["https://api.example.com"]
Url: "${base-url}/items"
- return:
body: "${fetch.body}"

The rule: Hosts: is required whenever the host is not a compile-time constant — a fully templated URL ("${full-url}"), a templated host ("https://${tenant}.example.com/x"), or a literal that runs straight into a placeholder with no /, ? or # between them ("https://api.example.com${path}", which could otherwise resolve to api.example.comEVIL.net). Leave it out and the flow fails validation. Redirects are re-checked against the same list on every hop, so a 3xx cannot escape it.

The HTTP connector is the universal escape hatch: when no dedicated connector exists for a service, point http.* at its OpenAPI spec and you have a typed client. The SOAP connector does the same for legacy WSDL services. This is why the catalog stays focused rather than shipping hundreds of bespoke connectors.

The HTTP/REST connectors support multiple authentication modes — bearer token, basic, API key header, OAuth client-credentials — configured on the connection and backed by secrets, so the flow never carries a credential.