---
title: "Worker API"
description: "Bootstrap workers, manage leases, and deliver results."
category: "Reference"
---

Base URL: your SDK-facing API, locally `http://localhost:8081`. Read [authentication and conventions](/docs/api) first. [Download OpenAPI 3.0](/openapi.yaml) for the full machine-readable contract.

## POST /stages/{stageId}/lease/acquire

Acquire the lease for a dispatched stage execution

Worker protocol endpoint. The worker session token binds the lease to
the authenticated worker session. `acquired=false` is a successful
response indicating that the delivery must not execute the handler.

The current lease duration is 60 seconds. A repeated acquisition is not
reentrant: an active Running execution returns lease_held, including when
the caller previously acquired it. The application comes from the session.


**Authentication:** `WorkerSessionAuth`

### Parameters

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `stageId` | path | Yes | integer | Stage ID (> 0) |

### Request body

Required.

Content type: `application/json`. [StageLeaseRequest](/docs/api/schemas#stageleaserequest)

```yaml
$ref: "#/components/schemas/StageLeaseRequest"
```

### Responses

| Status | Meaning | Schema |
| --- | --- | --- |
| `200` | Lease decision | [StageLeaseResponse](/docs/api/schemas#stageleaseresponse) |
| `400` | Invalid stage ID or request body | — |
| `401` | Missing or invalid worker session token | — |
| `500` | Lease operation failed | — |

## POST /stages/{stageId}/lease/renew

Renew the lease for a running stage execution

Worker-session endpoint. Renewal succeeds only for the current Running
execution and lease owner while its lease remains unexpired. Success extends
the execution lease by 60 seconds. It does not extend the HTTP delivery token's
visibility timeout. On a definitive refusal, stop further handler side effects
cooperatively. Server-side fencing and recovery determine which result applies.


**Authentication:** `WorkerSessionAuth`

### Parameters

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `stageId` | path | Yes | integer | Stage ID (> 0) |

### Request body

Required.

Content type: `application/json`. [StageLeaseRequest](/docs/api/schemas#stageleaserequest)

```yaml
$ref: "#/components/schemas/StageLeaseRequest"
```

### Responses

| Status | Meaning | Schema |
| --- | --- | --- |
| `200` | Lease renewal decision | [StageLeaseResponse](/docs/api/schemas#stageleaseresponse) |
| `400` | Invalid stage ID or request body | — |
| `401` | Missing or invalid worker session token | — |
| `500` | Lease operation failed | — |

## POST /jobs/pull

Pull the next stage job for a handler queue

HTTP gateway over the authenticated application's StageNext queues. Only the
application API key is checked; worker-session validation occurs on lease and
result operations. A queue outside this application's handler pattern is 403.

waitSeconds defaults to zero and accepts 0..20. A positive value polls roughly
every 250 ms until a message arrives or the deadline produces 204.

A 200 response includes a process-local acknowledgement token. The delivery
remains unacknowledged at the broker until acknowledged or requeued. Expiry
sweeps attempt requeue after GATEWAY_VISIBILITY_TIMEOUT (default 60 seconds).
Lease renewal does not extend that delivery timeout. GATEWAY_MAX_INFLIGHT
defaults to 128 pending deliveries per API process; capacity exhaustion is 429.


**Authentication:** `ApiKeyAuth`

### Request body

Required.

Content type: `application/json`. [PullJobRequest](/docs/api/schemas#pulljobrequest)

```yaml
$ref: "#/components/schemas/PullJobRequest"
```

### Responses

| Status | Meaning | Schema |
| --- | --- | --- |
| `200` | A stage job was dequeued | [PullJobResponse](/docs/api/schemas#pulljobresponse) |
| `204` | No message available before the deadline | — |
| `400` | Missing queue, or waitSeconds outside 0..20 | — |
| `401` | Missing or invalid API key | — |
| `403` | Queue does not belong to this application | — |
| `429` | Too many in-flight messages; back off and retry | — |
| `500` | Pull failed | — |

## POST /jobs/ack

Acknowledge or requeue a pulled stage job

The opaque body token authorizes acknowledgement; this handler does not check
an API key or worker session. Protect the token as a credential.

For executed work, send requeue:false only after the result endpoint returned
202. Stale or duplicate deliveries rejected by lease acquisition may be
acknowledged without executing. requeue:true returns a delivery to the broker;
it does not reset an execution lease or itself create a new execution attempt.

Tokens are held by the API process that performed the pull. Route pull and ack
to the same instance. A 404 means that process does not hold the token: it may
have expired, been acknowledged, or belong to another replica. A 404 does not
prove that requeue succeeded. Repeated acknowledgement is not idempotent.


**Authentication:** No header security scheme; read the operation description for body credentials or delivery-token requirements.

### Request body

Required.

Content type: `application/json`. [AckJobRequest](/docs/api/schemas#ackjobrequest)

```yaml
$ref: "#/components/schemas/AckJobRequest"
```

### Responses

| Status | Meaning | Schema |
| --- | --- | --- |
| `200` | Acknowledgement applied | — |
| `400` | Missing token | — |
| `404` | Token not held by this API process (including expired or previously acknowledged tokens) | — |
| `500` | Acknowledgement failed | — |

## POST /stages/{stageId}/result

Report a stage result over HTTP

Requires an application API key and a valid worker session for that application.
Validates the stage's application ownership and message shape, then publishes
persistently with broker confirms. A 202 means broker acceptance, not an applied
database update. Stale or duplicate results may be accepted and later discarded
by the asynchronous result consumer's execution-ID/attempt fencing.

The result string is limited to 262144 bytes; the complete JSON request body is
limited to 327680 bytes. Unknown fields are accepted for SDK compatibility and
ignored if the server message type does not recognize them. Acknowledge the
original pulled delivery after 202. On an unknown result-posting outcome, retry
the same computed result and execution identity rather than rerunning effects.


**Authentication:** `ApiKeyAuth` + `WorkerSessionAuth`

### Parameters

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `stageId` | path | Yes | integer | Stage ID (> 0) |

### Request body

Required.

Content type: `application/json`. [StageResultSubmit](/docs/api/schemas#stageresultsubmit)

```yaml
$ref: "#/components/schemas/StageResultSubmit"
```

### Responses

| Status | Meaning | Schema |
| --- | --- | --- |
| `202` | Result queued for the stage result consumer | [StageResultAccepted](/docs/api/schemas#stageresultaccepted) |
| `400` | Validation failed | [ProblemDetails](/docs/api/schemas#problemdetails) |
| `401` | Missing, invalid, expired, or application-mismatched worker session, or missing/invalid API key | [ProblemDetails](/docs/api/schemas#problemdetails) |
| `403` | Stage belongs to another application | [ProblemDetails](/docs/api/schemas#problemdetails) |
| `404` | Stage not found | [ProblemDetails](/docs/api/schemas#problemdetails) |
| `500` | Session, stage ownership, or result encoding operation failed | [ProblemDetails](/docs/api/schemas#problemdetails) |
| `503` | Message broker unavailable; retry the request | [ProblemDetails](/docs/api/schemas#problemdetails) |

## POST /workers/bootstrap

Register a worker and receive its session

Register a worker using an application API key and receive its workerId and
session token. Send X-Worker-Session to lease, result, heartbeat, events, and
shutdown operations; result submission also requires X-API-Key. HTTP workers
use jobs/pull and ignore messageBroker.connectionString.

WORKER_SESSION_TTL defaults to 24 hours. Heartbeats do not extend expiry.
Rebootstrap of an existing application/instanceId reuses the worker record and
replaces its token. Concurrent processes must use different instance IDs.


**Authentication:** `ApiKeyAuth`

### Request body

Required.

Content type: `application/json`. [WorkerBootstrapRequest](/docs/api/schemas#workerbootstraprequest)

```yaml
$ref: "#/components/schemas/WorkerBootstrapRequest"
```

### Responses

| Status | Meaning | Schema |
| --- | --- | --- |
| `200` | Worker registered | [WorkerBootstrapResponse](/docs/api/schemas#workerbootstrapresponse) |
| `400` | Malformed body | — |
| `401` | Missing or invalid API key | — |
| `500` | Application resolution or worker registration failed | — |
| `503` | Broker hand-out is enabled but no broker address is configured | — |

## POST /workers/heartbeat

Report worker liveness and counters

Records liveness and optional counters. Requires a valid, unexpired worker session matching workerId. Does not extend the session expiry.

**Authentication:** `WorkerSessionAuth`

### Request body

Required.

Content type: `application/json`. [WorkerHeartbeatRequest](/docs/api/schemas#workerheartbeatrequest)

```yaml
$ref: "#/components/schemas/WorkerHeartbeatRequest"
```

### Responses

| Status | Meaning | Schema |
| --- | --- | --- |
| `200` | Heartbeat recorded | — |
| `400` | Malformed body | — |
| `401` | Missing worker session token or token does not match workerId; heartbeat/events also reject expired sessions | — |
| `500` | Worker state or events could not be persisted | — |

## POST /workers/events

Append worker lifecycle events

Batched, at most `WORKER_EVENTS_MAX_BATCH` events per call. Events feed
the dashboard's worker activity feed and alerting.


**Authentication:** `WorkerSessionAuth`

### Request body

Required.

Content type: `application/json`. [WorkerEventsRequest](/docs/api/schemas#workereventsrequest)

```yaml
$ref: "#/components/schemas/WorkerEventsRequest"
```

### Responses

| Status | Meaning | Schema |
| --- | --- | --- |
| `200` | Events recorded | — |
| `400` | Malformed body or batch too large | — |
| `401` | Missing worker session token or token does not match workerId; heartbeat/events also reject expired sessions | — |
| `500` | Worker state or events could not be persisted | — |

## POST /workers/shutdown

Announce a graceful shutdown

Marks the matching worker record stopped and records a lifecycle event. This is not token revocation; the handler matches workerId and the stored token but does not check session expiry.

**Authentication:** `WorkerSessionAuth`

### Request body

Required.

Content type: `application/json`. [WorkerShutdownRequest](/docs/api/schemas#workershutdownrequest)

```yaml
$ref: "#/components/schemas/WorkerShutdownRequest"
```

### Responses

| Status | Meaning | Schema |
| --- | --- | --- |
| `200` | Worker marked stopped | — |
| `400` | Malformed body | — |
| `401` | Missing worker session token or token does not match workerId; heartbeat/events also reject expired sessions | — |
| `500` | Worker state or events could not be persisted | — |
