Argo Workflows can make HTTP requests to external services, which is incredibly useful for integrating with APIs, triggering other systems, or even just checking the health of a service.

Let’s see this in action. Imagine you have a workflow that needs to get some data from an API and then use that data in a subsequent step.

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: http-example-
spec:
  entrypoint: main
  templates:
  - name: main
    dag:
      tasks:
      - name: get-data
        template: http-get
      - name: process-data
        template: http-post
        dependencies: [get-data]
  - name: http-get
    http:
      url: http://example.com/api/data
      method: GET
      successCondition: status_code == 200
      headers:
      - name: Accept
        value: application/json
      - name: Authorization
        value: Bearer my-secret-token
      - name: X-Argo-Workflow

        value: "{{workflow.name}}"

      # The response body is captured and can be used by downstream steps
      # For example, in a script template:
      # - name: process-data
      #   script:
      #     command: [python]
      #     source: |
      #       import json

      #       data = json.loads("{{tasks.get-data.outputs.result}}")

      #       print(f"Received data: {data}")
  - name: http-post
    http:
      url: http://example.com/api/process
      method: POST
      successCondition: status_code == 201
      contentType: application/json
      body: |
        {
          "message": "Processing data from Argo",

          "workflow_id": "{{workflow.uid}}",


          "input_data": "{{tasks.get-data.outputs.result}}"

        }

This workflow defines two tasks: get-data which makes a GET request, and process-data which makes a POST request. The get-data task uses the http template type, specifying the url, method, and a successCondition to determine if the request was successful. It also shows how to include headers.

The process-data task, which depends on get-data completing, uses the http template type again but with a POST method. It demonstrates setting contentType and sending a body. Crucially, the body references the output of the get-data task using {{tasks.get-data.outputs.result}}. This result field automatically captures the response body from the HTTP request.

Internally, Argo Workflows uses a dedicated controller that manages these HTTP requests. When a step with an http template is executed, Argo sends the request to the specified URL. It then evaluates the successCondition against the response. If the condition is met, the step is considered successful, and its output (the response body) is made available to subsequent steps. If the condition is not met, or if there’s a network error, the step fails.

You can also use environment variables or secrets for sensitive information like tokens. For instance, to pass a token from a Kubernetes Secret named my-api-secret with a key token, you’d modify the http-get template:

  - name: http-get
    http:
      url: http://example.com/api/data
      method: GET
      successCondition: status_code == 200
      headers:
      - name: Authorization

        value: "{{=lookup 'secret' 'my-api-secret' 'token'}}"

Here, {{=lookup 'secret' 'my-api-secret' 'token'}} dynamically fetches the token from the Kubernetes Secret.

The successCondition is powerful. It allows you to define what constitutes a successful HTTP response beyond just a 2xx status code. For example, you could check for specific values in the response body: successCondition: status_code == 200 && response.body.status == "completed". The response object within the condition has access to status_code, body, and headers.

The most surprising thing most users don’t realize is that the successCondition can also directly reference the response object’s fields, not just the status_code. This means you can have a step succeed or fail based on the content of the HTTP response, making your workflows much more dynamic and responsive to API feedback. For example, successCondition: status_code == 200 && response.body.data.items.length > 0 would only succeed if the status code is 200 AND the response body (parsed as JSON) contains an array named items with at least one element.

The next concept you’ll likely explore is how to handle more complex error scenarios, such as retrying failed HTTP requests or implementing custom error handling logic based on specific response codes.

Want structured learning?

Take the full Argo-workflows course →