Authentication
How to authenticate with the emit.run API
Authentication
All API requests authenticate with an API key passed via request header.
API Keys
API keys authenticate all job-related operations. Pass the key via either header:
x-api-key: emit_YOUR_KEYAuthorization: Bearer emit_YOUR_KEYKeys are scoped to a single space by default — space scoping is enforced when a key includes a spaceId in its metadata. Avoid unscoped keys unless you explicitly need cross-space access.
Keys are prefixed with emit_ and the full key is only shown once at creation time.
Rate Limits
API keys are rate-limited to 1000 requests per second. If you exceed this, you'll receive a 429 response.
Scopes Reference
Each API key has one or more scopes that control what it can do. Scopes are checked on every request — if your key is missing a required scope, you'll get a 403 with the message Missing required scope: <scope>.
Granular Scopes
| Scope | Description | Used by |
|---|---|---|
jobs:create | Create new jobs in a space | POST /spaces/:id/jobs |
jobs:read | List jobs, get job details and events | GET /spaces/:id/jobs, GET /jobs/:id |
jobs:poll | Claim pending jobs from the dispatch queue | POST /spaces/:id/jobs/poll |
jobs:ack | Acknowledge receipt of a polled job | POST /jobs/:id/ack |
jobs:progress | Send in-progress updates for a running job | POST /jobs/:id/progress |
jobs:event | Publish checkpoint and custom events | POST /jobs/:id/checkpoint, POST /jobs/:id/event |
jobs:complete | Mark a job as successfully completed | POST /jobs/:id/complete |
jobs:fail | Fail a job (retry or mark dead) | POST /jobs/:id/fail |
jobs:kill | Force-stop a job and mark it as killed | POST /jobs/:id/kill |
jobs:keepalive | Extend a running job's timeout | POST /jobs/:id/keepalive |
jobs:read:progress | Read job progress via API or a single job's WebSocket stream only | GET /jobs/:id/progress, GET /realtime/:id |
Shorthand Scopes
These expand to multiple granular scopes for convenience. You can use them when creating tokens, and they'll be recognized during authorization.
| Shorthand | Expands to |
|---|---|
jobs:worker | jobs:read, jobs:poll, jobs:ack, jobs:progress, jobs:event, jobs:complete, jobs:fail, jobs:kill, jobs:keepalive, jobs:read:progress |
jobs:write | jobs:ack, jobs:progress, jobs:event, jobs:complete, jobs:fail, jobs:kill, jobs:keepalive |
jobs:worker is the most common — it includes everything a worker needs to poll, process, and report results.
Recommended Token Setups
| Role | Scopes | Why |
|---|---|---|
| Producer | jobs:create | Can only submit jobs, nothing else |
| Worker | jobs:worker | Full worker lifecycle: poll → ack → progress → complete/fail |
| Dashboard / monitor | jobs:read | REST read + both WS streams (job and space-wide) |
| Producer + monitor | jobs:create, jobs:read | Submit jobs and watch them complete |
| Third-party client | jobs:read:progress | Progress-only stream for a single job (no space-level access) |
| Minimal worker | jobs:poll, jobs:ack, jobs:complete, jobs:fail | Worker without progress/event/keepalive |
WebSocket Auth
WebSocket connections authenticate via ?token= query parameter — required on all realtime endpoints:
wss://emit.run/api/v1/realtime/:jobId?token=emit_YOUR_KEY| Endpoint | Minimum scope |
|---|---|
GET /realtime/:jobId | jobs:read:progress |
GET /realtime/spaces/:spaceId | jobs:read |
jobs:read:progress only grants access to job progress (API + single-job stream) — it cannot connect to the space-wide stream. This makes it safe to embed in frontend code for client-facing progress bars.
Space scoping is enforced on both endpoints: a space-scoped token can only subscribe to its own space's stream and to jobs within that space. Connecting to a job in a different space returns 403.
Your scope also controls what data you receive. With jobs:read:progress, the stream includes init (last known progress, if any), progress, and a completed signal without payload data. Other event types are not delivered. With jobs:read, you receive the full event stream and all payloads. See WebSockets for details.