Skip to content

REST API Reference

Will Luck edited this page Mar 3, 2026 · 4 revisions

REST API Reference

Docker Sentinel exposes a JSON REST API on the same port as the web dashboard (default :8080). All API endpoints return JSON unless stated otherwise.

Authentication

When authentication is enabled (the default after first-run setup), every API request must include one of:

  • Session cookie, set automatically by the browser after POST /login.
  • API bearer token, created on the My Account page or via POST /api/auth/tokens.
Authorization: Bearer sntkn_abc123...

Token-authenticated requests are CSRF-exempt. Session-authenticated requests must include the CSRF token from the sentinel_csrf cookie in the X-CSRF-Token header.

When authentication is disabled, all endpoints are accessible without credentials.

The webhook endpoint (POST /api/webhook) uses its own secret-based auth instead of sessions/tokens.

Permissions

10 granular permissions grouped into 3 built-in roles:

Permission Admin Operator Viewer
containers.view yes yes yes
containers.update yes yes no
containers.manage yes yes no
containers.approve yes yes no
containers.rollback yes yes no
history.view yes yes yes
logs.view yes yes yes
settings.view yes yes no
settings.modify yes no no
users.manage yes no no

Error Format

All error responses use a consistent JSON envelope:

{"error": "description of the problem"}
Code Meaning
400 Bad request / validation failure
401 Not authenticated
403 Insufficient permissions or self-protection
404 Resource not found
409 Conflict (e.g. setup already complete, username taken)
429 Rate limited (login attempts)
500 Internal server error
502 Registry check failed (upstream error)

Containers

Method Path Permission Description
GET /api/containers containers.view List all containers
GET /api/containers/{name} containers.view Container detail (history, snapshots)
GET /api/containers/{name}/versions containers.view Available semver versions from registry
GET /api/containers/{name}/tags containers.view All tags for the container's image
GET /api/containers/{name}/logs containers.view Container log output
GET /api/containers/{name}/row containers.view HTML partial + stats (for SSE row refresh)
GET /api/containers/{name}/ghcr containers.view GHCR alternative image info
GET /api/stats containers.view Dashboard stat card counts
GET /api/last-scan containers.view Timestamp of last completed scan
GET /api/ghcr/alternatives containers.view All known GHCR alternatives

GET /api/containers

curl -H "Authorization: Bearer $TOKEN" http://localhost:8080/api/containers
[
  {
    "id": "abc123def456...",
    "name": "nginx",
    "image": "nginx:1.27.4",
    "policy": "auto",
    "state": "running",
    "maintenance": false,
    "stack": "webstack"
  }
]

GET /api/containers/{name}

curl -H "Authorization: Bearer $TOKEN" http://localhost:8080/api/containers/nginx
{
  "id": "abc123def456...",
  "name": "nginx",
  "image": "nginx:1.27.4",
  "policy": "auto",
  "state": "running",
  "maintenance": false,
  "history": [
    {
      "timestamp": "2025-01-15T14:30:00Z",
      "container_name": "nginx",
      "type": "update",
      "old_image": "nginx:1.27.3",
      "new_image": "nginx:1.27.4",
      "outcome": "success",
      "duration": 12500000000
    }
  ],
  "snapshots": [
    {
      "container_name": "nginx",
      "timestamp": "2025-01-15T14:29:58Z"
    }
  ]
}

GET /api/containers/{name}/logs

Parameter Type Default Description
lines int 50 Number of lines (max 500)
host string Cluster host ID for remote containers
curl -H "Authorization: Bearer $TOKEN" \
  "http://localhost:8080/api/containers/nginx/logs?lines=100"
{
  "logs": "2025-01-15 10:30:00 ...\n...",
  "lines": 100,
  "remote": false
}

GET /api/stats

Returns lightweight counts for the dashboard stat cards.

curl -H "Authorization: Bearer $TOKEN" http://localhost:8080/api/stats
{
  "total": 25,
  "running": 23,
  "pending": 2
}

GET /api/last-scan

{"last_scan": "2025-01-15T14:00:00Z"}

Returns {"last_scan": null} if no scan has run yet.


Container Actions

All action endpoints accept an optional ?host=<hostID> query parameter to target remote cluster containers. Actions on the Sentinel container itself (identified by sentinel.self=true label) return 403 Forbidden.

