API reference
Jobs
A unit of background work: a task name, a payload and a lifecycle you can follow.
Overview
A job is one piece of work for your workers: a task name, a JSON payload and the queue it runs on. Halyard stores it durably before answering, hands it to a worker and records every attempt.
Jobs move from queued to running to succeeded. A failed attempt is retried with backoff until max_attempts is reached; then the job is failed and stays available for 30 days so you can inspect or retry it.
- Endpoints
- 5
- ID prefix
- job_
- Attributes
- 19
The job object
Every job endpoint returns this object, or a list of them. Attributes marked null are always present in the response, so you can rely on the shape.
Attributes
idstringUnique identifier, prefixed with job_.
objectstringAlways job.
queuestringName of the queue the job runs on.
taskstringThe task your worker runs, such as send-welcome-email.
payloadobjectThe JSON you passed when creating the job, handed to your worker as-is. Up to 256 KB.
statusenumWhere the job is in its lifecycle: scheduled, queued, running, succeeded, failed or cancelled.
priorityintegerFrom -10 to 10. Higher runs first within its queue.
attemptsintegerHow many times a worker has picked the job up so far.
max_attemptsintegerAttempts allowed before the job fails. Inherited from the queue's retry policy unless set.
run_attimestamp | nullIf set, the job waits in scheduled until this time.
schedulestring | nullID of the schedule that created this job, or null. Expandable to the full schedule object.
idempotency_keystring | nullThe Idempotency-Key header sent with the create request, if any.
resultobject | nullWhat your worker returned when the job succeeded.
last_errorobject | nullDetails of the most recent failed attempt.
Show 3 child attributesHide child attributes
codestringMachine-readable reason, such as task_timeout or worker_error.
messagestringHuman-readable message from Halyard or from your worker.
attimestampWhen the attempt failed.
metadataobjectUp to 20 string key-value pairs you can attach for your own reference. Halyard never reads them.
created_attimestampWhen the object was created, in ISO 8601 UTC.
started_attimestamp | nullWhen the first attempt started.
finished_attimestamp | nullWhen the job reached succeeded, failed or cancelled.
livemodebooleantrue for objects created with a live key, false for the test sandbox.
{ "id": "job_3Rk9Tq7Xw2", "object": "job", "queue": "emails", "task": "send-welcome-email", "payload": { "user_id": "usr_8KfQ2" }, "status": "queued", "priority": 0, "attempts": 0, "max_attempts": 5, "run_at": null, "schedule": null, "idempotency_key": "signup-usr_8KfQ2", "result": null, "last_error": null, "metadata": {}, "created_at": "2026-10-14T09:12:03Z", "started_at": null, "finished_at": null, "livemode": false}Create a job
/v3/jobsQueues a new job. The response comes back once the job is written to three zones, usually within a few milliseconds. Send an Idempotency-Key header so a retried request never creates the job twice.
Body parameters
queuestringrequiredName of an existing queue. Unknown queues return a 404.
taskstringrequiredTask name your worker registered, up to 120 characters.
payloadobjectdefault: {}Any JSON object up to 256 KB, passed to your worker unchanged.
priorityintegerdefault: 0From -10 to 10. Higher runs first within the queue.
run_attimestampDelay the job until this time. Up to one year ahead.
max_attemptsintegerOverride the queue's retry policy for this job only.
metadataobjectUp to 20 string key-value pairs you can attach for your own reference. Halyard never reads them.
Returns
The new job object, with status set to queued (or scheduled when run_at is in the future).
curl https://api.halyard.example/v3/jobs \ -H "Authorization: Bearer hy_test_51Hq8Zx2rTmV9cKpL3d" \ -H "Idempotency-Key: signup-usr_8KfQ2" \ -H "Content-Type: application/json" \ -d '{ "queue": "emails", "task": "send-welcome-email", "payload": { "user_id": "usr_8KfQ2" } }'import { Halyard } from "@halyard/node"; const halyard = new Halyard(process.env.HALYARD_KEY); const job = await halyard.jobs.create({ queue: "emails", task: "send-welcome-email", payload: { user_id: "usr_8KfQ2" },}, { idempotencyKey: "signup-usr_8KfQ2" });import osfrom halyard import Halyard halyard = Halyard(os.environ["HALYARD_KEY"]) job = halyard.jobs.create( queue="emails", task="send-welcome-email", payload={"user_id": "usr_8KfQ2"}, idempotency_key="signup-usr_8KfQ2",){ "id": "job_3Rk9Tq7Xw2", "object": "job", "queue": "emails", "task": "send-welcome-email", "payload": { "user_id": "usr_8KfQ2" }, "status": "queued", "priority": 0, "attempts": 0, "max_attempts": 5, "run_at": null, "schedule": null, "idempotency_key": "signup-usr_8KfQ2", "result": null, "last_error": null, "metadata": {}, "created_at": "2026-10-14T09:12:03Z", "started_at": null, "finished_at": null, "livemode": false}Retrieve a job
/v3/jobs/{id}Fetches a job by ID with its current status, attempt count and the latest error, if any.
Path parameters
idstringrequiredThe job's ID, such as job_3Rk9Tq7Xw2.
Query parameters
expand[]arrayFields to expand inline. Supports schedule.
Returns
The job object, or a 404 if no job has that ID.
curl https://api.halyard.example/v3/jobs/job_3Rk9Tq7Xw2 \ -H "Authorization: Bearer hy_test_51Hq8Zx2rTmV9cKpL3d"import { Halyard } from "@halyard/node"; const halyard = new Halyard(process.env.HALYARD_KEY); const job = await halyard.jobs.retrieve("job_3Rk9Tq7Xw2");import osfrom halyard import Halyard halyard = Halyard(os.environ["HALYARD_KEY"]) job = halyard.jobs.retrieve("job_3Rk9Tq7Xw2"){ "id": "job_3Rk9Tq7Xw2", "object": "job", "queue": "emails", "task": "send-welcome-email", "payload": { "user_id": "usr_8KfQ2" }, "status": "succeeded", "priority": 0, "attempts": 1, "max_attempts": 5, "run_at": null, "schedule": null, "idempotency_key": "signup-usr_8KfQ2", "result": { "message_id": "msg_61dQe" }, "last_error": null, "metadata": {}, "created_at": "2026-10-14T09:12:03Z", "started_at": "2026-10-14T09:12:04Z", "finished_at": "2026-10-14T09:12:05Z", "livemode": false}List jobs
/v3/jobsLists jobs, newest first. Filter by queue, task or status, and page through results with cursors.
Query parameters
queuestringOnly jobs on this queue.
taskstringOnly jobs with this task name.
statusenumOnly jobs in this status, such as failed.
created_aftertimestampOnly jobs created after this time.
limitintegerdefault: 20How many objects to return, between 1 and 100.
starting_afterstringA cursor: the ID of the last object on the previous page. The next page starts right after it.
ending_beforestringA cursor for paging backwards: the ID of the first object on the current page.
Returns
A list object with up to limit jobs in data and a has_more flag.
curl -G https://api.halyard.example/v3/jobs \ -H "Authorization: Bearer hy_test_51Hq8Zx2rTmV9cKpL3d" \ -d queue=billing \ -d status=failed \ -d limit=2import { Halyard } from "@halyard/node"; const halyard = new Halyard(process.env.HALYARD_KEY); const jobs = await halyard.jobs.list({ queue: "billing", status: "failed", limit: 2,});import osfrom halyard import Halyard halyard = Halyard(os.environ["HALYARD_KEY"]) jobs = halyard.jobs.list(queue="billing", status="failed", limit=2){ "object": "list", "url": "/v3/jobs", "has_more": true, "data": [ { "id": "job_7Pw4Hc2Zn8", "object": "job", "queue": "billing", "task": "sync-invoice", "payload": { "invoice_id": "inv_20931" }, "status": "failed", "priority": 0, "attempts": 5, "max_attempts": 5, "run_at": null, "schedule": null, "idempotency_key": null, "result": null, "last_error": { "code": "task_timeout", "message": "Task exceeded its 30s timeout.", "at": "2026-10-14T08:41:27Z" }, "metadata": {}, "created_at": "2026-10-14T08:02:11Z", "started_at": "2026-10-14T08:02:12Z", "finished_at": "2026-10-14T08:41:27Z", "livemode": false }, { "id": "job_1Qm8Df6Ts3", "object": "job", "queue": "billing", "task": "sync-invoice", "payload": { "invoice_id": "inv_20927" }, "status": "failed", "priority": 0, "attempts": 5, "max_attempts": 5, "run_at": null, "schedule": null, "idempotency_key": null, "result": null, "last_error": { "code": "task_timeout", "message": "Task exceeded its 30s timeout.", "at": "2026-10-14T08:41:27Z" }, "metadata": {}, "created_at": "2026-10-14T07:55:40Z", "started_at": "2026-10-14T08:02:12Z", "finished_at": "2026-10-14T08:41:27Z", "livemode": false } ]}Cancel a job
/v3/jobs/{id}/cancelCancels a job that is scheduled or queued. A running job is marked for cancellation and your worker sees job.cancelRequested on its next heartbeat. Finished jobs can't be cancelled and return a 409.
Path parameters
idstringrequiredThe ID of the job to cancel.
Body parameters
reasonstringA note stored on the job and shown in the dashboard, up to 500 characters.
Returns
The job object with status set to cancelled.
curl https://api.halyard.example/v3/jobs/job_3Rk9Tq7Xw2/cancel \ -H "Authorization: Bearer hy_test_51Hq8Zx2rTmV9cKpL3d" \ -H "Content-Type: application/json" \ -d '{ "reason": "User deleted their account" }'import { Halyard } from "@halyard/node"; const halyard = new Halyard(process.env.HALYARD_KEY); const job = await halyard.jobs.cancel("job_3Rk9Tq7Xw2", { reason: "User deleted their account",});import osfrom halyard import Halyard halyard = Halyard(os.environ["HALYARD_KEY"]) job = halyard.jobs.cancel( "job_3Rk9Tq7Xw2", reason="User deleted their account",){ "id": "job_3Rk9Tq7Xw2", "object": "job", "queue": "emails", "task": "send-welcome-email", "payload": { "user_id": "usr_8KfQ2" }, "status": "cancelled", "priority": 0, "attempts": 0, "max_attempts": 5, "run_at": null, "schedule": null, "idempotency_key": "signup-usr_8KfQ2", "result": null, "last_error": null, "metadata": {}, "created_at": "2026-10-14T09:12:03Z", "started_at": null, "finished_at": "2026-10-14T09:12:40Z", "livemode": false}Retry a job
/v3/jobs/{id}/retryPuts a failed or cancelled job back on its queue with a fresh attempt budget. The job keeps its ID, payload and history.
Path parameters
idstringrequiredThe ID of the job to retry.
Body parameters
run_attimestampRetry later instead of right away.
max_attemptsintegerA new attempt budget. Defaults to the queue's retry policy.
Returns
The job object with status set to queued and attempts reset to 0.
curl -X POST https://api.halyard.example/v3/jobs/job_7Pw4Hc2Zn8/retry \ -H "Authorization: Bearer hy_test_51Hq8Zx2rTmV9cKpL3d"import { Halyard } from "@halyard/node"; const halyard = new Halyard(process.env.HALYARD_KEY); const job = await halyard.jobs.retry("job_7Pw4Hc2Zn8");import osfrom halyard import Halyard halyard = Halyard(os.environ["HALYARD_KEY"]) job = halyard.jobs.retry("job_7Pw4Hc2Zn8"){ "id": "job_7Pw4Hc2Zn8", "object": "job", "queue": "billing", "task": "sync-invoice", "payload": { "invoice_id": "inv_20931" }, "status": "queued", "priority": 0, "attempts": 0, "max_attempts": 5, "run_at": null, "schedule": null, "idempotency_key": null, "result": null, "last_error": { "code": "task_timeout", "message": "Task exceeded its 30s timeout.", "at": "2026-10-14T08:41:27Z" }, "metadata": {}, "created_at": "2026-10-14T08:02:11Z", "started_at": "2026-10-14T08:02:12Z", "finished_at": null, "livemode": false}