Authentication
The API binds to 0.0.0.0:8090 so anything on the same network can
reach it. The PIN file at %APPDATA%\Seraph\pin.txt gates access.
The PIN itself is printed at startup
(PIN=<6 digits> at <path>) and rotates per process.
Flow
# 1. Exchange the PIN for a long-lived token.
curl -s -X POST http://localhost:8090/auth/pin \
-H 'content-type: application/json' \
-d '{"pin":"798465"}'
{ "token": "DLqXoY3WJmWqf3rL...0+9pjSjuBKP" }
# 2. Pass the token on every subsequent call.
curl -s http://localhost:8090/api/bots \
-H 'authorization: Bearer DLqXoY3WJmWqf3rL...0+9pjSjuBKP'
The token can also be sent as ?token=<token> on the query string —
useful for <img> / EventSource callers that can't set headers.
Endpoints
GET /health
No auth required. Used by external monitors / load balancers to check the process is alive.
Response (200, text/plain):
ok
POST /auth/pin
Exchange the local PIN for a long-lived bearer token.
Body:
{ "pin": "798465" }
Response (200):
{ "token": "<base64-48-byte-token>" }
Errors:
| Status | Body |
|---|---|
401 | {"error":"wrong pin"} |
429 | {"error":"locked, retry in 38s"} |
GET /api-info
Bearer-protected helper that the embedded webview uses to discover its own port + token. Useful as a "did my token survive a restart?" ping from external tooling.
Response (200):
{
"port": 8090,
"token": "<the-same-token-you-just-sent>"
}
Rate limiting
A single token-bucket on /auth/pin slows down brute-force attempts.
After enough wrong PINs the bucket locks and returns:
429 Too Many Requests
{"error":"locked, retry in 38s"}
The bucket is per-process; restarting Seraph resets it. The PIN itself is 6 digits = 1,000,000 candidates, but the bucket caps you at ~12 attempts/minute, so a real brute-force takes >50 days on average.