Method Path Permission Description
POST /api/containers/{name}/restart containers.manage Restart a container
POST /api/containers/{name}/stop containers.manage Stop a container
POST /api/containers/{name}/start containers.manage Start a container
POST /api/update/{name} containers.update Trigger update (pull + recreate)
POST /api/check/{name} containers.update Check registry for updates
POST /api/containers/{name}/rollback containers.rollback Rollback to last snapshot
POST /api/containers/{name}/switch-ghcr containers.update Migrate from Docker Hub to GHCR
POST /api/containers/{name}/update-to-version containers.update Update to a specific tag
POST /api/scan containers.update Trigger a full scan cycle
POST /api/self-update settings.modify Self-update Sentinel

POST /api/update/{name}

Triggers a container update. If a newer version was found during scanning, the container is recreated with the new image. Runs asynchronously.

curl -X POST -H "Authorization: Bearer $TOKEN" \
  http://localhost:8080/api/update/nginx
{
  "status": "started",
  "name": "nginx",
  "message": "update started for nginx"
}

POST /api/containers/{name}/update-to-version

Recreates a container with an explicit image tag. For Sentinel containers, routes through the self-updater helper.

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"tag": "1.27.5"}' \
  http://localhost:8080/api/containers/nginx/update-to-version
{
  "status": "started",
  "name": "nginx",
  "message": "Updating nginx to nginx:1.27.5"
}

POST /api/check/{name}

Runs a synchronous registry check for a single container. If an update is found, it is added to the queue and SSE events are emitted. Ignored versions are filtered out.

curl -X POST -H "Authorization: Bearer $TOKEN" \
  http://localhost:8080/api/check/nginx

Update available:

{
  "status": "update_available",
  "name": "nginx",
  "message": "Update available for nginx",
  "newer_versions": ["1.27.5"]
}

Up to date:

{
  "status": "up_to_date",
  "name": "nginx",
  "message": "nginx is up to date"
}

POST /api/containers/{name}/rollback

Rolls back to the most recent pre-update snapshot. If a rollback_policy setting is configured (manual or pinned), the container's policy is changed after rollback to prevent the next scan from retrying the same update.

curl -X POST -H "Authorization: Bearer $TOKEN" \
  http://localhost:8080/api/containers/nginx/rollback
{
  "status": "started",
  "name": "nginx",
  "message": "rollback started for nginx"
}

POST /api/scan

Triggers an immediate full scan of all containers. Runs asynchronously.

curl -X POST -H "Authorization: Bearer $TOKEN" \
  http://localhost:8080/api/scan
{"message": "Scan started"}

POST /api/self-update

Triggers a self-update via an ephemeral helper container. Sentinel will restart.

curl -X POST -H "Authorization: Bearer $TOKEN" \
  http://localhost:8080/api/self-update
{
  "status": "started",
  "message": "Self-update to v2.1.0 initiated -- Sentinel will restart shortly"
}

Queue / Approvals

Method Path Permission Description
GET /api/queue containers.view List pending updates (with release notes URLs)
GET /api/queue/count containers.view Pending update count
POST /api/approve/{key} containers.approve Approve and execute a pending update
POST /api/reject/{key} containers.approve Reject and remove a pending update
POST /api/ignore/{key} containers.approve Ignore a specific version

The {key} is the container name for local containers, or hostID::name for remote cluster containers.

GET /api/queue

Returns pending updates enriched with release notes URLs when available.

curl -H "Authorization: Bearer $TOKEN" http://localhost:8080/api/queue
[
  {
    "container_name": "nginx",
    "current_image": "nginx:1.27.4",
    "newer_versions": ["1.27.5"],
    "resolved_current_version": "1.27.4",
    "resolved_target_version": "1.27.5",
    "release_notes_url": "https://github.com/nginx/nginx/releases/tag/1.27.5"
  }
]

GET /api/queue/count

Lightweight count without release notes enrichment.

{"count": 3}

POST /api/approve/{key}

Approves a pending update and triggers the update asynchronously. For remote containers, dispatches to the cluster agent.

curl -X POST -H "Authorization: Bearer $TOKEN" \
  http://localhost:8080/api/approve/nginx
{
  "status": "approved",
  "name": "nginx",
  "message": "update started for nginx"
}

POST /api/ignore/{key}

Ignores the top version in the pending update. That version will be excluded from future queue entries.

curl -X POST -H "Authorization: Bearer $TOKEN" \
  http://localhost:8080/api/ignore/nginx
{
  "status": "ignored",
  "name": "nginx",
  "version": "1.27.5",
  "message": "version 1.27.5 ignored for nginx"
}

