Skip to content

HTTP / REST

Call any HTTP API — REST, webhooks, or raw requests.

The auth block supports four modes. Pick the one your API requires.

# No auth (public APIs)
# Omit the auth block entirely.
# API key in a header
auth:
type: api_key
header: X-API-Key
key: "{{ secrets.SERVICE_KEY }}"
# Bearer token
auth:
type: bearer
token: "{{ secrets.ACCESS_TOKEN }}"
# Basic auth
auth:
type: basic
username: "{{ secrets.API_USER }}"
password: "{{ secrets.API_PASS }}"
FieldRequiredDefaultDescription
urlYesRequest URL. Supports {{ }} templates.
methodNoGETHTTP method: GET, POST, PUT, PATCH, DELETE.
headersNo{}Request headers. Supports templates.
bodyNoRequest body for POST/PUT/PATCH. Supports templates.
authNoAuthentication config (see above).
retryNo{ attempts: 3, backoff: exponential }Retry policy for failed requests.
timeoutNo30000Request timeout in milliseconds.
extractNoDot-path mappings from response body to output fields.
flow.yaml
fetch-users:
type: service
op: api.call
params:
url: https://api.example.com/users
method: GET
headers:
Accept: application/json
auth:
type: bearer
token: "{{ secrets.API_TOKEN }}"
outputs:
response: { type: Table }
create-ticket:
type: service
op: api.call
params:
url: https://api.example.com/tickets
method: POST
headers:
Content-Type: application/json
body:
title: "{{ title }}"
description: "{{ description }}"
priority: "{{ priority }}"
auth:
type: bearer
token: "{{ secrets.API_TOKEN }}"
inputs:
request: { type: Record, from: ref(prepare.ticket) }
outputs:
result: { type: Record }

When the input is a Table, api.call makes one request per row. Use this pattern to follow pagination cursors.

enrich-contacts:
type: service
op: api.call
params:
url: "https://api.clearbit.com/v1/people/find?email={{ email }}"
method: GET
auth:
type: api_key
header: Authorization
key: "Bearer {{ secrets.CLEARBIT_KEY }}"
inputs:
contacts: { type: Table, from: ref(read-csv.rows) }
outputs:
enriched: { type: Table }
notify-slack:
type: service
op: api.call
params:
url: "{{ secrets.SLACK_WEBHOOK_URL }}"
method: POST
body:
text: "Pipeline complete: {{ summary }}"
inputs:
report: { type: Record, from: ref(summarize.result) }
outputs:
response: { type: Record }

Each response produces three fields: status_code (number), body (parsed JSON), and headers (object).

Use extract to pull nested fields from the response body into flat output columns.

params:
extract:
name: body.user.name
plan: body.account.plan
email: body.user.email

Status codes in the 2xx range are treated as success. A 4xx or 5xx response triggers the retry policy. If all retries fail, the node errors.

Configure retry behavior with the retry block.

params:
retry:
attempts: 5
backoff: exponential # exponential or fixed
initial_delay: 1000 # ms before first retry
max_delay: 30000 # ms cap for exponential backoff
timeout: 60000 # per-request timeout in ms

When Radhflow receives a 429 Too Many Requests response, it reads the Retry-After header and waits before retrying. If no header is present, it falls back to the configured backoff strategy.

SSL errors. If you see UNABLE_TO_VERIFY_LEAF_SIGNATURE, the API uses a self-signed or corporate CA certificate. Mount the CA bundle into the runtime environment.

Timeout. Increase the timeout value. For slow APIs, set it to 120000 (2 minutes) or higher.

Auth failures (401/403). Double-check your secret names. Run rf validate to confirm all {{ secrets.* }} references resolve. Make sure the token has the required scopes.

Redirect loops. By default, Radhflow follows up to 5 redirects. If you hit a loop, check the API documentation for the correct endpoint URL.