The HTTP Request Execution surface lets you invoke libcurl against any target URL, optionally as a background job, and stream lifecycle events back to your client. This page documents the synchronous GET and POST execution endpoints, the SSE and WebSocket event streams, and the multiplexed WebSocket execution channel.
HTTP Request Execution
Section titled “HTTP Request Execution”GET /api/v1/curl/request
Section titled “GET /api/v1/curl/request”Execute a single HTTP request whose configuration is fully encoded in the URL query string. This form is intended for simple GETs and quick testing; for advanced configuration (retry policy, scheduling, proxies, session cookies) use the POST variant.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
url | query | string | Yes | Target URL (required) |
method | query | string | No | HTTP method (default: GET) |
response | query | string | No | Response mode: transparent or json (default: json) |
mode | query | string | No | Execution mode: sync or async (default: sync) |
session_id | query | string | No | Session ID for cookie persistence |
follow_redirects | query | boolean | No | Follow redirects (default: true) |
timeout | query | integer | No | Timeout in seconds |
user_agent | query | string | No | User-Agent header |
referer | query | string | No | Referer header |
bearer_token | query | string | No | Bearer token |
save | query | boolean | No | Save to storage |
save_path | query | string | No | Custom save path, relative to downloads/by-job/{job_id} (no absolute paths or ..) |
insecure | query | boolean | No | Allow insecure SSL |
compressed | query | boolean | No | Request compressed |
job_name | query | string | No | Job name for async |
data | query | string | No | Raw request body (curl --data); alias body; presence upgrades default method to POST |
json | query | string | No | JSON request body, sent with Content-Type: application/json (curl --json); upgrades default method to POST |
header | query | array | No | Custom header as Name: Value. Repeatable — supply once per header |
data_base64 | query | string | No | Base64 request body (binary-safe; standard or URL-safe); alias body_base64. Takes precedence over data/json; upgrades default method to POST |
curl -G "https://proj-abc123-cnt-xyz789-curl-1.us-east-1.containers.hoody.icu/api/v1/curl/request" \ --data-urlencode "url=https://api.github.com/zen" \ --data-urlencode "method=GET" \ --data-urlencode "response=json" \ --data-urlencode "timeout=30" \ --data-urlencode "header=Accept: application/json" \ --data-urlencode "header=X-Trace-Id: req-7f3a"await client.curl.executeCurlRequestGet({ url: "https://api.github.com/zen", method: "GET", response: "json", timeout: 30, header: ["Accept: application/json", "X-Trace-Id: req-7f3a"]});{ "success": true, "status_code": 200, "headers": { "content-type": "application/json; charset=utf-8", "x-ratelimit-remaining": "59" }, "body": "{\"message\":\"Speak like a human\"}", "is_binary": false, "job_id": null, "metadata": { "effective_url": "https://api.github.com/zen", "content_type": "application/json", "redirect_count": 0, "size_download": 34, "size_upload": 0, "speed_download": 4821.7, "speed_upload": 0 }, "timing": { "namelookup": 0.0124, "connect": 0.0381, "pretransfer": 0.0487, "starttransfer": 0.1192, "redirect": 0, "total": 0.1245 }}{ "job_id": "01HMZ8X9K2QF3N5P7R8T6V4WYD", "status": "queued", "name": "fetch-quote"}{ "error": "INVALID_URL", "message": "Missing required parameter: url"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_URL | Missing or invalid URL | URL parameter is required and must be valid | Provide url parameter with complete URL including protocol |
INVALID_PARAMETER | Invalid query parameter | One or more query parameters have invalid values | Check parameter values match expected types (e.g., timeout as number) |
{ "error": "NETWORK_ERROR", "message": "Network connection failed"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
NETWORK_ERROR | Network request failed | Failed to execute HTTP request via cURL | Verify target URL accessibility and network connectivity |
POST /api/v1/curl/request
Section titled “POST /api/v1/curl/request”Execute an HTTP request using libcurl with full configuration. Supports both sync (immediate response) and async (background job) execution modes, plus transparent and json response modes.
Common use cases include API integrations with automatic retry, large file downloads with progress tracking, multi-step authentication flows with session cookies, and scheduled recurring requests via cron expressions.
This endpoint takes no parameters.
Request Body
Section titled “Request Body”Pass the request configuration as a JSON body. The body is validated against the cURL request schema; unknown fields are rejected.
curl -X POST "https://proj-abc123-cnt-xyz789-curl-1.us-east-1.containers.hoody.icu/api/v1/curl/request" \ -H "Content-Type: application/json" \ -d '{ "url": "https://api.example.com/v1/orders", "method": "POST", "headers": { "Accept": "application/json", "X-Trace-Id": "ord-7f3a" }, "bearer_token": "eyJhbGciOi...", "json": { "sku": "HOODY-001", "qty": 2 }, "response": "json", "mode": "sync", "follow_redirects": true, "timeout": 30, "retry_count": 3, "retry_delay": 1000 }'await client.curl.execute({ url: "https://api.example.com/v1/orders", method: "POST", headers: { Accept: "application/json", "X-Trace-Id": "ord-7f3a" }, bearer_token: "eyJhbGciOi...", json: { sku: "HOODY-001", qty: 2 }, response: "json", mode: "sync", follow_redirects: true, timeout: 30, retry_count: 3, retry_delay: 1000});{ "success": true, "status_code": 201, "headers": { "content-type": "application/json", "location": "/v1/orders/ord_7421" }, "body": "{\"id\":\"ord_7421\",\"status\":\"created\"}", "is_binary": false, "job_id": null, "metadata": { "effective_url": "https://api.example.com/v1/orders", "content_type": "application/json", "redirect_count": 0, "size_download": 41, "size_upload": 32, "speed_download": 6120.4, "speed_upload": 4880.1 }, "timing": { "namelookup": 0.0101, "connect": 0.0345, "pretransfer": 0.0452, "starttransfer": 0.1821, "redirect": 0, "total": 0.1907 }}{ "job_id": "01HMZ8X9K2QF3N5P7R8T6V4WYD", "status": "queued", "name": "ingest-feed"}{ "error": "INVALID_URL", "message": "Invalid URL format"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_URL | Malformed URL | The provided URL is not in valid format | Provide a complete URL with protocol (e.g., https://example.com) |
INVALID_PARAMETER | Invalid parameter value | One or more parameters contain invalid values | Check parameter types and allowed values in API documentation |
{ "error": "NETWORK_ERROR", "message": "Connection timeout after 30 seconds"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
NETWORK_ERROR | Network request failed | cURL could not complete the HTTP request | Check target URL is accessible, verify network connectivity, check timeout settings |
Real-time Job Events
Section titled “Real-time Job Events”These endpoints stream lifecycle events for asynchronous jobs. Use them to track progress without polling.
GET /api/v1/curl/sse
Section titled “GET /api/v1/curl/sse”Establish a Server-Sent Events connection. Each lifecycle event is delivered as a standard SSE frame with event: set to the message type and data: containing the JSON payload.
Events emitted:
jobstarted— data{job_id, name}jobprogress— data{job_id, progress}jobcompleted— data{job_id, status}error— data{message}lagged— data{missed}; emitted if the broadcast subscriber falls behind
Pass ?job_id= to filter the stream to a single job. The Last-Event-Id header is accepted for spec compliance but ignored (no replay buffer is maintained). The connection counts against a global SSE concurrency cap; when exhausted the server returns 503 with Retry-After: 5.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
job_id | query | string | No | Optional job ID filter |
curl -N "https://proj-abc123-cnt-xyz789-curl-1.us-east-1.containers.hoody.icu/api/v1/curl/sse?job_id=01HMZ8X9K2QF3N5P7R8T6V4WYD"await client.curl.events.sseJobEvents({ job_id: "01HMZ8X9K2QF3N5P7R8T6V4WYD" });event: jobstarteddata: {"job_id":"01HMZ8X9K2QF3N5P7R8T6V4WYD","name":"ingest-feed"}
event: jobprogressdata: {"job_id":"01HMZ8X9K2QF3N5P7R8T6V4WYD","progress":0.42}
event: jobcompleteddata: {"job_id":"01HMZ8X9K2QF3N5P7R8T6V4WYD","status":"ok"}{ "statusCode": 503, "error": "Service Unavailable", "message": "SSE concurrency cap exhausted", "retryAfter": 5}GET /api/v1/curl/ws
Section titled “GET /api/v1/curl/ws”Establish a WebSocket connection that receives job lifecycle events as JSON messages.
Messages:
jobstarted—{job_id, name}jobprogress—{job_id, progress}(progress is a0..=1fraction)jobcompleted—{job_id, status}error—{message}
Pass the job_id query parameter to filter events to a single job. Use the job snapshot endpoint (getJob) for point-in-time state, and this WebSocket for live updates.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
job_id | query | string | No | Optional job ID filter |
curl --include \ --no-buffer \ --header "Connection: Upgrade" \ --header "Upgrade: websocket" \ --header "Sec-WebSocket-Version: 13" \ --header "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \ "https://proj-abc123-cnt-xyz789-curl-1.us-east-1.containers.hoody.icu/api/v1/curl/ws?job_id=01HMZ8X9K2QF3N5P7R8T6V4WYD"await client.curl.events.streamWs("01HMZ8X9K2QF3N5P7R8T6V4WYD");{ "description": "Switching Protocols (WebSocket established)"}{ "description": "Bad request"}{ "description": "Internal server error"}WebSocket Execution Channel
Section titled “WebSocket Execution Channel”GET /api/v1/curl/channel
Section titled “GET /api/v1/curl/channel”Establish a persistent WebSocket connection for multiplexed, validated CurlRequest execution. Each upstream response is fully buffered by hoody-curl before response body chunks are emitted as WebSocket frames.
Query parameters configure per-connection limits. The connection counts against the global SSE/WebSocket concurrency budget.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
max_concurrent | query | integer | No | Alias for max concurrent streams on this channel connection |
max_concurrent_streams | query | integer | No | Maximum concurrently executing streams on this channel connection |
max_pool | query | integer | No | Alias for max_concurrent; does not configure outbound libcurl connection pooling |
max_queue | query | integer | No | Maximum queued streams waiting for a per-connection execution slot |
max_frame_bytes | query | integer | No | Maximum inbound WebSocket text frame size in bytes |
max_request_bytes | query | integer | No | Maximum assembled request JSON size in bytes |
chunk_bytes | query | integer | No | Maximum upstream response bytes encoded into one channel body frame |
stream_timeout_secs | query | integer | No | Per-stream execution timeout in seconds |
idle_timeout_secs | query | integer | No | Idle channel timeout in seconds |
max_outbound_messages | query | integer | No | Maximum queued outbound channel messages |
curl --include \ --no-buffer \ --header "Connection: Upgrade" \ --header "Upgrade: websocket" \ --header "Sec-WebSocket-Version: 13" \ --header "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \ "https://proj-abc123-cnt-xyz789-curl-1.us-east-1.containers.hoody.icu/api/v1/curl/channel?max_concurrent_streams=4&max_queue=16&max_frame_bytes=262144&chunk_bytes=65536&stream_timeout_secs=30&idle_timeout_secs=120"await client.curl.events.wsRequestChannel({ max_concurrent_streams: 4, max_queue: 16, max_frame_bytes: 262144, chunk_bytes: 65536, stream_timeout_secs: 30, idle_timeout_secs: 120});{ "description": "Switching Protocols (WebSocket channel established)"}{ "description": "Bad request"}{ "description": "Internal server error"}