POST /api/reject/{key}

Removes the pending update from the queue without ignoring the version. It may reappear on the next scan.

{
  "status": "rejected",
  "name": "nginx",
  "message": "update rejected for nginx"
}

Policy

Method Path Permission Description
POST /api/containers/{name}/policy containers.manage Set policy override
DELETE /api/containers/{name}/policy containers.manage Remove policy override (revert to label)
POST /api/bulk/policy containers.manage Bulk policy change

Valid policies: auto, manual, pinned.

For remote containers, add ?host=<hostID> to scope the override.

POST /api/containers/{name}/policy

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"policy": "manual"}' \
  http://localhost:8080/api/containers/nginx/policy
{
  "status": "ok",
  "name": "nginx",
  "policy": "manual",
  "message": "policy set to manual for nginx"
}

POST /api/bulk/policy

Supports two modes: preview (default) shows what would change, confirm applies the changes. Self-protected containers are blocked.

Preview:

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"containers": ["nginx", "redis"], "policy": "pinned"}' \
  http://localhost:8080/api/bulk/policy
{
  "mode": "preview",
  "changes": [{"name": "nginx", "from": "auto", "to": "pinned"}],
  "blocked": [],
  "unchanged": [{"name": "redis", "reason": "already pinned"}]
}

Confirm:

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"containers": ["nginx", "redis"], "policy": "pinned", "confirm": true}' \
  http://localhost:8080/api/bulk/policy
{
  "mode": "executed",
  "applied": 1,
  "blocked": 0,
  "unchanged": 1
}

Settings

Reading

Method Path Permission Description
GET /api/settings settings.view All settings (env + runtime overrides)
GET /api/about settings.view Version, uptime, stats, channels
GET /api/ratelimits containers.view Registry rate limit status
GET /api/release-sources settings.view Release note source mappings

GET /api/settings

Returns all configuration values merged from environment variables and runtime overrides stored in BoltDB.

curl -H "Authorization: Bearer $TOKEN" http://localhost:8080/api/settings
{
  "SENTINEL_POLL_INTERVAL": "6h",
  "poll_interval": "6h",
  "default_policy": "auto",
  "paused": "false"
}

GET /api/about

{
  "version": "v2.0.1",
  "commit": "a1b2c3d",
  "go_version": "go1.24.4",
  "data_directory": "/data",
  "uptime": "3d 12h 5m",
  "started_at": "2025-01-12T08:00:00Z",
  "poll_interval": "6h",
  "last_scan": "2025-01-15T14:00:00Z",
  "containers": 25,
  "updates_applied": 42,
  "snapshots": 150,
  "channels": [{"name": "Gotify", "type": "gotify"}],
  "registries": ["docker.io", "ghcr.io"]
}

GET /api/ratelimits

{
  "health": "ok",
  "registries": [
    {
      "registry": "docker.io",
      "remaining": 95,
      "limit": 100,
      "reset": "2025-01-15T15:00:00Z"
    }
  ]
}

Modifying

All setting modification endpoints accept JSON request bodies and require settings.modify permission. They return a status message on success.

