Skip to main content

http

The http step type performs an HTTP request from a workflow or custom command — call an API, notify a service, trigger a CI job, hit a deployment webhook, or poll a health endpoint. It supports any HTTP verb, query-string parameters, headers, and a request body (raw or form/JSON), with per-attempt timeouts and HTTP-aware retries that compose with the step's retry policy. No shelling out to curl.

Alias

webhook is an accepted alias for httptype: webhook behaves identically and reads naturally for the fire-a-notification use case.

steps:
- name: notify
type: http
url: "https://ci.example.com/hook/{{ .env.JOB_ID }}"
method: POST
query:
ref: "{{ .env.GIT_SHA }}"
headers:
Authorization: "Bearer {{ .env.TOKEN }}"
Content-Type: application/json
body: '{"status":"deployed"}'
expect:
status: [200, 201, 202, 204]
response:
- /"status"\s*:\s*"deployed"/
timeout: 30s
retry:
max_attempts: 5
backoff_strategy: exponential
initial_delay: 1s
max_delay: 30s

Send form parameters instead of a raw body with form (mutually exclusive with body). By default form is sent as application/x-www-form-urlencoded; set a JSON Content-Type header to send it as a JSON object instead:

steps:
- name: notify-slack
type: http
url: "{{ .env.SLACK_WEBHOOK_URL }}"
method: POST
headers:
Content-Type: application/json
form:
text: "Deployment of {{ .steps.plan.value }} complete"

Fields

url
Required. Request URL. Supports Go templates.
method
HTTP method/verb: GET (default), POST, PUT, PATCH, DELETE, HEAD, OPTIONS.
query
Query-string parameters as key-value pairs (supports templates).
headers
Request headers as key-value pairs (supports templates).
body
Raw request body (supports templates). Mutually exclusive with form.
form
Form/JSON body parameters as key-value pairs. Sent as application/x-www-form-urlencoded unless the Content-Type header is application/json. Mutually exclusive with body.
expect.status
List of acceptable HTTP status codes. When set, the response status must be in this list. Defaults to any 2xx.
expect.response
List of regular expressions; the response body must match at least one. Patterns may be written as /.../ literals (surrounding slashes are stripped) or bare regex strings.
timeout
Per-attempt timeout (e.g., 30s, 1m). Defaults to 30s. Each retry attempt gets its own deadline.
retry
Retry policy (see retry). Transport errors, 5xx, and 429 responses are retried by default; other 4xx responses fail fast. Use retry.conditions (regexes matched against "<status> <body>") to retry additional cases.

Polling

Because http retries are HTTP-aware, the step doubles as a poller — GET an endpoint and retry until the body matches:

steps:
- name: health
type: http
url: "{{ .env.HEALTH_URL }}"
expect:
status: [200]
response:
- /"status"\s*:\s*"(ok|healthy)"/
retry:
max_attempts: 10
backoff_strategy: constant
initial_delay: 2s

Result

The response body becomes the step's value, and useful details land in metadata (see outputs):

{{ .steps.<name>.value }}
The response body.
{{ .steps.<name>.metadata.status_code }}
The numeric HTTP status code (e.g., 200).
{{ .steps.<name>.metadata.status }}
The HTTP status text (e.g., 200 OK).
{{ .steps.<name>.metadata.response_headers }}
Response headers as a map.