> ## Documentation Index
> Fetch the complete documentation index at: https://helpcenter.magure.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# API node

> Call any external HTTP API as a workflow step, with built-in auth, templating, and SSRF protection

## Purpose

The **API node** calls an external HTTP endpoint directly from your workflow, like a Postman request as a node. Use it to integrate any REST API that doesn't have a dedicated tool: post to a CRM, fetch a record, trigger a downstream system, or send data to a partner service.

Where the [Tool node](/workflows/tool-node) runs a governed MCP tool and the [Agent node](/workflows/agent-node) lets an LLM decide, the API node is fully deterministic: you define the request, and it runs exactly as configured every time. Every field supports template variables, so requests are built from data produced earlier in the workflow.

## How it works

<Steps>
  <Step title="Workflow reaches the API node">
    Execution arrives at the node with the outputs of previous steps available as template variables.
  </Step>

  <Step title="Request is assembled">
    The URL, headers, query parameters, and body are resolved from templates. Secret references (`{{vault:...}}`) are pulled from HashiCorp Vault at this moment, never stored in the workflow.
  </Step>

  <Step title="Safety checks run">
    The target is validated against SSRF protection before the request is sent, so a templated URL can't be pointed at internal infrastructure.
  </Step>

  <Step title="Request is sent">
    The HTTP call is made with your configured method, auth, and timeout.
  </Step>

  <Step title="Response is captured">
    The status code, headers, and body are captured (JSON is parsed automatically) and made available to later nodes.
  </Step>
</Steps>

<Note>
  SSRF protection is always on. Requests to private, loopback, and link-local addresses are blocked so a workflow can only reach genuinely external services.
</Note>

## Configuration

### Method and URL

Choose the HTTP method and target URL. The URL supports templates, so you can build it from earlier outputs.

**Supported methods:** `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD`, `OPTIONS`

```json theme={null}
{
  "method": "POST",
  "url": "https://api.example.com/users/{{input.user_id}}"
}
```

### Headers and query parameters

Add any request headers and URL query parameters. Values support templates.

```json theme={null}
{
  "headers": {
    "X-Trace-Id": "{{system.execution_id}}",
    "Accept": "application/json"
  },
  "query_params": {
    "include": "profile",
    "verbose": "1"
  }
}
```

### Request body

Set `body_type` to control how the body is encoded, then provide the `body`.

| `body_type` | Body value      | Content-Type                        |
| ----------- | --------------- | ----------------------------------- |
| `json`      | object or array | `application/json`                  |
| `text`      | string          | `text/plain`                        |
| `form`      | object          | `application/x-www-form-urlencoded` |
| `multipart` | object          | `multipart/form-data`               |
| `none`      | omitted         | no body                             |

```json theme={null}
{
  "body_type": "json",
  "body": {
    "name": "{{extract_agent.name}}",
    "email": "{{extract_agent.email}}"
  }
}
```

### Authentication

The API node supports six auth modes. Every secret-bearing field accepts an inline value or a Vault reference like `{{vault:org/api/example}}`, resolved at execution time.

<Tabs>
  <Tab title="None">
    No authentication.

    ```json theme={null}
    { "auth": { "type": "none" } }
    ```
  </Tab>

  <Tab title="Bearer">
    Sends an `Authorization: Bearer <token>` header.

    ```json theme={null}
    {
      "auth": {
        "type": "bearer",
        "token": "{{vault:org/api/example}}"
      }
    }
    ```
  </Tab>

  <Tab title="Basic">
    HTTP Basic authentication.

    ```json theme={null}
    {
      "auth": {
        "type": "basic",
        "username": "service_account",
        "password": "{{vault:org/api/example-password}}"
      }
    }
    ```
  </Tab>

  <Tab title="API key">
    Sends a key in a header or query parameter.

    ```json theme={null}
    {
      "auth": {
        "type": "api_key",
        "key_name": "X-Api-Key",
        "key_value": "{{vault:org/api/example-key}}",
        "placement": "header"
      }
    }
    ```

    Set `placement` to `query` to send the key as a URL parameter instead.
  </Tab>

  <Tab title="Custom headers">
    Send one or more arbitrary auth headers.

    ```json theme={null}
    {
      "auth": {
        "type": "custom_headers",
        "headers": {
          "X-Client-Id": "magone",
          "X-Client-Secret": "{{vault:org/api/example-secret}}"
        }
      }
    }
    ```
  </Tab>

  <Tab title="HMAC">
    Sign the request with an HMAC signature, for APIs that verify request integrity.

    ```json theme={null}
    {
      "auth": {
        "type": "hmac",
        "algorithm": "sha256",
        "secret": "{{vault:org/api/webhook-secret}}",
        "signed_payload": "method+path+body",
        "header_name": "X-Signature",
        "encoding": "hex",
        "include_timestamp": true,
        "timestamp_header": "X-Timestamp"
      }
    }
    ```

    Choose the `algorithm` (`sha256`, `sha512`, `sha1`), what to sign (`body`, `method+path+body`, or `canonical`), and the `encoding` (`hex` or `base64`).
  </Tab>
