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 — a key created for space A cannot access jobs in space B.
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 events (for resumable work) | POST /jobs/:id/event |
jobs:complete | Mark a job as successfully completed | POST /jobs/:id/complete |
jobs:fail | Mark a job as failed | POST /jobs/:id/fail |
jobs:keepalive | Extend a running job's timeout | POST /jobs/:id/keepalive |
jobs:read:progress | Subscribe to a single job's WebSocket stream (no space-wide feed) | 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:keepalive |
jobs:write | jobs:ack, jobs:progress, jobs:event, jobs:complete, jobs:fail, 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 | Single-job stream only — progress bar without 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 single-job streams — 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, progress and init events are delivered in full, but the data field is stripped from every other event type — this covers result payloads (completed), error details (dead), checkpoint payloads (checkpoint), and retry information including the error and attempt number (retried). Clients still receive the event type and status for every event, so they always know what happened. With jobs:read, you receive full event data for every event type. See WebSockets for details.