Control Plane API Reference (v1)
Base URL: http://localhost:8000
- Content-Type:
application/json - Error format:
{ "detail": string } - Authentication:
- Session cookie via
POST /api/v1/auth/login - Bearer token via
Authorization: Bearer <token>(Master token fromMASTER_API_TOKENor service tokens from/api/v1/auth/tokens)
- Session cookie via
Conventions
- Unless noted otherwise, endpoints require authentication via session cookie or bearer token.
- Endpoints that manage tokens (
/api/v1/auth/tokens) require the master token. - Error responses use
{ "detail": string }with appropriate HTTP status codes. - Path parameters appear as
{param}(for example{domain}).
Models
Upstream
| Field | Type | Required | Description | Example |
|---|---|---|---|---|
| scheme | string | yes | Origin protocol | "http" or "https" |
| host | string | yes | Origin host | "origin.example.com" |
| port | integer | yes | Origin port | 80 |
| weight | integer | yes | Weighted round-robin weight | 1 |
Rule
| Field | Type | Required | Description | Example |
|---|---|---|---|---|
| path | string | yes | Path prefix or regex (interpreted by OpenResty) | "^/assets/" |
| ttl | integer | yes | TTL in seconds | 600 |
| methods | string[] | yes | Allowed HTTP methods | ["GET","HEAD"] |
| slice | boolean | no | Enable slice for this rule (overrides global) | false |
DomainConf
| Field | Type | Required | Description | Example |
|---|---|---|---|---|
| origins | Upstream[] | yes | List of upstream origins | [Upstream, ...] |
| upstream_headers | object | no | Extra headers to send to origin | {"X-From":"CDN"} |
| cache_enable | boolean | yes | Enable caching | true |
| slice_enable | boolean | yes | Enable slice globally | false |
| rules | Rule[] | yes | Cache rules | [Rule, ...] |
| use_acme_dns01 | boolean | no | Enable ACME dns-01 automation | false |
| acme_cname_target | string or null | no | Target CNAME for _acme-challenge (filled after acme-dns registration) | null |
CacheUpdate (PUT /cache-rules)
| Field | Type | Required | Description |
|---|---|---|---|
| cache_enable | boolean | no | Toggle caching |
| slice_enable | boolean | no | Toggle slice |
| rules | Rule[] | no | Cache rules |
UpstreamsPayload (PUT /upstreams)
| Field | Type | Required | Description |
|---|---|---|---|
| origins | Upstream[] | yes | Complete upstream list (replaces all) |
CertPayload (PUT /cert)
| Field | Type | Required | Description |
|---|---|---|---|
| fullchain_pem | string | yes | Certificate chain in PEM |
| key_pem | string | yes | Private key in PEM |
AssignedNode
| Field | Type | Description |
|---|---|---|
| id | string | Node identifier |
| a | string | IPv4 address or null |
| aaaa | string | IPv6 address or null |
Endpoints
GET /healthz
Authentication: None
- Success 200:
{ "ok": true } - Failure 500:
{ "detail": string }
Example request
curl -s http://localhost:8000/healthz
Example response
{ "ok": true }
POST /api/v1/auth/login
Authentication: None
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| username | string | yes | Username |
| password | string | yes | Password |
- Success 200:
{ "ok": true }(sets session cookie) - Errors:
401 invalid credentials,403 password authentication disabled
Example request
curl -i -X POST 'http://localhost:8000/api/v1/auth/login' \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"******"}'
Example response
{ "ok": true }
POST /api/v1/auth/logout
- Success 200:
{ "ok": true }(clears session cookie)
GET /api/v1/auth/me
Authentication: Session or bearer
Success 200
| Field | Type | Description |
|---|---|---|
| username | string | Current username |
| auth_method | string | one of session/token/master/dev |
| token_id | string or null | Service token id (null for master token) |
Example request
curl -s 'http://localhost:8000/api/v1/auth/me' -b cookies.txt -c cookies.txt
Example response
{ "username": "admin", "auth_method": "session", "token_id": null }
GET /api/v1/auth/tokens
Authentication: Master token
- Success 200
| Field | Type | Description |
|---|---|---|
| tokens | array | Array of Token objects |
Token object
| Field | Type | Description |
|---|---|---|
| id | string | Token id |
| label | string | Human label |
| created_at | string (ISO 8601) | Creation time |
| last_used_at | string or null | Last use time |
| suffix | string | Last 2 chars of token |
Example request
curl -s 'http://localhost:8000/api/v1/auth/tokens' \
-H 'Authorization: Bearer ${MASTER_API_TOKEN}'
POST /api/v1/auth/tokens
Authentication: Master token
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| label | string | yes | Token label |
- Success 200: Token object plus
token(one-time value)
| Extra Field | Type | Description |
|---|---|---|
| token | string | Full token (returned only once) |
Example request
curl -s -X POST 'http://localhost:8000/api/v1/auth/tokens' \
-H 'Authorization: Bearer ${MASTER_API_TOKEN}' \
-H 'Content-Type: application/json' \
-d '{"label":"ci token"}'
Example response
{
"id": "4f8a1c9e5d3b",
"label": "ci token",
"created_at": "2024-04-02T07:20:00+00:00",
"last_used_at": null,
"suffix": "3b",
"token": "qjP...<one-time>..."
}
DELETE /api/v1/auth/tokens/{token_id}
- Requires master token
- Success 200:
{ "ok": true }
GET /api/v1/users
Authentication: Session or bearer
Success 200
| Field | Type | Description |
|---|---|---|
| users | array | Array of user objects |
User object
| Field | Type | Description |
|---|---|---|
| username | string | Username |
| string | Email (may be empty) | |
| status | string | "Active" or "Inactive" |
| lastLogin | string | "Never" or timestamp |
Example request
curl -s 'http://localhost:8000/api/v1/users' \
-H 'Authorization: Bearer <token>'
POST /api/v1/users
Request body
| Field | Type | Required |
|---|---|---|
| username | string | yes |
| string | yes | |
| password | string | yes |
| status | string | yes ("Active"/"Inactive") |
- Success 200:
{ "ok": true } - Error 409:
user already exists
PUT /api/v1/users/{username}
Request body (all optional)
| Field | Type |
|---|---|
| string | |
| password | string |
| status | string |
- Success 200:
{ "ok": true } - Error 404:
user not found
DELETE /api/v1/users/{username}
- Success 200:
{ "ok": true }
POST /api/v1/domains/{domain}
Authentication: Session or bearer
Path params
| Param | Type | Description |
|---|---|---|
| domain | string | Domain name |
Request body: DomainConf
- Success 200:
{ "ok": true } - Errors:
400 origins must be a non-empty list,409 domain already exists
Example request
curl -X POST 'http://localhost:8000/api/v1/domains/example.com' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <token>' \
-d '{
"origins":[{"scheme":"http","host":"10.0.0.10","port":80,"weight":2}],
"cache_enable": true,
"slice_enable": false,
"rules": []
}'
GET /api/v1/domains
Success 200
| Field | Type | Description |
|---|---|---|
| domains | string[] | Domain names |
GET /api/v1/domains/{domain}
- Success 200:
DomainConf - Error 404:
domain not found
GET /api/v1/domains/{domain}/cname
Authentication: Session or bearer
Path params
| Param | Type | Description |
|---|---|---|
| domain | string | Domain name |
Success 200
| Field | Type | Description |
|---|---|---|
| access_domain | string | Access FQDN |
| replicas | integer | Replica count |
| assigned_nodes | AssignedNode[] | Nodes assigned |
| ttl | integer | TTL |
Errors
- 405:
cname is disabled
Example response
{
"access_domain": "example.com.cdn.local.test.",
"replicas": 2,
"assigned_nodes": [
{"id":"node-1","a":"100.64.2.61","aaaa":null},
{"id":"node-2","a":"100.64.2.62","aaaa":null}
],
"ttl": 60
}
PUT /api/v1/domains/{domain}
Request body: DomainConf
- Success 200:
{ "ok": true } - Errors:
404 domain not found,400 origins must be a non-empty list
DELETE /api/v1/domains/{domain}
- Success 200:
{ "ok": true }(also cleans related keys)
PUT /api/v1/domains/{domain}/cache-rules
Request body: CacheUpdate
- Success 200:
{ "ok": true }
PUT /api/v1/domains/{domain}/upstreams
Request body: UpstreamsPayload
- Success 200:
{ "ok": true }
PUT /api/v1/domains/{domain}/cert
Request body: CertPayload
- Success 200:
{ "ok": true } - Error 400:
invalid PEM
GET /api/v1/domains/{domain}/acme
Success 200
Response fields
| Field | Type | Description |
|---|---|---|
| use_acme_dns01 | boolean | Whether ACME is enabled |
| acme_cname_target | string or null | Target CNAME for _acme-challenge |
| status | string | "registered" / "disabled" / other statuses |
| registered | boolean | Whether acme-dns is registered |
| fulldomain | string or null | Full domain returned by acme-dns |
| subdomain | string or null | Subdomain part used by acme-dns |
POST /api/v1/domains/{domain}/acme
- Optional body:
{ "force_renew": true }(ignored by current implementation) - Success 202:
{ "ok": true, "task_id": string } - Conflict 409:
acme issuance already running or queued for this domain
DELETE /api/v1/domains/{domain}/acme
- Success 200:
{ "ok": true }
POST /api/v1/purge
Authentication: Session or bearer
Query params
| Param | Type | Required | Description |
|---|---|---|---|
| domain | string | yes | Target domain |
| path | string | yes | Path; supports prefix wildcard * (e.g., /images/cat*); /* clears all |
- Success 200:
{ "ok": true }(message published; cleanup completes asynchronously)
Example request
curl -X POST 'http://localhost:8000/api/v1/purge?domain=example.com&path=/images/cat*' \
-H 'Authorization: Bearer <token>'
PUT /api/v1/nodes
Authentication: Session or bearer
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| nodes | array | yes | Array of node objects |
Node object
| Field | Type | Description |
|---|---|---|
| id | string | Node id |
| name | string | Human name |
| a | string | IPv4 |
| aaaa | string or null | IPv6 |
- Notes:
activeis not accepted (maintained by health checks). Update triggers CNAME zone rebuild and NOTIFY. - Success 200:
{ "ok": true, "count": number }
Example request
curl -X PUT 'http://localhost:8000/api/v1/nodes' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"nodes": [
{"id":"node-1","name":"edge-1","a":"100.64.2.61","aaaa":null},
{"id":"node-2","name":"edge-2","a":"100.64.2.62","aaaa":null}
]
}'