Files
dashcaddy/API-SURFACE.md
T
Hermes b4e09af712 [grade=A urn:ump:swcz3quualvlmdanpqm5v46cr6zkazes7erbftk6rj3jxv6ip4fa] docs(DC-170): changelog rebuild, version sync, API-SURFACE regen (audit batch 7)
Customer-facing professionalism tier (AUDIT-2026-10-27.md findings 34-39):

- CHANGELOG.md rebuilt to Keep-a-Changelog: ONE Unreleased section, the
  2026-08-12 hardening sprint folded into 1.17.0 (no v1.16.0 tag exists,
  verified via git tag -l), ALL 7 judge-grade/URN lines moved out of
  customer copy into RELEASE-EVIDENCE-internal.md, missing DC-166/169
  entries added, full DC-170 sweep entry written, DC-171 DNS-parity
  ticket recorded, date order strictly descending across all 22
  sections (1.1.5 restored with its true content after the re-sort ate
  the heading), compare-link chain filled (Unreleased from v1.17.0,
  1.17.0 from v1.14.6-patched, 18 missing version links added)
- VERSION 1.15.0 -> 1.17.0 + openapi.yaml 1.15.0 -> 1.17.0 (three-way
  drift closed: VERSION=package.json=openapi; start.sh build stamps
  single-sourced)
