Worker Registration
Worker register and runtime JWT.
Register a daemon or custom worker with the Rensei platform and obtain a short-lived runtime JWT that authorizes all subsequent worker-protocol calls.
Overview
Every worker must register before it can poll for sessions or send heartbeats. Registration validates a project-scoped registration token, creates a worker record, and returns a workerId plus a runtimeJwt (or runtimeToken on the legacy path). All subsequent calls use Authorization: Bearer <runtimeJwt>.
Two registration paths exist. The daemon-native /v1/daemon/register path is preferred for af-compatible workers. The AF-compatible /api/workers/register path is supported for custom worker implementations and legacy tooling. Both issue a runtime JWT; only the request shape differs.
Daemon-native path (preferred)
POST /v1/daemon/register
The af daemon calls this endpoint. The registration token is passed in the request body rather than the Authorization header.
Request body
{
"registrationToken": "rsk_live_...",
"hostname": "build-host-01",
"maxAgents": 4,
"version": "0.11.0",
"machineId": "A1B2C3D4E5F6",
"region": "us-east-1",
"capabilities": ["code-survival-scan"],
"activeAgentCount": 0,
"status": "idle"
}| Field | Type | Required | Description |
|---|---|---|---|
registrationToken | string | Yes | Project-scoped registration token (rsk_live_* or rsp_live_*) |
hostname | string | Yes | Human-readable host identifier |
maxAgents | number | Yes | Maximum concurrent agent sessions this worker can handle (must be > 0) |
version | string | No | Daemon version string (e.g. "0.11.0") |
machineId | string | No | Stable machine identifier for host deduplication |
region | string | No | Cloud/datacenter region (e.g. "us-east-1") |
capabilities | string[] | No | Capability tokens the worker advertises. Include "code-survival-scan" to receive batch work items. |
activeAgentCount | number | No | Current active session count (used for initial capacity state) |
status | string | No | Initial status hint: "idle", "busy", or "draining" |
Success response (201 Created)
{
"workerId": "wkr_a1b2c3d4e5f6g7h8",
"runtimeJwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"heartbeatIntervalSeconds": 30,
"pollIntervalSeconds": 5
}| Field | Type | Description |
|---|---|---|
workerId | string | Unique worker identifier. Pass as the {id} path parameter on all subsequent worker routes. |
runtimeJwt | string | Signed JWT for authenticating all subsequent worker-protocol requests. See Auth Reference. |
heartbeatIntervalSeconds | number | How often to send heartbeats (default: 30). |
pollIntervalSeconds | number | How often to poll for work (default: 5). |
Error responses
| Status | Condition |
|---|---|
400 Bad Request | Missing or invalid hostname or maxAgents |
401 Unauthorized | registrationToken absent, invalid, revoked, or not bound to a project |
503 Service Unavailable | Worker registry (Redis) unavailable |
Example - curl
curl -s -X POST https://app.rensei.ai/v1/daemon/register \
-H "Content-Type: application/json" \
-d '{
"registrationToken": "rsk_live_...",
"hostname": "build-host-01",
"maxAgents": 4,
"version": "0.11.0"
}' | jq .AF-compatible path
POST /api/workers/register
Custom workers and legacy integrations use this path. The registration token is passed as the Authorization: Bearer header value.
Headers
Authorization: Bearer rsk_live_...
Content-Type: application/jsonRequest body
{
"hostname": "build-host-01",
"capacity": 4,
"version": "1.0.0",
"projects": ["my-project"]
}| Field | Type | Required | Description |
|---|---|---|---|
hostname | string | Yes | Human-readable host identifier |
capacity | number | Yes | Maximum concurrent sessions (must be > 0) |
version | string | No | Worker version |
projects | string[] | No | Linear project name filter. Omit to accept all projects. |
Success response (201 Created)
{
"workerId": "wkr_a1b2c3d4e5f6g7h8",
"runtimeToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"runtimeTokenExpiresAt": "2026-06-03T00:00:00.000Z",
"heartbeatInterval": 30000,
"pollInterval": 5000
}The AF-compatible path returns runtimeToken and intervals in milliseconds (heartbeatInterval, pollInterval). The daemon-native path returns runtimeJwt and intervals in seconds (heartbeatIntervalSeconds, pollIntervalSeconds).
Generating a registration token
Registration tokens are project-scoped API keys of type worker_registration. You create them in the Rensei dashboard under Settings → Projects → API Keys, or via the management API:
curl -s -X POST https://app.rensei.ai/api/org/<orgId>/keys \
-H "Authorization: Bearer rsk_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "build-host-01 registration key",
"keyType": "worker_registration",
"projectIds": ["<projectId>"]
}'Token format: rsk_live_<random> (new unified keys) or rsp_live_<random> (legacy). Both are accepted at registration.
The deprecated POST /api/org/api-keys endpoint emits a Deprecation: true header. Use POST /api/org/[orgId]/keys as the canonical path.
Runtime JWT lifecycle
After registration, store the runtimeJwt (or runtimeToken) securely in memory. All worker-protocol endpoints require this token:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...Token refresh
Refresh the runtime JWT before it expires using:
POST /api/workers/{workerId}/refresh-token
Authorization: Bearer <current runtimeJwt>The response returns a new runtimeToken and updated runtimeTokenExpiresAt. Implement refresh proactively (e.g. 5 minutes before expiry) rather than waiting for a 401.
Rehydration after Redis eviction
If the platform's Redis state is evicted (restart, TTL expiry, memory pressure), worker registration state can disappear even though the SQL record remains. When this happens, calling poll or heartbeat returns a 404 Worker not found. Rather than re-registering, the platform self-heals via rehydrateWorkerFromSql: on a 404 from poll, the platform attempts to reconstruct the Redis entry from the SQL row, and the worker's next poll succeeds without any re-registration round-trip.
Self-hosting operators do not need to handle this explicitly; the af daemon's built-in retry logic covers it. Custom workers should retry a 404 on poll once after a short delay before concluding the worker truly needs to re-register.
Full registration flow
Create a registration token in Settings → Projects → API Keys. Select key type Worker Registration and bind it to the project your agents run under.
Call POST /v1/daemon/register (daemon) or POST /api/workers/register (custom) with the token. Store the returned workerId and runtimeJwt.
Begin the work loop: poll every pollIntervalSeconds seconds and send heartbeats every heartbeatIntervalSeconds seconds. See Poll & Heartbeat.
Refresh the runtime JWT before expiry using POST /api/workers/{workerId}/refresh-token.
Deregister gracefully by calling DELETE /api/workers/{workerId}. The platform re-queues any sessions the worker held.
Related pages
- Auth Reference - runtime JWT claims, three auth modes, legacy fallback
- Poll & Heartbeat - work polling, inbox messages, heartbeat contract
- Session Lifecycle - status transitions, activity reporting
- Worker Credentials - credential snapshot and rotate-stream SSE