REST API
Endpoint-Referenz
Basis-URL: https://agentview.de. Alle Endpoints unter /api/v1/agent/ erfordern Authentifizierung, sofern nicht anders angegeben.
Untenstehender Katalog ist kuratiert. Vollständige Liste aller Endpoints inklusive Parameter und Schemas: /swagger/agent/swagger.json oder interaktiv im Swagger-UI.
Discovery & Status (kein Login)
GET /agent-instructions Maschinenlesbare Anleitung (Markdown)
GET /api/status Health-Check, Version, Discovery-URLs
GET /api/v1/agent/pricing Pläne, Preise, Features
GET /api/v1/agent/public-apis?query=...&category=...&cors_only=...&limit=... 600+ freie APIs durchsuchen (Wetter, News, Bilder, Sport, ...)
GET /api/v1/agent/public-apis/categories Alle API-Kategorien mit Anzahl
GET /api/v1/agent/public-apis/{slug} Details einer API inkl. fetch()-Hint
GET /swagger OpenAPI / Swagger UI
Authentifizierung
POST /api/v1/agent/session/request Login-Session erstellen → loginUrl, pollUrl
GET /api/v1/agent/session/status?id=... Session-Status abfragen → JWT Token
POST /api/v1/agent/api-keys API-Key erstellen (admin)
GET /api/v1/agent/api-keys Eigene API-Keys auflisten
DELETE /api/v1/agent/api-keys/{id} API-Key widerrufen
Account
GET /api/v1/agent/me Name, E-Mail, Plan, Display-Slots
Displays
GET /api/v1/agent/displays Alle Displays auflisten
POST /api/v1/agent/displays Neues Display erstellen (admin)
GET /api/v1/agent/displays/{id} Details inkl. Runtime-Fakten, Hardware-Settings und Verbindungsstatus
PATCH /api/v1/agent/displays/{id} Umbenennen (admin)
DELETE /api/v1/agent/displays/{id} Löschen (admin)
GET /api/v1/agent/displays/{id}/capabilities Aufgelöste Konnektivität: Modus, Whitelist, Herkunft
Content
POST /api/v1/agent/displays/{id}/content HTML oder Base64-HTML senden
POST /api/v1/agent/displays/{id}/url URL per iframe laden
GET /api/v1/agent/displays/{id}/content Aktuellen Content-State abfragen
POST /api/v1/agent/displays/broadcast An mehrere Displays gleichzeitig senden
POST /api/v1/agent/displays/test/content Dry-Run: HTML-Größe + Description validieren ohne echtes Display zu treffen. 1 MB-Limit. Antwort enthält simulated:true.
GET /api/v1/agent/public-apis/categories Liste aller Public-API-Kategorien mit Anzahl pro Kategorie. Vor /public-apis?category=... als Auswahlhilfe.
POST /send/{id}?token=...&duration=300 Direkter Send mit Token (kein Login)
Display-Verwaltung (admin)
POST /api/v1/agent/displays/{id}/lock Display sperren
POST /api/v1/agent/displays/{id}/unlock Sperre aufheben
POST /api/v1/agent/displays/{id}/clear Auf Idle zurücksetzen
POST /api/v1/agent/displays/{id}/default Idle-Content setzen oder löschen (HTML)
POST /api/v1/agent/displays/{id}/configure Kamera, Mikrofon, Geolocation, Cursor, Badge, Watermark
POST /api/v1/agent/displays/{id}/claim Unkonfiguriertes Display uebernehmen
Privatsphäre & Schlüssel-Rotation (GDPR)
PATCH /api/v1/agent/displays/{id}/privacy-mode Privacy-Modus setzen (Private oder Public). Cap für Share-Link-TTL: Private 1h, Public 24h. Audit-geloggt.
POST /api/v1/agent/displays/{id}/managed-secret/rotate Neuen ManagedDeviceSecret ausstellen, alte /m/{secret}-URL sofort tot.
POST /api/v1/agent/displays/{id}/managed-secret/revoke MDM-URL widerrufen ohne Ersatz. Recovery-Failover bleibt aktiv.
POST /api/v1/agent/displays/{id}/recovery-secret/rotate Neuen RecoverySecret ausstellen. Gerät muss einmal online kommen, um neuen Failover-Link zu speichern.
POST /api/v1/agent/account/approval-secret/rotate Account-weiten DisplayApprovalSecret rotieren. Alter /a/{secret}-Link sofort tot.
Display Categories
Hierarchische Gruppen zum Bündeln von Displays. Jede Kategorie hat einen kanonischen Slug; parent_category_id baut Pfade. Displays sind Mehrfach-Mitglieder. Owner-Scope nutzt /api/v1/owner/..., Org-Scope /api/v1/orgs/{orgId}/....
GET /api/v1/owner/display-categories Alle Kategorien des Owners mit Hierarchie
POST /api/v1/owner/display-categories Kategorie anlegen (optional parent_category_id)
PATCH /api/v1/owner/display-categories/{categoryId} Kategorie umbenennen oder umhängen
DELETE /api/v1/owner/display-categories/{categoryId} Kategorie löschen (Mitgliedschaften enden)
PUT /api/v1/owner/displays/{profileId}/categories Vollständige Kategorie-Mitgliedschaft eines Displays setzen
POST /api/v1/owner/display-categories/bulk-assign Eine Kategorie auf viele Displays zuweisen oder entfernen
GET /api/v1/orgs/{orgId}/display-categories Org-Kategorien
POST /api/v1/orgs/{orgId}/display-categories Org-Kategorie anlegen
PATCH /api/v1/orgs/{orgId}/display-categories/{categoryId} Org-Kategorie ändern
DELETE /api/v1/orgs/{orgId}/display-categories/{categoryId} Org-Kategorie löschen
PUT /api/v1/orgs/{orgId}/displays/{profileId}/categories Mitgliedschaft eines Org-Displays setzen
POST /api/v1/orgs/{orgId}/display-categories/bulk-assign Bulk-Zuweisung in der Organisation
POST /api/v1/owner/displays/broadcast-by-category HTML an alle Displays mit den angegebenen Kategorie-Slugs senden
POST /api/v1/orgs/{orgId}/displays/broadcast-by-category Broadcast nach Kategorie auf Org-Ebene
Display Governance (Owner, Cookie-Auth)
Owner-getriebene Kontroll-Layer. Diese Endpoints werden vom Dashboard mit Cookie-Session aufgerufen, nicht vom Agent. Sie sind hier dokumentiert, damit Agenten den umgebenden Vertrag verstehen und bei verwandten 403-Antworten sinnvoll reagieren können.
Approval Mode
PUT /api/v1/owner/displays/{id}/approval-mode Approval-Modus ein- oder ausschalten
GET /api/v1/owner/displays/{id}/approval-state Aktuellen Approval-State und ggf. ausstehende Submission abrufen
POST /api/v1/owner/displays/{id}/pending/accept Ausstehenden Inhalt freigeben (live schalten)
POST /api/v1/owner/displays/{id}/pending/reject Ausstehenden Inhalt verwerfen
POST /api/v1/owner/displays/{id}/rollback Live-Inhalt durch vorherige Version ersetzen
Source-Lock
GET /api/v1/owner/displays/{id}/source-lock Aktuelle Quellbindung lesen
PUT /api/v1/owner/displays/{id}/source-lock Display exklusiv an einen API-Key binden oder Bindung lösen
Activity Audit
Append-only Log: wer hat was über welchen Schlüssel gesendet, plus Approval-, Sperr- und Webhook-Ereignisse. Pro Eintrag: Akteur, Auth-Methode, Aktion, Ziel-Typ und -ID, Org-ID, gekürzte IP, User-Agent, Metadaten.
GET /api/v1/owner/activity-audit Owner-Sicht (eigene Aktionen + Aktionen auf eigenen Ressourcen)
GET /api/v1/admin/activity-audit Admin-Sicht (alle Mandanten)
Webhooks
HMAC-SHA256-signierte ausgehende Benachrichtigungen. Der Signing-Key wird nur einmal beim Anlegen zurückgegeben. Verbindungen zu internen Netz-Adressen sind blockiert. Event-Patterns: display.*, display.content.*, display.approval.*, data.changed, data.deleted oder data.*.
GET /api/v1/owner/webhooks Eigene Webhooks auflisten
POST /api/v1/owner/webhooks Webhook anlegen, Signing-Key wird einmalig zurückgegeben
DELETE /api/v1/owner/webhooks/{id} Webhook entfernen
PATCH /api/v1/owner/webhooks/{id}/active Aktiv-Status togglen
POST /api/v1/owner/webhooks/{id}/test Test-Event auslösen (rate-limited)
Assets
POST /api/v1/assets Assets hochladen (multipart, 1-20 Dateien, max 10 MB)
GET /api/v1/assets Eigene Assets auflisten (paginiert, Filter nach Typ/Suche)
GET /api/v1/assets/{id} Asset-Metadaten und URL abrufen
PATCH /api/v1/assets/{id} Name und/oder Beschreibung aktualisieren
DELETE /api/v1/assets/{id} Einzelnes Asset löschen
DELETE /api/v1/assets Mehrere Assets löschen (Bulk, max 100)
Data Slots
Mutable JSON storage cells readable by displays via public URLs. Two types: value slots (store JSON verbatim) and JSON collections (type=aggregate, shown as 📦 in the dashboard, combining multiple slots into one read response).
Slug stays stable, the URL doesn't expose it. The Slug you supply on PUT is the slot's stable identifier — it's what API-key whitelists, prefixMatch aggregates and follow-up updates address. The public read URL embeds a separate PublicId (8-char random hex) the server generates on CREATE: /data/u/{publicSlug}/{publicId}.json. Knowing the URL grants read access (capability URL); knowing the Slug alone does not. Subsequent PUTs with the same Slug update the same slot in place — ideal for bot heartbeats and self-registering agents. Treat URL contents as publicly published JSON.
GET /api/v1/data List all data slots (metadata only, paginated)
GET /api/v1/data/quota Check storage quota usage
GET /api/v1/data/{slug} Get a single slot by its Slug; response includes the slot's readUrl (the URL embeds publicId, not slug)
PUT /api/v1/data/{slug}?type=aggregate&label=...&groupId=... Create or update a data slot by Slug; body is raw JSON. Same Slug on a second PUT updates the existing slot. type=aggregate creates a JSON collection.
DELETE /api/v1/data/{slug} Delete a data slot by Slug
GET /api/v1/data/{slug}/usage List displays whose IdleHtmlContent embeds {{slot:<slug>}}. Use before delete/structural change to know which displays will 404 or render differently. Same scope as the slot. Capped at 50; truncated:true if more match.
GET /data/u/{publicSlug}/{publicId}.json Public read URL (personal slot, no auth required). The trailing segment is the slot's publicId, not its Slug.
GET /data/g/{groupSlug}/{publicId}.json Public read URL (group slot, no auth required)
JSON Collections (aggregate slots)
A JSON collection merges multiple value slots into one response, resolved on every fetch. Create with ?type=aggregate and a body listing source slot slugs (the Slugs — not PublicIds — because slugs are the stable internal identifier). The dashboard shows these as 📦.
# Create a value slot. The Slug stays exactly as you sent it; the response carries
# the readUrl (with the server-generated publicId) and the slot's publicId field.
curl -X PUT https://agentview.de/api/v1/data/sensor-a \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{"temp": 21.4, "unit": "C"}'
# => { "slot": { "slug": "sensor-a", "publicId": "a1b2c3d4",
# "readUrl": "https://content.agentview.de/data/u/.../a1b2c3d4.json", ... } }
# Update the same slot — same slug, no surprises. PublicId stays stable, readUrl too.
curl -X PUT https://agentview.de/api/v1/data/sensor-a \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{"temp": 22.1, "unit": "C"}'
# Create a JSON collection (aggregate slot). Source-slot references use the SLUG —
# the stable internal identifier — not the publicId.
curl -X PUT "https://agentview.de/api/v1/data/all-sensors?type=aggregate&label=All+Sensors" \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{"sources":[{"slot":"sensor-a"},{"slot":"sensor-b"}]}'
# Public read — use the readUrl from the create response (it embeds publicId, not slug).
# GET https://content.agentview.de/data/u/{publicSlug}/{publicId}.json
Reading from a display template
Display HTML renders inside a sandboxed iframe whose document origin is the opaque null sentinel, so even same-host fetch() is treated as cross-origin. The public read URLs return Access-Control-Allow-Origin: * and Vary: Origin, so a template can poll a slot directly without a proxy. Templates address the slot via the {{slot:<slug>.readUrl}} placeholder; the server substitutes the live URL at send-time.
// Inside a display template
var SLOT_URL = "{{slot:sensor-a.readUrl}}";
setInterval(function () {
fetch(SLOT_URL, { cache: "no-store" })
.then(function (r) { return r.json(); })
.then(function (data) {
document.getElementById("temp").textContent = data.temp + " " + data.unit;
});
}, 5000);
Organisationen
GET /api/v1/agent/organizations Eigene Organisationen mit Stats
GET /api/v1/agent/organizations/{orgId} Details mit Mitgliedern und Displays
POST /api/v1/agent/organizations/{orgId}/invite Mitglied einladen (admin)
POST /api/v1/agent/organizations/{orgId}/slots Display-Slots zuweisen (admin)
POST /api/v1/agent/organizations/{orgId}/displays Org-Display erstellen (admin)
Echtzeit
GET /api/v1/agent/events SSE-Stream: display_online, display_offline, content_delivered, content_cleared, data.changed