Method Path Body Description
POST /api/settings/poll-interval {"interval": "6h"} Poll interval (5m to 24h)
POST /api/settings/default-policy {"policy": "auto"} Default policy (auto/manual/pinned)
POST /api/settings/grace-period {"duration": "30s"} Grace period (0 to 10m)
POST /api/settings/pause {"paused": true} Pause/unpause scanning
POST /api/settings/latest-auto-update {"enabled": true} Auto-update :latest containers
POST /api/settings/filters {"patterns": ["test-*"]} Scan exclusion filters
POST /api/settings/image-cleanup {"enabled": true} Remove old images after update
POST /api/settings/image-backup {"enabled": true} Backup images before update
POST /api/settings/schedule {"schedule": "0 3 * * *"} Cron schedule (empty to disable)
POST /api/settings/hooks-enabled {"enabled": true} Toggle lifecycle hooks
POST /api/settings/hooks-write-labels {"enabled": true} Toggle hook label persistence
POST /api/settings/dependency-aware {"enabled": true} Dependency-aware update ordering
POST /api/settings/rollback-policy {"policy": "manual"} Policy after rollback (none/manual/pinned)
POST /api/settings/version-scope {"scope": "minor"} Default version scope
POST /api/settings/dry-run {"enabled": true} Dry-run mode
POST /api/settings/pull-only {"enabled": true} Pull-only mode (no recreate)
POST /api/settings/update-delay {"delay": "1h"} Delay before applying updates
POST /api/settings/show-stopped {"enabled": true} Show stopped containers on dashboard
POST /api/settings/remove-volumes {"enabled": true} Remove volumes on container recreate
POST /api/settings/scan-concurrency {"concurrency": 4} Concurrent registry checks
POST /api/settings/maintenance-window {"window": "..."} Maintenance window
POST /api/settings/stack-order {"order": ["a", "b"]} Dashboard stack display order
POST /api/settings/dashboard-columns {"columns": ["image","status"]} Visible dashboard columns
POST /api/settings/compose-sync {"enabled": true} Compose sync
POST /api/settings/ha-discovery {"enabled": true, ...} HA discovery settings
POST /api/settings/switch-role {"role": "server"} Switch instance role
POST /api/settings/docker-tls {"ca":"..","cert":"..","key":".."} Docker TLS cert paths
POST /api/settings/docker-tls-test (same as above) Test Docker TLS connection
POST /api/settings/general {"key": "web_port", "value": "9090"} General settings (web_port, tls_mode, log_format)
PUT /api/release-sources [{"image_pattern":"..","github_repo":".."}] Replace release note source mappings

Example:

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"interval": "4h"}' \
  http://localhost:8080/api/settings/poll-interval
{
  "status": "ok",
  "interval": "4h0m0s",
  "message": "poll interval updated to 4h0m0s"
}

Notifications

Method Path Permission Description
GET /api/settings/notifications settings.view List channels (secrets masked)
PUT /api/settings/notifications settings.modify Save channels
POST /api/settings/notifications/test settings.modify Send test notification
GET /api/settings/notifications/event-types settings.view Available event types for filtering
GET /api/settings/notifications/templates settings.view Custom notification templates
PUT /api/settings/notifications/templates settings.modify Save a custom template
DELETE /api/settings/notifications/templates/{type} settings.modify Delete template (revert to default)
POST /api/settings/notifications/templates/preview settings.modify Preview template with sample data

PUT /api/settings/notifications

Saves the full channel list. Secrets from previously saved channels are restored if the value is masked in the request.

curl -X PUT -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '[{
    "id": "ch1",
    "name": "Gotify",
    "type": "gotify",
    "enabled": true,
    "settings": {"url": "http://gotify:8080", "token": "abc123"}
  }]' \
  http://localhost:8080/api/settings/notifications
{"status": "ok", "message": "notification settings saved"}

POST /api/settings/notifications/test

Test a specific channel by ID, or the entire notification chain if no ID is provided.

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"id": "ch1"}' \
  http://localhost:8080/api/settings/notifications/test
{"status": "ok", "message": "test notification sent to Gotify"}

PUT /api/settings/notifications/templates

curl -X PUT -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"event_type": "update_available", "template": "Update: {{.ContainerName}}"}' \
  http://localhost:8080/api/settings/notifications/templates

POST /api/settings/notifications/templates/preview

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"event_type": "update_available", "template": "Update: {{.ContainerName}}"}' \
  http://localhost:8080/api/settings/notifications/templates/preview
{"preview": "Update: sentinel-test"}

Per-Container Notification Preferences

Method Path Permission Description
GET /api/containers/{name}/notify-pref settings.view Get notification mode
POST /api/containers/{name}/notify-pref settings.modify Set notification mode
GET /api/settings/container-notify-prefs settings.view All per-container preferences
DELETE /api/notify-states settings.modify Clear all notification dedup states

Valid modes: default, every_scan, digest_only, muted.

For remote containers, add ?host=<hostID>.

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode": "muted"}' \
  http://localhost:8080/api/containers/nginx/notify-pref
{"status": "ok", "mode": "muted"}

Digest

Method Path Permission Description
GET /api/settings/digest settings.view Get digest settings
POST /api/settings/digest settings.modify Save digest settings
POST /api/digest/trigger settings.modify Trigger immediate digest
GET /api/digest/banner containers.view Pending digest banner info
POST /api/digest/banner/dismiss containers.view Dismiss the banner

POST /api/settings/digest

All fields are optional; only provided fields are updated.

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"digest_enabled": true, "digest_time": "09:00", "digest_interval": "24h"}' \
  http://localhost:8080/api/settings/digest

