Job management
Section titled “Job management”List, inspect, retrieve results from, and cancel async cURL jobs submitted with mode=async. These endpoints expose the lifecycle of background HTTP requests, letting you monitor long-running downloads, audit historical activity, and recover response bodies after asynchronous execution.
A job progresses through these states:
pending— queued, waiting for executionrunning— currently executingcompleted— finished successfully, response data availablefailed— execution failed, error details recordedcancelled— user-cancelled before completion
Browse and monitor jobs
Section titled “Browse and monitor jobs”GET /api/v1/curl/jobs
Section titled “GET /api/v1/curl/jobs”Retrieve a list of all async jobs sorted by creation time (newest first). Use this endpoint to discover job IDs, audit historical request activity, and monitor long-running downloads.
Each row’s url has its credentials masked as in client.curl.jobs.get(), and method is the method that was sent: POST for a request with a body and no method, never null.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
page | query | integer | No | 1-based page number |
limit | query | integer | No | Items per page. The current handler returns all items when omitted. |
Response
Section titled “Response”Paginated list of job summaries returned in newest-first order. Each summary carries the job id, current status, target URL, HTTP method, display name, and timestamps.
{ "items": [ { "completed_at": "2024-01-15T10:30:45Z", "created_at": "2024-01-15T10:30:00Z", "id": "550e8400-e29b-41d4-a716-446655440000", "method": "GET", "name": "daily-report-download", "status": "completed", "url": "https://reports.example.com/daily.pdf" }, { "completed_at": null, "created_at": "2024-01-15T10:31:00Z", "id": "660e8400-e29b-41d4-a716-446655440111", "method": "POST", "name": "api-batch-request", "status": "running", "url": "https://api.example.com/batch" } ], "meta": { "limit": 50, "page": 1, "total": 2 }}The server runs in origin-list CORS mode and the request’s Origin header is not on the allowed list, so the request is refused before it reaches a handler.
{ "error": "Origin not allowed", "code": "ORIGIN_NOT_ALLOWED"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
ORIGIN_NOT_ALLOWED | Origin rejected | The server runs in origin-list CORS mode and the request’s Origin header is not on the list; the request is refused before it reaches a handler | Call from an allowed origin, or add the origin to the server’s --cors list |
Jobs could not be read from persistent storage.
{ "error": "Failed to read jobs from storage", "code": "STORAGE_ERROR"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
STORAGE_ERROR | Storage read failed | Unable to read jobs from persistent storage | Verify storage directory permissions and disk space availability |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_PARAMETER | Invalid request | A parameter, query value or JSON body is missing, malformed or out of range | Check the message for the offending field and fix the request; retrying unchanged fails again |
SDK usage
Section titled “SDK usage”curl -X GET "https://{projectId}-{containerId}-curl-1.{server}.containers.hoody.com/api/v1/curl/jobs?page=1&limit=50" \ -H "Authorization: Bearer <token>"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-curl-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
for await (const item of client.curl.jobs.listIterator({ page: 1, limit: 50 })) { console.log(item);}GET /api/v1/curl/jobs/{id}
Section titled “GET /api/v1/curl/jobs/{id}”Retrieve complete details of a specific job, including its request configuration, current status, response data (when completed), and execution metadata. Use this endpoint to check job progress or retrieve full results after completion.
Credentials are redacted: in request, auth_password, proxy_password, bearer_token and cookie, credential headers and form fields (Authorization, Proxy-Authorization, Cookie, X-Api-Key, names with token, secret, password and similar, any case), credential keys in a json body and in a raw data body that is JSON or a URL-encoded form, auth_user / proxy_user when they have no password (the user is then the token), and in the URL, proxy URL and referer: the password, the user name when there is no password (https://TOKEN@host), and credential parameters of the query and of the fragment (#access_token=) read [REDACTED]. The job ran with the real values.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Unique job identifier (UUID format) |
Response
Section titled “Response”Full job details with the original request configuration, current status, and recorded response (when present).
{ "completed_at": "2024-01-15T10:30:01Z", "created_at": "2024-01-15T10:30:00Z", "error": null, "id": "550e8400-e29b-41d4-a716-446655440000", "name": "api-request", "request": { "follow_redirects": true, "method": "GET", "timeout": 30, "url": "https://jsonplaceholder.typicode.com/posts/1" }, "response": { "body": [ 123, 34, 105, 100, 34 ], "connect_time": 0.045, "content_type": "application/json", "effective_url": "https://jsonplaceholder.typicode.com/posts/1", "headers": { "content-type": "application/json" }, "namelookup_time": 0.012, "pretransfer_time": 0.098, "redirect_count": 0, "redirect_time": 0, "size_download": 5, "size_upload": 0, "speed_download": 21, "speed_upload": 0, "starttransfer_time": 0.221, "status_code": 200, "total_time": 0.234 }, "retry_attempts": 1, "retry_count": 0, "started_at": "2024-01-15T10:30:00Z", "status": "completed"}The server runs in origin-list CORS mode and the request’s Origin header is not on the allowed list, so the request is refused before it reaches a handler.
{ "error": "Origin not allowed", "code": "ORIGIN_NOT_ALLOWED"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
ORIGIN_NOT_ALLOWED | Origin rejected | The server runs in origin-list CORS mode and the request’s Origin header is not on the list; the request is refused before it reaches a handler | Call from an allowed origin, or add the origin to the server’s --cors list |
The requested job does not exist, or has been deleted.
{ "error": "Job not found", "code": "JOB_NOT_FOUND"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
JOB_NOT_FOUND | Job does not exist | No job exists with the provided ID | Verify job ID from client.curl.jobs.list(), or check if job was deleted |
The job record could not be read from storage.
{ "error": "Failed to read job data", "code": "STORAGE_ERROR"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
STORAGE_ERROR | Storage read failed | Unable to read job data from storage | Check storage permissions and retry operation |
SDK usage
Section titled “SDK usage”curl -X GET "https://{projectId}-{containerId}-curl-1.{server}.containers.hoody.com/api/v1/curl/jobs/550e8400-e29b-41d4-a716-446655440000" \ -H "Authorization: Bearer <token>"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-curl-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.curl.jobs.get('550e8400-e29b-41d4-a716-446655440000');Retrieve a result
Section titled “Retrieve a result”GET /api/v1/curl/jobs/{id}/result
Section titled “GET /api/v1/curl/jobs/{id}/result”Retrieve only the HTTP response body from a completed job in transparent mode. The response is returned in raw format with the original headers preserved, exactly as received from the target server.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Unique job identifier (UUID format) |
Response
Section titled “Response”Returns the raw response body from a completed job, with the original upstream headers preserved. The exact content type and body shape match what the target server returned.
The server runs in origin-list CORS mode and the request’s Origin header is not on the allowed list, so the request is refused before it reaches a handler.
{ "error": "Origin not allowed", "code": "ORIGIN_NOT_ALLOWED"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
ORIGIN_NOT_ALLOWED | Origin rejected | The server runs in origin-list CORS mode and the request’s Origin header is not on the list; the request is refused before it reaches a handler | Call from an allowed origin, or add the origin to the server’s --cors list |
The job does not exist, or its result is not available yet (the job has not completed, or it failed without recording a response).
{ "error": "Job not found", "code": "JOB_NOT_FOUND"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
JOB_NOT_FOUND | Job does not exist | No job found with the provided ID | Verify job ID is correct using client.curl.jobs.list() |
JOB_RESULT_NOT_READY | Result not available | Job has not completed yet or failed without response | Check job status with client.curl.jobs.get(), wait for completion |
The job result could not be read from storage.
{ "error": "Failed to retrieve job result", "code": "STORAGE_ERROR"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
STORAGE_ERROR | Storage read failed | Failed to read job result from storage | Check storage integrity and retry |
SDK usage
Section titled “SDK usage”curl -X GET "https://{projectId}-{containerId}-curl-1.{server}.containers.hoody.com/api/v1/curl/jobs/550e8400-e29b-41d4-a716-446655440000/result" \ -H "Authorization: Bearer <token>"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-curl-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.curl.jobs.getResult('550e8400-e29b-41d4-a716-446655440000');Cancel a job
Section titled “Cancel a job”DELETE /api/v1/curl/jobs/{id}
Section titled “DELETE /api/v1/curl/jobs/{id}”Cancel a job that is currently pending or running. Once cancelled, the job cannot be restarted. Cancelling is idempotent: a job that already finished is left as it is and the call still succeeds. With purge=true, a finished job (completed, failed or cancelled) is deleted instead, with its saved downloads; a job that is still pending or running is then refused with 409 JOB_NOT_FINISHED.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Unique job identifier (UUID format) |
purge | query | boolean | No | true deletes a finished job and its saved downloads instead of cancelling it (default false) |
Response
Section titled “Response”The job was cancelled, or it had already finished and is left as it is. With purge=true, the job and its saved downloads were deleted.
{ "success": true, "message": "Job cancelled", "purged": false, "removed_files": 0}The server runs in origin-list CORS mode and the request’s Origin header is not on the allowed list, so the request is refused before it reaches a handler.
{ "error": "Origin not allowed", "code": "ORIGIN_NOT_ALLOWED"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
ORIGIN_NOT_ALLOWED | Origin rejected | The server runs in origin-list CORS mode and the request’s Origin header is not on the list; the request is refused before it reaches a handler | Call from an allowed origin, or add the origin to the server’s --cors list |
No job has this ID: it never existed, it was purged, or its record passed the retention period.
{ "error": "Job not found", "code": "JOB_NOT_FOUND"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
JOB_NOT_FOUND | Job does not exist | Cannot cancel job that doesn’t exist | Verify job ID using client.curl.jobs.list() |
The cancellation operation failed before the job’s status was updated.
{ "error": "Failed to cancel job", "code": "INTERNAL_ERROR"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
INTERNAL_ERROR | Cancellation failed | Job cancellation operation encountered an error | Retry cancellation or contact support if persistent |
STORAGE_ERROR | Storage failure | Reading or writing the service’s storage directory failed | Retry; check the storage directory’s permissions and free space if it persists |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
JOB_NOT_FINISHED | Job is still pending or running | The operation needs a finished job (completed, failed or cancelled) | Cancel the job first (client.curl.jobs.cancel(), without purge), then retry once client.curl.jobs.get() reports it cancelled |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_PARAMETER | Invalid request | A parameter, query value or JSON body is missing, malformed or out of range | Check the message for the offending field and fix the request; retrying unchanged fails again |
SDK usage
Section titled “SDK usage”curl -X DELETE "https://{projectId}-{containerId}-curl-1.{server}.containers.hoody.com/api/v1/curl/jobs/550e8400-e29b-41d4-a716-446655440000" \ -H "Authorization: Bearer <token>"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-curl-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.curl.jobs.cancel('550e8400-e29b-41d4-a716-446655440000');
// Delete a finished job and its saved downloads (sends purge=true)await client.curl.jobs.delete('550e8400-e29b-41d4-a716-446655440000');