</Tabs>

### Response handling

Control timeouts, redirects, and how failures are treated.

* **`timeout_seconds`** — Per-request timeout. Default 30, maximum 60.
* **`follow_redirects`** — Whether to follow `3xx` redirects. Default true.
* **`fail_on_error_status`** — When true, a `4xx`/`5xx` response fails the node so [error handling](/workflows/triggers-and-execution) can retry or branch. When false (default), the response is captured and passed on for your workflow to inspect.
* **`max_response_bytes`** — Caps how much of the response body is captured. Default 1 MB, maximum 16 MB.

```json theme={null}
{
  "timeout_seconds": 30,
  "follow_redirects": true,
  "fail_on_error_status": true,
  "max_response_bytes": 1048576
}
```

## Use cases

### Post to a system without a dedicated tool

**Scenario:** Push an extracted record into an internal CRM.

```
Workflow:
  1. Extract customer data (Agent)
  2. API node: POST to CRM
  3. Condition: response.status == "created"
     ├─ True: Send confirmation (Tool)
     └─ False: Human Task: "CRM write failed, review"
```

```json theme={null}
{
  "method": "POST",
  "url": "https://crm.internal.example.com/api/v2/contacts",
  "body_type": "json",
  "body": {
    "name": "{{extract_agent.name}}",
    "email": "{{extract_agent.email}}",
    "source": "magoneai"
  },
  "auth": { "type": "bearer", "token": "{{vault:project/crm/token}}" },
  "fail_on_error_status": true
}
```

### Fetch reference data for an agent

**Scenario:** Look up live pricing before an agent drafts a quote.

```
Workflow:
  1. API node: GET current pricing
  2. Draft quote using pricing (Agent)
  3. Human Task: "Approve quote"
```

### Trigger a downstream webhook

**Scenario:** Notify a partner system when a workflow completes, signing the payload with HMAC.

```json theme={null}
{
  "method": "POST",
  "url": "https://partner.example.com/hooks/magone",
  "body_type": "json",
  "body": { "event": "processed", "reference": "{{input.reference}}" },
  "auth": {
    "type": "hmac",
    "secret": "{{vault:project/partner/hmac}}",
    "signed_payload": "body",
    "include_timestamp": true
  }
}
```

## Best practices

<AccordionGroup>
  <Accordion title="Store secrets in Vault, not in the node">
    Use `{{vault:...}}` references for tokens, passwords, and secrets. They are resolved at execution time and never saved into the workflow definition or version history.
  </Accordion>

  <Accordion title="Fail loudly on critical writes">
    For requests that change state (POST/PUT/DELETE), set `fail_on_error_status: true` so a rejected request triggers retry or a fallback branch instead of silently continuing.
  </Accordion>

  <Accordion title="Keep timeouts realistic">
    Set `timeout_seconds` to match the endpoint's expected latency. A slow third-party API shouldn't stall the whole workflow indefinitely, but don't set it so low that normal responses are cut off.
  </Accordion>

  <Accordion title="Cap large responses">
    If an endpoint can return a large payload you don't need in full, lower `max_response_bytes` to keep only what downstream nodes will use.
  </Accordion>

  <Accordion title="Validate before you branch">
    When `fail_on_error_status` is false, use a [Condition node](/workflows/condition-node) to check the response status or body before acting on it.
  </Accordion>
</AccordionGroup>

<Tip>
  Reach for the API node when no built-in tool covers the integration. If you find yourself calling the same API across many workflows, consider wrapping it as a [custom MCP tool](/tools/custom-tools) so it becomes a reusable, governed tool with managed credentials.
</Tip>

## Next steps

<CardGroup cols={2}>
  <Card title="Tool node" icon="wrench" href="/workflows/tool-node">
    Run governed MCP tools instead of raw HTTP calls
  </Card>

  <Card title="Custom tools" icon="puzzle-piece" href="/tools/custom-tools">
    Turn a frequent API into a reusable MCP tool
  </Card>

  <Card title="Secrets and Vault" icon="key" href="/security/secrets-management">
    Store API credentials securely with Vault references
  </Card>

  <Card title="Condition node" icon="code-branch" href="/workflows/condition-node">
    Branch on the API response status or body
  </Card>
</CardGroup>
