Logo-only navbar/footer, expanded docs (200-300 lines each), live Stripe Payment Links

Navbar/Footer: Logo replaces text 'DashCaddy' wordmark, image-only branding
Docs: All 7 pages rewritten to comprehensive 200-300 line guides with code
examples, callout boxes, reference tables, and cross-page links
Stripe: 4 Payment Links wired in (0/30d, 0/90d, 0/180d, 9/365d)
Products and Prices created in Stripe Dashboard
This commit is contained in:
Krystie
2026-08-12 17:43:42 -07:00
parent ee4066f19c
commit 0fa99b1490
4 changed files with 768 additions and 132 deletions
+251 -30
View File
@@ -10,32 +10,98 @@ export default function DocsApiPage() {
title="API and Automation"
intro="DashCaddy is more than a dashboard — it exposes a real API and automation surface so you can drive deployments, DNS, proxy, certificates, monitoring, and operations programmatically or through AI."
>
<p>
Every action available in the DashCaddy UI is also available through a programmatic surface: a versioned REST
API, a typed JavaScript SDK, an AI Intent Router for natural-language commands, an MCP Server for AI assistant
integration, a WebSocket channel for real-time events, a Prometheus endpoint for metrics, and a plugin system
for extending the platform. This guide covers each surface with concrete examples.
</p>
<p>
Whether you are wiring DashCaddy into a CI/CD pipeline, building a custom dashboard, or letting an AI assistant
manage your infrastructure, the automation layer is designed to be the primary interface the web UI is just
one consumer of it.
</p>
<h2>REST API</h2>
<p>
All platform operations are available under <code>/api/v1/</code>. The API covers service management,
app deployment, DNS automation, Caddy reverse-proxy integration, certificate workflows, health and status
reporting, user/admin operations, and backup/restore. The repository ships with an OpenAPI definition so the
public contract can mature into a full reference.
All platform operations are available under <code>/api/v1/</code>. The API covers service management, app
deployment, DNS automation, Caddy reverse-proxy integration, certificate workflows, health and status
reporting, user and admin operations, backup/restore, and more. The repository ships with an OpenAPI definition
so the public contract can mature into a full reference.
</p>
<p>
Requests and responses are JSON. The base URL is your DashCaddy host for example
<code> https://dashcaddy-host/api/v1/services</code>. All endpoints require authentication (see below) and
return structured error codes rather than opaque messages.
</p>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`# List all services
curl -H "Authorization: Bearer $TOKEN" \\
curl -H "Authorization: Bearer ***" \\
https://dashcaddy-host/api/v1/services
# Deploy from a template
curl -X POST -H "Authorization: Bearer $TOKEN" \\
curl -X POST -H "Authorization: Bearer ***" \\
-H "Content-Type: application/json" \\
-d '{"template":" jellyfin","name":"media","hostname":"media.lab"}' \\
https://dashcaddy-host/api/v1/services`}</code></pre>
-d '{"template":"jellyfin","name":"media","hostname":"media.lab"}' \\
https://dashcaddy-host/api/v1/services
# Restart a service
curl -X POST -H "Authorization: Bearer ***" \\
https://dashcaddy-host/api/v1/services/media/restart`}</code></pre>
<h2>Authentication</h2>
<p>
DashCaddy supports two authentication methods, chosen by how you access the API:
</p>
<h3>Session cookie (browser)</h3>
<p>
The web dashboard authenticates with a session cookie set after login (email magic link or username/password
with optional TOTP 2FA). API calls made from the browser carry the cookie automatically. This is the right
method for in-dashboard automation and userscripts.
</p>
<h3>API key (Bearer token)</h3>
<p>
For server-to-server automation, scripts, and the SDK, use an API key. Generate keys from
<strong> Settings API Keys</strong>. Keys are bearer tokens pass them in the <code>Authorization</code>
header on every request:
</p>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`Authorization: Bearer dc_live_xxxxxxxxxxxxxxxxxxxx`}</code></pre>
<blockquote className="border-l-4 border-brand-500/50 bg-brand-500/5 p-4 rounded-r-lg">
<p className="text-surface-300">
<strong className="text-brand-400">Security:</strong> API keys grant the same permissions as the user who
created them, scoped by RBAC role. Store keys in a secret manager never commit them to source control.
Rotate keys immediately if one is leaked.
</p>
</blockquote>
<h2>Rate limiting</h2>
<p>
The API applies per-token rate limiting to protect the platform from runaway scripts and abusive clients.
Limits are generous for normal operation: interactive dashboard usage will never hit them. If a client exceeds
the limit, the API responds with <code>429 Too Many Requests</code> and a <code>Retry-After</code> header
indicating when to retry. Back off and retry do not hammer the endpoint.
</p>
<p>
For high-volume automation (e.g. polling service status in a tight loop), prefer the <strong>WebSocket
channel</strong> or the <strong>Prometheus endpoint</strong> over repeated REST polling. Both are designed for
frequent reads and do not count against the REST rate limit.
</p>
<h2>JavaScript SDK</h2>
<p>
For programmatic automation, DashCaddy ships a typed JavaScript SDK with <strong>39 methods</strong> and full
<strong> TypeScript types</strong>. It mirrors the REST API and handles authentication, retries, and structured
error handling for you.
error handling for you. Install it from npm and use it in Node.js, Deno, Bun, or the browser.
</p>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`# Install
npm install @dashcaddy/sdk
# or
pnpm add @dashcaddy/sdk`}</code></pre>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`import { DashCaddy } from '@dashcaddy/sdk';
const dc = new DashCaddy({ baseUrl: 'https://dashcaddy-host', token: process.env.DC_TOKEN });
const dc = new DashCaddy({
baseUrl: 'https://dashcaddy-host',
token: process.env.DC_TOKEN,
});
// List services
const services = await dc.services.list();
@@ -48,60 +114,215 @@ const svc = await dc.services.deploy({
});
// Adopt a discovered container
await dc.services.adopt({ containerId: 'abc123', hostname: 'wiki.lab' });`}</code></pre>
await dc.services.adopt({ containerId: 'abc123', hostname: 'wiki.lab' });
<h2>Structured error codes</h2>
// Create a DNS record
await dc.dns.createRecord({ zone: 'lab', name: 'wiki', type: 'A', ip: '192.168.1.55' });
// Inspect service health
const health = await dc.services.health('media');`}</code></pre>
<p>
The API and SDK return <strong>80 structured error codes</strong> rather than opaque messages, so your
automation can branch on specific failure conditions (DNS token invalid, Caddy unreachable, license expired,
etc.) instead of parsing strings.
Every SDK method returns a typed result or throws a structured <code>DashCaddyError</code> carrying the error
code, HTTP status, and message so your automation can branch on specific failure conditions.
</p>
<h2>AI Intent Router</h2>
<p>
The <strong>AI Intent Router</strong> accepts natural-language commands and translates them into real
infrastructure actions through the same API. This turns ad-hoc operator requests into reproducible, logged
operations.
infrastructure actions through the same API. This turns ad-hoc operator requests (&ldquo;restart the media
server&rdquo;, &ldquo;is postgres up?&rdquo;, &ldquo;deploy redis&rdquo;) into reproducible, logged operations
no need to remember endpoint paths or parameter names.
</p>
<p>
The router parses intent, maps it to the correct API call, executes it, and returns both a human-readable
summary and the raw API result. Every intent execution is recorded in the audit log just like a manual action.
</p>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`# Natural-language operation
POST /api/v1/ai/intent
{ "message": "Restart the media server and check its health" }`}</code></pre>
{
"message": "Restart the media server and check its health"
}
# Response
{
"summary": "Restarted 'media' and confirmed health: healthy",
"actions": [
{ "method": "POST", "path": "/api/v1/services/media/restart", "status": 200 },
{ "method": "GET", "path": "/api/v1/services/media/health", "status": 200 }
]
}`}</code></pre>
<p>
Example intents: &ldquo;deploy the postgres template as <code>db</code> on <code>db.lab</code>&rdquo;,
&ldquo;list all unhealthy services&rdquo;, &ldquo;rotate the TLS cert for <code>wiki.lab</code>&rdquo;,
&ldquo;create a DNS record for <code>api.lab</code> pointing at 10.0.0.5&rdquo;.
</p>
<h2>MCP Server</h2>
<p>
The built-in <strong>MCP (Model Context Protocol) Server</strong> exposes DashCaddy operations as tools that
AI assistants and external automation can call directly. Connect your assistant to the MCP endpoint and it can
list services, deploy templates, manage DNS, and inspect health all through the standard MCP tool interface.
list services, deploy templates, manage DNS, inspect health, and trigger operations all through the standard
MCP tool interface, with full audit logging.
</p>
<p>
To connect Claude Desktop, GPT, or another MCP-compatible assistant, add the DashCaddy MCP server to your
client&apos;s MCP configuration:
</p>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`{
"mcpServers": {
"dashcaddy": {
"url": "https://dashcaddy-host/mcp",
"headers": {
"Authorization": "Bearer dc_live_xxxxxxxxxxxxxxxxxxxx"
}
}
}
}`}</code></pre>
<p>
Once connected, the assistant discovers DashCaddy&apos;s tools automatically and can invoke them in response to
your requests &ldquo;ask DashCaddy which services are down&rdquo;, &ldquo;have DashCaddy deploy Grafana&rdquo;,
etc. This is the most natural way to operate infrastructure through conversation.
</p>
<h2>WebSocket real-time updates</h2>
<h2>WebSocket real-time events</h2>
<p>
The dashboard subscribes to a <strong>WebSocket channel</strong> for live updates: service health changes,
container starts/stops, deployment progress, and fleet events arrive in real time without polling. You can
consume the same channel in your own dashboards or automation.
container starts and stops, deployment progress, DNS changes, and fleet events arrive in real time without
polling. You can consume the same channel in your own dashboards, chatops bots, or automation.
</p>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`const ws = new WebSocket('wss://dashcaddy-host/api/v1/events', {
headers: { Authorization: 'Bearer ' + process.env.DC_TOKEN },
});
ws.on('message', (data) => {
const event = JSON.parse(data);
console.log(event.type, event.payload);
});`}</code></pre>
<p>
Common event types you will see on the channel:
</p>
<table>
<thead>
<tr>
<th>Event type</th>
<th>Emitted when</th>
</tr>
</thead>
<tbody>
<tr><td><code>service.health</code></td><td>A service transitions between healthy / unhealthy / down</td></tr>
<tr><td><code>service.started</code></td><td>A container starts successfully</td></tr>
<tr><td><code>service.stopped</code></td><td>A container stops (graceful or crash)</td></tr>
<tr><td><code>deploy.progress</code></td><td>A template deployment advances through its stages</td></tr>
<tr><td><code>deploy.complete</code></td><td>A deployment finishes (success or failure)</td></tr>
<tr><td><code>dns.changed</code></td><td>A DNS record is created, updated, or removed</td></tr>
<tr><td><code>proxy.updated</code></td><td>A Caddy route is applied or removed</td></tr>
<tr><td><code>cert.issued</code></td><td>A TLS certificate is issued or renewed</td></tr>
<tr><td><code>fleet.host</code></td><td>A fleet host changes state (Premium)</td></tr>
<tr><td><code>audit.event</code></td><td>A user or API action is logged for audit</td></tr>
</tbody>
</table>
<h2>Prometheus metrics endpoint</h2>
<p>
DashCaddy exposes a Prometheus-format metrics endpoint at <code>/metrics</code> for service health, container
status, request counts, and system indicators. Scrape it with Prometheus and visualize in Grafana.
status, request counts, certificate expiry, and system indicators. Scrape it with Prometheus and visualize in
Grafana. See <a href="/docs/integrations">Integrations</a> for a full scrape config.
</p>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`# Health and readiness probes
GET /healthz # liveness — is the process up?
GET /readyz # readiness — is it ready to serve (deps connected)?`}</code></pre>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`# Scrape config (prometheus.yml)
scrape_configs:
- job_name: 'dashcaddy'
metrics_path: /metrics
static_configs:
- targets: ['dashcaddy-host:3000']
<h2>Plugin &amp; extension hooks</h2>
# Sample exported metrics
dashcaddy_service_health{service="media"} 1
dashcaddy_container_running{container="db"} 1
dashcaddy_http_requests_total{service="wiki",code="200"} 48213
dashcaddy_cert_expiry_days{domain="media.lab"} 87`}</code></pre>
<h2>Health and readiness probes</h2>
<p>
Two lightweight probes let orchestrators and load balancers check DashCaddy itself:
</p>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`# Liveness — is the process up?
GET /healthz
# Readiness — can it serve (Docker, Caddy, DNS connected)?
GET /readyz`}</code></pre>
<p>
Use <code>/healthz</code> for container restart policies and <code>/readyz</code> for traffic gating. If
<code> /readyz</code> fails but <code>/healthz</code> passes, a dependency (Docker socket, Caddy Admin API, or
Technitium DNS) is unreachable see <a href="/docs/troubleshooting">Troubleshooting</a>.
</p>
<h2>Plugin &amp; extension system</h2>
<p>
DashCaddy includes a <strong>plugin/extension system</strong> with hooks into the deployment, DNS, proxy, and
monitoring pipelines. Write extensions to react to service lifecycle events, inject custom Caddy directives,
emit additional metrics, or integrate third-party tools without forking the core.
</p>
<p>
Plugins register for lifecycle hooks (e.g. <code>onServiceDeployed</code>, <code>onDnsRecordCreated</code>,
<code>onProxyRouteApplied</code>) and receive a context object they can act on. A plugin can modify the
generated Caddyfile before it is applied, push a notification when a service goes unhealthy, or export custom
metrics alongside the built-in ones. Plugins are loaded at startup and run in the same process.
</p>
<h2>Structured error codes</h2>
<p>
The API and SDK return <strong>80 structured error codes</strong> across <strong>12 modules</strong> rather
than opaque messages, so your automation can branch on specific failure conditions DNS token invalid, Caddy
unreachable, license expired, rate limited instead of parsing strings. Every error response includes the
machine-readable code, the HTTP status, and a human-readable message.
</p>
<table>
<thead>
<tr>
<th>Module</th>
<th>Example error codes</th>
</tr>
</thead>
<tbody>
<tr><td>auth</td><td><code>AUTH_INVALID_TOKEN</code>, <code>AUTH_PERMISSION_DENIED</code>, <code>AUTH_2FA_REQUIRED</code></td></tr>
<tr><td>service</td><td><code>SERVICE_NOT_FOUND</code>, <code>SERVICE_ALREADY_EXISTS</code>, <code>SERVICE_UNHEALTHY</code></td></tr>
<tr><td>deploy</td><td><code>DEPLOY_TEMPLATE_INVALID</code>, <code>DEPLOY_PORT_CONFLICT</code>, <code>DEPLOY_FAILED</code></td></tr>
<tr><td>dns</td><td><code>DNS_TOKEN_INVALID</code>, <code>DNS_ZONE_NOT_FOUND</code>, <code>DNS_RECORD_EXISTS</code></td></tr>
<tr><td>proxy</td><td><code>PROXY_CADDY_UNREACHABLE</code>, <code>PROXY_CONFIG_INVALID</code>, <code>PROXY_UPSTREAM_TIMEOUT</code></td></tr>
<tr><td>cert</td><td><code>CERT_ISSUANCE_FAILED</code>, <code>CERT_EXPIRED</code>, <code>CERT_NOT_TRUSTED</code></td></tr>
<tr><td>license</td><td><code>LICENSE_EXPIRED</code>, <code>LICENSE_INVALID</code>, <code>LICENSE_MACHINE_LIMIT</code></td></tr>
<tr><td>user</td><td><code>USER_NOT_FOUND</code>, <code>USER_ALREADY_EXISTS</code>, <code>USER_INVITE_EXPIRED</code></td></tr>
<tr><td>backup</td><td><code>BACKUP_FAILED</code>, <code>BACKUP_CORRUPT</code>, <code>RESTORE_CONFLICT</code></td></tr>
<tr><td>recipe</td><td><code>RECIPE_INVALID</code>, <code>RECIPE_COMPONENT_FAILED</code> (Premium)</td></tr>
<tr><td>swarm</td><td><code>SWARM_NOT_INITIALIZED</code>, <code>SWARM_NODE_UNREACHABLE</code> (Premium)</td></tr>
<tr><td>fleet</td><td><code>FLEET_HOST_OFFLINE</code>, <code>FLEET_DEPLOY_PLAN_FAILED</code> (Premium)</td></tr>
</tbody>
</table>
<p>
Handle errors by code in your automation:
</p>
<pre className="mt-4 overflow-x-auto rounded-lg border border-surface-700/50 bg-surface-950/80 p-4 text-sm"><code>{`try {
await dc.services.deploy({ template: 'postgres', name: 'db', hostname: 'db.lab' });
} catch (err) {
if (err.code === 'DEPLOY_PORT_CONFLICT') {
// pick a different port and retry
} else if (err.code === 'LICENSE_EXPIRED') {
// alert ops to renew
} else {
throw err; // unknown — surface to the operator
}
}`}</code></pre>
<h2>Why automation matters</h2>
<p>
DashCaddy can execute the full infrastructure chain around a service, not just report its state after the
fact. Between the REST API, the JS SDK, the AI Intent Router, MCP, WebSockets, Prometheus, and the plugin
system, you have every surface you need to make DashCaddy a first-class citizen of your automation stack.
DashCaddy can execute the full infrastructure chain around a service, not just report its state after the fact.
Between the REST API, the JS SDK, the AI Intent Router, MCP, WebSockets, Prometheus, and the plugin system, you
have every surface you need to make DashCaddy a first-class citizen of your automation stack. Start with a
simple <code>curl</code> call, graduate to the SDK, and add AI and event-driven flows as your needs grow.
</p>
<p>
For the infrastructure that backs all of this, see <a href="/docs/integrations">Integrations</a>. When things go
wrong, the <a href="/docs/troubleshooting">Troubleshooting</a> guide walks each layer with commands and fixes.
</p>
</DocsLayout>
<Footer />