Registry Credentials

Method Path Permission Description
GET /api/settings/registries settings.view List credentials (masked) with rate limit status
PUT /api/settings/registries settings.modify Save credentials
POST /api/settings/registries/test settings.modify Test a credential
DELETE /api/settings/registries/{id} settings.modify Delete a credential

PUT /api/settings/registries

Secrets ending in **** are restored from previously saved values.

curl -X PUT -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '[{"id":"r1","registry":"docker.io","username":"myuser","secret":"dckr_pat_abc"}]' \
  http://localhost:8080/api/settings/registries
{"status": "ok", "message": "registry credentials saved"}

POST /api/settings/registries/test

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"registry":"docker.io","username":"myuser","secret":"dckr_pat_abc"}' \
  http://localhost:8080/api/settings/registries/test
{"success": true, "message": "Credentials valid"}

Hooks

Method Path Permission Description
GET /api/hooks/{container} settings.view List hooks for a container
POST /api/hooks/{container} settings.modify Create or update a hook
DELETE /api/hooks/{container}/{phase} settings.modify Delete a hook

Valid phases: pre-update, post-update. For remote containers, add ?host=<hostID>.

POST /api/hooks/{container}

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"phase":"pre-update","command":["sh","-c","pg_dump > backup.sql"],"timeout":60}' \
  http://localhost:8080/api/hooks/postgres
{
  "container_name": "postgres",
  "phase": "pre-update",
  "command": ["sh", "-c", "pg_dump > backup.sql"],
  "timeout": 60
}

Dependencies

Method Path Permission Description
GET /api/deps containers.view Full dependency graph
GET /api/deps/{container} containers.view Dependencies for one container

GET /api/deps

curl -H "Authorization: Bearer $TOKEN" http://localhost:8080/api/deps
{
  "containers": [
    {"name": "app", "dependencies": ["db"], "dependents": []},
    {"name": "db", "dependencies": [], "dependents": ["app"]}
  ],
  "order": ["db", "app"],
  "has_cycles": false
}

GET /api/deps/{container}

{
  "name": "app",
  "dependencies": ["db"],
  "dependents": []
}

Swarm Services

Available when Docker is running in Swarm mode.

Method Path Permission Description
GET /api/services containers.view List all Swarm services
GET /api/services/{name}/detail containers.view Service detail with tasks
POST /api/services/{name}/update containers.update Update service image
POST /api/services/{name}/rollback containers.rollback Native Swarm rollback
POST /api/services/{name}/scale containers.manage Scale replicas

POST /api/services/{name}/scale

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"replicas": 3}' \
  http://localhost:8080/api/services/web/scale
{"status": "scaled", "previous_replicas": 1}

Maximum 100 replicas. Scaling to 0 saves the previous count so "scale up" can restore it.


Cluster

All cluster endpoints require settings.modify permission.

Method Path Description
GET /api/cluster/hosts List enrolled hosts with connection status
POST /api/cluster/enroll-token Generate enrolment token
DELETE /api/cluster/hosts/{id} Remove a host
POST /api/cluster/hosts/{id}/revoke Revoke a host's certificate
POST /api/cluster/hosts/{id}/pause Pause a host
GET /api/settings/cluster Get cluster settings
POST /api/settings/cluster Save cluster settings

POST /api/cluster/enroll-token

curl -X POST -H "Authorization: Bearer $TOKEN" \
  http://localhost:8080/api/cluster/enroll-token
{"token": "enroll_abc123...", "id": "host-uuid"}

Connectors

Portainer

Method Path Permission Description
GET /api/portainer/endpoints containers.view List Portainer endpoints
GET /api/portainer/endpoints/{id}/containers containers.view Containers for an endpoint
POST /api/settings/portainer-enabled settings.modify Toggle Portainer integration
POST /api/settings/portainer-url settings.modify Set Portainer URL
POST /api/settings/portainer-token settings.modify Set Portainer API token
POST /api/settings/portainer-test settings.modify Test connection

Nginx Proxy Manager

Method Path Permission Description
POST /api/settings/npm-enabled settings.modify Toggle NPM integration
POST /api/settings/npm-url settings.modify Set NPM URL
POST /api/settings/npm-credentials settings.modify Set NPM login credentials
POST /api/settings/npm-test settings.modify Test connection
POST /api/settings/npm-sync settings.modify Sync proxy host mappings
GET /api/settings/npm-mappings settings.view Get cached mappings

