HTTP Plugins
The HTTP plugins provide native HTTP networking from within the V8 execution context. They allow workflows to make API calls, fetch data, and open long-lived streaming connections — all without leaving the workflow engine.
Both plugins use the same shared infrastructure for URL construction, header management, redirect following, and authentication.
httpRequest
Make a single HTTP request and return the response. Supports GET, POST, PUT, DELETE, PATCH, and OPTIONS methods. The response is also forwarded to the next entity in the workflow via Kinesis entity-resume so downstream nodes can process the result.
Signature
const result = await httpRequest(options);
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
options.url | string | Yes | — | Full URL (when using the blueprint wizard) |
options.domain | string | Yes* | — | Base URL, e.g. "https://api.example.com" |
options.path | string | Yes* | — | URL path appended to domain |
options.method | string | No | "GET" | HTTP verb: GET, POST, PUT, DELETE, PATCH, OPTIONS |
options.followRedirects | boolean | No | true | Automatically follow HTTP 3xx redirects |
options.apiKey | string | No | — | API key value (typically from an environment variable) |
options.apiKeyHeader | string | No | "x-api-key" | Header name for the API key |
options.headers | object | No | — | Custom headers as key-value pairs |
options.body | any | No | — | Request body: objects are auto-serialized to JSON with Content-Type: application/json |
*Either url (via blueprint) or domain + path (via script) is required.
Return Value
{
status: number; // HTTP status code (e.g. 200, 404)
data: unknown; // Parsed response body (JSON object or plain text)
headers: object; // Response headers as key-value pairs
elapsedMs: number; // Round-trip time in milliseconds
}
Entity-Resume Dispatch
After the HTTP call completes, httpRequest automatically dispatches the response to the next entity in the workflow via Kinesis. The dispatched message includes a responseData field containing the full response object. When the next entity runs, responseData is available as a V8 global.
On resume (when the downstream entity runs), the plugin detects responseData on the global scope and returns it directly — skipping the actual HTTP call. This prevents duplicate requests when the same plugin node is re-entered.
Example: Simple GET Request
Fetch data from a public API and log the result.
const res = await httpRequest({
url: "https://jsonplaceholder.typicode.com/posts/1",
method: "GET",
});
print("Status:", res.status);
print("Title:", res.data.title);
print("Body:", res.data.body);
Example: GET with API Key Authentication
Call a protected endpoint using an environment variable for the API key.
const res = await httpRequest({
url: "https://api.sportradar.com/nfl/official/production/v7/en/league/teams.json",
method: "GET",
apiKey: SPORTRADAR_API_KEY,
apiKeyHeader: "x-api-key",
});
print("Status:", res.status);
print("Teams:", res.data.teams.length);
for (const team of res.data.teams) {
print(` ${team.market} ${team.name} (${team.alias})`);
}
Example: POST JSON Payload
Send a JSON body to a webhook or REST API.
const res = await httpRequest({
url: "https://hooks.slack.com/services/T00/B00/XXX",
method: "POST",
body: {
text: "New order received: #" + payload.orderId,
channel: "#orders",
},
});
print("Slack response status:", res.status);
Example: POST with Custom Headers
Use Bearer token auth and custom content type.
const res = await httpRequest({
url: "https://api.example.com/v1/documents",
method: "POST",
headers: {
"Authorization": "Bearer " + MY_ACCESS_TOKEN,
"X-Request-ID": correlationId,
},
body: {
title: payload.title,
content: payload.body,
tags: ["automated", "workflow"],
},
});
print("Created document:", res.data.id);
print("Response time:", res.elapsedMs + "ms");
Example: PUT Update with Error Handling
Update a resource with robust error handling.
try {
const res = await httpRequest({
url: "https://api.example.com/v1/users/" + payload.userId,
method: "PUT",
apiKey: API_KEY,
body: {
name: payload.newName,
email: payload.newEmail,
},
});
if (res.status === 200) {
print("User updated successfully:", res.data.id);
} else {
print("Unexpected status:", res.status, res.data);
}
} catch (err) {
print("HTTP request failed:", err.message);
}
Example: DELETE Request
Remove a resource by ID.
const res = await httpRequest({
url: "https://api.example.com/v1/cache/" + payload.cacheKey,
method: "DELETE",
apiKey: API_KEY,
});
print("Cache cleared, status:", res.status);
Example: Chain HTTP Calls in a Script
Use the result of one request as input for another.
// Step 1: Look up the user
const userRes = await httpRequest({
url: "https://api.example.com/v1/users/" + payload.userId,
apiKey: API_KEY,
});
print("Found user:", userRes.data.name);
// Step 2: Fetch their recent orders
const ordersRes = await httpRequest({
url: "https://api.example.com/v1/orders?userId=" + payload.userId + "&limit=5",
apiKey: API_KEY,
});
print("Recent orders:", ordersRes.data.length);
// Step 3: Post a summary to a webhook
await httpRequest({
url: WEBHOOK_URL,
method: "POST",
body: {
user: userRes.data.name,
orderCount: ordersRes.data.length,
lastOrder: ordersRes.data[0],
},
});
print("Summary posted to webhook");
Example: Using responseData in Downstream Entity
When httpRequest dispatches to the next entity, the response is available via responseData:
// This runs in the NEXT entity after an httpRequest node
print("HTTP status was:", responseData.status);
print("Response data:", JSON.stringify(responseData.data));
// Use the response data in a prompt (requires `modelConfiguration` from a configured Prompt / model on this path)
const { result: summary } = await promptCallUniversal(
modelConfiguration,
"Summarize this API response: " + JSON.stringify(responseData.data)
);
print("Summary:", summary);
httpStreamConnect
Open a long-lived HTTP streaming connection (chunked transfer encoding). Each non-empty line received from the stream is parsed and dispatched via Kinesis to the next entity in the workflow. This is ideal for server-sent events, real-time data feeds, and streaming APIs.
Signature
const result = await httpStreamConnect(options);
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
options.url | string | Yes | — | Full URL (when using the blueprint wizard) |
options.domain | string | Yes* | — | Base URL, e.g. "https://api.sportradar.com" |
options.path | string | Yes* | — | URL path appended to domain |
options.followRedirects | boolean | No | true | Automatically follow HTTP 3xx redirects |
options.apiKey | string | No | — | API key value (typically from an environment variable) |
options.apiKeyHeader | string | No | "x-api-key" | Header name for the API key |
options.headers | object | No | — | Custom headers as key-value pairs |
options.maxDuration | string | number | Yes | — | Max stream duration: number (ms) or human string "30s", "5m", "2h" |
options.workflowId | string | No | — | Target sub-workflow ID. Omit to forward to the next entity (entity-resume) |
*Either url (via blueprint) or domain + path (via script) is required.
Return Value
{
success: boolean; // true unless the stream ended with an error
linesProcessed: number; // total non-empty lines received and dispatched
elapsedMs: number; // how long the stream was open in milliseconds
reason: string; // "max_duration", "stream_closed", or "error"
error?: string; // error message (only when reason === "error")
}
Dispatch Modes
| Mode | When | Behavior |
|---|---|---|
| Entity-resume (default) | workflowId omitted | Each line dispatches to the first child entity of the stream node. The child entity receives streamData as a V8 global containing the parsed line. |
| Sub-workflow | workflowId set | Each line dispatches to an entirely different workflow. The sub-workflow receives the full V8 state plus streamData. |
Entity-resume requires at least one child entity connected to the stream node. If no children are connected, the plugin throws an error.
Duration Limits
The maxDuration parameter accepts human-readable strings:
| Format | Example | Milliseconds |
|---|---|---|
| Seconds | "30s" | 30,000 |
| Minutes | "5m" | 300,000 |
| Hours | "2h" | 7,200,000 |
| Raw ms | 3600000 | 3,600,000 |
A hard cap of 12 hours is enforced by the HTTP_STREAM_MAX_DURATION_MS environment variable (default: 43200000).
Example: Stream a Sports Data Feed
Connect to a live sports data stream and process each event.
const result = await httpStreamConnect({
url: "https://api.sportradar.com/nfl/official/stream/events/subscribe",
apiKey: SPORTRADAR_API_KEY,
apiKeyHeader: "x-api-key",
maxDuration: "2h",
});
print("Stream ended:", result.reason);
print("Total events processed:", result.linesProcessed);
print("Duration:", result.elapsedMs + "ms");
Each line from the stream is dispatched to the next entity in the workflow where it is available as streamData:
// Runs in the child entity after the stream node
print("Received stream event:", JSON.stringify(streamData));
if (streamData.event_type === "score_change") {
print("Score update:", streamData.home_score, "-", streamData.away_score);
await pubsubPublish("scores:" + streamData.game_id, JSON.stringify(streamData));
}
Example: Stream with Short Duration for Testing
Use a short duration for development and testing.
const result = await httpStreamConnect({
url: "https://stream.example.com/v1/events",
apiKey: TEST_API_KEY,
maxDuration: "30s",
});
print("Test stream result:", result.reason, "lines:", result.linesProcessed);
Example: Stream to a Sub-Workflow
Route each stream line to a different workflow for complex processing.
const targetWorkflow = await getWorkflowByName("Process Stream Event");
const result = await httpStreamConnect({
url: "https://firehose.example.com/v1/feed",
apiKey: FEED_API_KEY,
maxDuration: "1h",
workflowId: targetWorkflow.id,
});
print("Stream completed:", result.linesProcessed, "events routed to sub-workflow");
Example: Process streamData in Downstream Entity
When using entity-resume mode (the default), the downstream entity receives each line:
// This entity is a child of the httpStreamConnect node
// streamData contains the parsed JSON line from the stream
print("Stream line received:", JSON.stringify(streamData));
// Example: filter and store interesting events
if (streamData.type === "trade" && streamData.amount > 10000) {
await stmStore(
["trades", "large"],
streamData,
streamData.id + ".json"
);
print("Stored large trade:", streamData.id);
}
Example: Stream with Custom Headers
Connect to an authenticated streaming endpoint with custom headers.
const result = await httpStreamConnect({
url: "https://stream.example.com/v2/firehose",
headers: {
"Authorization": "Bearer " + ACCESS_TOKEN,
"Accept": "application/x-ndjson",
"X-Client-ID": "rocketwave-" + organizationId,
},
maxDuration: "4h",
});
print("Firehose ended:", result.reason);
print("Lines:", result.linesProcessed, "in", result.elapsedMs + "ms");
Example: Error Handling with Streams
Handle connection errors and unexpected closures.
try {
const result = await httpStreamConnect({
url: STREAM_URL,
apiKey: API_KEY,
maxDuration: "1h",
});
if (result.reason === "error") {
print("Stream error:", result.error);
} else if (result.reason === "max_duration") {
print("Stream hit duration limit after", result.linesProcessed, "lines");
} else {
print("Stream closed normally after", result.linesProcessed, "lines");
}
} catch (err) {
print("Failed to connect to stream:", err.message);
}
Shared Configuration
Both httpRequest and httpStreamConnect share the same URL, header, and authentication infrastructure.
URL Construction
When using domain + path (script mode):
- The
domainprovides the base URL (protocol + host) - The
pathis appended, with automatic slash normalization - Example:
domain: "https://api.example.com",path: "/v1/data"→https://api.example.com/v1/data
When using url (blueprint mode):
- The full URL is passed directly
Authentication
| Method | How |
|---|---|
| API Key | Set apiKey to the key value and apiKeyHeader to the header name (default x-api-key) |
| Bearer Token | Use headers: { "Authorization": "Bearer " + TOKEN } |
| Basic Auth | Use headers: { "Authorization": "Basic " + btoa(user + ":" + pass) } |
| Custom | Pass any headers in the headers object |
Redirect Handling
By default, both plugins follow HTTP 3xx redirects (up to 10 hops). Set followRedirects: false to disable and receive the redirect response directly.
Blueprint Integration
Both HTTP plugins have corresponding blueprints in the Plugin Catalog. When you add an "HTTP Request" or "HTTP Stream" node from the catalog, the blueprint wizard collects configuration values and generates the script automatically. See Blueprints & Plugins for details.
Environment Variables
| Variable | Default | Description |
|---|---|---|
HTTP_STREAM_MAX_DURATION_MS | 43200000 (12h) | Hard cap on stream duration |
API keys should be stored as organization-level environment variables (e.g., SPORTRADAR_API_KEY, MY_API_KEY) and referenced by name in scripts.