{ "openapi": "3.1.0", "info": { "title": "Hookvolley API (Bulk HTTP Request & Webhook Sender)", "version": "1.0.0", "summary": "💰 $0.80 per 1,000 requests answered; no-response requests free, no start fee.", "description": "💰 $0.80 per 1,000 requests answered; no-response requests free, no start fee. Bulk GET, POST, PUT, PATCH or DELETE to any API or webhook, from a URL list or one request per dataset row with {{field}} templates. Retries, rate limits, JSON parsing. Cheaper than memo23's HTTP request ($5/1K).\n\nRuns the Hookvolley Actor (`cybermax/bulk-http-requests`) on Apify with the caller's own Apify API token and returns its dataset. Pricing (pay per event, billed by Apify):\n- Request answered: $0.0008\n\nPublisher: CyberMax. Catalog: https://cybermax-tools-cybermax.static.hf.space/market/catalog.json", "contact": { "name": "CyberMax", "url": "https://apify.com/cybermax/bulk-http-requests" }, "x-logo": { "url": "https://cybermax-tools-cybermax.static.hf.space/favicon.ico" } }, "x-cybermax-referral": { "program": "CyberMax affiliate and referral program", "status": "open", "ratePct": 30, "appliesTo": "Digital products sold through CyberMax's own Stripe checkout (store downloads, app Pro plans, API plans, bundles, data briefs).", "basis": "net amount CyberMax receives for the order (after payment fees, refunds and chargebacks)", "recurring": "the first 12 months of a subscription; one-time orders once", "attributionWindowDays": 60, "passRef": { "queryParam": "ref", "stripeParam": "client_reference_id", "stripeValue": "aff_", "example": "https://buy.stripe.com/?client_reference_id=aff_" }, "payouts": "Paid manually by CyberMax once a month for eligible sales whose 14-day refund window has closed (owner approval 10 Oct 2026).", "terms": "https://cybermaxtools.com/affiliates/", "details": "https://cybermaxtools.com/.well-known/referral.json", "note": "Runs of this tool are billed by Apify on Apify's checkout, so they are not covered by the CyberMax referral program; it covers CyberMax Stripe checkout sales (store, API plans, bundles)." }, "externalDocs": { "description": "Apify Store page", "url": "https://apify.com/cybermax/bulk-http-requests" }, "servers": [ { "url": "https://api.apify.com", "description": "Apify API" } ], "security": [ { "apifyToken": [] } ], "tags": [ { "name": "Hookvolley", "description": "💰 $0.80 per 1,000 requests answered; no-response requests free, no start fee." } ], "paths": { "/v2/acts/cybermax~bulk-http-requests/run-sync-get-dataset-items": { "post": { "operationId": "runHookvolleySync", "tags": [ "Hookvolley" ], "summary": "Hookvolley: run and return results", "description": "💰 $0.80 per 1,000 requests answered; no-response requests free, no start fee. Waits for the run to finish (up to 300 s) and returns the output records.", "parameters": [ { "name": "timeout", "in": "query", "required": false, "description": "Run timeout in seconds (max 300 for synchronous runs).", "schema": { "type": "integer", "minimum": 1, "maximum": 300 } }, { "name": "clean", "in": "query", "required": false, "description": "Omit empty records and hidden fields.", "schema": { "type": "boolean", "default": true } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Input" }, "example": { "urls": [ "https://jsonplaceholder.typicode.com/posts/1", "https://jsonplaceholder.typicode.com/users/1" ], "headers": {} } } } }, "responses": { "201": { "description": "Run finished; body is the list of output records.", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/OutputRecord" } } } } }, "400": { "description": "Invalid input.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApifyError" } } } }, "401": { "description": "Missing or invalid Apify token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApifyError" } } } }, "402": { "description": "Apify account has no credit left for this run.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApifyError" } } } }, "408": { "description": "The run did not finish within the synchronous timeout; start it asynchronously instead.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApifyError" } } } }, "429": { "description": "Rate limited by Apify.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApifyError" } } } } } } }, "/v2/acts/cybermax~bulk-http-requests/runs": { "post": { "operationId": "startHookvolleyRun", "tags": [ "Hookvolley" ], "summary": "Hookvolley: start an asynchronous run", "description": "Starts a run and returns immediately. Poll GET https://api.apify.com/v2/actor-runs/{runId} and read items from GET https://api.apify.com/v2/datasets/{defaultDatasetId}/items.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Input" } } } }, "responses": { "201": { "description": "Run started.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RunStarted" } } } }, "400": { "description": "Invalid input.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApifyError" } } } }, "401": { "description": "Missing or invalid Apify token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApifyError" } } } }, "402": { "description": "Apify account has no credit left for this run.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApifyError" } } } }, "429": { "description": "Rate limited by Apify.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApifyError" } } } } } } } }, "components": { "securitySchemes": { "apifyToken": { "type": "http", "scheme": "bearer", "description": "Your Apify API token (https://console.apify.com/settings/integrations). Runs are billed to your Apify account." } }, "schemas": { "Input": { "type": "object", "properties": { "urls": { "type": "array", "title": "URLs", "description": "One request per URL, using the method, headers and body below.", "examples": [ [ "https://jsonplaceholder.typicode.com/posts/1", "https://jsonplaceholder.typicode.com/users/1" ] ], "items": { "type": "string" } }, "method": { "type": "string", "title": "Method", "description": "HTTP method for the URLs and dataset requests (individual requests can set their own).", "default": "GET", "enum": [ "GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS" ] }, "headers": { "type": "object", "title": "Headers", "description": "Sent with every request, e.g. {\"Authorization\": \"Bearer ...\", \"Accept\": \"application/json\"}. {{field}} placeholders work with a dataset.", "examples": [ {} ] }, "body": { "type": "string", "title": "Body", "description": "Request body for POST, PUT and PATCH (JSON or text). Set a Content-Type header for non-JSON bodies." }, "requests": { "type": "array", "title": "Individual requests (advanced)", "description": "Full control per request: [{\"url\": \"...\", \"method\": \"POST\", \"headers\": {...}, \"body\": {...}, \"label\": \"order-1\"}]. Object bodies are sent as JSON.", "items": {} }, "datasetId": { "type": "string", "title": "One request per row of this dataset", "description": "Optional. Each row (or batch of rows) becomes a request built from the templates below." }, "datasetIds": { "type": "array", "title": "Datasets (API alias)", "description": "API alias of \"datasetId\" (the field name Rowmold and Rowmeld use): one request per row of each dataset. Hidden in the form.", "items": {} }, "urlTemplate": { "type": "string", "title": "URL template", "description": "e.g. https://api.example.com/companies/{{domain|url}} or your webhook URL. {{field}}, {{nested.field}}, {{field|url}}, {{json}}." }, "bodyTemplate": { "type": "string", "title": "Body template", "description": "Optional, e.g. {\"name\": {{name|json}}, \"site\": {{url|json}}}. Empty with POST/PUT/PATCH = the row (or batch) as JSON." }, "batchSize": { "type": "integer", "title": "Rows per request", "description": "Above 1, rows are sent in batches: the body is a JSON array of rows (templates see {{items}} and {{count}}).", "default": 1, "minimum": 1, "maximum": 1000 }, "maxConcurrency": { "type": "integer", "title": "Parallel requests", "description": "How many requests run at the same time.", "default": 5, "minimum": 1, "maximum": 20 }, "maxRequestsPerSecondPerHost": { "type": "integer", "title": "Max requests per second per host", "description": "Keeps you within the API's rate limit.", "default": 5, "minimum": 1, "maximum": 50 }, "timeoutSecs": { "type": "integer", "title": "Timeout per request (seconds)", "description": "A request that takes longer is retried, then reported as failed.", "default": 30, "minimum": 1, "maximum": 300 }, "maxRetries": { "type": "integer", "title": "Retries", "description": "Retries network errors, timeouts, 408, 425, 429 and 5xx with exponential backoff, honouring Retry-After.", "default": 3, "minimum": 0, "maximum": 8 }, "followRedirects": { "type": "boolean", "title": "Follow redirects", "description": "Follow 3xx redirects (up to 5; each hop is checked for safety).", "default": true }, "responseFormat": { "type": "string", "title": "Response body", "description": "How the response body is saved in each row.", "default": "auto", "enum": [ "auto", "json", "text", "none" ], "x-enumTitles": [ "Auto (JSON when JSON, else text)", "JSON", "Text", "Don't save the body" ] }, "maxResponseKb": { "type": "integer", "title": "Max body size saved (KB)", "description": "Longer bodies are cut and marked truncated.", "default": 512, "minimum": 1, "maximum": 9000 }, "extractFields": { "type": "array", "title": "Extract fields from JSON responses", "description": "Optional dotted paths, e.g. data.price or items.0.id, returned in an extracted object.", "items": { "type": "string" } }, "includeResponseHeaders": { "type": "boolean", "title": "Save response headers", "description": "Adds the response headers to each row.", "default": false }, "includeInputRow": { "type": "boolean", "title": "Save the dataset row with each result", "description": "Adds the dataset row a request was built from.", "default": false }, "monitor": { "type": "boolean", "title": "Monitor mode: changed responses only", "description": "Returns a request only when its status or body changed since the last monitor run. Unchanged responses are not charged.", "default": false }, "monitorKey": { "type": [ "string", "null" ], "title": "Watchlist name", "description": "Optional name for this watchlist's saved state." } }, "title": "Hookvolley input", "additionalProperties": false }, "OutputRecord": { "type": "object", "properties": { "label": { "description": "Label" }, "method": { "description": "Method" }, "url": { "description": "URL" }, "status": { "description": "Status" }, "ok": { "description": "OK" }, "durationMs": { "description": "ms" }, "attempts": { "description": "Attempts" }, "extracted": { "description": "Extracted" }, "change": { "description": "Change" }, "error": { "description": "Error" } }, "x-inferredFrom": "the Actor dataset view field list (types not declared)" }, "RunStarted": { "type": "object", "properties": { "data": { "type": "object", "properties": { "id": { "type": "string" }, "status": { "type": "string" }, "defaultDatasetId": { "type": "string" } } } } }, "ApifyError": { "type": "object", "properties": { "error": { "type": "object", "properties": { "type": { "type": "string" }, "message": { "type": "string" } } } } } } } }