Time API
A simple REST API for current time information with timezone support.
Repository: https://github.com/csmith416/smith-time
Served at / in the container, typically /time-api behind Caddy.
Overview
This service provides a small, stable HTTP API for retrieving current time data with timezone support.
# time curl -H "X-API-Key: <api-key>" "https://smith-lab.ddns.net/time-api/v1/time?timezone=UTC"
Authentication
API Key (User Requests)
User endpoints (/v1/time, /v1/timezones) may require an API key via the header below.
Enforcement is controlled by REQUIRE_API_KEY:
- unset (default): auto — requires a key only after at least one key exists.
- true: required — always requires a key (returns 503 if no keys exist).
- false: disabled — key is not required.
Admin Token (Key Management)
Admin endpoints (/v1/keys, revoke endpoints) require the admin token header below.
Configure one of:
- ADMIN_TOKEN_SHA256_HEX (preferred) — hex-encoded SHA-256 of the token
- ADMIN_TOKEN (fallback) — plaintext token (will be hashed in-memory)
If admin token is not configured, admin endpoints return 503 with {"error":"admin token not configured"}.
Configuration
Configuration is done via environment variables.
| Variable | Description | Default |
|---|---|---|
| KEY_DB_PATH | Where API keys are stored (hashed JSON file). | /data/keys.json if /data exists; otherwise data/keys.json |
| REQUIRE_API_KEY | Controls API key enforcement mode (auto/required/disabled). | unset (auto) |
| ADMIN_TOKEN_SHA256_HEX | Preferred admin token configuration (hex SHA-256 of token). | unset |
| ADMIN_TOKEN | Fallback admin token configuration (plaintext; hashed in-memory). | unset |
| STATIC_DIR | Dev-only: serve UI assets from disk instead of embedded files. | unset (use embedded) |
# Require API keys once you have them REQUIRE_API_KEY=true # Store keys on the persistent /data volume KEY_DB_PATH=/data/keys.json # Admin token stored as a SHA-256 hex hash (no plaintext in env) ADMIN_TOKEN_SHA256_HEX=<hex_sha256_of_token>
CLI
The built binary includes a small key-management CLI. It operates on the same key DB path as the server.
Create key (one-time view):
./time-api keys create --name "my-service"
List keys (no plaintext):
./time-api keys list
Revoke key:
./time-api keys revoke <id>
Errors
All JSON errors use the same shape:
{"error": "..."}
| Status | When it happens | Example |
|---|---|---|
| 400 | Invalid request (example: bad timezone) | {"error":"Invalid timezone"} |
| 401 | Missing/invalid X-API-Key or X-Admin-Token | {"error":"unauthorized"} |
| 404 | Unknown endpoint or missing key id | {"error":"Page not found"} |
| 405 | Unsupported method on an endpoint | {"error":"method not allowed"} |
| 500 | Server error (storage/read/verify failures) | {"error":"internal error"} |
| 503 | Auth configured but prerequisites missing (no keys / admin token not configured) | {"error":"no api keys configured"} |
Operations
API Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /v1/time | API key (conditional) | Current time in a requested timezone |
| GET | /v1/timezones | API key (conditional) | All supported timezones |
| GET | /v1/healthz | None | Liveness/health check |
| GET | /v1/version | None | Build/version info |
| GET | /v1/status | None | Operational status (non-sensitive) |
| GET | /v1/openapi.json | None | OpenAPI 3.0.3 spec |
| GET POST | /v1/keys | Admin token | List keys / create key (one-time view) |
| POST | /v1/keys/{id}/revoke | Admin token | Revoke a key |
| DELETE | /v1/keys/{id} | Admin token | Revoke a key (alternate route) |
Get Current Time
Headers: X-API-Key (required if key enforcement is enabled)
Query parameters:
- timezone (optional): e.g. UTC, Europe/London. Defaults to UTC.
Example call:
curl -H "X-API-Key: <api-key>" "https://smith-lab.ddns.net/time-api/v1/time?timezone=UTC"
Status codes:
- 200 OK
- 400 Invalid timezone
- 401 Unauthorized (missing/invalid API key)
- 503 No API keys configured (when enforcement is required)
Sample response:
{
"timestamp": 1634567890,
"time": "10:13:44.323435",
"date": "2021-10-18",
"timezone": "UTC",
"abbr": "GMT",
"offset": "+00:00",
"iso8601": "2021-10-18T10:13:44+00:00"
}
Sample error (invalid timezone):
{"error":"Invalid timezone"}
List Available Timezones
Headers: X-API-Key (required if key enforcement is enabled)
Query parameters: none
Example call:
curl -H "X-API-Key: <api-key>" "https://smith-lab.ddns.net/time-api/v1/timezones"
Status codes:
- 200 OK
- 401 Unauthorized (missing/invalid API key)
- 503 No API keys configured (when enforcement is required)
Sample response:
{
"timezones": [
{"name": "Africa/Abidjan", "abbr": "GMT"},
{"name": "Africa/Accra", "abbr": "GMT"},
{"name": "Europe/London", "abbr": "BST"}
]
}
Health
Headers: none
Query parameters: none
Example call:
curl "https://smith-lab.ddns.net/time-api/v1/healthz"
Status codes: 200 OK
Sample response:
{
"ok": true,
"status": "ok",
"time_utc": "2026-02-01T12:34:56.123456789Z",
"uptime_seconds": 12345
}
Version
Headers: none
Query parameters: none
Example call:
curl "https://smith-lab.ddns.net/time-api/v1/version"
Status codes: 200 OK
Sample response:
{
"version": "dev",
"commit": "",
"build_date": ""
}
Status
Headers: none
Query parameters: none
Example call:
curl "https://smith-lab.ddns.net/time-api/v1/status"
Status codes: 200 OK, 500 internal error
Sample response:
{
"ok": true,
"time_utc": "2026-02-01T12:34:56.123456789Z",
"uptime_seconds": 12345,
"api_key_mode": "auto",
"keys_total": 3
}
OpenAPI
Headers: none
Query parameters: none
Example call:
curl "https://smith-lab.ddns.net/time-api/v1/openapi.json"
Status codes: 200 OK
Returns the OpenAPI spec for the service.
Tip: import this into Postman/Insomnia or use it to generate a client.
Admin Keys
Headers: X-Admin-Token (required)
Query parameters (GET):
- include_revoked (optional): set to true to include revoked keys (default: omitted/false)
What each method does:
- GET /v1/keys: returns active keys only by default (no plaintext; includes id, name, timestamps, last4).
- POST /v1/keys: creates a new key and returns api_key once.
Body (POST):
- name (required): friendly label for the key (recommended: service or human owner)
No plaintext keys are stored on disk. api_key is returned only on create.
Example call (GET):
curl -H "X-Admin-Token: <admin-token>" "https://smith-lab.ddns.net/time-api/v1/keys"
Example call (POST):
Bash/macOS/Linux:
curl -H "X-Admin-Token: <admin-token>" \
-H "Content-Type: application/json" \
-d '{"name":"my-service"}' \
"https://smith-lab.ddns.net/time-api/v1/keys"
Windows PowerShell 5.1 (use curl.exe):
curl.exe -H "X-Admin-Token: <admin-token>" `
-H "Content-Type: application/json" `
-d '{"name":"my-service"}' `
"https://smith-lab.ddns.net/time-api/v1/keys"
Status codes:
- 200 OK (GET)
- 201 Created (POST; plaintext key shown once)
- 401 Unauthorized (missing/invalid admin token)
- 503 Admin token not configured
- 405 Method not allowed
Sample response (GET):
[
{"id": "9978eac73fdcc28a", "name": "web-test", "created_at": "2026-02-01T20:51:23Z", "last4": "eTgA"}
]
Sample request (POST):
{"name": "my-service"}
Sample response (POST, shown once):
{"api_key": "slk_...", "id": "...", "name": "my-service", "created_at": "2026-02-01T20:51:23Z", "last4": "eTgA"}