DATEYE

Onboarding & Authentifizierung

Setup-Code einlösen — POST /api/v1/setup/redeem

Nicht authentifiziert (IP-Rate-Limit). Tauscht einen Einmal-Setup-Code gegen Zugangsdaten ein.

Setup-Code-Format: ^(MK|MD)-[A-Z2-9]{4}-[A-Z2-9]{4}$ Alphabet 23456789ABCDEFGHJKMNPQRSTUVWXYZ (31 Zeichen, ohne 0/1/I/L/O — geringes Verwechslungsrisiko). Das Präfix ist frei wählbar (MK = Prod, MD = Dev in der Referenzimplementierung). Der Server speichert nur den SHA-256-Hash des Codes (code_hash), niemals den Klartext.

Request:

{ "code": "MK-7X3F-9K2P", "hostname": "PRACTICE-PC-01" }

hostname ist optional (druckbares ASCII, ≤255).

Response 200:

{
  "success": true,
  "data": {
    "apiKey": "mk_live_1a2b…(64 hex)",
    "host": "https://myopia.kids",
    "encryptionKey": "e3f1…(64 hex)"
  }
}
  • apiKey wird im Klartext nur hier, einmalig zurückgegeben (danach nicht mehr abrufbar).
  • encryptionKey = per-Account-Schlüssel, der ausschließlich für das DB-Passphrase-Backup verwendet wird (siehe unten), nicht für Importdaten.

Fehler:

CodeHTTPBedeutung
INVALID_CODE400Ungültiges Format oder unbekannter Code
INVALID_HOSTNAME400hostname kein druckbares ASCII / >255
ALREADY_REDEEMED409Code bereits eingelöst
CODE_EXPIRED410Code abgelaufen (expires_at < now)
RATE_LIMIT_EXCEEDED429>10 Versuche/h/IP (mit Retry-After)
INVALID_REQUEST400JSON nicht parsierbar
INTERNAL_ERROR500Serverfehler

API-Key & Authentifizierung

  • Format: mk_live_ + 64 Hex-Zeichen (32 Zufallsbytes). Das Präfix ist kosmetisch — für das eigene Produkt frei wählbar (z.B. mc_live_).
  • Serverseitige Speicherung: Nur der SHA-256-Hash (key_hash, hex) plus ein gekürztes Anzeigepräfix (key_prefix). Der Klartext-Key wird nie gespeichert.
  • Eingehende Requests validieren: Bearer-Token extrahieren → SHA-256 berechnen → SELECT … FROM api_keys WHERE key_hash = $1 AND revoked_at IS NULL. Kein Treffer → 401 INVALID_API_KEY. Ein Treffer liefert die account_id (Tenant) für den weiteren Request.
  • Nebeneffekt: Bei jedem authentifizierten Request last_used_at (und die Telemetrie-Header) fire-and-forget aktualisieren — darf die Response nicht blockieren.

Verschlüsselungsschlüssel abrufen — GET /api/v1/config

Authentifiziert. Gibt denselben encryptionKey erneut zurück (z.B. nach einer Neuinstallation) sowie den aktiven Update-Kanal.

Response 200:

{ "success": true, "data": { "encryptionKey": "e3f1…", "updateChannel": "stable" } }

updateChannel = stable | canary (aus dem canary_consent-Flag des Keys; der Header X-DATEYE-Canary-Consent überschreibt ihn für die aktuelle Response).

DB-Passphrase-Backup (mit dem encryptionKey)

Der DATEYE-Client verschlüsselt lokale Patientendaten in seiner eigenen DB mit einer Passphrase. Zur Wiederherstellung nach Geräteverlust kann er diese Passphrase clientseitig verschlüsselt beim Server hinterlegen. Der Server speichert nur einen undurchsichtigen Blob und kann ihn nicht entschlüsseln.

Verschlüsselungsformat (AES-256-GCM):

iv_hex : authTag_hex : ciphertext_hex
  • Algorithmus aes-256-gcm, Schlüssel = die 32 Bytes aus encryptionKey (hex-dekodiert)
  • iv = 16 Zufallsbytes, authTag = 16 Bytes (GCM), alle Teile hex, getrennt durch :
  • Dies ist exakt das Format, das der Client selbst erzeugt und erwartet.

POST /api/v1/setup/db-key — Blob speichern (einmalig)

{ "encryptedDbKey": "iv_hex:authTag_hex:ciphertext_hex" }

Wird nur gespeichert, wenn noch kein Blob existiert (… WHERE dateye_db_key IS NULL). Ein zweiter Aufruf → 409 KEY_ALREADY_SET (Signal an den Client: zuerst GET und lokal vergleichen). Response { "success": true }.

GET /api/v1/setup/db-key — Blob abrufen

{ "success": true, "data": { "encryptedDbKey": "iv_hex:authTag_hex:ciphertext_hex" } }

Kein Blob gespeichert → 404 KEY_NOT_FOUND. Der Client entschlüsselt lokal mit encryptionKey.

Historisch existiert ein zweiter Pfad /api/v1/config/db-key, bei dem der Server ver-/entschlüsselt und überschreibbar speichert. Für die OEM-Integration ist der /setup/db-key-Pfad (undurchsichtiger Blob, keine serverseitige Entschlüsselung) der autoritative, datenschutzkonforme Weg. /config/db-key kann weggelassen werden.