Reference

Step HTTP (:http)

Quick Answer

Use this reference for the :http step schema, required fields, persistence behavior, and large-payload safety defaults.

Use for HTTP APIs. Prefer :connection with a :http-api slot.

Canonical Shape

Core fields:

FieldTypeRequiredNotes
:connectionkeyword/stringYes*Slot or connection id
:urlstringYes*Full URL (ad hoc request)
:pathstringNoAppended to connection base URL
:methodkeywordNo:get, :post, :put, :patch, :delete
:headersmapNoHeader map
:querymapNoQuery params
:jsonmapNoJSON body
:formmapNoURL-encoded form body
:multipartvectorNoMultipart parts
:bodyanyNoRaw body
:body-from-refmapNoLoad body from blob ref
:content-typekeyword/stringNoBody content type
:acceptkeywordNoAccept header helper
:response-askeywordNo:auto, :json, :text, :bytes, :edn, :xml
:parser-fnformNoCustom parse function
:templatekeywordNo:http-request template id
:datamapNoTemplate variables
:authmapNoStep-level auth (if not from connection)
:client-optsmapNoTransport overrides
:timeoutintNoTimeout seconds (common option)
:retrymapNoRetry policy (common option)
:persistmapNoPersist large/binary response refs

* Provide either :connection or :url.

Limits And Behavior

  • Request body modes are mutually exclusive in practice: prefer one of :json, :form, :multipart, :body, :body-from-ref.
  • When both :json and :body are set, :json wins.
  • :response-as :auto uses the response Content-Type to choose :json, :text, or :bytes.
  • Results are inlined up to the 256 KB limit; larger payloads require :persist.
  • If payload size is unknown/unbounded (exports, pagination, generated files), prefer :persist from the start.
  • If the persisted response is just a temporary runtime artifact, make that explicit with :persist {:type :blob :tier :ephemeral} instead of relying on the retained default.
  • Binary responses are not inlined; use :persist {:type :blob ...} for any binary body.
  • If the response is truncated, the step fails unless :persist {:type :blob ...} is set.
  • Use :persist {:type :blob} for large payloads; downstream function steps can hydrate persisted HTTP responses explicitly with :input {:resp http-step-result} and :load [:resp].
  • Prefer :tier :ephemeral for downloads, exports, generated media, and other response blobs that only need to survive the current workflow or near-term consumption.
  • Use :persist {:type :blob :path ... :filename ...} when you want artifacts grouped under a stable relative subpath beneath the default runtime-managed path workspaces/<ws>/persist/<flow>/<step>/<uuid>/....
  • Use :persist {:type :blob :slot <slot> ...} when installers should control the storage binding and storage root.
  • To download binaries safely, set :response-as :bytes and :persist {:type :blob :tier :ephemeral}. In this mode Breyta can stream the HTTP response directly to blob storage (avoids buffering the full payload in memory).
  • For streamed blob responses, Breyta enforces persist-tier write limits by default (for example, ephemeral up to 4 GB) instead of the default inline HTTP response limit.
  • For retained artifacts, switch back to the default retained tier intentionally; do not use retained storage just because a response is large.
  • :tier :ephemeral is the HTTP-step option for temporary streamed response blobs; downstream non-HTTP persists still use the retained default.
  • If you set :client-opts {:max-response-bytes ...} explicitly, streamed blob responses enforce both limits (the lower of :max-response-bytes and the persist-tier write limit).
  • Leave :client-opts :max-response-bytes unset when you want streamed blob persists to use the full persist-tier cap. The explicit override remains bounded for buffered, non-streaming response safety.
  • Non-streaming responses (e.g. JSON parsing) are buffered in memory up to :max-response-bytes.
  • Binary blobs persisted from :http are searchable by metadata/path context; :ephemeral tier does not extract raw content text by default.
  • To make binary blobs searchable by domain text, use :persist {:type :blob :search-index {...}} (for example :text, :tags, :source-label).
  • :persist :path and :persist :filename support {{...}} interpolation from resolved step params (for example data.*, input.*, query.*) plus runtime fields like workspace-id, flow-slug, and step-id.
  • :persist :path must be a relative subpath. Do not include a leading / or ...
  • When :persist :slot points at a blob-storage slot, platform-backed writes land at workspaces/<ws>/storage/<root>/<path>/<filename>.
  • For end-user installations, <root> defaults to installations/<profile-id>/<prefix> from the slot config until the installer explicitly saves another root.
  • Connected persists do not add the default persist/<flow>/<step>/<uuid> segments.
  • :persist :slot always uses a local blob-storage slot declared in :requires, such as :archive.
  • Two flows share persisted HTTP outputs only when installers explicitly point their local blob-storage slots at the same concrete storage root.
  • Blob-storage slots always synthesize required setup for the storage root. Authors can customize it with :config {:prefix ...} on the slot, but cannot turn it off.
  • Templates only cover request shape; step-level keys like :persist stay on the step.
  • Auth must use secret references. Inline tokens or API keys are rejected.
  • Prefer connection auth (:requires with :auth), or set step-level auth with :auth {:type :bearer|:api-key :secret-ref :my-secret}.
  • :body-from-ref and multipart :from-ref are preferred for large uploads from prior persisted artifacts.

Auth Variant: Google Service Account (:google-service-account)

Use this when you need unattended OAuth access to Google APIs on a schedule (e.g., Drive folder sync). The flow mints access tokens from a service account JSON secret.

Example (Google Drive list):

(flow/step :http :list-drive-files
           {:type :http
            :title "List Drive files"
            :url "https://www.googleapis.com/drive/v3/files"
            :method :get
            :query {:q "'<folder-id>' in parents and trashed = false"
                    :fields "nextPageToken,files(id,name,mimeType,modifiedTime,size,driveId)"
                    :pageSize 1000
                    :supportsAllDrives "true"
                    :includeItemsFromAllDrives "true"}
            :auth {:type :google-service-account
                   :secret-ref :google-drive-service-account
                   :scopes ["https://www.googleapis.com/auth/drive.readonly"
                            "https://www.googleapis.com/auth/drive.metadata.readonly"]}})

Canonical Example

;; In the flow definition:
;; :templates [{:id :download-report
;;              :type :http-request
;;              :request {:path "/reports/latest" :method :get}}]
;; :functions [{:id :http-headers
;;              :language :clojure
;;              :code "(fn [input] {\"X-Request-Id\" (:request-id input)})"}]

'(let [headers (flow/step :function :build-http-headers
                 {:ref :http-headers
                  :input (flow/input)})
       users (flow/step :http :get-users
               {:connection :api
                :path "/users"
                :method :get
                :query {:limit 10}
                :headers headers
                :retry {:max-attempts 3
                        :backoff-ms 500}})
       report (flow/step :http :download-report
                {:connection :api
                 :template :download-report
                 :data {:customer-id "cust-77"
                        :report-id "rep-42"
                        :run-date "2026-03-23"}
                 :response-as :bytes
                 :persist {:type :blob
                           :slot :archive
                           :path "{{data.customer-id}}/{{data.run-date}}"
                           :filename "summary-{{data.report-id}}.pdf"
                           :tier :ephemeral}})]
   {:users users
    :report report})

Author the matching blob-storage slot like this:

{:requires [{:slot :archive
             :type :blob-storage
             :label "Archive storage"
             :config {:prefix {:default "reports"
                               :label "Folder prefix"
                               :placeholder "reports/customer-a"}}}]}

With :persist {:slot :archive ...}, platform-backed writes land under:

workspaces/<ws>/storage/<root>/<path>/<filename>

Related

As of Mar 30, 2026