Worker Events
Progress, checkpoints, custom events, keepalive, and log ingestion
Worker Events
Endpoints for reporting progress, saving checkpoints, emitting custom events, extending timeouts, and appending logs during job execution.
Report Progress
POST /api/v1/jobs/:jobId/progress
Scope: jobs:progress
Send a progress update for a running job. The body supports:
percent— number from0to100message— non-empty user-facing stringsubProgress(optional) — object keyed by stage name, each withpercentand optionalmessage
Progress events are broadcast to WebSocket subscribers and reset the execution timeout window.
curl -X POST https://emit.run/api/v1/jobs/$JOB_ID/progress \
-H "x-api-key: $EMIT_KEY" \
-H "Content-Type: application/json" \
-d '{
"percent": 65,
"message": "Encoding video",
"subProgress": {
"download": { "percent": 100, "message": "Source fetched" },
"transcode": { "percent": 42, "message": "Pass 1/2" }
}
}'await fetch(`${API}/jobs/${jobId}/progress`, {
method: "POST",
headers: { "x-api-key": key, "Content-Type": "application/json" },
body: JSON.stringify({
percent: 65,
message: "Encoding video",
subProgress: {
download: { percent: 100, message: "Source fetched" },
transcode: { percent: 42, message: "Pass 1/2" },
},
}),
});Checkpoint
POST /api/v1/jobs/:jobId/checkpoint
Scope: jobs:event
Store checkpoint data for resumable work. If the job fails and retries, your worker can read past checkpoints to resume where it left off. Resets the execution timeout.
curl -X POST https://emit.run/api/v1/jobs/$JOB_ID/checkpoint \
-H "x-api-key: $EMIT_KEY" \
-H "Content-Type: application/json" \
-d '{"checkpoint": "processed_frames", "count": 1500, "last_offset": 45000}'await fetch(`${API}/jobs/${jobId}/checkpoint`, {
method: "POST",
headers: { "x-api-key": key, "Content-Type": "application/json" },
body: JSON.stringify({
checkpoint: "processed_frames",
count: 1500,
last_offset: 45000,
}),
});Custom Event
POST /api/v1/jobs/:jobId/event
Scope: jobs:event
Store an arbitrary debug/admin event payload on the job. Does not change job state — only records and broadcasts. Resets the execution timeout.
curl -X POST https://emit.run/api/v1/jobs/$JOB_ID/event \
-H "x-api-key: $EMIT_KEY" \
-H "Content-Type: application/json" \
-d '{"phase":"encoder","host":"worker-3","note":"switched bitrate ladder"}'await fetch(`${API}/jobs/${jobId}/event`, {
method: "POST",
headers: { "x-api-key": key, "Content-Type": "application/json" },
body: JSON.stringify({
phase: "encoder",
host: "worker-3",
note: "switched bitrate ladder",
}),
});Keepalive
POST /api/v1/jobs/:jobId/keepalive
Scope: jobs:keepalive
Extend the job's timeout. Call this periodically for long-running jobs to prevent timeout. Each call resets the timeout window.
curl -X POST https://emit.run/api/v1/jobs/$JOB_ID/keepalive \
-H "x-api-key: $EMIT_KEY"const interval = setInterval(async () => {
await fetch(`${API}/jobs/${jobId}/keepalive`, {
method: "POST",
headers: { "x-api-key": key },
});
}, 60_000);
try {
await doLongRunningWork();
await fetch(`${API}/jobs/${jobId}/complete`, { method: "POST", headers });
} finally {
clearInterval(interval);
}Append Logs
POST /api/v1/jobs/:jobId/logs
Scope: jobs:event
Append one or more log lines to a job. Allowed for any job status so workers can emit diagnostics before ack, during retries, and during teardown.
Supported formats
- JSON (
application/json) — array of entries, or object withlogs: [...] - NDJSON (
application/x-ndjson) — one log entry per line - gzip — send
Content-Encoding: gzipfor JSON or NDJSON batches
Each entry can be a string or an object:
{
"message": "transcode pass started",
"level": "info",
"timestamp": "2026-03-01T09:21:01.120Z",
"source": "worker-a",
"metadata": { "pass": 1 }
}curl -X POST https://emit.run/api/v1/jobs/$JOB_ID/logs \
-H "x-api-key: $EMIT_KEY" \
-H "Content-Type: application/json" \
-d '{
"logs": [
{ "level": "info", "message": "worker boot" },
{ "level": "warn", "message": "fallback codec selected" },
"done with preflight"
]
}'printf '%s\n' \
'{"level":"debug","message":"started"}' \
'{"level":"error","message":"disk full"}' \
| gzip \
| curl -X POST https://emit.run/api/v1/jobs/$JOB_ID/logs \
-H "x-api-key: $EMIT_KEY" \
-H "Content-Type: application/x-ndjson" \
-H "Content-Encoding: gzip" \
--data-binary @-await fetch(`${API}/jobs/${jobId}/logs`, {
method: "POST",
headers: { "x-api-key": key, "Content-Type": "application/json" },
body: JSON.stringify({
logs: [
{ level: "info", message: "worker boot" },
{ level: "debug", message: "download 42%" },
],
}),
});Response:
{
"success": true,
"inserted": 2,
"fromSeq": 1201,
"toSeq": 1202
}