- README: quickstart endpoints rewritten against the live router (the
  fictional /api/caddy/{config,reload} section replaced with the real
  /api/v1/caddy/* routes from routes/sites.js), 50+ -> 78 templates
  (proven in VERIFY-OUTPUT.txt via require of src/docker/app-templates),
  version badge 1.17.0, yourusername links -> sami7777, roadmap
  reconciled with shipped features (multi-user DC-048, DNS UI DC-166,
  backup automation marked shipped), verification note scoped to the
  MCP drift gate's actual coverage
- API-SURFACE.md regenerated: 443 handler rows / 368 unique paths / 441
  unique operations / 88 public rows, Known Limitations section (static
  extraction, line-oriented, may omit multiline/computed/chained
  registrations), exact duplicate registrations with file:line
- VERIFY-OUTPUT.txt: verbatim command/output transcript proving all
  version + count claims (sha256 of the generated doc recorded and
  matching)
- state-manager test mock extended for the atomic tmp+rename contract

Judge rounds: r1 D -> r2 D -> r3 D -> r4 D -> r5 C -> r6 C -> r7 C ->
r8 C -> r9 C -> r10 A (each round fixed blockers in-lane; no bypasses).
r10 independently reproduced all counts and the generated doc hash
against the live repository.
2026-10-29 02:29:07 -07:00

838 lines
53 KiB
Markdown

# DashCaddy API Surface
> **Handler rows (method+path per route file):** 443
> **Public rows (matched by PUBLIC_ROUTES allowlist):** 88
> **Methodology:** statically derived from route declarations + the mount/composition map in the generator (lazy and composed mounts encoded from src/app.js with cited line refs). Code-derived counts are authoritative for what is DECLARED; boot-time verification lives in the MCP route-existence drift gate.
> **Files scanned:** 81
> **Generated by:** `dashcaddy/scripts/api-surface-extract.py`
## Auth & Rate Limit Model
- `public` = in `PUBLIC_ROUTES` (`src/utilities/middleware.js`), bypasses TOTP
- `protected` = requires TOTP session OR API key/JWT
- CSRF: state-changing requests need `X-CSRF-Token` matching `csrf_token` cookie
- Rate limits: GENERAL 1000/15m, STRICT 20/15m (auth keys), TOTP 10/15m
## Summary by Area
| Area | Routes | Public | Protected |
|---|---:|---:|---:|
| Other | 135 | 13 | 122 |
| Authentication | 34 | 18 | 16 |
| App catalog | 28 | 0 | 28 |
| DNS | 20 | 0 | 20 |
| Tailscale | 20 | 20 | 0 |
| Monitoring | 19 | 3 | 16 |
| Backups | 18 | 0 | 18 |
| Logs | 17 | 0 | 17 |
| Updates | 16 | 6 | 10 |
| Configuration | 13 | 9 | 4 |
| Health | 13 | 3 | 10 |
| Services | 12 | 4 | 8 |
| Containers (lifecycle) | 11 | 0 | 11 |
| Core / system | 9 | 6 | 3 |
| Dependencies | 8 | 0 | 8 |
| Notifications | 8 | 0 | 8 |
| App recipes | 8 | 0 | 8 |
| Docker resources | 7 | 0 | 7 |
| Caddy / sites | 7 | 0 | 7 |
| Certificate authority | 6 | 3 | 3 |
| Updates / workflows | 6 | 0 | 6 |
| Auto-restart | 5 | 0 | 5 |
| OpenClaw integration | 5 | 0 | 5 |
| Config drift | 4 | 0 | 4 |
| Licensing | 4 | 2 | 2 |
| File browser | 3 | 0 | 3 |
| Theming | 3 | 1 | 2 |
| Service credentials | 2 | 0 | 2 |
| Events | 2 | 0 | 2 |
| **TOTAL** | **443** | **88** | **355** |
## Other
_135 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| GET | `/api/v1/ai/capabilities` | protected | GENERAL (1000/15m) | `routes/ai-intent.js:681` |
| POST | `/api/v1/ai/intent` | protected | GENERAL (1000/15m) | `routes/ai-intent.js:569` |
| DELETE | `/api/v1/ai/settings` | protected | GENERAL (1000/15m) | `routes/ai-intent.js:642` |
| GET | `/api/v1/ai/settings` | protected | GENERAL (1000/15m) | `routes/ai-intent.js:597` |
| PUT | `/api/v1/ai/settings` | protected | GENERAL (1000/15m) | `routes/ai-intent.js:614` |
| POST | `/api/v1/ai/settings/test` | protected | GENERAL (1000/15m) | `routes/ai-intent.js:652` |
| DELETE | `/api/v1/audit-logs` | protected | GENERAL (1000/15m) | `routes/audit-log.js:176` |
| GET | `/api/v1/audit-logs` | protected | GENERAL (1000/15m) | `routes/audit-log.js:63` |
| GET | `/api/v1/audit-logs/actions` | protected | GENERAL (1000/15m) | `routes/audit-log.js:148` |
| POST | `/api/v1/billing/checkout` | public | GENERAL (1000/15m) | `routes/billing.js:143` |
| GET | `/api/v1/billing/lookup/:sessionId` | public | GENERAL (1000/15m) | `routes/billing.js:184` |
| GET | `/api/v1/caddy/upstreams` | protected | GENERAL (1000/15m) | `routes/caddy-upstreams.js:66` |
| POST | `/api/v1/caddy/upstreams/:host/mute` | protected | GENERAL (1000/15m) | `routes/caddy-upstreams.js:120` |
| POST | `/api/v1/caddy/upstreams/:host/unmute` | protected | GENERAL (1000/15m) | `routes/caddy-upstreams.js:133` |
| GET | `/api/v1/caddy/upstreams/incidents` | protected | GENERAL (1000/15m) | `routes/caddy-upstreams.js:80` |
| POST | `/api/v1/caddy/upstreams/mute` | protected | GENERAL (1000/15m) | `routes/caddy-upstreams.js:107` |
| POST | `/api/v1/caddycode/generate` | protected | GENERAL (1000/15m) | `routes/caddycode.js:244` |
| GET | `/api/v1/caddycode/templates` | protected | GENERAL (1000/15m) | `routes/caddycode.js:320` |
| POST | `/api/v1/caddycode/validate` | protected | GENERAL (1000/15m) | `routes/caddycode.js:276` |
| POST | `/api/v1/calendar/discover` | protected | GENERAL (1000/15m) | `routes/calendar.js:280` |
| GET | `/api/v1/calendar/events` | protected | GENERAL (1000/15m) | `routes/calendar.js:176` |
| POST | `/api/v1/calendar/radicale/provision` | protected | GENERAL (1000/15m) | `routes/calendar.js:234` |
| GET | `/api/v1/calendar/sources` | protected | GENERAL (1000/15m) | `routes/calendar.js:99` |
| POST | `/api/v1/calendar/sources` | protected | GENERAL (1000/15m) | `routes/calendar.js:105` |
| DELETE | `/api/v1/calendar/sources/:id` | protected | GENERAL (1000/15m) | `routes/calendar.js:166` |
| PUT | `/api/v1/calendar/sources/:id` | protected | GENERAL (1000/15m) | `routes/calendar.js:131` |
| GET | `/api/v1/capabilities` | public | GENERAL (1000/15m) | `routes/capabilities.js:38` |
| GET | `/api/v1/catalog` | protected | GENERAL (1000/15m) | `routes/catalog.js:52` |
| GET | `/api/v1/catalog/:appId` | protected | GENERAL (1000/15m) | `routes/catalog.js:102` |
| GET | `/api/v1/catalog/search` | protected | GENERAL (1000/15m) | `routes/catalog.js:82` |
| GET | `/api/v1/deploys/catalog/apps` | protected | GENERAL (1000/15m) | `routes/deploys.js:101` |
| POST | `/api/v1/deploys/catalog/deploy` | protected | GENERAL (1000/15m) | `routes/deploys.js:113` |
| POST | `/api/v1/deploys/deploy` | protected | GENERAL (1000/15m) | `routes/deploys.js:244` |
| POST | `/api/v1/deploys/gitea-repos` | protected | GENERAL (1000/15m) | `routes/deploys.js:358` |
| POST | `/api/v1/deploys/install` | protected | GENERAL (1000/15m) | `routes/deploys.js:300` |
| GET | `/api/v1/deploys/journal` | protected | GENERAL (1000/15m) | `routes/deploys.js:197` |
| GET | `/api/v1/deploys/repos` | protected | GENERAL (1000/15m) | `routes/deploys.js:181` |
| POST | `/api/v1/deploys/rollback` | protected | GENERAL (1000/15m) | `routes/deploys.js:271` |
| GET | `/api/v1/deploys/services` | protected | GENERAL (1000/15m) | `routes/deploys.js:189` |
| GET | `/api/v1/deploys/status` | protected | GENERAL (1000/15m) | `routes/deploys.js:210` |
| POST | `/api/v1/disaster/backup` | protected | GENERAL (1000/15m) | `routes/disaster-recovery.js:135` |
| POST | `/api/v1/disaster/restore` | protected | GENERAL (1000/15m) | `routes/disaster-recovery.js:223` |
| GET | `/api/v1/disaster/status` | protected | GENERAL (1000/15m) | `routes/disaster-recovery.js:410` |
| GET | `/api/v1/discover` | protected | GENERAL (1000/15m) | `routes/discover.js:45` |
| POST | `/api/v1/discover/adopt` | protected | GENERAL (1000/15m) | `routes/discover-adopt.js:39` |
| GET | `/api/v1/disk-settings/` | protected | GENERAL (1000/15m) | `routes/disk-settings.js:13` |
| POST | `/api/v1/disk-settings/` | protected | GENERAL (1000/15m) | `routes/disk-settings.js:54` |
| POST | `/api/v1/disk-settings/cleanup` | protected | GENERAL (1000/15m) | `routes/disk-settings.js:92` |
| GET | `/api/v1/disk/` | protected | GENERAL (1000/15m) | `routes/disk-space.js:88` |
| GET | `/api/v1/disk/breakdown` | protected | GENERAL (1000/15m) | `routes/disk-space.js:94` |
| POST | `/api/v1/disk/cleanup` | protected | GENERAL (1000/15m) | `routes/disk-space.js:130` |
| GET | `/api/v1/disk/config` | protected | GENERAL (1000/15m) | `routes/disk-space.js:100` |
| POST | `/api/v1/disk/config` | protected | GENERAL (1000/15m) | `routes/disk-space.js:105` |
| POST | `/api/v1/fleet/deploy` | protected | GENERAL (1000/15m) | `routes/fleet.js:311` |
| GET | `/api/v1/fleet/hosts` | protected | GENERAL (1000/15m) | `routes/fleet.js:136` |
| POST | `/api/v1/fleet/hosts` | protected | GENERAL (1000/15m) | `routes/fleet.js:142` |
| DELETE | `/api/v1/fleet/hosts/:hostId` | protected | GENERAL (1000/15m) | `routes/fleet.js:223` |
| GET | `/api/v1/fleet/status` | protected | GENERAL (1000/15m) | `routes/fleet.js:246` |
| GET | `/api/v1/i18n/languages` | public | GENERAL (1000/15m) | `routes/i18n.js:16` |
| GET | `/api/v1/i18n/translations/:lang` | public | GENERAL (1000/15m) | `routes/i18n.js:28` |
| GET | `/api/v1/log-insights` | protected | GENERAL (1000/15m) | `routes/log-insights.js:103` |
| POST | `/api/v1/log-insights/dispose` | protected | GENERAL (1000/15m) | `routes/log-insights.js:222` |
| DELETE | `/api/v1/mcp/` | protected | GENERAL (1000/15m) | `routes/mcp.js:276` |
| GET | `/api/v1/mcp/` | protected | GENERAL (1000/15m) | `routes/mcp.js:266` |
| POST | `/api/v1/mcp/` | protected | GENERAL (1000/15m) | `routes/mcp.js:165` |
| POST | `/api/v1/mcp/config` | protected | GENERAL (1000/15m) | `routes/mcp.js:315` |
| GET | `/api/v1/mcp/connections` | protected | GENERAL (1000/15m) | `routes/mcp.js:302` |
| GET | `/api/v1/mcp/info` | protected | GENERAL (1000/15m) | `routes/mcp.js:285` |
| GET | `/api/v1/network/access/` | protected | GENERAL (1000/15m) | `routes/network-access.js:79` |
| PUT | `/api/v1/network/access/` | protected | GENERAL (1000/15m) | `routes/network-access.js:85` |
| GET | `/api/v1/network/access/effective/:principalType/:principalId` | protected | GENERAL (1000/15m) | `routes/network-access.js:135` |
| DELETE | `/api/v1/network/access/grant` | protected | GENERAL (1000/15m) | `routes/network-access.js:116` |
| POST | `/api/v1/network/access/grant` | protected | GENERAL (1000/15m) | `routes/network-access.js:101` |
| POST | `/api/v1/network/devices/:id/revoke` | protected | GENERAL (1000/15m) | `routes/network-lifecycle.js:92` |
| GET | `/api/v1/network/forward-auth/` | public | GENERAL (1000/15m) | `routes/network-forward-auth.js:134` |
| POST | `/api/v1/network/forward-auth/` | public | GENERAL (1000/15m) | `routes/network-forward-auth.js:135` |
| GET | `/api/v1/network/groups/` | protected | GENERAL (1000/15m) | `routes/network-groups.js:67` |
| POST | `/api/v1/network/groups/` | protected | GENERAL (1000/15m) | `routes/network-groups.js:72` |
| DELETE | `/api/v1/network/groups/:id` | protected | GENERAL (1000/15m) | `routes/network-groups.js:90` |
| PATCH | `/api/v1/network/groups/:id` | protected | GENERAL (1000/15m) | `routes/network-groups.js:81` |
| GET | `/api/v1/network/invites/` | protected | GENERAL (1000/15m) | `routes/network-invites.js:161` |
| POST | `/api/v1/network/invites/` | protected | GENERAL (1000/15m) | `routes/network-invites.js:179` |
| DELETE | `/api/v1/network/invites/:id` | protected | GENERAL (1000/15m) | `routes/network-invites.js:246` |
| GET | `/api/v1/network/people/` | protected | GENERAL (1000/15m) | `routes/network-people.js:60` |
| POST | `/api/v1/network/people/` | protected | GENERAL (1000/15m) | `routes/network-people.js:73` |
| DELETE | `/api/v1/network/people/:id` | protected | GENERAL (1000/15m) | `routes/network-people.js:125` |
| GET | `/api/v1/network/people/:id` | protected | GENERAL (1000/15m) | `routes/network-people.js:65` |
| PATCH | `/api/v1/network/people/:id` | protected | GENERAL (1000/15m) | `routes/network-people.js:101` |
| POST | `/api/v1/network/people/:id/block` | protected | GENERAL (1000/15m) | `routes/network-lifecycle.js:74` |
| POST | `/api/v1/network/people/:id/remove` | protected | GENERAL (1000/15m) | `routes/network-lifecycle.js:87` |
| POST | `/api/v1/network/people/:id/unblock` | protected | GENERAL (1000/15m) | `routes/network-lifecycle.js:79` |
| POST | `/api/v1/network/people/sync` | protected | GENERAL (1000/15m) | `routes/network-people.js:151` |
| GET | `/api/v1/network/resources/` | protected | GENERAL (1000/15m) | `routes/network-resources.js:63` |
| POST | `/api/v1/network/resources/` | protected | GENERAL (1000/15m) | `routes/network-resources.js:74` |
| DELETE | `/api/v1/network/resources/:name` | protected | GENERAL (1000/15m) | `routes/network-resources.js:93` |
| GET | `/api/v1/network/resources/:name` | protected | GENERAL (1000/15m) | `routes/network-resources.js:68` |
| PATCH | `/api/v1/network/resources/:name` | protected | GENERAL (1000/15m) | `routes/network-resources.js:84` |
| GET | `/api/v1/network/wg/:token` | protected | GENERAL (1000/15m) | `routes/network-wg-redeem.js:278` |
| POST | `/api/v1/network/wg/:token` | protected | GENERAL (1000/15m) | `routes/network-wg-redeem.js:288` |
| GET | `/api/v1/network/wizard/` | protected | GENERAL (1000/15m) | `routes/network-wizard.js:207` |
| POST | `/api/v1/network/wizard/admin` | protected | GENERAL (1000/15m) | `routes/network-wizard.js:160` |
| POST | `/api/v1/network/wizard/ca` | protected | GENERAL (1000/15m) | `routes/network-wizard.js:149` |
| POST | `/api/v1/network/wizard/complete` | protected | GENERAL (1000/15m) | `routes/network-wizard.js:171` |
| POST | `/api/v1/network/wizard/connect` | protected | GENERAL (1000/15m) | `routes/network-wizard.js:127` |
| POST | `/api/v1/network/wizard/dns` | protected | GENERAL (1000/15m) | `routes/network-wizard.js:138` |
| POST | `/api/v1/network/wizard/domain` | protected | GENERAL (1000/15m) | `routes/network-wizard.js:116` |
| POST | `/api/v1/network/wizard/mode` | protected | GENERAL (1000/15m) | `routes/network-wizard.js:105` |
| GET | `/api/v1/network/wizard/state` | protected | GENERAL (1000/15m) | `routes/network-wizard.js:99` |
| GET | `/api/v1/network/wizard/status` | protected | GENERAL (1000/15m) | `routes/network-wizard.js:182` |
| GET | `/api/v1/security/events` | protected | GENERAL (1000/15m) | `routes/security.js:52` |
| GET | `/api/v1/security/events/:id` | protected | GENERAL (1000/15m) | `routes/security.js:207` |
| POST | `/api/v1/security/events/batch` | public | GENERAL (1000/15m) | `routes/security.js:235` |
| POST | `/api/v1/security/events/ingest` | public | GENERAL (1000/15m) | `routes/security.js:216` |
| GET | `/api/v1/security/events/perimeter` | protected | GENERAL (1000/15m) | `routes/security.js:96` |
| GET | `/api/v1/security/events/stats` | protected | GENERAL (1000/15m) | `routes/security.js:71` |
| GET | `/api/v1/security/events/stream` | protected | GENERAL (1000/15m) | `routes/security.js:176` |
| GET | `/api/v1/security/hosts` | protected | GENERAL (1000/15m) | `routes/security.js:262` |
| POST | `/api/v1/security/hosts` | protected | GENERAL (1000/15m) | `routes/security.js:267` |
| DELETE | `/api/v1/security/hosts/:id` | protected | GENERAL (1000/15m) | `routes/security.js:294` |
| GET | `/api/v1/security/hosts/:id` | protected | GENERAL (1000/15m) | `routes/security.js:280` |
| PATCH | `/api/v1/security/hosts/:id` | protected | GENERAL (1000/15m) | `routes/security.js:287` |
| GET | `/api/v1/security/hosts/:id/health` | protected | GENERAL (1000/15m) | `routes/security.js:305` |
| POST | `/api/v1/security/hosts/:id/rotate-key` | protected | GENERAL (1000/15m) | `routes/security.js:335` |
| GET | `/api/v1/share` | protected | GENERAL (1000/15m) | `routes/share.js:287` |
| POST | `/api/v1/share` | protected | GENERAL (1000/15m) | `routes/share.js:147` |
| DELETE | `/api/v1/share/:id` | protected | GENERAL (1000/15m) | `routes/share.js:292` |
| GET | `/api/v1/share/:token/preview` | public | GENERAL (1000/15m) | `routes/share.js:328` |
| POST | `/api/v1/share/:token/redeem-tailscale` | public | GENERAL (1000/15m) | `routes/share.js:367` |
| POST | `/api/v1/share/:token/subscribe` | public | GENERAL (1000/15m) | `routes/share.js:345` |
| POST | `/api/v1/share/tailscale` | protected | GENERAL (1000/15m) | `routes/share.js:183` |
| GET | `/api/v1/shield` | protected | GENERAL (1000/15m) | `routes/shield.js:108` |
| GET | `/api/v1/version` | public | GENERAL (1000/15m) | `routes/version.js:30` |
| POST | `/api/v1/wizard/apply` | protected | GENERAL (1000/15m) | `routes/wizard.js:146` |
| GET | `/api/v1/wizard/categories` | protected | GENERAL (1000/15m) | `routes/wizard.js:76` |
| POST | `/api/v1/wizard/recommend` | protected | GENERAL (1000/15m) | `routes/wizard.js:88` |
## Authentication
_34 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| GET | `/api/v1/auth/admin/allowlist` | protected | GENERAL (1000/15m) | `routes/auth/admin.js:200` |
| GET | `/api/v1/auth/admin/invites` | protected | GENERAL (1000/15m) | `routes/auth/admin.js:207` |
| POST | `/api/v1/auth/admin/invites` | protected | GENERAL (1000/15m) | `routes/auth/admin.js:212` |
| DELETE | `/api/v1/auth/admin/invites/:id` | protected | GENERAL (1000/15m) | `routes/auth/admin.js:287` |
| GET | `/api/v1/auth/admin/users` | protected | GENERAL (1000/15m) | `routes/auth/admin.js:146` |
| POST | `/api/v1/auth/admin/users` | protected | GENERAL (1000/15m) | `routes/auth/admin.js:151` |
| DELETE | `/api/v1/auth/admin/users/:id` | protected | GENERAL (1000/15m) | `routes/auth/admin.js:186` |
| PATCH | `/api/v1/auth/admin/users/:id` | protected | GENERAL (1000/15m) | `routes/auth/admin.js:172` |
| GET | `/api/v1/auth/app-token/:serviceId` | public | STRICT (20/15m) | `routes/auth/sso-gate.js:105` |
| POST | `/api/v1/auth/disable/:provider` | public | GENERAL (1000/15m) | `routes/auth/login.js:102` |
| GET | `/api/v1/auth/gate/:serviceId` | public | STRICT (20/15m) | `routes/auth/sso-gate.js:27` |
| GET | `/api/v1/auth/invites/:token` | public | GENERAL (1000/15m) | `routes/auth/admin.js:296` |
| POST | `/api/v1/auth/invites/:token/accept` | public | GENERAL (1000/15m) | `routes/auth/admin.js:315` |
| POST | `/api/v1/auth/jwt` | protected | STRICT (20/15m) | `routes/auth/keys.js:103` |
| GET | `/api/v1/auth/keys` | protected | STRICT (20/15m) | `routes/auth/keys.js:36` |
| POST | `/api/v1/auth/keys` | protected | STRICT (20/15m) | `routes/auth/keys.js:47` |
| DELETE | `/api/v1/auth/keys/:keyId` | protected | STRICT (20/15m) | `routes/auth/keys.js:81` |
| GET | `/api/v1/auth/login-page` | public | GENERAL (1000/15m) | `routes/auth/sso-gate.js:270` |
| POST | `/api/v1/auth/login/:provider/initiate` | public | GENERAL (1000/15m) | `routes/auth/login.js:57` |
| POST | `/api/v1/auth/login/:provider/verify` | public | GENERAL (1000/15m) | `routes/auth/login.js:74` |
| GET | `/api/v1/auth/login/methods` | public | GENERAL (1000/15m) | `routes/auth/login.js:49` |
| GET | `/api/v1/auth/login/recovery-info` | public | GENERAL (1000/15m) | `routes/auth/login.js:88` |
| GET | `/api/v1/auth/me` | protected | GENERAL (1000/15m) | `routes/auth/admin.js:112` |
| GET | `/api/v1/auth/me` | protected | GENERAL (1000/15m) | `routes/auth/index.js:158` |
| GET | `/api/v1/auth/sso-exchange` | public | GENERAL (1000/15m) | `routes/auth/sso-gate.js:245` |
| GET | `/api/v1/auth/sso-handoff` | protected | GENERAL (1000/15m) | `routes/auth/sso-gate.js:221` |
| GET | `/api/v1/totp/check-session` | public | TOTP (10/15m) | `routes/auth/totp.js:246` |
| GET | `/api/v1/totp/config` | public | TOTP (10/15m) | `routes/auth/totp.js:31` |
| POST | `/api/v1/totp/config` | public | TOTP (10/15m) | `routes/auth/totp.js:307` |
| POST | `/api/v1/totp/disable` | protected | TOTP (10/15m) | `routes/auth/totp.js:274` |
| GET | `/api/v1/totp/recovery-info` | public | TOTP (10/15m) | `routes/auth/totp.js:57` |
| POST | `/api/v1/totp/setup` | public | TOTP (10/15m) | `routes/auth/totp.js:117` |
| POST | `/api/v1/totp/verify` | public | TOTP (10/15m) | `routes/auth/totp.js:195` |
| POST | `/api/v1/totp/verify-setup` | public | TOTP (10/15m) | `routes/auth/totp.js:158` |
## App catalog
_28 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| DELETE | `/api/v1/apps/:appId` | protected | GENERAL (1000/15m) | `routes/apps/removal.js:39` |
| GET | `/api/v1/apps/:appId/backup-points` | protected | GENERAL (1000/15m) | `routes/apps/restore.js:133` |
| POST | `/api/v1/apps/:appId/restore` | protected | GENERAL (1000/15m) | `routes/apps/restore.js:40` |
| POST | `/api/v1/apps/:appId/revert/:filename` | protected | GENERAL (1000/15m) | `routes/apps/restore.js:187` |
| POST | `/api/v1/apps/check-existing` | protected | GENERAL (1000/15m) | `routes/apps/deploy.js:242` |
| DELETE | `/api/v1/apps/compose-stack/:stackName` | protected | GENERAL (1000/15m) | `routes/apps/compose.js:308` |
| POST | `/api/v1/apps/deploy` | protected | GENERAL (1000/15m) | `routes/apps/deploy.js:255` |
| POST | `/api/v1/apps/deploy-compose` | protected | GENERAL (1000/15m) | `routes/apps/compose.js:170` |
| POST | `/api/v1/apps/import-compose` | protected | GENERAL (1000/15m) | `routes/apps/compose.js:159` |
| GET | `/api/v1/apps/ports/:basePort/suggest` | protected | GENERAL (1000/15m) | `routes/apps/templates.js:77` |
| GET | `/api/v1/apps/ports/:port/check` | protected | GENERAL (1000/15m) | `routes/apps/templates.js:65` |
| POST | `/api/v1/apps/restore-all` | protected | GENERAL (1000/15m) | `routes/apps/restore.js:60` |
| GET | `/api/v1/apps/restore-status` | protected | GENERAL (1000/15m) | `routes/apps/restore.js:99` |
| GET | `/api/v1/apps/templates` | protected | GENERAL (1000/15m) | `routes/apps/templates.js:45` |
| GET | `/api/v1/apps/templates/:appId` | protected | GENERAL (1000/15m) | `routes/apps/templates.js:54` |
| POST | `/api/v1/apps/update-subdomain` | protected | GENERAL (1000/15m) | `routes/apps/templates.js:91` |
| POST | `/api/v1/arr/auto-setup` | protected | GENERAL (1000/15m) | `routes/arr/config.js:282` |
| POST | `/api/v1/arr/configure-overseerr` | protected | GENERAL (1000/15m) | `routes/arr/config.js:27` |
| GET | `/api/v1/arr/credentials` | protected | GENERAL (1000/15m) | `routes/arr/credentials.js:109` |
| POST | `/api/v1/arr/credentials` | protected | GENERAL (1000/15m) | `routes/arr/credentials.js:21` |
| DELETE | `/api/v1/arr/credentials/:service` | protected | GENERAL (1000/15m) | `routes/arr/credentials.js:134` |
| GET | `/api/v1/arr/detect` | protected | GENERAL (1000/15m) | `routes/arr/detect.js:20` |
| GET | `/api/v1/arr/quality-profiles` | protected | GENERAL (1000/15m) | `routes/arr/config.js:499` |
| POST | `/api/v1/arr/quality-profiles` | protected | GENERAL (1000/15m) | `routes/arr/config.js:568` |
| POST | `/api/v1/arr/smart-connect` | protected | GENERAL (1000/15m) | `routes/arr/smart-connect.js:26` |
| GET | `/api/v1/arr/smart-detect` | protected | GENERAL (1000/15m) | `routes/arr/detect.js:78` |
| POST | `/api/v1/arr/test-connection` | protected | GENERAL (1000/15m) | `routes/arr/config.js:208` |
| GET | `/api/v1/plex/libraries` | protected | GENERAL (1000/15m) | `routes/arr/plex.js:26` |
## DNS
_20 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| GET | `/api/v1/dns/check-update` | protected | GENERAL (1000/15m) | `routes/dns.js:684` |
| DELETE | `/api/v1/dns/credentials` | protected | GENERAL (1000/15m) | `routes/dns.js:612` |
| POST | `/api/v1/dns/credentials` | protected | GENERAL (1000/15m) | `routes/dns.js:505` |
| GET | `/api/v1/dns/logs` | protected | GENERAL (1000/15m) | `routes/dns.js:352` |
| GET | `/api/v1/dns/propagation` | protected | GENERAL (1000/15m) | `routes/dns.js:828` |
| GET | `/api/v1/dns/propagation/:domain` | protected | GENERAL (1000/15m) | `routes/dns.js:873` |
| POST | `/api/v1/dns/propagation/verify` | protected | GENERAL (1000/15m) | `routes/dns.js:841` |
| GET | `/api/v1/dns/provider/status` | protected | GENERAL (1000/15m) | `routes/dns.js:55` |
| GET | `/api/v1/dns/providers` | protected | GENERAL (1000/15m) | `routes/dns.js:48` |
| DELETE | `/api/v1/dns/record` | protected | GENERAL (1000/15m) | `routes/dns.js:191` |
| POST | `/api/v1/dns/record` | protected | GENERAL (1000/15m) | `routes/dns.js:240` |
| GET | `/api/v1/dns/records` | protected | GENERAL (1000/15m) | `routes/dns.js:72` |
| POST | `/api/v1/dns/refresh-token` | protected | GENERAL (1000/15m) | `routes/dns.js:670` |
| GET | `/api/v1/dns/resolve` | protected | GENERAL (1000/15m) | `routes/dns.js:307` |
| POST | `/api/v1/dns/restart/:dnsId` | protected | GENERAL (1000/15m) | `routes/dns.js:636` |
| GET | `/api/v1/dns/token-status` | protected | GENERAL (1000/15m) | `routes/dns.js:489` |
| DELETE | `/api/v1/dns/universal/record` | protected | GENERAL (1000/15m) | `routes/dns.js:134` |
| POST | `/api/v1/dns/universal/record` | protected | GENERAL (1000/15m) | `routes/dns.js:86` |
| GET | `/api/v1/dns/universal/resolve` | protected | GENERAL (1000/15m) | `routes/dns.js:160` |
| POST | `/api/v1/dns/update` | protected | GENERAL (1000/15m) | `routes/dns.js:753` |
## Tailscale
_20 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| GET | `/api/v1/tailscale/acl` | public | GENERAL (1000/15m) | `routes/tailscale.js:316` |
| GET | `/api/v1/tailscale/admin/devices` | public | GENERAL (1000/15m) | `routes/tailscale-admin.js:280` |
| DELETE | `/api/v1/tailscale/admin/devices/:id` | public | GENERAL (1000/15m) | `routes/tailscale-admin.js:296` |
| GET | `/api/v1/tailscale/admin/keys` | public | GENERAL (1000/15m) | `routes/tailscale-admin.js:328` |
| POST | `/api/v1/tailscale/admin/keys` | public | GENERAL (1000/15m) | `routes/tailscale-admin.js:337` |
| DELETE | `/api/v1/tailscale/admin/keys/:id` | public | GENERAL (1000/15m) | `routes/tailscale-admin.js:369` |
| GET | `/api/v1/tailscale/admin/users` | public | GENERAL (1000/15m) | `routes/tailscale-admin.js:317` |
| GET | `/api/v1/tailscale/api-devices` | public | GENERAL (1000/15m) | `routes/tailscale.js:289` |
| GET | `/api/v1/tailscale/check-connection` | public | GENERAL (1000/15m) | `routes/tailscale.js:107` |
| POST | `/api/v1/tailscale/config` | public | GENERAL (1000/15m) | `routes/tailscale.js:80` |
| GET | `/api/v1/tailscale/devices` | public | GENERAL (1000/15m) | `routes/tailscale.js:124` |
| DELETE | `/api/v1/tailscale/oauth-config` | public | GENERAL (1000/15m) | `routes/tailscale.js:274` |
| POST | `/api/v1/tailscale/oauth-config` | public | GENERAL (1000/15m) | `routes/tailscale.js:216` |
| POST | `/api/v1/tailscale/protect-service` | public | GENERAL (1000/15m) | `routes/tailscale.js:158` |
| DELETE | `/api/v1/tailscale/settings` | public | GENERAL (1000/15m) | `routes/tailscale-admin.js:239` |
| GET | `/api/v1/tailscale/settings` | public | GENERAL (1000/15m) | `routes/tailscale-admin.js:172` |
| PUT | `/api/v1/tailscale/settings` | public | GENERAL (1000/15m) | `routes/tailscale-admin.js:188` |
| POST | `/api/v1/tailscale/settings/test` | public | GENERAL (1000/15m) | `routes/tailscale-admin.js:246` |
| GET | `/api/v1/tailscale/status` | public | GENERAL (1000/15m) | `routes/tailscale.js:36` |
| POST | `/api/v1/tailscale/sync` | public | GENERAL (1000/15m) | `routes/tailscale.js:302` |
## Monitoring
_19 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| GET | `/api/v1/certificates` | protected | GENERAL (1000/15m) | `routes/ssl-monitor.js:26` |
| GET | `/api/v1/certificates/:serviceId` | protected | GENERAL (1000/15m) | `routes/ssl-monitor.js:35` |
| POST | `/api/v1/check` | protected | GENERAL (1000/15m) | `routes/ssl-monitor.js:50` |
| POST | `/api/v1/check/:serviceId` | protected | GENERAL (1000/15m) | `routes/ssl-monitor.js:59` |
| GET | `/api/v1/config` | public | GENERAL (1000/15m) | `routes/ssl-monitor.js:80` |
| POST | `/api/v1/config` | public | GENERAL (1000/15m) | `routes/ssl-monitor.js:90` |
| GET | `/api/v1/monitoring/aggregated/:containerId` | protected | GENERAL (1000/15m) | `routes/monitoring.js:72` |
| GET | `/api/v1/monitoring/alerts` | protected | GENERAL (1000/15m) | `routes/monitoring.js:104` |
| DELETE | `/api/v1/monitoring/alerts/:containerId` | protected | GENERAL (1000/15m) | `routes/monitoring.js:174` |
| GET | `/api/v1/monitoring/alerts/:containerId` | protected | GENERAL (1000/15m) | `routes/monitoring.js:168` |
| POST | `/api/v1/monitoring/alerts/:containerId` | protected | GENERAL (1000/15m) | `routes/monitoring.js:162` |
| POST | `/api/v1/monitoring/alerts/:containerId/test` | protected | GENERAL (1000/15m) | `routes/monitoring.js:111` |
| GET | `/api/v1/monitoring/alerts/config` | protected | GENERAL (1000/15m) | `routes/monitoring.js:85` |
| POST | `/api/v1/monitoring/alerts/config` | protected | GENERAL (1000/15m) | `routes/monitoring.js:91` |
| GET | `/api/v1/monitoring/history/:containerId` | protected | GENERAL (1000/15m) | `routes/monitoring.js:49` |
| GET | `/api/v1/monitoring/stats` | public | GENERAL (1000/15m) | `routes/monitoring.js:20` |
| GET | `/api/v1/monitoring/stats/:containerId` | protected | GENERAL (1000/15m) | `routes/monitoring.js:38` |
| GET | `/api/v1/stats/container/:id` | protected | GENERAL (1000/15m) | `routes/monitoring.js:240` |
| GET | `/api/v1/stats/containers` | protected | GENERAL (1000/15m) | `routes/monitoring.js:182` |
## Backups
_18 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| POST | `/api/v1/backups/backup/:appId` | protected | GENERAL (1000/15m) | `routes/backups.js:165` |
| POST | `/api/v1/backups/compare/:filename` | protected | GENERAL (1000/15m) | `routes/backups.js:377` |
| GET | `/api/v1/backups/config` | protected | GENERAL (1000/15m) | `routes/backups.js:484` |
| POST | `/api/v1/backups/config` | protected | GENERAL (1000/15m) | `routes/backups.js:490` |
| DELETE | `/api/v1/backups/credentials/:provider` | protected | GENERAL (1000/15m) | `routes/backups.js:615` |
| GET | `/api/v1/backups/credentials/:provider` | protected | GENERAL (1000/15m) | `routes/backups.js:542` |
| POST | `/api/v1/backups/credentials/:provider` | protected | GENERAL (1000/15m) | `routes/backups.js:574` |
| POST | `/api/v1/backups/execute` | protected | GENERAL (1000/15m) | `routes/backups.js:503` |
| GET | `/api/v1/backups/files` | protected | GENERAL (1000/15m) | `routes/backups.js:122` |
| GET | `/api/v1/backups/files/:appId` | protected | GENERAL (1000/15m) | `routes/backups.js:193` |
| GET | `/api/v1/backups/history` | protected | GENERAL (1000/15m) | `routes/backups.js:509` |
| POST | `/api/v1/backups/restore-file/:filename` | protected | GENERAL (1000/15m) | `routes/backups.js:241` |
| POST | `/api/v1/backups/restore/:backupId` | protected | GENERAL (1000/15m) | `routes/backups.js:522` |
| GET | `/api/v1/backups/schedule` | protected | GENERAL (1000/15m) | `routes/backups.js:37` |
| POST | `/api/v1/backups/schedule` | protected | GENERAL (1000/15m) | `routes/backups.js:67` |
| DELETE | `/api/v1/backups/schedule/:appId` | protected | GENERAL (1000/15m) | `routes/backups.js:106` |
| GET | `/api/v1/backups/storage-info` | protected | GENERAL (1000/15m) | `routes/backups.js:516` |
| POST | `/api/v1/backups/test-destination` | protected | GENERAL (1000/15m) | `routes/backups.js:530` |
## Logs
_17 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| DELETE | `/api/v1/error-logs` | protected | GENERAL (1000/15m) | `routes/errorlogs.js:216` |
| GET | `/api/v1/error-logs` | protected | GENERAL (1000/15m) | `routes/errorlogs.js:143` |
| GET | `/api/v1/error-logs/contexts` | protected | GENERAL (1000/15m) | `routes/errorlogs.js:125` |
| GET | `/api/v1/logs/container/:id` | protected | GENERAL (1000/15m) | `routes/logs.js:48` |
| GET | `/api/v1/logs/containers` | protected | GENERAL (1000/15m) | `routes/logs.js:32` |
| GET | `/api/v1/logs/digest/:date` | protected | GENERAL (1000/15m) | `routes/logs.js:197` |
| POST | `/api/v1/logs/digest/generate` | protected | GENERAL (1000/15m) | `routes/logs.js:185` |
| GET | `/api/v1/logs/digest/history` | protected | GENERAL (1000/15m) | `routes/logs.js:178` |
| GET | `/api/v1/logs/digest/latest` | protected | GENERAL (1000/15m) | `routes/logs.js:161` |
| GET | `/api/v1/logs/digest/live` | protected | GENERAL (1000/15m) | `routes/logs.js:171` |
| GET | `/api/v1/logs/docker-disk` | protected | GENERAL (1000/15m) | `routes/logs.js:216` |
| POST | `/api/v1/logs/docker-maintenance` | protected | GENERAL (1000/15m) | `routes/logs.js:224` |
| GET | `/api/v1/logs/file` | protected | GENERAL (1000/15m) | `routes/logs.js:320` |
| GET | `/api/v1/logs/journal` | protected | GENERAL (1000/15m) | `routes/logs.js:245` |
| GET | `/api/v1/logs/journal/stream` | protected | GENERAL (1000/15m) | `routes/logs.js:260` |
| GET | `/api/v1/logs/journal/units` | protected | GENERAL (1000/15m) | `routes/logs.js:236` |
| GET | `/api/v1/logs/stream/:id` | protected | GENERAL (1000/15m) | `routes/logs.js:102` |
## Updates
_16 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| POST | `/api/v1/system/rollback` | protected | GENERAL (1000/15m) | `routes/updates.js:164` |
| GET | `/api/v1/system/rollback-versions` | protected | GENERAL (1000/15m) | `routes/updates.js:158` |
| POST | `/api/v1/system/update-apply` | protected | GENERAL (1000/15m) | `routes/updates.js:95` |
| GET | `/api/v1/system/update-check` | public | GENERAL (1000/15m) | `routes/updates.js:89` |
| GET | `/api/v1/system/update-history` | public | GENERAL (1000/15m) | `routes/updates.js:152` |
| POST | `/api/v1/system/update-notify` | public | GENERAL (1000/15m) | `routes/updates.js:126` |
| GET | `/api/v1/system/update-status` | public | GENERAL (1000/15m) | `routes/updates.js:143` |
| GET | `/api/v1/system/version` | public | GENERAL (1000/15m) | `routes/updates.js:83` |
| GET | `/api/v1/updates/auto-update` | protected | GENERAL (1000/15m) | `routes/updates.js:65` |
| POST | `/api/v1/updates/auto-update/:containerId` | protected | GENERAL (1000/15m) | `routes/updates.js:59` |
| GET | `/api/v1/updates/available` | public | GENERAL (1000/15m) | `routes/updates.js:29` |
| POST | `/api/v1/updates/check` | protected | GENERAL (1000/15m) | `routes/updates.js:22` |
| GET | `/api/v1/updates/history` | protected | GENERAL (1000/15m) | `routes/updates.js:49` |
| POST | `/api/v1/updates/rollback/:containerId` | protected | GENERAL (1000/15m) | `routes/updates.js:43` |
| POST | `/api/v1/updates/schedule/:containerId` | protected | GENERAL (1000/15m) | `routes/updates.js:71` |
| POST | `/api/v1/updates/update/:containerId` | protected | GENERAL (1000/15m) | `routes/updates.js:37` |
## Configuration
_13 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| POST | `/api/v1/assets/upload` | protected | GENERAL (1000/15m) | `routes/config/assets.js:58` |
| GET | `/api/v1/backup/export` | protected | GENERAL (1000/15m) | `routes/config/backup.js:51` |
| POST | `/api/v1/backup/preview` | protected | GENERAL (1000/15m) | `routes/config/backup.js:153` |
| POST | `/api/v1/backup/restore` | protected | GENERAL (1000/15m) | `routes/config/backup.js:218` |
| DELETE | `/api/v1/config` | public | GENERAL (1000/15m) | `routes/config/settings.js:86` |
| GET | `/api/v1/config` | public | GENERAL (1000/15m) | `routes/config/settings.js:26` |
| POST | `/api/v1/config` | public | GENERAL (1000/15m) | `routes/config/settings.js:43` |
| DELETE | `/api/v1/favicon` | public | GENERAL (1000/15m) | `routes/config/assets.js:280` |
| GET | `/api/v1/favicon` | public | GENERAL (1000/15m) | `routes/config/assets.js:216` |
| POST | `/api/v1/favicon` | public | GENERAL (1000/15m) | `routes/config/assets.js:225` |
| DELETE | `/api/v1/logo` | public | GENERAL (1000/15m) | `routes/config/assets.js:183` |
| GET | `/api/v1/logo` | public | GENERAL (1000/15m) | `routes/config/assets.js:94` |
| POST | `/api/v1/logo` | public | GENERAL (1000/15m) | `routes/config/assets.js:129` |
## Health
_13 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| DELETE | `/api/v1/health-checks/:serviceId/configure` | protected | GENERAL (1000/15m) | `routes/health.js:357` |
| POST | `/api/v1/health-checks/:serviceId/configure` | protected | GENERAL (1000/15m) | `routes/health.js:351` |
| GET | `/api/v1/health-checks/:serviceId/stats` | protected | GENERAL (1000/15m) | `routes/health.js:340` |
| GET | `/api/v1/health-checks/incidents` | protected | GENERAL (1000/15m) | `routes/health.js:363` |
| GET | `/api/v1/health-checks/incidents/history` | protected | GENERAL (1000/15m) | `routes/health.js:371` |
| GET | `/api/v1/health-checks/status` | public | GENERAL (1000/15m) | `routes/health.js:319` |
| GET | `/api/v1/health/ca` | public | GENERAL (1000/15m) | `routes/health.js:267` |
| GET | `/api/v1/health/cached` | protected | GENERAL (1000/15m) | `routes/health.js:179` |
| GET | `/api/v1/health/probe` | protected | GENERAL (1000/15m) | `routes/health.js:230` |
| GET | `/api/v1/health/pylon` | protected | GENERAL (1000/15m) | `routes/health.js:245` |
| GET | `/api/v1/health/service/:id` | protected | GENERAL (1000/15m) | `routes/health.js:188` |
| GET | `/api/v1/health/services` | protected | GENERAL (1000/15m) | `routes/health.js:109` |
| GET | `/api/v1/system/health` | public | GENERAL (1000/15m) | `routes/health.js:383` |
## Services
_12 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| DELETE | `/api/v1/seedhost-creds` | protected | GENERAL (1000/15m) | `routes/services.js:315` |
| GET | `/api/v1/seedhost-creds` | protected | GENERAL (1000/15m) | `routes/services.js:294` |
| POST | `/api/v1/seedhost-creds` | protected | GENERAL (1000/15m) | `routes/services.js:277` |
| GET | `/api/v1/services` | public | GENERAL (1000/15m) | `routes/services.js:379` |
| POST | `/api/v1/services` | public | GENERAL (1000/15m) | `routes/services.js:394` |
| PUT | `/api/v1/services` | public | GENERAL (1000/15m) | `routes/services.js:441` |
| DELETE | `/api/v1/services/:id` | protected | GENERAL (1000/15m) | `routes/services.js:470` |
| DELETE | `/api/v1/services/:serviceId/credentials` | protected | GENERAL (1000/15m) | `routes/services.js:241` |
| GET | `/api/v1/services/:serviceId/credentials` | protected | GENERAL (1000/15m) | `routes/services.js:256` |
| POST | `/api/v1/services/:serviceId/credentials` | protected | GENERAL (1000/15m) | `routes/services.js:217` |
| GET | `/api/v1/services/status` | public | GENERAL (1000/15m) | `routes/services.js:332` |
| POST | `/api/v1/services/update` | protected | GENERAL (1000/15m) | `routes/services.js:495` |
## Containers (lifecycle)
_11 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| GET | `/api/v1/containers/` | protected | GENERAL (1000/15m) | `routes/containers.js:76` |
| DELETE | `/api/v1/containers/:id` | protected | GENERAL (1000/15m) | `routes/containers.js:295` |
| GET | `/api/v1/containers/:id/check-update` | protected | GENERAL (1000/15m) | `routes/containers.js:211` |
| GET | `/api/v1/containers/:id/logs` | protected | GENERAL (1000/15m) | `routes/containers.js:249` |
| GET | `/api/v1/containers/:id/resources` | protected | GENERAL (1000/15m) | `routes/containers.js:283` |
| PUT | `/api/v1/containers/:id/resources` | protected | GENERAL (1000/15m) | `routes/containers.js:261` |
| POST | `/api/v1/containers/:id/restart` | protected | GENERAL (1000/15m) | `routes/containers.js:104` |
| POST | `/api/v1/containers/:id/start` | protected | GENERAL (1000/15m) | `routes/containers.js:90` |
| POST | `/api/v1/containers/:id/stop` | protected | GENERAL (1000/15m) | `routes/containers.js:97` |
| POST | `/api/v1/containers/:id/update` | protected | GENERAL (1000/15m) | `routes/containers.js:111` |
| GET | `/api/v1/containers/discover` | protected | GENERAL (1000/15m) | `routes/containers.js:302` |
## Core / system
_9 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| GET | `/api/v1/docs` | protected | GENERAL (1000/15m) | `src/app.js:1358` |
| GET | `/api/v1/docs/spec` | protected | GENERAL (1000/15m) | `src/app.js:1376` |
| GET | `/api/v1/network/ips` | protected | GENERAL (1000/15m) | `src/app.js:1332` |
| GET | `/health` | public | GENERAL (1000/15m) | `src/app.js:1210` |
| GET | `/health/live` | public | GENERAL (1000/15m) | `src/app.js:1211` |
| GET | `/health/ready` | public | GENERAL (1000/15m) | `src/app.js:1215` |
| GET | `/healthz` | public | GENERAL (1000/15m) | `src/app.js:1212` |
| GET | `/probe/:id` | public | GENERAL (1000/15m) | `src/app.js:1219` |
| GET | `/readyz` | public | GENERAL (1000/15m) | `src/app.js:1216` |
## Dependencies
_8 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| DELETE | `/api/v1/dependencies/:serviceId` | protected | GENERAL (1000/15m) | `routes/dependencies.js:199` |
| GET | `/api/v1/dependencies/:serviceId` | protected | GENERAL (1000/15m) | `routes/dependencies.js:108` |
| POST | `/api/v1/dependencies/:serviceId` | protected | GENERAL (1000/15m) | `routes/dependencies.js:151` |
| GET | `/api/v1/dependencies/:serviceId/chain` | protected | GENERAL (1000/15m) | `routes/dependencies.js:133` |
| POST | `/api/v1/dependencies/:serviceId/restart` | protected | GENERAL (1000/15m) | `routes/dependencies.js:233` |
| GET | `/api/v1/dependencies/:serviceId/status` | protected | GENERAL (1000/15m) | `routes/dependencies.js:142` |
| GET | `/api/v1/dependencies/graph` | protected | GENERAL (1000/15m) | `routes/dependencies.js:76` |
| GET | `/api/v1/dependencies/validate` | protected | GENERAL (1000/15m) | `routes/dependencies.js:84` |
## Notifications
_8 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| GET | `/api/v1/notifications/config` | protected | GENERAL (1000/15m) | `routes/notifications.js:20` |
| POST | `/api/v1/notifications/config` | protected | GENERAL (1000/15m) | `routes/notifications.js:61` |
| POST | `/api/v1/notifications/health-check` | protected | GENERAL (1000/15m) | `routes/notifications.js:300` |
| DELETE | `/api/v1/notifications/history` | protected | GENERAL (1000/15m) | `routes/notifications.js:294` |
| GET | `/api/v1/notifications/history` | protected | GENERAL (1000/15m) | `routes/notifications.js:278` |
| POST | `/api/v1/notifications/send` | protected | GENERAL (1000/15m) | `routes/notifications.js:332` |
| GET | `/api/v1/notifications/status` | protected | GENERAL (1000/15m) | `routes/notifications.js:310` |
| POST | `/api/v1/notifications/test` | protected | GENERAL (1000/15m) | `routes/notifications.js:245` |
## App recipes
_8 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| DELETE | `/api/v1/recipes/:recipeId` | protected | GENERAL (1000/15m) | `routes/recipes/manage.js:215` |
| POST | `/api/v1/recipes/:recipeId/restart` | protected | GENERAL (1000/15m) | `routes/recipes/manage.js:188` |
| POST | `/api/v1/recipes/:recipeId/start` | protected | GENERAL (1000/15m) | `routes/recipes/manage.js:123` |
| POST | `/api/v1/recipes/:recipeId/stop` | protected | GENERAL (1000/15m) | `routes/recipes/manage.js:155` |
| POST | `/api/v1/recipes/deploy` | protected | GENERAL (1000/15m) | `routes/recipes/deploy.js:29` |
| GET | `/api/v1/recipes/deployed` | protected | GENERAL (1000/15m) | `routes/recipes/manage.js:39` |
| GET | `/api/v1/recipes/templates` | protected | GENERAL (1000/15m) | `routes/recipes/index.js:34` |
| GET | `/api/v1/recipes/templates/:recipeId` | protected | GENERAL (1000/15m) | `routes/recipes/index.js:63` |
## Docker resources
_7 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| GET | `/api/v1/docker/disk-usage` | protected | GENERAL (1000/15m) | `routes/docker-resources.js:84` |
| GET | `/api/v1/docker/networks` | protected | GENERAL (1000/15m) | `routes/docker-resources.js:50` |
| POST | `/api/v1/docker/networks` | protected | GENERAL (1000/15m) | `routes/docker-resources.js:64` |
| DELETE | `/api/v1/docker/networks/:id` | protected | GENERAL (1000/15m) | `routes/docker-resources.js:76` |
| GET | `/api/v1/docker/volumes` | protected | GENERAL (1000/15m) | `routes/docker-resources.js:17` |
| POST | `/api/v1/docker/volumes` | protected | GENERAL (1000/15m) | `routes/docker-resources.js:30` |
| DELETE | `/api/v1/docker/volumes/:name` | protected | GENERAL (1000/15m) | `routes/docker-resources.js:42` |
## Caddy / sites
_7 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| GET | `/api/v1/caddy/cas` | protected | GENERAL (1000/15m) | `routes/sites.js:60` |
| GET | `/api/v1/caddy/config` | protected | GENERAL (1000/15m) | `routes/sites.js:34` |
| POST | `/api/v1/caddy/reload` | protected | GENERAL (1000/15m) | `routes/sites.js:41` |
| GET | `/api/v1/caddyfile` | protected | GENERAL (1000/15m) | `routes/sites.js:28` |
| POST | `/api/v1/site` | protected | GENERAL (1000/15m) | `routes/sites.js:167` |
| DELETE | `/api/v1/site/:domain` | protected | GENERAL (1000/15m) | `routes/sites.js:138` |
| POST | `/api/v1/site/external` | protected | GENERAL (1000/15m) | `routes/sites.js:212` |
## Certificate authority
_6 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| POST | `/api/v1/ca/backup` | protected | GENERAL (1000/15m) | `routes/ca.js:402` |
| GET | `/api/v1/ca/cert/:domain` | protected | GENERAL (1000/15m) | `routes/ca.js:176` |
| GET | `/api/v1/ca/certs` | protected | GENERAL (1000/15m) | `routes/ca.js:354` |
| GET | `/api/v1/ca/info` | public | GENERAL (1000/15m) | `routes/ca.js:15` |
| GET | `/api/v1/ca/install-script` | public | GENERAL (1000/15m) | `routes/ca.js:63` |
| GET | `/api/v1/ca/root.crt` | public | GENERAL (1000/15m) | `routes/ca.js:45` |
## Updates / workflows
_6 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| GET | `/api/v1/workflows/` | protected | GENERAL (1000/15m) | `routes/workflows.js:44` |
| POST | `/api/v1/workflows/:workflowId/disable` | protected | GENERAL (1000/15m) | `routes/workflows.js:58` |
| POST | `/api/v1/workflows/:workflowId/enable` | protected | GENERAL (1000/15m) | `routes/workflows.js:50` |
| GET | `/api/v1/workflows/:workflowId/history` | protected | GENERAL (1000/15m) | `routes/workflows.js:86` |
| POST | `/api/v1/workflows/:workflowId/run` | protected | GENERAL (1000/15m) | `routes/workflows.js:66` |
| GET | `/api/v1/workflows/history` | protected | GENERAL (1000/15m) | `routes/workflows.js:79` |
## Auto-restart
_5 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| GET | `/api/v1/policies` | protected | GENERAL (1000/15m) | `routes/auto-restart.js:30` |
| DELETE | `/api/v1/policies/:serviceId` | protected | GENERAL (1000/15m) | `routes/auto-restart.js:103` |
| GET | `/api/v1/policies/:serviceId` | protected | GENERAL (1000/15m) | `routes/auto-restart.js:39` |
| POST | `/api/v1/policies/:serviceId` | protected | GENERAL (1000/15m) | `routes/auto-restart.js:60` |
| POST | `/api/v1/policies/:serviceId/test` | protected | GENERAL (1000/15m) | `routes/auto-restart.js:123` |
## OpenClaw integration
_5 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| DELETE | `/api/v1/openclaw/` | protected | GENERAL (1000/15m) | `routes/openclaw.js:467` |
| POST | `/api/v1/openclaw/deploy` | protected | GENERAL (1000/15m) | `routes/openclaw.js:373` |
| GET | `/api/v1/openclaw/proxy/*` | protected | GENERAL (1000/15m) | `routes/openclaw.js:439` |
| POST | `/api/v1/openclaw/proxy/*` | protected | GENERAL (1000/15m) | `routes/openclaw.js:453` |
| GET | `/api/v1/openclaw/status` | protected | GENERAL (1000/15m) | `routes/openclaw.js:339` |
## Config drift
_4 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| POST | `/api/v1/fix` | protected | GENERAL (1000/15m) | `routes/config-drift.js:51` |
| GET | `/api/v1/last` | protected | GENERAL (1000/15m) | `routes/config-drift.js:39` |
| POST | `/api/v1/polling` | protected | GENERAL (1000/15m) | `routes/config-drift.js:66` |
| GET | `/api/v1/report` | protected | GENERAL (1000/15m) | `routes/config-drift.js:30` |
## Licensing
_4 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| POST | `/api/v1/license/activate` | protected | GENERAL (1000/15m) | `routes/license.js:29` |
| POST | `/api/v1/license/deactivate` | protected | GENERAL (1000/15m) | `routes/license.js:55` |
| GET | `/api/v1/license/feature/:feature` | public | GENERAL (1000/15m) | `routes/license.js:66` |
| GET | `/api/v1/license/status` | public | GENERAL (1000/15m) | `routes/license.js:48` |
## File browser
_3 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| GET | `/api/v1/browse/directories` | protected | GENERAL (1000/15m) | `routes/browse.js:52` |
| GET | `/api/v1/browse/roots` | protected | GENERAL (1000/15m) | `routes/browse.js:34` |
| GET | `/api/v1/media/detected-mounts` | protected | GENERAL (1000/15m) | `routes/browse.js:137` |
## Theming
_3 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| GET | `/api/v1/themes` | public | GENERAL (1000/15m) | `routes/themes.js:40` |
| DELETE | `/api/v1/themes/:slug` | protected | GENERAL (1000/15m) | `routes/themes.js:65` |
| POST | `/api/v1/themes/:slug` | protected | GENERAL (1000/15m) | `routes/themes.js:45` |
## Service credentials
_2 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| GET | `/api/v1/credentials/list` | protected | GENERAL (1000/15m) | `routes/credentials.js:15` |
| POST | `/api/v1/credentials/rotate-key` | protected | GENERAL (1000/15m) | `routes/credentials.js:21` |
## Events
_2 routes_
| Method | Full path | Auth | Rate limit | Defined in |
|---|---|---|---|---|
| GET | `/api/v1/events/clients` | protected | GENERAL (1000/15m) | `routes/events.js:154` |
| GET | `/api/v1/events/stream` | protected | GENERAL (1000/15m) | `routes/events.js:126` |
## Mount Point Map
| Route file(s) | Mounted at |
|---|---|
| `routes/billing` | `/api/v1/billing` |
| `routes/ca` | `/api/v1/ca` |
| `routes/calendar` | `/api/v1/calendar` |
| `routes/containers` | `/api/v1/containers` |
| `routes/dependencies` | `/api/v1/dependencies` |
| `routes/deploys` | `/api/v1/deploys` |
| `routes/disk-space` | `/api/v1/disk` |
| `routes/dns` | `/api/v1/dns` |
| `routes/docker-resources` | `/api/v1/docker` |
| `routes/events` | `/api/v1/events` |
| `routes/license` | `/api/v1/license` |
| `routes/mcp` | `/api/v1/mcp` |
| `routes/network-lifecycle` | `/api/v1/network` |
| `routes/network-access` | `/api/v1/network/access` |
| `routes/network-groups` | `/api/v1/network/groups` |
| `routes/network-invites` | `/api/v1/network/invites` |
| `routes/network-people` | `/api/v1/network/people` |
| `routes/network-resources` | `/api/v1/network/resources` |
| `routes/network-wizard` | `/api/v1/network/wizard` |
| `routes/notifications` | `/api/v1/notifications` |
| `routes/openclaw` | `/api/v1/openclaw` |
| `routes/recipes/` | `/api/v1/recipes` |
| `routes/security` | `/api/v1/security` |
| `routes/tailscale` | `/api/v1/tailscale` |
| `routes/tailscale-admin` | `/api/v1/tailscale` |
| `routes/workflows` | `/api/v1/workflows` |
| `routes/auth/` | `/api/v1 (root)` |
| `routes/config/` | `/api/v1 (root)` |
| `routes/share` | `/api/v1 (root)` |
| `routes/services` | `/api/v1 (root)` |
| `routes/health` | `/api/v1 (root)` |
| `routes/monitoring` | `/api/v1 (root)` |
| `routes/i18n` | `/api/v1 (root)` |
| `routes/discover` | `/api/v1 (root)` |
| `routes/discover-adopt` | `/api/v1 (root)` |
| `routes/catalog` | `/api/v1 (root)` |
| `routes/wizard` | `/api/v1 (root)` |
| `routes/disaster-recovery` | `/api/v1 (root)` |
| `routes/caddycode` | `/api/v1 (root)` |
| `routes/fleet` | `/api/v1 (root)` |
| `routes/updates` | `/api/v1 (root)` |
| `routes/sites` | `/api/v1 (root)` |
| `routes/credentials` | `/api/v1 (root)` |
| `routes/arr/` | `/api/v1 (root)` |
| `routes/apps/` | `/api/v1 (root)` |
| `routes/logs` | `/api/v1 (root)` |
| `routes/backups` | `/api/v1 (root)` |
| `routes/browse` | `/api/v1 (root)` |
| `routes/errorlogs` | `/api/v1 (root)` |
| `routes/themes` | `/api/v1 (root)` |
| `routes/ai-intent` | `/api/v1 (root)` |
| `routes/log-insights` | `/api/v1 (root)` |
| `routes/audit-log` | `/api/v1 (root)` |
| `routes/auto-restart` | `/api/v1 (root)` |
| `routes/config-drift` | `/api/v1 (root)` |
| `routes/ssl-monitor` | `/api/v1 (root)` |
| `routes/caddy-upstreams` | `/api/v1 (root)` |
## OpenAPI Spec Cross-Check
- Unique paths in code: **367**
- Unique (method, path) operations in code: **440**
- Handler rows exceed unique operations when the same (method, path) is registered more than once (e.g. GET /api/v1/auth/me, GET+POST /api/v1/config appear in more than one route file).
- Paths in openapi.yaml: **290**
- Note: openapi.yaml lags the code (spec documents the 2026-07 surface); code-derived rows above reflect the declared router (static extraction).
### In code but NOT documented (100)
- `/api/v1/audit-logs/actions`
- `/api/v1/auth/sso-handoff`
- `/api/v1/ca/backup`
- `/api/v1/caddy/upstreams`
- `/api/v1/caddy/upstreams/:host/mute`
- `/api/v1/caddy/upstreams/:host/unmute`
- `/api/v1/caddy/upstreams/incidents`
- `/api/v1/caddy/upstreams/mute`
- `/api/v1/caddycode/generate`
- `/api/v1/caddycode/templates`
- `/api/v1/caddycode/validate`
- `/api/v1/catalog`
- `/api/v1/catalog/:appId`
- `/api/v1/catalog/search`
- `/api/v1/certificates`
- `/api/v1/certificates/:serviceId`
- `/api/v1/check`
- `/api/v1/check/:serviceId`
- `/api/v1/containers/`
- `/api/v1/deploys/catalog/apps`
- `/api/v1/deploys/catalog/deploy`
- `/api/v1/deploys/deploy`
- `/api/v1/deploys/gitea-repos`
- `/api/v1/deploys/install`
- `/api/v1/deploys/journal`
- `/api/v1/deploys/repos`
- `/api/v1/deploys/rollback`
- `/api/v1/deploys/services`
- `/api/v1/deploys/status`
- `/api/v1/disaster/backup`
- ... and 70 more
### Documented but NOT in code (23)
- `/api/v1/auto-restart/policies`
- `/api/v1/auto-restart/policies/:serviceId`
- `/api/v1/auto-restart/policies/:serviceId/test`
- `/api/v1/config-drift/fix`
- `/api/v1/config-drift/last`
- `/api/v1/config-drift/polling`
- `/api/v1/config-drift/report`
- `/api/v1/csrf-token`
- `/api/v1/disk`
- `/api/v1/mcp`
- `/api/v1/metrics`
- `/api/v1/openclaw`
- `/api/v1/ssl/certificates`
- `/api/v1/ssl/certificates/:serviceId`
- `/api/v1/ssl/check`
- `/api/v1/ssl/check/:serviceId`
- `/api/v1/ssl/config`
- `/api/v1/workflows/workflows`
- `/api/v1/workflows/workflows/:workflowId/disable`
- `/api/v1/workflows/workflows/:workflowId/enable`
- `/api/v1/workflows/workflows/:workflowId/history`
- `/api/v1/workflows/workflows/:workflowId/run`
- `/api/v1/workflows/workflows/history`
## Known Limitations
- Literal single-line `router.<method>('path', ...)` declarations only;
multiline, computed, chained, `router.route()`, and `app.all()`
registrations may be omitted. Mount resolution relies on the
maintained composition map above. Treat this file as a
high-coverage declarative inventory, not a guaranteed-complete listing.
- Duplicate registrations (3): the handler-row total exceeds
unique operations because of these:
- GET /api/v1/auth/me: routes/auth/admin.js:112, routes/auth/index.js:158
- GET /api/v1/config: routes/config/settings.js:26, routes/ssl-monitor.js:80
- POST /api/v1/config: routes/config/settings.js:43, routes/ssl-monitor.js:90