Skip to main content

HTTP Activities

One activity, http.request, makes an HTTP call from a workflow. It is the most common way to reach a service that has no dedicated activity provider.

Setup​

No configuration is required. Two environment variables on the worker affect every call:

VariableEffect
MOCO_HTTP_PROXYUsed as the proxy when proxy is not set on the activity
MOCO_HTTP_PROXY_BYPASSSemicolon-separated host patterns that skip the proxy, * glob supported — e.g. localhost;127.0.0.1;*.internal.corp

Bearer authentication uses an encrypted token rather than a secret key name — see Authentication below.

Destinations can be restricted

Every call asserts the internal.http_activities / invoke privilege with the target's <scheme>://<host> as evidence, so a deployment can allowlist destinations. If no such policy is deployed the check passes — see Authz Activities.


http.request​

Sends an HTTP request and returns the status, headers and body. The body is returned as text by default, or parsed JSON with output_json: true.

A non-2xx response is not an error by default: the activity returns normally with is_success: false. Set raise_for_status: true to fail the activity instead.

Input

FieldTypeRequiredDefaultDescription
methodstryes—HTTP method: GET, POST, PUT, DELETE, PATCH, …
urlstryes—Target URL
contentstrnonullRaw string body. Use for plain text or a pre-serialized payload
datadictnonullForm body, sent as application/x-www-form-urlencoded
json_dataanynonullJSON body. Sets Content-Type: application/json
headersdict[str, str]nonullExtra request headers
encrypted_auth_tokenEncryptedDatanonullEncrypted bearer token, decrypted inside the activity and sent as Authorization: Bearer <token>
follow_redirectsboolnoclient defaultFollow 3xx redirects
proxystrnoMOCO_HTTP_PROXYProxy URL, e.g. http://proxy.example.com:8080
output_jsonboolnofalseParse the response body as JSON into json instead of returning text
skip_cert_verifyboolnofalseSkip TLS certificate verification
raise_for_statusboolnofalseFail the activity on a 4xx/5xx response

Only one of content, data and json_data should be set.

EncryptedData​

The output of builtin.secret.get. Pass it through unchanged.

FieldTypeRequiredDescription
encrypted_datastryesThe encrypted secret
encrypt_key_namestryesName of the key it was encrypted with

Output

FieldTypeDescription
status_codeintHTTP status code
is_successboolTrue for a 2xx response
headersdict[str, str]Response headers
textstrResponse body, when output_json is false or unset
jsonanyParsed response body, when output_json is true

text and json are mutually exclusive — exactly one of them is present.

Examples

A GET with an explicit retry policy, reading the parsed body:

- task_name: fetch-with-retry
activity:
type: http.request
input:
method: GET
url: https://httpbin.org/get?demo=retry
output_json: true
options:
retry_policy:
timeout_sec: 10
max_attempts: 3
initial_interval_sec: 1
backoff_coefficient: 2.0
non_retryable_error_types:
- ValueError
output:
set:
- fetched_args: '{{ _["json"].get("args") }}'

A POST with a JSON body, keeping the whole response:

- task_name: create-order
activity:
type: http.request
input:
method: POST
url: https://api.example.com/orders
headers:
Accept: application/json
json_data:
order_id: '{{ order_id }}'
items: '{{ items }}'
output_json: true
raise_for_status: true
options:
retry_policy:
max_attempts: 1 # POST is not idempotent
output:
as: created # -> status_code, is_success, headers, json

A non-2xx response is data unless raise_for_status is set, so branch on is_success. With raise_for_status: true, handle the failure with on_error instead:

- task_name: lookup-customer
activity:
type: http.request
input:
method: GET
url: 'https://api.example.com/customers/{{ customer_id }}'
output_json: true
raise_for_status: true
output:
data: '{{ _["json"] }}'
as: customer
on_error:
catch: true # the error is consumed; `do`'s result becomes the task's result
do:
set:
- customer: null
- lookup_error: '{{ _["error_message"] }}'

More request shapes (form body, bearer token, 404 as data) are in moco-examples/activities/http-request.yaml.

Authentication​

http.request does not take a *_secret_key field. Fetch the token with builtin.secret.get, which returns it still encrypted, and hand the blob straight to encrypted_auth_token — the activity decrypts it internally, so the plaintext token never enters workflow context.

- task_name: get-token
activity:
type: builtin.secret.get
input:
secret_name: PARTNER_API_TOKEN
output:
as: api_token

- task_name: list-accounts
activity:
type: http.request
input:
method: GET
url: https://api.partner.example.com/v1/accounts
encrypted_auth_token: '{{ api_token }}'
output_json: true
output:
as: accounts

For any other scheme — an API key header, basic auth — build the header yourself, but note that doing so puts the credential into workflow context and history.

The default retry policy retries writes

http.request inherits the platform default of 3 attempts. A POST that is not idempotent will be sent up to three times on transient failures; set options.retry_policy.max_attempts: 1 for those.

Request timeout

When options.retry_policy.timeout_sec is not set, the underlying HTTP client uses a 45-second timeout — shorter than the 60-second activity default. Set timeout_sec explicitly for slow endpoints.