173 lines
3.8 KiB
Markdown
173 lines
3.8 KiB
Markdown
|
|
# API
|
||
|
|
|
||
|
|
Public REST-API für CoreX NexRedirect. Versioniert unter `/api/v1`. JSON-only.
|
||
|
|
|
||
|
|
## Auth
|
||
|
|
|
||
|
|
Tokens erstellen unter **Einstellungen → API-Tokens** im Web-UI. Token wird nur einmalig angezeigt — sicher kopieren.
|
||
|
|
|
||
|
|
Format: `nrx_<64-hex>`. Im Header senden:
|
||
|
|
|
||
|
|
```
|
||
|
|
Authorization: Bearer nrx_<your-token>
|
||
|
|
```
|
||
|
|
|
||
|
|
Tokens haben **Scopes**:
|
||
|
|
|
||
|
|
| Scope | Erlaubt |
|
||
|
|
|-------|---------|
|
||
|
|
| `read:domains` | Domains lesen |
|
||
|
|
| `write:domains` | Domains anlegen/löschen |
|
||
|
|
| `read:analytics` | Aggregierte Statistiken |
|
||
|
|
| `read:hits` | Roh-Hits (nur ip_hash, kein Klartext-IP) |
|
||
|
|
|
||
|
|
Fehler-Format:
|
||
|
|
```json
|
||
|
|
{ "error": "forbidden", "code": "missing_scope", "required": "read:domains" }
|
||
|
|
```
|
||
|
|
|
||
|
|
## Endpoints
|
||
|
|
|
||
|
|
### `GET /api/v1/health`
|
||
|
|
Liveness-Check. Kein Token nötig.
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl https://admin.firma.de/api/v1/health
|
||
|
|
# {"ok":true,"ts":1714500000000}
|
||
|
|
```
|
||
|
|
|
||
|
|
### `GET /api/v1/version`
|
||
|
|
Aktuelle Version + Update-Status. Kein Token nötig.
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"current": "0.1.0",
|
||
|
|
"latest": "0.1.1",
|
||
|
|
"update_available": true,
|
||
|
|
"release_url": "https://github.com/.../releases/tag/v0.1.1",
|
||
|
|
"auto_update": false
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### `GET /api/v1/domains`
|
||
|
|
Scope: `read:domains`
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -H "Authorization: Bearer nrx_..." https://admin.firma.de/api/v1/domains
|
||
|
|
```
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"domains": [
|
||
|
|
{
|
||
|
|
"id": 1, "domain": "alt-firma.de", "status": "active",
|
||
|
|
"target_url": "https://www.firma.de", "redirect_code": 301,
|
||
|
|
"preserve_path": 1, "include_www": 1,
|
||
|
|
"total_hits": 142, "last_hit": 1714499000000
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### `POST /api/v1/domains`
|
||
|
|
Scope: `write:domains`
|
||
|
|
|
||
|
|
Body:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"domain": "alt-firma.de",
|
||
|
|
"target_url": "https://www.firma.de",
|
||
|
|
"redirect_code": 301,
|
||
|
|
"preserve_path": true,
|
||
|
|
"include_www": true
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
Response (`201`):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"domain": { "id": 5, "status": "pending", ... },
|
||
|
|
"dns_records": [
|
||
|
|
{ "type": "A", "name": "alt-firma.de", "value": "203.0.113.42" },
|
||
|
|
{ "type": "A", "name": "www.alt-firma.de", "value": "203.0.113.42" }
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
DNS muss anschließend gesetzt + verifiziert werden (über UI oder via internen `/api/domains/:id/verify`-Endpoint, der einen User-Login erfordert).
|
||
|
|
|
||
|
|
### `GET /api/v1/domains/:id`
|
||
|
|
Scope: `read:domains`
|
||
|
|
|
||
|
|
### `DELETE /api/v1/domains/:id`
|
||
|
|
Scope: `write:domains`
|
||
|
|
|
||
|
|
### `GET /api/v1/domains/:id/stats?days=30`
|
||
|
|
Scope: `read:analytics`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"domain_id": 1, "days": 30, "total": 412,
|
||
|
|
"daily": [{"day":"2026-04-01","hits":12}, ...],
|
||
|
|
"by_country": [{"country":"DE","hits":380},{"country":"AT","hits":18}, ...]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### `GET /api/v1/analytics/summary?days=30`
|
||
|
|
Scope: `read:analytics`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"days": 30, "total": 12480,
|
||
|
|
"daily": [...],
|
||
|
|
"top": [{"id":1,"domain":"alt-firma.de","hits":412}, ...],
|
||
|
|
"by_country": [...]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### `GET /api/v1/hits?domain_id=1&limit=100`
|
||
|
|
Scope: `read:hits`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"hits": [
|
||
|
|
{
|
||
|
|
"id": 9001, "domain_id": 1, "ts": 1714499000000,
|
||
|
|
"ip_hash": "9f4a...", "country": "DE",
|
||
|
|
"user_agent": "Mozilla/5.0 ...", "referer": null, "path": "/"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
`ip_hash` = `sha256(ip + täglicher Salt)`. Kein Klartext-IP wird gespeichert.
|
||
|
|
|
||
|
|
## Versionierung
|
||
|
|
|
||
|
|
`/api/v1` ist stabil. Breaking-Changes erscheinen unter `/api/v2`. Deprecation-Hinweise im `Sunset`-Header.
|
||
|
|
|
||
|
|
## Rate-Limits
|
||
|
|
|
||
|
|
Kein hartes Limit aktuell. Empfehlung: max. 60 Requests/Minute pro Token. Bei Problemen Token rotieren.
|
||
|
|
|
||
|
|
## Beispiele
|
||
|
|
|
||
|
|
**Uptime-Check eines Tokens:**
|
||
|
|
```bash
|
||
|
|
curl -fsS -H "Authorization: Bearer $NRX" https://admin.firma.de/api/v1/health || echo "DOWN"
|
||
|
|
```
|
||
|
|
|
||
|
|
**Liste tote Domains (0 Hits / 90d):**
|
||
|
|
```bash
|
||
|
|
curl -s -H "Authorization: Bearer $NRX" \
|
||
|
|
"https://admin.firma.de/api/v1/analytics/summary?days=90" \
|
||
|
|
| jq '.top | map(select(.hits == 0))'
|
||
|
|
```
|
||
|
|
|
||
|
|
**Domain anlegen + DNS-Records anzeigen:**
|
||
|
|
```bash
|
||
|
|
curl -X POST -H "Authorization: Bearer $NRX" -H "Content-Type: application/json" \
|
||
|
|
-d '{"domain":"shop.alt.de","target_url":"https://shop.firma.de"}' \
|
||
|
|
https://admin.firma.de/api/v1/domains | jq '.dns_records'
|
||
|
|
```
|