GET /api/settings/npm-mappings supports ?grouped=true for mappings grouped by forward host.

Port Configuration

Custom URL overrides per container port. Used for dashboard port link chips.

Method Path Permission Description
GET /api/containers/{name}/port-config containers.view Get port overrides
POST /api/containers/{name}/port-config/{port} settings.modify Set a port override
DELETE /api/containers/{name}/port-config/{port} settings.modify Remove a port override
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://app.example.com"}' \
  http://localhost:8080/api/containers/nginx/port-config/8080

Auth & Users

Public (no auth required)

Method Path Description
POST /login Login (form or JSON)
POST /setup First-run admin setup
POST /logout End session
POST /api/auth/totp/verify Complete 2FA login
POST /api/auth/passkeys/login/begin Begin passkey login
POST /api/auth/passkeys/login/finish Finish passkey login
GET /api/auth/passkeys/available Check if passkeys are configured
GET /api/auth/oidc/login Initiate OIDC login flow
GET /api/auth/oidc/callback OIDC callback handler
GET /api/auth/oidc/available Check if OIDC is configured

Authenticated (any role)

Method Path Description
GET /api/auth/me Current user info and permissions
POST /api/auth/change-password Change own password
GET /api/auth/sessions List own sessions
DELETE /api/auth/sessions/{token} Revoke a session
DELETE /api/auth/sessions Revoke all other sessions
POST /api/auth/tokens Create API bearer token
DELETE /api/auth/tokens/{id} Delete API token
POST /api/auth/passkeys/register/begin Begin passkey registration
POST /api/auth/passkeys/register/finish Finish passkey registration
GET /api/auth/passkeys List own passkeys
DELETE /api/auth/passkeys/{id} Delete a passkey
POST /api/auth/totp/setup Begin 2FA setup (returns secret + QR)
POST /api/auth/totp/confirm Confirm 2FA (returns recovery codes)
POST /api/auth/totp/disable Disable 2FA (requires password)
GET /api/auth/totp/status 2FA status

Admin only (users.manage)

Method Path Description
GET /api/auth/users List all users
POST /api/auth/users Create user
DELETE /api/auth/users/{id} Delete user
POST /api/auth/settings Toggle auth on/off
GET /api/settings/oidc Get OIDC settings
POST /api/settings/oidc Save OIDC settings

POST /login (JSON)

curl -X POST -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"secret"}' \
  http://localhost:8080/login

Success:

{"redirect": "/"}

2FA required:

{"totp_required": true, "totp_token": "pending_abc123"}

POST /api/auth/totp/verify

curl -X POST -H "Content-Type: application/json" \
  -d '{"totp_token":"pending_abc123","code":"123456"}' \
  http://localhost:8080/api/auth/totp/verify
{"redirect": "/"}

POST /api/auth/tokens

curl -X POST -H "Authorization: Bearer $SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "CI Token"}' \
  http://localhost:8080/api/auth/tokens
{
  "id": "tok_abc123",
  "name": "CI Token",
  "token": "sntkn_full_token_shown_once"
}

The plaintext token is returned only once at creation time.

POST /api/auth/users

Valid roles: admin, operator, viewer.

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"username":"operator1","password":"strongpass123","role_id":"operator"}' \
  http://localhost:8080/api/auth/users
{"id": "usr_abc123", "username": "operator1"}

GET /api/auth/me

{
  "id": "usr_abc123",
  "username": "admin",
  "role_id": "admin",
  "permissions": ["containers.view", "containers.update", "..."],
  "auth_enabled": true
}

Webhooks (Inbound)

Method Path Auth Description
POST /api/webhook Webhook secret Receive push events from registries or CI
POST /api/settings/webhook-enabled Session/token Toggle webhooks
POST /api/settings/webhook-secret Session/token Regenerate secret
GET /api/settings/webhook-info Session/token Webhook config (secret masked)

POST /api/webhook

Uses webhook secret authentication (not session/token). Pass the secret as a query parameter or X-Webhook-Secret header.

curl -X POST "http://localhost:8080/api/webhook?secret=your_secret" \
  -H "Content-Type: application/json" \
  -d '{"push_data":{"tag":"latest"},"repository":{"repo_name":"myuser/myapp"}}'
{
  "status": "accepted",
  "image": "myuser/myapp",
  "tag": "latest",
  "source": "dockerhub"
}

