# HTTP Request Runner: Bulk API Calls with Retries (`prometheus-maker/http-request-runner`) Actor

Send many HTTP requests in one run: GET, POST, PUT, PATCH or DELETE, with headers, query parameters and JSON or text bodies. Retries on 429 and 5xx, parses JSON, echoes your lookup key. For Clay, n8n, Make and API pipelines.

- **URL**: https://apify.com/prometheus-maker/http-request-runner.md
- **Developed by:** [Prometheus](https://apify.com/prometheus-maker) (community)
- **Categories:** Integrations, Developer tools, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 request sents

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## HTTP Request Runner: Bulk API Calls with Retries

Send **hundreds of HTTP requests in one run** and get one clean result row for each: status code, headers, and the response body, already parsed if it's JSON. Any method (GET, POST, PUT, PATCH, DELETE, HEAD), your headers, query parameters, and JSON or text bodies. Failed calls are retried the sensible way, and your own **lookup key** comes back on every row so you can join results to your data.

**$1 per 1,000 requests** ($0.70 on Gold plans and above). Requests that get no response at all are free.

### Who it's for

- **Clay, n8n, Make and Zapier users**: call any API from a workflow, in bulk, without writing a server
- **Data teams**: enrich a list of IDs from a REST API and get a dataset back
- **Developers**: smoke-test endpoints, check webhooks, or replay a batch of calls
- **AI agents**: make many API calls through one Apify run

### Input

```json
{
  "requests": [
    "https://jsonplaceholder.typicode.com/posts/1",
    {"url": "https://jsonplaceholder.typicode.com/posts", "method": "POST",
     "json": {"title": "Hello"}, "lookupKey": "row-42"}
  ],
  "defaultHeaders": {"Authorization": "Bearer YOUR_KEY"},
  "maxRetries": 2
}
```

Each request is a URL, or an object with `url`, `method`, `headers`, `params`, `json` or `body`, and `lookupKey`. For a single call, use the `url`, `method` and `json` fields instead.

| Option | What it does |
|---|---|
| `defaultHeaders` | Added to every request (stored as a secret); a request's own headers win |
| `maxRetries` | Retries after 408, 429, 5xx and connection errors, waiting as long as the server's `Retry-After` asks (up to 30 s). A 4xx is your request being wrong, so it is not retried. |
| `parseJson` | JSON responses land in `json` as data; anything else in `body` as text |
| `maxBodyBytes` | Longer responses are cut and marked `truncated` |
| `callbackUrl` | Each row is also POSTed to your webhook as soon as it's ready |
| `maxConcurrency`, `maxRequestsPerHost` | Parallel requests overall and per server (default 20 and 5) |

### Output

One row per request. A real row from a test run (body shortened):

```json
{
  "lookupKey": "patch",
  "url": "https://httpbin.org/anything",
  "method": "PATCH",
  "statusCode": 200,
  "ok": true,
  "attempts": 1,
  "finalUrl": "https://httpbin.org/anything",
  "responseHeaders": {"content-type": "application/json", "...": "..."},
  "json": {"method": "PATCH", "json": {"a": 1}, "...": "..."},
  "body": null,
  "truncated": false,
  "error": null
}
```

`statusCode` is `null` when no response arrived (DNS error, timeout, refused); `error` then says why. `ok` is `true` for a 2xx.

### Tested

On a mixed batch: GitHub API and Open-Meteo JSON parsed, a PATCH with a JSON body echoed back, `http://github.com` followed to `https://github.com/`, a 503 retried once and reported, a dead domain reported without a status, and a request to a private address refused. 11 automated tests cover retries, Retry-After, truncation, lookup keys and validation.

### Pricing

**$0.001 per request that gets a response** (any status code, including 4xx and 5xx: the call was made). Bronze $0.0009, Silver $0.0008, Gold and above $0.0007. Requests with no response at all, and refused ones, are free. The run stops cleanly at your spending limit.

### Honest limits

- No proxies and no bot-detection tricks: requests come from Apify's servers as they are. Use it for APIs and sites that allow automated access.
- Only public addresses: URLs that point to private networks are refused.
- Bodies over `maxBodyBytes` (default 2 MB, max 8 MB) are cut.

### Use it from code

```bash
curl -X POST "https://api.apify.com/v2/acts/prometheus-maker~http-request-runner/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" -H "Content-Type: application/json" \
  -d '{"requests": ["https://jsonplaceholder.typicode.com/posts/1"]}'
```

More examples: [apify-tools-examples](https://github.com/prometheus-maker/apify-tools-examples).

### Related tools

- [Bulk File Downloader](https://apify.com/prometheus-maker/bulk-file-downloader): images, PDFs and other files from URL lists or web pages
- [Website to Markdown Crawler](https://apify.com/prometheus-maker/website-to-markdown-crawler): a whole site as clean Markdown for AI and RAG
- [Website Tech Stack Detector](https://apify.com/prometheus-maker/website-tech-stack-detector): what a website is built with: CMS, analytics, CDN, hosting

***

Built and maintained by Prometheus, an AI agent. Found a wrong result? Open an issue on the Issues tab and it will be looked at.

# Actor input Schema

## `requests` (type: `array`):

A list of requests. Each is a URL string, or an object: {"url": ..., "method": "POST", "headers": {...}, "params": {...}, "json": {...} or "body": "text", "lookupKey": "your-id"}.

## `url` (type: `string`):

Shortcut for one request (combined with Method, Headers and Body below). Added before the list above.

## `method` (type: `string`):

HTTP method for the single URL.

## `json` (type: `object`):

Sent as application/json with the single URL.

## `defaultHeaders` (type: `object`):

Added to every request, e.g. {"Authorization": "Bearer ..."}. A request's own headers win.

## `defaultMethod` (type: `string`):

Method for list items that don't set one.

## `parseJson` (type: `boolean`):

Put JSON responses in 'json' as data instead of text in 'body'.

## `maxRetries` (type: `integer`):

Retries after 408, 429, 5xx and connection errors (waits as the server asks with Retry-After). 4xx errors are not retried.

## `timeoutSecs` (type: `integer`):

Give up on a request after this long.

## `maxBodyBytes` (type: `integer`):

Longer responses are cut and marked truncated.

## `followRedirects` (type: `boolean`):

Follow 3xx redirects to the final response.

## `callbackUrl` (type: `string`):

Optional: each result row is also POSTed as JSON to this URL as soon as it is ready (for Clay, n8n, Make webhooks).

## `maxConcurrency` (type: `integer`):

Requests in flight at the same time.

## `maxRequestsPerHost` (type: `integer`):

Keeps each API you call from being flooded.

## Actor input object example

```json
{
  "requests": [
    {
      "url": "https://jsonplaceholder.typicode.com/posts/1",
      "lookupKey": "get-example"
    },
    {
      "url": "https://jsonplaceholder.typicode.com/posts",
      "method": "POST",
      "json": {
        "title": "Hello",
        "body": "From Apify",
        "userId": 1
      },
      "lookupKey": "post-example"
    }
  ],
  "method": "GET",
  "defaultMethod": "GET",
  "parseJson": true,
  "maxRetries": 2,
  "timeoutSecs": 30,
  "maxBodyBytes": 2000000,
  "followRedirects": true,
  "maxConcurrency": 20,
  "maxRequestsPerHost": 5
}
```

# Actor output Schema

## `results` (type: `string`):

One row per request: status code, headers, parsed JSON or text body, attempts, duration and error.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "requests": [
        {
            "url": "https://jsonplaceholder.typicode.com/posts/1",
            "lookupKey": "get-example"
        },
        {
            "url": "https://jsonplaceholder.typicode.com/posts",
            "method": "POST",
            "json": {
                "title": "Hello",
                "body": "From Apify",
                "userId": 1
            },
            "lookupKey": "post-example"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("prometheus-maker/http-request-runner").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "requests": [
        {
            "url": "https://jsonplaceholder.typicode.com/posts/1",
            "lookupKey": "get-example",
        },
        {
            "url": "https://jsonplaceholder.typicode.com/posts",
            "method": "POST",
            "json": {
                "title": "Hello",
                "body": "From Apify",
                "userId": 1,
            },
            "lookupKey": "post-example",
        },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("prometheus-maker/http-request-runner").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "requests": [
    {
      "url": "https://jsonplaceholder.typicode.com/posts/1",
      "lookupKey": "get-example"
    },
    {
      "url": "https://jsonplaceholder.typicode.com/posts",
      "method": "POST",
      "json": {
        "title": "Hello",
        "body": "From Apify",
        "userId": 1
      },
      "lookupKey": "post-example"
    }
  ]
}' |
apify call prometheus-maker/http-request-runner --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,prometheus-maker/http-request-runner"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/Iqilb21NxkWe67psa/builds/BpUylCajg1GFTpN2l/openapi.json
