emit.run

Callbacks

Webhooks, Slack notifications, and HTTP push for worker wake

Callbacks

Jobs can optionally specify a callbackUrl when created. When the job reaches a terminal state — completed, dead, or killed — the system sends a POST request to that URL.

When callbacks fire

Terminal stateTrigger
completedWorker calls the complete endpoint
deadJob fails and has no retries remaining
killedJob is force-stopped via the kill endpoint

Callbacks do not fire on intermediate failures that will be retried.

Callback payload

The POST body is JSON:

{
  "jobId": "01JLQX...",
  "spaceId": "01JLQ...",
  "name": "process-video",
  "status": "completed",
  "attemptNumber": 0,
  "result": { "output_url": "s3://bucket/output.mp4" },
  "timestamp": "2025-02-24T10:35:00.000Z"
}

For dead jobs, result contains the final error:

{
  "jobId": "01JLQX...",
  "spaceId": "01JLQ...",
  "name": "process-video",
  "status": "dead",
  "attemptNumber": 3,
  "result": { "error": "FFmpeg exited with code 1: out of memory" },
  "timestamp": "2025-02-24T10:42:00.000Z"
}

For killed jobs, result includes the kill metadata:

{
  "jobId": "01JLQX...",
  "spaceId": "01JLQ...",
  "name": "process-video",
  "status": "killed",
  "attemptNumber": 1,
  "result": { "reason": "manual stop" },
  "timestamp": "2025-02-24T10:36:00.000Z"
}

Request headers

Every callback request includes:

HeaderValue
Content-Typeapplication/json
User-Agentemit.run/1.0

Any headers you set in callbackHeaders at job creation time are merged in:

{
  "callbackUrl": "https://emit.run/webhooks/jobs",
  "callbackHeaders": {
    "Authorization": "Bearer whsec_abc123"
  }
}

Delivery tracking

Callback delivery is recorded as a job event:

Event typeMeaning
callback_sentRequest succeeded with 200 OK. Event data includes url, statusCode, and retryAttempt (0 on first try).
callback_failedRequest send failed, or callback returned non-200. Event data includes url, error, statusCode, optional responseBody, retryAttempt, willRetry, and optional nextRetryAt.

Inspect these events via GET /api/v1/jobs/:jobId in the events array.

Retry behavior

Callback delivery retries are automatic for failed delivery.

  • Retries use exponential backoff (capped) for up to 50 retry attempts in a 24-hour window.
  • Retries happen when the request cannot be sent (for example DNS/TCP/TLS/network errors) or when the callback responds with any non-200 status.
  • Only 200 OK is treated as delivered (callback_sent).
  • callback_failed events include retry metadata (retryAttempt, willRetry, nextRetryAt) so you can observe retry progress.

Slack Notifications

Each space can configure a Slack Incoming Webhook in dashboard settings.

Setup: Dashboard → Space → Settings → Slack Webhook

EventWhen it fires
createdJob is accepted
startedWorker acknowledges the job
completedJob completes successfully
failedJob failure is recorded (including retriable failures)
deadFinal failure after retries are exhausted
killedJob is force-stopped

Slack delivery is best-effort and asynchronous — job processing does not fail if Slack is unavailable.


HTTP Push (Worker Wake)

Spaces can configure an HTTP push endpoint for serverless worker wake signals.

Setup: Dashboard → Space → Settings → HTTP Push (Worker Wake)

When enabled, emit.run sends a lightweight webhook whenever a job becomes pending due to creation, schedule trigger, retry, or delivery timeout requeue.

{
  "event": "job.pending",
  "source": "emit.run",
  "reason": "created",
  "timestamp": "2025-03-02T01:23:45.000Z",
  "spaceId": "01SPACE...",
  "jobId": "01JOB...",
  "jobName": "send-email",
  "status": "pending",
  "attemptNumber": 0,
  "claim": {
    "method": "POST",
    "path": "/api/v1/jobs/01JOB.../claim",
    "requiredScope": "jobs:poll"
  }
}

Push is best-effort and asynchronous. You can limit pushes to specific job names and add custom headers in space settings.

On this page