Skip to content

Alle Artikel

Provider API v1

Emperor holt registrierte Nutzer und Tagesaktivität per gemeinsamem Vertrag aus Anwendungen. Jede Anwendung kann ihn umsetzen, nicht nur eigene. Die Anwendung bleibt die Quelle; spätere Syncs aktualisieren Daten. Derselbe Mensch aus mehreren Apps erzeugt keine doppelte Person.

Diese Seite richtet sich an Teams, die den Vertrag implementieren. Das maschinenlesbare OpenAPI-3.1-Dokument ist die Provider-API-Spezifikation. Client-Typen erzeugt man aus diesem Pfad auf demselben Origin wie diese Site.

v1 ist ein Entwurf und kann sich bis zur Finalisierung ändern. Nach der Finalisierung kommen inkompatible Änderungen als /v2.

Ressourcen

Die Anwendung stellt drei GET-Ressourcen unter /v1 bereit, relativ zur baseUrl der Facility-Verbindung:

  • /v1/manifest — Vertragsversion (1), Anwendungsname, IANA-Zeitzone für Aktivitätstage und der Katalog der Aktivitätsschlüssel mit Labels.
  • /v1/users — Nutzer. Query: updatedSince, cursor, limit.
  • /v1/activity — Tagesaggregate, eine Zeile je Nutzer, Kalendertag und Schlüssel aus dem Katalog. Dieselben Query-Parameter wie bei users.

Ist contractVersion nicht 1, lehnt Emperor die Verbindung mit einem klaren Fehler ab.

Cursor und Überschreiben der Aktivität

updatedSince ist ein ISO-8601-DateTime mit Offset oder Z. Es kommen Datensätze mit updatedAt größer oder gleich diesem Wert. Ohne Parameter: voller Export. cursor ist ein undurchsichtiger String aus dem nextCursor der vorigen Seite. limit ist standardmäßig 100, höchstens 100.

Listenantworten sind { "data": [...], "nextCursor": null | string }. nextCursor ist null auf der letzten Seite.

Eine spätere Aktivitätszeile für dasselbe (externalUserId, day, metricKey) ersetzt den gespeicherten Zähler. Anwendungen senden Tagessummen, keine Rohereignisse.

E-Mail oder Telefon

Jeder Nutzer braucht email, phone (E.164, zum Beispiel +79991234567) oder beides. Ein Datensatz ohne beides wird vom Vertrag abgelehnt. Emperor zählt ihn im Sync als abgelehnt und legt keine Person an.

Wie Emperor Kontakte zuordnet

Ein Mensch im CRM ist Person. E-Mail und Telefon sind Contact (Typen EMAIL und TELEPHONE). Die Anwendungsidentität liegt auf einem eigenen Link: eine Person, mehrere Apps.

  • E-Mail wird normalisiert. Telefon steht in E.164.
  • Eine bereits verknüpfte Identität wird aktualisiert.
  • Eine neue Identität ohne Treffer erzeugt eine Person.
  • Jeder Treffer auf eine vorhandene Person, inklusive Konflikt bei E-Mail/Telefon, landet in einer manuellen Prüfliste. Es gibt kein automatisches Zusammenführen.

Checkliste für den Anschluss

  1. /v1/manifest, /v1/users und /v1/activity in Production nur über HTTPS anbieten.
  2. Ein Bearer-Token mit hoher Entropie pro Projekt–Anwendung ausstellen, nur Leserechte für diese API. Kein dienstweiter Schlüssel.
  3. Token zeitkonstant vergleichen. Eine Anfrage ohne gültiges Bearer liefert 401 als RFC-7807 application/problem+json. Nicht unterscheiden, ob der Token fehlt oder falsch ist.
  4. User-Agent: Emperor-AppProvider/1.0 und X-Request-Id (UUID) annehmen. Dieselbe Id in Problem-Dokumenten bei Fehlern zurückgeben.
  5. Bei 429 Retry-After senden.
  6. Rotation: im Rotationsfenster aktuellen und vorherigen Token akzeptieren, danach den alten widerrufen.
  7. In der lokalen Entwicklung ist Plain-HTTP-baseUrl nur erlaubt, wenn APP_PROVIDER_ALLOW_PLAIN_HTTP=true (setzt das Frontend-Dev- Skript). Production akzeptiert nur HTTPS.

Sicherheit und Audit-Log der Anwendung

v1 ist HTTPS plus Bearer-Token an der Bindung Projekt–Anwendung. HMAC, mTLS und OAuth2 gehören nicht zu dieser Version.

Empfohlen (kein Schema-Zwang): jede Provider-API-Anfrage mit Zeit, Quell-IP, X-Request-Id, User-Agent, Ressource (manifest / users / activity), updatedSince, HTTP-Status und Anzahl gelieferter Datensätze loggen. Token, Authorization, E-Mail, Telefon und Antwortkörper nicht loggen.

Ebenfalls empfohlen: ein Token nur für diese API; Rate-Limit; Alarme bei einer 401-Serie, fremdem User-Agent, unerwarteter IP oder plötzlichem Mengensprung. Keine IP-Allowlist verlangen: Emperor-Egress in Kubernetes ist nicht fest.

Artikel