Supported payload formats: Docker Hub, GHCR, and generic. Unrecognised payloads trigger a full scan as a fallback.


History & Logs

Method Path Permission Description
GET /api/history history.view Recent update history
GET /api/history/export history.view Export all history
GET /api/logs logs.view Activity log entries

GET /api/history

Parameter Type Default Description
limit int 50 Max records (up to 200)
before string RFC3339 timestamp for cursor-based pagination
curl -H "Authorization: Bearer $TOKEN" \
  "http://localhost:8080/api/history?limit=10"
[
  {
    "timestamp": "2025-01-15T14:30:00Z",
    "container_name": "nginx",
    "type": "update",
    "old_image": "nginx:1.27.3",
    "new_image": "nginx:1.27.4",
    "outcome": "success",
    "duration": 12500000000,
    "host_id": "",
    "host_name": ""
  }
]

GET /api/history/export

Parameter Type Default Description
format string json json or csv
curl -H "Authorization: Bearer $TOKEN" -o history.csv \
  "http://localhost:8080/api/history/export?format=csv"

CSV columns: timestamp, container, type, old_image, new_image, outcome, duration_s, error, host_id, host_name.


Images

Method Path Permission Description
GET /api/images containers.view List all Docker images
POST /api/images/prune containers.manage Remove dangling images
DELETE /api/images/{id} containers.manage Remove a specific image
curl -X POST -H "Authorization: Bearer $TOKEN" \
  http://localhost:8080/api/images/prune

Config Export / Import

Method Path Permission Description
GET /api/config/export settings.modify Download full config backup
POST /api/config/import settings.modify Import config from backup (max 5 MB)
GET /api/grafana-dashboard settings.modify Download Grafana dashboard JSON

GET /api/config/export

By default, secrets are replaced with ***REDACTED***. Add ?secrets=true to include them.

curl -H "Authorization: Bearer $TOKEN" -o sentinel-config.json \
  http://localhost:8080/api/config/export
{
  "version": "1",
  "exported_at": "2025-01-15T14:00:00Z",
  "settings": {"poll_interval": "6h", "default_policy": "auto"},
  "notifications": [],
  "registries": []
}

POST /api/config/import

Redacted values (***REDACTED***) are skipped. Unknown setting keys are rejected.

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d @sentinel-config.json \
  http://localhost:8080/api/config/import
{
  "message": "Imported 15 settings, 2 notification channels, 1 registry credentials",
  "settings_imported": 15,
  "notifications_imported": 2,
  "registries_imported": 1,
  "redacted_skipped": 3,
  "warnings": []
}

Metrics

Method Path Auth Description
GET /metrics None Prometheus metrics

Standard Prometheus exposition format. Only available when SENTINEL_METRICS=true is set.


SSE (Server-Sent Events)

Method Path Permission Description
GET /api/events containers.view Real-time event stream

The SSE endpoint keeps a long-lived connection open and pushes events as they occur. The web dashboard uses this for live updates without polling.

Connecting

curl -N -H "Authorization: Bearer $TOKEN" http://localhost:8080/api/events

On connect, the server sends an initial event:

event: connected
data: {}

Event Types

Event Type Fired When
container_update Update started, completed, or failed
container_state Container started, stopped, or restarted
queue_change Queue item added or removed
scan_complete Full scan finished
policy_change Policy override changed
digest_ready Digest notification ready
settings_change Settings modified
rate_limits Rate limit status changed
ghcr_check GHCR alternative detected
service_update Swarm service update event
cluster_host Cluster host connected, disconnected, or enrolled

Event Payload

All events share a common JSON structure:

{
  "type": "container_update",
  "container_name": "nginx",
  "message": "Update available for nginx",
  "host_id": "",
  "host_name": "",
  "timestamp": "2025-01-15T14:30:00Z"
}

host_id and host_name are populated for cluster events. They are empty for local events.

Example Stream

event: connected
data: {}

event: scan_complete
data: {"type":"scan_complete","message":"Scan complete","timestamp":"2025-01-15T14:00:00Z"}

event: container_update
data: {"type":"container_update","container_name":"nginx","message":"Update available","timestamp":"2025-01-15T14:00:01Z"}

event: queue_change
data: {"type":"queue_change","container_name":"nginx","message":"Added to queue","timestamp":"2025-01-15T14:00:01Z"}

Clone this wiki locally