HTTP API Reference
Endpoint-level overview of Durabull API resources, capabilities, and key limits.
This is an endpoint overview of the current HTTP API. Paths are relative to the app origin
unless a section specifies a connection-scoped prefix. JSON request bodies need
Content-Type: application/json. URL-encode path parameters such as queue names, job IDs, and Redis keys.
Base URL
REST endpoints use /api. MCP transport uses /mcp, outside that prefix. In development, the
API is at http://localhost:3001; the Vite web origin proxies /api to it.
curl -fsS http://localhost:3001/api/health
curl -fsS http://localhost:3001/api/modeBootstrap and health:
GET /api/healthGET /api/app/configGET /api/app/versionGET /api/modeGET /api/telemetry/statusPOST /api/telemetry/events
Authentication and Session
- Better Auth endpoints under
/api/auth/* - Session snapshot:
GET /api/session
Protected REST routes use the Better Auth session and its active organization. Send the session
cookie with requests made outside the browser. A valid session without an active organization
can receive 403; select or create an organization first. MCP OAuth bearer tokens authenticate
/mcp; they do not replace the REST session flow.
In authless mode, auth endpoints return local session/sign-out behavior and reject unsupported auth actions. All reachable callers have owner access.
Remote App Config
GET /api/app/config is the client bootstrap endpoint used by the web app to load runtime mode and analytics settings.
Behavior:
- Returns
200with JSON config on a successful request; middleware or initialization failures can still produce errors. - Works for both authenticated and unauthenticated requests.
- In authless mode, returns authless/runtime flags from server env and mode.
- If a valid signed-in user is present (non-authless mode), the API attempts to update that user's
lastSignInAttimestamp before returning config.
Response shape:
{
"authless": false,
"envConnections": false,
"persistence": "postgres",
"stateless": false,
"environment": "production",
"posthog": {
"enabled": true,
"key": "phc_***",
"host": "/ingest",
"uiHost": "https://us.posthog.com"
},
"telemetry": {
"enabled": true,
"collectionRequired": true,
"dedupeIdentifiedPosthogEvents": false,
"disclosureUrl": "https://durabull.io/privacy"
}
}Field notes:
authless: whetherDURABULL_AUTHLESSmode is active.envConnections: whether env-driven connection mode is active.persistence: server persistence mode (postgresorpglite).stateless:truewhen running inpglitemode. This is an API mode label; PGlite still persists state on disk.environment:NODE_ENV(development,test, orproduction; defaults todevelopment).posthog.enabled:truewhenPOSTHOG_KEYis set.posthog.key: PostHog project key (ornullwhen disabled). When set, Durabull preserves PostHog's native browser collection and sends manual analytics calls with their original properties to that project.posthog.host: always/ingest(Durabull's reverse-proxied analytics endpoint).posthog.uiHost: PostHog UI host used by the frontend.telemetry.enabled: whether Durabull anonymous/pseudonymous telemetry is active for this runtime.telemetry.collectionRequired: alwaystrueas a disclosure flag, even whentelemetry.enabledis false in development or CI.telemetry.dedupeIdentifiedPosthogEvents:trueonly when the configured PostHog project is Durabull-managed, so anonymous Durabull telemetry can be deduplicated once a user has been identified in the same Durabull-owned PostHog stream.telemetry.disclosureUrl: public documentation for Durabull telemetry collection.
Anonymous Telemetry
Durabull routes sanitized product analytics through POST /api/telemetry/events. Event names remain
the same canonical names used by the app, such as queue_paused, connection_created, and
$pageview. Self-hosted instances re-sanitize payloads before forwarding them to Durabull's
existing cloud API at POST /api/telemetry/collect.
POSTHOG_KEY configures a PostHog destination for the cloud product or instance owner. It does not
disable Durabull anonymous telemetry, and Durabull does not provide a product-level telemetry
opt-out. When a self-hosted owner provides POSTHOG_KEY, they receive the full PostHog browser
stream for their project. Sanitized forwarding to Durabull requires a configured signing secret
and is best-effort; see Environment Variables.
Durabull telemetry includes feature and route usage, safe runtime context, booleans, enums, and aggregate buckets. It does not include Redis URLs, queue names, Redis key names, job data, logs, emails, names, organizations, hostnames, raw URLs, search patterns, stack traces, or raw error messages.
When telemetry is enabled, endpoints return 202 after accepting a sanitized event or batch
into the bounded background queue. When disabled, /events returns 202 with accepted: false
and enabled: false, without enqueueing. If the queue is full, the endpoint returns 503 and
the API emits a stdout telemetry_queue signal with signal: "queue_dropped" and the operational queue name. That signal
contains only queue depth counters and does not include product event properties.
Connection Management
GET /api/connectionsGET /api/connections/:idPOST /api/connectionsPATCH /api/connections/:idDELETE /api/connections/:idPOST /api/connections/test
When DURABULL_ENV_CONNECTIONS=true, create/update/delete routes return 403. The test route is
still available. Connection payloads support name, url, environment, isDefault, prefix,
and allowSelfSignedCerts; set prefix to match the BullMQ application (default bull).
Organization resources
| Method | Path | Purpose |
|---|---|---|
GET | /api/team/members | List organization members |
GET | /api/invitations/:id | Public invitation preview |
GET, PUT | /api/user-settings | Read or update the signed-in user's theme |
GET | /api/alerts/events | List alert events across the organization |
GET | /api/alerts/summary | Organization alert summary |
POST | /api/alerts/events/:eventId/resolve | Resolve an event |
POST, DELETE | /api/alerts/events/:eventId/acknowledge | Acknowledge or clear acknowledgement |
GET, POST | /api/alerts/destinations | List or create reusable notification destinations |
PATCH, DELETE | /api/alerts/destinations/:destinationId | Update or delete a destination |
POST | /api/alerts/destinations/:destinationId/test | Test a destination |
GET, POST | /api/alerts/webhook-destinations | List or create saved webhooks |
PATCH, DELETE | /api/alerts/webhook-destinations/:destinationId | Update or delete a saved webhook |
POST | /api/alerts/webhook-destinations/:destinationId/test | Send a test webhook |
Organization event lists accept offset, limit (maximum 100), status, acknowledged, and
optional connectionId. Member/invitation mutations are provided by the Better Auth organization
endpoints under /api/auth, rather than /api/team.
Linear integration
| Method | Path | Purpose |
|---|---|---|
GET, PUT, DELETE | /api/alerts/integrations/linear | Read, configure defaults, or disconnect |
POST | /api/alerts/integrations/linear/connect | Start OAuth authorization |
GET | /api/alerts/integrations/linear/callback | OAuth callback |
POST | /api/alerts/integrations/linear/test | Validate the connected integration |
GET | /api/alerts/integrations/linear/metadata | Fetch teams and routing metadata |
See Linear Integration for configuration and delivery behavior.
Connection-Scoped Resources
All routes below are under:
/api/c/:connectionId/...
Queues
GET /queuesGET /queues/discoveryPOST /queues/discoveryGET /queues/:queueNameGET /queues/:queueName/metricsPOST /queues/:queueName/pausePOST /queues/:queueName/resumePOST /queues/:queueName/cleanPOST /queues/:queueName/purgePOST /queues/:queueName/obliterateDELETE /queues/:queueNameGET /queues/:queueName/can-delete
Queue discovery scans for <prefix>:*:meta and stores the discovered inventory. POST /queues/discovery
starts a scan and returns 202; add wait=true to wait for completion and receive 200.
Jobs
GET /queues/:queueName/jobsGET /queues/:queueName/jobs/:jobIdGET /queues/:queueName/jobs/:jobId/logsDELETE /queues/:queueName/jobs/:jobId/logsGET /queues/:queueName/jobs/:jobId/stacktracesPOST /queues/:queueName/jobsPOST /queues/:queueName/jobs/retryPOST /queues/:queueName/jobs/removePOST /queues/:queueName/jobs/invokePOST /queues/:queueName/jobs/:jobId/dataPOST /queues/:queueName/jobs/:jobId/retryPOST /queues/:queueName/jobs/:jobId/logs/clearPOST /queues/:queueName/jobs/:jobId/stacktraces/clear
Job listing accepts status, name, jobId, and data search. Without search filters, page,
index cursor (not Redis SCAN), and pageSize paginate results with a maximum page size of 100.
Name and payload searches return all matches for client-side pagination. jobId tries an exact
lookup first; if absent, it returns all matching ID substrings. These searches scan the selected
job states and can be expensive on large queues.
Data edits require { "data": ... } and return 409 while a job is active. Single-job retry accepts
{} or { "data": ... } and requires a failed job. Bulk retry accepts either jobIds (maximum 100)
or statuses (failed, completed, or all), but not both. Retrying completed work can repeat
application side effects.
The two /clear routes accept { "keepMostRecent": N }, defaulting to 0. They permanently
remove older logs or stack traces. DELETE .../logs removes all logs.
POST /queues/:queueName/jobs accepts optional BullMQ job options alongside name and data:
{
"name": "send-welcome-email",
"data": { "userId": "123" },
"delay": 5000,
"priority": 5,
"attempts": 3,
"backoff": {
"type": "exponential",
"delay": 1000
},
"removeOnComplete": 100,
"removeOnFail": true
}Supported option fields match scheduled job template options plus delay: attempts, priority, backoff, removeOnComplete, and removeOnFail.
Scheduled Jobs
GET /scheduled-jobsGET /scheduled-jobs/queue/:queueNamePOST /scheduled-jobs/queue/:queueNameGET /scheduled-jobs/queue/:queueName/:schedulerIdPUT /scheduled-jobs/queue/:queueName/:schedulerIdDELETE /scheduled-jobs/queue/:queueName/:schedulerId
Workers
GET /workers
Metrics
GET /metrics
Native Queue Metrics
Route:
GET /queues/:queueName/metrics
Query parameters:
windowMinutes(optional): convenience range in minutesstart(optional): BullMQ metrics start index (0is newest point)end(optional): BullMQ metrics end index (-1means oldest available)priorities(optional): comma-separated buckets forgetCountsPerPriority(for example1,2,5,10,20,50)includePrometheus(optional):1ortrueto include nativeexportPrometheusMetrics()output
Response includes BullMQ-native telemetry only:
- raw completed/failed metrics buckets + metadata
- queue state (
isPaused,isMaxed, workers/schedulers) - native job counts by status
- queue meta fields (
concurrency,max,duration,maxLenEvents,paused,version) - native rate-limit + global limiter info
- sampled counts per priority bucket
- provider-compat warnings if some introspection calls are unavailable
Connection Metrics API
Route:
GET /metrics
Optional query parameters:
detailed:1ortrueto return full native payload per queuewindowMinutesprioritiesincludePrometheus
Redis Health History
GET /metrics/redis-health
Query parameters: windowMinutes (5–43200, default 1440) and targetPoints (30–1000,
default 480). Returns bounded history, coverage, the latest sample, active thresholds, collection
status, retention days, and the freshness threshold. This is separate from BullMQ throughput metrics.
Connection Alerts
These paths are relative to /api/c/:connectionId:
| Method | Path | Purpose |
|---|---|---|
GET, POST | /alerts/rules | List or create rules |
PATCH, DELETE | /alerts/rules/:ruleId | Update or delete a rule |
POST, DELETE | /alerts/rules/:ruleId/snooze | Snooze or unsnooze a rule |
POST | /alerts/rules/:ruleId/test | Evaluate a rule without creating an incident |
GET | /alerts/events | List events for this connection |
POST | /alerts/events/resolve-bulk | Resolve selected events |
POST | /alerts/events/:eventId/resolve | Resolve one event |
POST, DELETE | /alerts/events/:eventId/acknowledge | Acknowledge or clear acknowledgement |
POST | /alerts/events/:eventId/deliveries/:deliveryId/retry | Retry a failed delivery |
POST | /alerts/webhooks/test | Send a test to a custom webhook |
Snooze requests use { "minutes": N } with 1–10080 minutes. Rules support job failures,
queue thresholds, failure rates, stalled queues, and Redis health conditions. See
Redis Health Alerts and the integration guides.
Redis Keys
GET /redis-keys/searchGET /redis-keys/value/:keyDELETE /redis-keys/:key
Rate Limits and Payload Constraints
- Production general API limits are
600/minute; auth is50/10 seconds; connection tests are10/minuteper limiter key. - Limits are in-memory and per process; test, development, CI, or
DISABLE_RATE_LIMIT=trueskip them. - Request body limit is
1 MiB. - Bulk job actions cap
jobIdsat100per request. - Pagination page sizes are typically capped at
100.
Error Semantics
Common status patterns:
400: validation/input mismatch401: unauthenticated403: forbidden (org scope, env connection mode restrictions)404: missing connection/resource409: state conflict or partial operation failure429: rate limited500: internal error503: service unavailable or telemetry queue full
Queue Purge API (Destructive)
Use this endpoint to remove jobs from a queue by selected statuses, or purge all supported statuses in one operation.
Route:
POST /api/c/:connectionId/queues/:queueName/purge
Required Safety Confirmation
This route is intentionally destructive and always requires exact queue-name confirmation:
- request body
confirmNamemust exactly equal:queueName - mismatch returns
400
Request Body
{
"confirmName": "send-welcome-email",
"statuses": ["active", "failed", "waiting"]
}For all supported statuses (excluding waiting-children and schedulers):
{
"confirmName": "send-welcome-email",
"statuses": ["all"]
}Allowed statuses values:
allwaitingactivedelayedcompletedfailedpausedprioritized
Optional keepMostRecent is an integer from 0 to 1000000 (default 0). It keeps the newest
N jobs across all selected statuses, ordered by finished, processed, or created timestamp.
Operational Behavior
- The API deduplicates requested statuses.
- If
statusescontainsall, it expands to all purgeable statuses. - Without retention, the API cleans in batches of
1000; prioritized jobs are removed individually. - With
keepMostRecent, the API selects the newest jobs to retain, then removes the rest individually. - Locked jobs can remain or produce a conflict. A purge is not atomic; inspect counts after failure.
allexpands to the listed purgeable statuses; it does not includewaiting-childrenor remove schedulers.- A safety cap of
500batches per status is enforced to avoid unbounded loops.- If reached, route returns
409and indicates which status hit the cap.
- If reached, route returns
Success Response
{
"success": true,
"queueName": "send-welcome-email",
"statusesPurged": ["waiting", "active", "failed"],
"keepMostRecent": 0,
"keptMostRecent": 0,
"totalRemoved": 18,
"removedByStatus": {
"waiting": 3,
"active": 10,
"failed": 5
},
"removedJobIdsSample": ["1", "2", "3"]
}Notes:
removedJobIdsSampleis intentionally capped (sample only), not an exhaustive list.removedByStatuscontains counts for statuses actually purged in that request.
Error Responses
400:- queue name confirmation mismatch
- empty/invalid
statusespayload
409:- purge safety cap reached for a specific status
- job removal conflict (some earlier removals may already have succeeded)