DrydockDrydock
API

REST API

Access Drydock state and trigger actions using the HTTP REST API.

You can access drydock state and trigger actions using the HTTP REST API.

By default, the API is enabled and exposed on port 3000. You can override this behaviour using environment variables.

API Versioning

Starting in v1.4.0, the canonical API base path is /api/v1/*. The unversioned /api/* path remains as a backward-compatible alias during migration.

PathStatusDescription
/api/v1/*CanonicalVersioned API path — use this for new integrations
/api/*Deprecated aliasPlanned for removal in v2.0.0

Both paths return identical responses. Third-party integrations should migrate to /api/v1/* at their convenience.

Error Contract

All error responses (HTTP 4xx/5xx) return a consistent JSON structure:

{
  "error": "Container not found"
}
FieldTypeDescription
errorstringHuman-readable error message (derived from the HTTP status when not explicitly set)
detailsobjectOptional contextual metadata (present only when additional context is available)

Authentication

When authentication is enabled, all API endpoints require a valid session (cookie-based via Basic or OIDC login). For cross-domain OIDC providers, keep DD_SERVER_COOKIE_SAMESITE=lax (default) unless you have a specific same-site policy requirement.

The webhook endpoints use a separate Bearer token authentication.

Destructive action confirmation

Some destructive endpoints require an explicit confirmation header:

X-DD-Confirm-Action: <token>

If the header is missing or does not match the expected token, the API responds with 428 Precondition Required.

EndpointMethodRequired header
/api/containers/:id/rollbackPOSTX-DD-Confirm-Action: container-rollback
/api/containers/:idDELETEX-DD-Confirm-Action: container-delete

Endpoint overview

CategoryEndpointsDescription
AppGET /api/app, GET /api/serverApplication info, server configuration, security runtime
ContainersGET /api/containers, POST, PATCH, DELETEContainer state, actions, update policy, security
AgentsGET /api/agentsRemote agent status and logs
LogsGET /api/logApplication log entries
RegistriesGET /api/registriesRegistry configurations
StoreGET /api/storeData store info
TriggersGET /api/triggersTrigger configurations
WatchersGET /api/watchersWatcher configurations

Additional endpoints

EndpointMethodDescription
/api/openapi.jsonGETOpenAPI 3.1.0 specification (machine-readable API docs)
/healthGETHealth check (returns 200 when healthy)
/metricsGETPrometheus metrics (optional auth via DD_SERVER_METRICS_AUTH)
/api/events/uiGETServer-Sent Events for real-time UI updates
/api/auditGETAudit trail (paginated, filterable by action/container/date)
/api/notificationsGET, PATCH /:idNotification rules (per-event enable/disable and trigger assignments)
/api/settingsGET, PATCHUI settings (internetless mode; PUT compatibility alias is deprecated)
/api/serverGETServer configuration and compatibility info (see App API)
/api/server/security/runtimeGETSecurity tools availability (see App API)
/api/containers/groupsGETContainer groups (by stack/compose project)
/api/webhook/watchPOSTWebhook — trigger watch on all containers
/api/webhook/watch/:containerNamePOSTWebhook — watch specific container
/api/webhook/update/:containerNamePOSTWebhook — update specific container
See each sub-page for detailed request/response examples.

Command endpoint convention

Some endpoints are intentional action commands and use POST under a resource path (for example container watch/scan/reveal). These are RPC-style operations rather than CRUD updates.

Notification rules

Notification rules control which events trigger notifications and which triggers receive them. Five default rules are created automatically.

Get all notification rules

curl http://drydock:3000/api/notifications

{
  "data": [
    {
      "id": "update-available",
      "name": "Update Available",
      "description": "When a container has a new version",
      "enabled": true,
      "triggers": []
    },
    {
      "id": "update-applied",
      "name": "Update Applied",
      "description": "After a container is successfully updated",
      "enabled": true,
      "triggers": []
    },
    {
      "id": "update-failed",
      "name": "Update Failed",
      "description": "When an update fails or is rolled back",
      "enabled": true,
      "triggers": []
    },
    {
      "id": "security-alert",
      "name": "Security Alert",
      "description": "Critical/High vulnerability detected",
      "enabled": true,
      "triggers": []
    },
    {
      "id": "agent-disconnect",
      "name": "Agent Disconnected",
      "description": "When a remote agent loses connection",
      "enabled": false,
      "triggers": []
    }
  ],
  "total": 5
}

Response fields

FieldTypeDescription
dataarrayList of notification rules
totalintegerNumber of rules returned
data[].idstringRule identifier (e.g. update-available, security-alert)
data[].namestringHuman-readable rule name
data[].descriptionstringWhat this rule covers
data[].enabledbooleanWhether the rule is active
data[].triggersstring[]Trigger IDs that receive this notification (empty = all triggers)

Update a notification rule

Update the enabled status and/or triggers list for a rule. Only the fields you include are changed.

curl -X PATCH http://drydock:3000/api/notifications/update-available \
  -H 'Content-Type: application/json' \
  -d '{"enabled": true, "triggers": ["slack.alerts", "ntfy.one"]}'

Returns 200 with the updated rule, 400 if the body is invalid or a trigger ID is not recognized, or 404 if the rule ID does not exist.

Audit trail

Returns paginated audit log entries for container lifecycle events, updates, rollbacks, webhooks, and more.

Get audit entries

curl "http://drydock:3000/api/audit?offset=0&limit=25&action=update-applied&container=homeassistant"

{
  "data": [
    {
      "id": "a1b2c3d4-...",
      "timestamp": "2024-12-01T10:01:30.000Z",
      "action": "update-applied",
      "containerName": "homeassistant",
      "containerImage": "homeassistant/home-assistant",
      "fromVersion": "2024.11.3",
      "toVersion": "2024.12.0",
      "triggerName": "docker.local",
      "status": "success",
      "details": ""
    }
  ],
  "total": 42,
  "limit": 25,
  "offset": 0,
  "hasMore": true
}

Query parameters

ParameterTypeDefaultDescription
offsetinteger0Number of entries to skip
limitinteger50Results per page (max 200)
actionstringFilter by action type
containerstringFilter by container name
fromstringISO 8601 date -- only entries on or after this timestamp
tostringISO 8601 date -- only entries on or before this timestamp

Action types

update-available, update-applied, update-failed, container-update, security-alert, agent-disconnect, container-added, container-removed, rollback, preview, container-start, container-stop, container-restart, webhook-watch, webhook-watch-container, webhook-update, hook-configured, hook-pre-success, hook-pre-failed, hook-post-success, hook-post-failed, auto-rollback, auth-login

Server-Sent Events (SSE)

The /api/events/ui endpoint provides real-time push notifications to the UI via Server-Sent Events.

Connect

curl -N -H "Accept: text/event-stream" http://drydock:3000/api/events/ui

Connection limits: max 10 per IP, max 10 per session. Returns 429 when exceeded.

Event types

EventPayloadDescription
dd:connected{ "clientId": "...", "clientToken": "..." }Sent immediately on connection. The clientToken is used for self-update acknowledgment.
dd:heartbeat{}Sent every 15 seconds to keep the connection alive
dd:container-addedContainer objectA new container was discovered by a watcher
dd:container-updatedContainer objectAn existing container's state changed (new tag, status, scan result)
dd:container-removedContainer objectA container was removed
dd:scan-started{ "containerId": "..." }A security scan started for a container
dd:scan-completed{ "containerId": "...", "status": "..." }A security scan finished
dd:self-update{ "opId": "...", "requiresAck": bool, "ackTimeoutMs": int, "startedAt": "..." }Drydock is updating its own container. If requiresAck is true, the UI should POST an acknowledgment before the timeout.
dd:agent-connectedAgent payloadA remote agent connected to the controller
dd:agent-disconnectedAgent payloadA remote agent disconnected

Self-update acknowledgment

When a dd:self-update event has requiresAck: true, the UI must POST an acknowledgment before the timeout expires. The clientId and clientToken are provided in the initial dd:connected event.

curl -X POST http://drydock:3000/api/events/ui/self-update/op-abc123/ack \
  -H 'Content-Type: application/json' \
  -d '{"clientId": "client-1", "clientToken": "tok-xyz"}'
StatusResponseDescription
202{ "status": "accepted", "operationId": "..." }Acknowledgment recorded
202{ "status": "ignored", "operationId": "..." }No pending ack for this operation
400{ "error": "..." }Missing required field (operationId, clientId, or clientToken)
403{ "status": "rejected", "operationId": "..." }Invalid token, mismatched client, or client not bound to operation

SSE message format

event: dd:container-updated
data: { "id": "31a61a...", "name": "homeassistant", ... }

Settings

Persistent UI preferences stored in the drydock database.

Get settings

curl http://drydock:3000/api/settings

{
  "internetlessMode": false
}

Update settings

curl -X PATCH http://drydock:3000/api/settings \
  -H 'Content-Type: application/json' \
  -d '{"internetlessMode": true}'

{
  "internetlessMode": true
}
FieldTypeDefaultDescription
internetlessModebooleanfalseWhen enabled, disables registry icon lookups and other external requests

Returns 200 with the updated settings, or 400 if the body is invalid. PUT /api/settings is still accepted as a temporary compatibility alias but is deprecated.

Container groups

Returns containers grouped by stack or group label. Group priority: dd.group > wud.group > com.docker.compose.project > ungrouped.

curl http://drydock:3000/api/containers/groups

{
  "data": [
    {
      "name": "monitoring",
      "containers": [
        {
          "id": "31a61a...",
          "name": "prometheus",
          "displayName": "Prometheus",
          "updateAvailable": false
        },
        {
          "id": "e5f6a7...",
          "name": "grafana",
          "displayName": "Grafana",
          "updateAvailable": true
        }
      ],
      "containerCount": 2,
      "updatesAvailable": 1
    },
    {
      "name": null,
      "containers": [
        {
          "id": "abc123...",
          "name": "standalone-app",
          "displayName": "standalone-app",
          "updateAvailable": false
        }
      ],
      "containerCount": 1,
      "updatesAvailable": 0
    }
  ],
  "total": 2
}

Response fields

FieldTypeDescription
dataarrayList of container groups
totalintegerNumber of groups returned
data[].namestring | nullGroup name (null for ungrouped containers)
data[].containersarrayList of containers with id, name, displayName, updateAvailable
data[].containerCountintegerNumber of containers in the group
data[].updatesAvailableintegerNumber of containers with a pending update

Authentication routes

When authentication is enabled, these endpoints manage the login flow. Auth routes are mounted at /auth (not /api/auth).

Get available strategies

Returns the list of configured authentication strategies. This endpoint is unauthenticated so the login screen can render.

curl http://drydock:3000/auth/strategies

A legacy alias is available at GET /api/auth/methods (rate-limited).

Login

Authenticate with credentials. The response sets a session cookie.

curl -X POST http://drydock:3000/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"username": "admin", "password": "..."}'

Get current user

Returns the currently authenticated user. Requires a valid session.

curl http://drydock:3000/auth/user

Logout

End the current session.

curl -X POST http://drydock:3000/auth/logout

When the active auth strategy exposes an OIDC end-session URL, the response includes logoutUrl so the UI can complete IdP logout. If logoutUrl is missing, logout is local-session-only.

Remember me

Store a remember-me preference for the current authenticated session.

curl -X POST http://drydock:3000/auth/remember \
  -H 'Content-Type: application/json' \
  -d '{"remember": true}'

OpenAPI

Machine-readable API documentation is available as an OpenAPI 3.1.0 specification.

curl http://drydock:3000/api/openapi.json

The spec covers all API endpoints with request/response schemas. You can import the URL into tools like Swagger UI, Redoc, or Postman for interactive exploration.

On this page