1DE1DEDeveloper Hub
Entwickler-Doku

Baue MiniApps für die SuperApp.

Alles, was du brauchst: Silent SSO ohne Login-Screen, Container-Steuerung, Deeplinks, die Plattform-APIs für Chat, Signatur & Payment — und ein MCP-Server, mit dem dein KI-Agent sofort loslegt.

Einführung — SuperApp & MiniApps

Die KOBIL SuperApp ist ein nativer Container (Mobile-App). Einzelne Funktionen — Terminbuchung, KI-Chat, Behördengänge — sind MiniApps: eigenständige Web-Apps, die in einem WebView innerhalb der SuperApp laufen.

┌─────────────────────────────────────┐ │ KOBIL SuperApp (nativer Container) │ │ ┌────────────────────────────────┐ │ │ │ WebView │ │ ← lädt deine MiniApp-URL │ │ ┌──────────────────────────┐ │ │ ← liest miniApp.json │ │ │ Deine MiniApp (Next.js) │ │ │ ← Cookie-Injection → Silent SSO │ │ └──────────────────────────┘ │ │ │ └────────────────────────────────┘ │ │ native Tab-Bar (immer sichtbar) │ └─────────────────────────────────────┘

Für den Endnutzer fühlt es sich nativ an:

  • Login ohne Eintippen — der Nutzer ist in der SuperApp angemeldet, deine MiniApp übernimmt die Identität automatisch (Silent SSO).
  • System-UI vom Container gesteuert — Vollbild, Status-Bar-Farbe und Navigation steuert die SuperApp über deine miniApp.json.
  • Overlay-Navigation — deine MiniApp kann per Deeplink eine andere öffnen.
Alle MiniApps einer Umgebung hängen am selben Identity-Provider → gleiches OIDC-sub pro Nutzer über alle Apps. Darauf bauen App-übergreifende Features.

Schnellstart — in 5 Minuten zur ersten MiniApp

Registrieren

Lege im Partner Hub einen Account an (E-Mail + Passwort).

MiniApp anlegen

Im Dashboard URL + Name eintragen. Wir registrieren sie als OIDC-Service und veröffentlichen sie im Store. Du erhältst deine Service-ID (= sID = OIDC client_id) und ein client_secret.

Code-Starter holen

Im Dashboard die vorbefüllte Doku öffnen oder per MCP scaffold_miniapp.env und OIDC-Flow sind mit deinen Werten gefüllt.

Deployen

Hoste deine Web-App unter der angegebenen MiniApp-URL.

In der SuperApp öffnen

Silent SSO läuft automatisch — kein Login-Screen.

Du willst nicht selbst klicken? Binde deinen KI-Agenten per MCP an (siehe unten) und lass ihn das alles erledigen.

miniApp.json — Container-Steuerung

Eine statische Datei im Web-Root: public/miniApp.json (→ /miniApp.json). Die SuperApp liest sie beim Laden deiner MiniApp.

// public/miniApp.json
{
  "version": "2.0",
  "fullScreen": true,
  "theme": "app-default",
  "statusBar": { "theme": { "light": { "backgroundColor": "#ffffff" }, "dark": { "backgroundColor": "#ffffff" } } },
  "navigationBar": { "visible": false, "theme": { "light": { "backgroundColor": "#ffffff" }, "dark": { "backgroundColor": "#ffffff" } } }
}
FeldBedeutung
fullScreentrue = MiniApp zeichnet bis unter die Status-Bar (Vollbild).
themeapp-default übernimmt das SuperApp-Theme.
navigationBar.visiblefalse = keine Container-Navigation; du baust die UI selbst.
statusBar.themeStatus-Bar-Farbe je Light/Dark-Modus.
Design-Konsequenz: Status-Bar & native Tab-Bar sind weiß. Lass den oberen Safe-Area-Bereich frei (kein Header direkt oben) und ziehe deine Hintergrundfarbe entsprechend mit.

Design & Native Feel

Mit fullScreen: true zeichnet deine MiniApp von ganz oben (unter der Status-Bar) bis ganz unten. Über deiner Web-UI liegt aber das native SuperApp-Menü: oben rechts eine schwebende Pille mit zwei Buttons — Optionen (Raster ⊞) und Schließen (✕). Dieser Bereich gehört der SuperApp — du musst ihn freihalten.

┌───────────────────────────────────────────┐ │ 14:48 📶 ▢ 🔋 │ ← System-Status-Bar (Safe-Area) │ │ │ Umfrage ┌ ⊞ │ ✕ ┐ │ ← NATIVE Pille: Optionen + Schließen │ ╰─ links frei nutzbar ─╯ └─ FREIHALTEN ┘ │ │ │ deine MiniApp · Vollbild │ │ (mobile-first, native feel) │ │ │ │ ▁▁▁ ✓ Umfragen ◌ Profil ▽ Erfolge ▁▁▁ │ ← eigene Bottom-Tab-Bar (nativ-Stil) └───────────────────────────────────────────┘
Oben rechts reservieren: Plane ~128 px breit × 52 px hoch (unterhalb der Status-Bar) komplett frei ein. Lege dort keine tippbaren oder wichtigen Elemente ab — sie verschwinden sonst unter der nativen Pille. Baue niemals einen eigenen Schließen-/Zurück-Button oben rechts — das übernimmt die SuperApp.
Den Platz links davon aktiv nutzen wirkt am hochwertigsten: ein Screen-Titel oder Logo oben links (wie „Umfrage" im Beispiel) füllt die Kopfzeile aus und lässt die native Pille rechts wie einen natürlichen Teil der App wirken.

Safe Areas & reservierte Zone — so geht's konkret

Aktiviere viewport-fit=cover und nutze die env()-Safe-Area-Insets. Halte oben rechts Platz für die Pille frei.

<!-- Safe-Areas (viewport-fit) + ALLE Zoom-Arten aus -->
<meta name="viewport"
      content="width=device-width, initial-scale=1, viewport-fit=cover, maximum-scale=1, user-scalable=no">

Alle Zoom-Arten abschalten (Pflicht fürs Native-Gefühl)

Nichts verrät eine Web-App schneller als zoombarer Inhalt. Es gibt drei Zoom-Quellen — schalte alle ab:

Zoom-ArtAbschalten mit
Pinch-to-Zoom (zwei Finger)maximum-scale=1, user-scalable=no im Viewport-Meta (siehe oben). Im SuperApp-WebView wird das respektiert.
Doppeltipp-Zoomtouch-action: manipulation (global, z. B. auf html).
Auto-Zoom beim Fokus von Input/SelectSchriftgröße der Felder ≥ 16px — sonst zoomt iOS beim Antippen automatisch rein.
/* gegen Doppeltipp-Zoom; Eingaben nie unter 16px */
html{ touch-action: manipulation; -webkit-text-size-adjust: 100%; }
input, select, textarea{ font-size: 16px; }
Das Viewport-Meta deckt Pinch- & Doppeltipp-Zoom im Container ab; die 16px-Regel ist trotzdem nötig, weil der Fokus-Auto-Zoom unabhängig davon greift. Zur Sicherheit zusätzlich gegen iOS-Gesten: document.addEventListener('gesturestart', e => e.preventDefault()).

Native Feeling — Pflicht-Checkliste

Die MiniApp muss sich anfühlen wie ein nativer Screen, nicht wie eine Website im Browser. Mobile-first (entwirf zuerst für 360–430 px Breite):

ThemaRegel
Höhe100svh/100dvh statt 100vh — sonst springt das Layout mit der Adressleiste.
Touch-TargetsMindestens 44×44 px für alles Tippbare.
SchriftSystem-Stack: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, system-ui, sans-serif.
Kein HoverKeine reine Hover-UI — Touch hat kein Hover. Nutze klare :active-States für sofortiges Feedback.
ZoomAlle drei Zoom-Arten aus (Pinch, Doppeltipp, Fokus-Auto-Zoom) — siehe Abschnitt oben. Plus touch-action: manipulation killt zugleich das 300 ms-Tap-Delay.
ScrollMomentum-Scroll, overscroll-behavior: contain gegen „Durchziehen". Keine horizontalen Overflow-Wackler.
Auswahluser-select: none auf Buttons/Nav; Text-Auswahl nur wo sinnvoll.
NavigationNative Muster: Bottom-Tab-Bar (mit safe-area-inset-bottom), Bottom-Sheets statt Desktop-Modals, Swipe wo passend.
BewegungKurze, weiche Transitions (cubic-bezier(.2,.8,.2,1)), keine Layout-Shifts. Optimistische UI + Skeletons statt Spinner.
FarbeStatus-Bar & Tab-Bar sind weiß (miniApp.json) → oben/unten in Weiß auflösen; prefers-color-scheme respektieren.
Faustregel: Würde dein Screen als App-Store-Screenshot durchgehen? Tab-Bar unten, Titel oben links, Karten mit weichen Schatten, große Tap-Flächen, sofortiges Feedback — dann fühlt es sich nativ an.

Authentifizierung — Silent SSO (OIDC + PKCE)

Deine MiniApp authentifiziert per Authorization Code + PKCE (confidential client) gegen den KOBIL-IDP. Weil die SuperApp die Keycloak-Session injiziert, läuft das ohne Login-Screen.

Silent SSO funktioniert NUR in der SuperApp. Öffnest du die MiniApp-URL einfach im normalen Browser, gibt es keine automatische Anmeldung — der IDP findet keine injizierte Session und der Login schlägt fehl bzw. landet in einer Endlosschleife. Zum Testen im Browser brauchst du den WebFlow-Modus + den Test-Account (siehe Deploy → Im Browser testen).

Der Flow

  1. Kein user_session-Cookie → Redirect auf /api/auth/login?next=<pfad>.
  2. /api/auth/login: erzeugt state, nonce, PKCE-verifier, legt sie in ein kurzlebiges oidc_tx-Cookie (HttpOnly, 10 min) und redirectet zum authorization_endpoint (code_challenge=S256).
  3. IDP → Silent SSO → Redirect auf /api/auth/callback?code=…&state=….
  4. /api/auth/callback: prüft state, tauscht den Code (mit client_secret + code_verifier), verifiziert das id_token via JWKS, extrahiert Claims und setzt dein eigenes signiertes user_session-Cookie.
  5. Folge-Requests prüfen nur noch das user_session-Cookie (kein IDP-Roundtrip).
// PKCE + Authorize-URL
import { createHash, randomBytes } from "crypto";

export function pkce() {
  const verifier = randomBytes(32).toString("base64url");
  const challenge = createHash("sha256").update(verifier).digest("base64url");
  return { verifier, challenge };
}

export function authUrl(state, nonce, challenge) {
  const p = new URLSearchParams({
    client_id: process.env.OIDC_CLIENT_ID, response_type: "code",
    scope: "openid profile email", redirect_uri: BASE + "/api/auth/callback",
    state, nonce, code_challenge: challenge, code_challenge_method: "S256",
  });
  return ISSUER + "/protocol/openid-connect/auth?" + p;
}
CookieInhalt · TTL · Flags
oidc_txstate/nonce/PKCE-verifier · 10 min · HttpOnly, SameSite=Lax
user_sessionsignierte Claims (sub, name, …) · z. B. 8 h · HttpOnly, SameSite=Lax
SameSite=Lax ist Pflicht. Der Redirect vom IDP zurück ist cross-site — Strict würde deine Cookies blocken.
Dev-Fallback: Ist OIDC_CLIENT_ID lokal nicht gesetzt, überspringe die OIDC-Ebene (sub = "dev-user") — so entwickelst du ohne IDP.

mPower — Grundlagen & Authentifizierung

mPower ist die Server-zu-Server-Schnittstelle der Plattform. Damit schickt dein Backend Nachrichten in den SuperApp-Chat des Bürgers, lässt ihn Buttons antippen, PDFs unterschreiben und Zahlungen auslösen — alles, ohne dass der Bürger sich irgendwo separat einloggt. Die folgenden vier Abschnitte (Chat & Auswahl, PDF-Signatur, Payment) bauen alle auf diesem Grundlagen-Teil auf.

Zwei APIs, zwei Clients, ein Realm

Es gibt zwei getrennte APIs. Chat, Auswahl & Signatur laufen über deinen normalen OIDC-Client; Payment läuft über einen eigenen Merchant-Client. Verwechsle die beiden nicht — das ist die häufigste Fehlerquelle.

APIWofürClient
mPower (mercury)Chat, Auswahl-Nachrichten, PDF-Signatur, Mediendein OIDC-Client (sID + client_secret)
Payment (mpay-merchant)Zahlung anstoßen + Statusseparater Merchant-Client (eigene merchantId + Secret + tenantId)
Deine sID, dein client_secret und alle Endpoint-URLs findest du fertig vorbefüllt im Dashboard. Die Merchant-Credentials für Payment bekommst du separat von deinem 1DE-Ansprechpartner.

Schritt 1: Access-Token holen (client_credentials)

Beide APIs authentifizieren per client_credentials gegen denselben Token-Endpoint des Realms. Das Token ist ~300 Sekunden gültig — hole es einmal und cache es, statt es bei jedem Call neu anzufragen.

# Token fuer mPower (mit deinem OIDC-Client)
curl -X POST "<ISSUER>/protocol/openid-connect/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=<DEINE_SID>" \
  -d "client_secret=<DEIN_CLIENT_SECRET>"
# → { "access_token": "eyJ…", "expires_in": 300, … }

Wichtige Begriffe

BegriffBedeutung
userIdDas OIDC-sub des Bürgers — exakt der Wert, den du beim Login aus dem user_session bzw. /api/auth/me bekommst. Kein Login nötig (S2S).
serviceUuidDeine sID — identifiziert deinen Service als Absender.
versionSchema-Version der mPower-Nachricht. Aktuell 3.
{tenant}Der Realm/Tenant in der URL (für mPower derselbe wie dein OIDC-Realm).

Das Callback-Modell (sehr wichtig)

Ausgehende Calls (du → Plattform) bekommen sofort eine kleine Quittung { messageId, instanceId } zurück. Die eigentliche Antwort des Bürgers (er hat unterschrieben, einen Button getippt, geschrieben) kommt asynchron als Callback.

  • Eine globale Service-Callback-URL (in deiner Service-Config hinterlegt) bekommt ALLE mPower-Callbacks deines Service — Signatur, Auswahl und Chat landen am selben Endpoint. Du unterscheidest sie über messageType.
  • Payment hat einen eigenen Callback (merchantCallback), den du pro Transaktion mitgibst.
mPower spiegelt deine Query-Parameter im Callback NICHT zurück. Hängst du an die callbackUrl ein ?applicationId=…, kommt es leer zurück. Korreliere deshalb über den von dir gewählten Dateinamen (bei Signatur) bzw. über from.userId + internen Status. Der Payment-Callback spiegelt den Query-Param dagegen schon.

Chat & Auswahl-Nachrichten

Mit zwei Nachrichtentypen sprichst du den Bürger direkt im SuperApp-Chat an: Klartext (processChatMessage) und Auswahl mit Buttons (choiceRequest). Beide gehen an denselben Endpoint:

# Authorization: Bearer <access_token> (siehe Grundlagen)
POST <MPOWER_BASE>/auth/realms/<TENANT>/mpower/v1/users/{userId}/message

Klartext-Nachricht

Eine einfache Textnachricht, die im Chat erscheint — z. B. eine Bestätigung.

{
  "serviceUuid": "<DEINE_SID>",
  "messageType": "processChatMessage",
  "version": 3,
  "messageContent": { "messageText": "Danke! Dein Antrag ist eingegangen." }
}

Auswahl-Nachricht (Buttons)

Zeigt dem Bürger antippbare Buttons. Sein Tipp kommt als choiceResponse-Callback zurück.

{
  "serviceUuid": "<DEINE_SID>",
  "messageType": "choiceRequest",
  "version": 3,
  "messageContent": {
    "messageText": "Möchtest du jetzt bezahlen?",
    "choices": [{ "text": "Bezahlen" }, { "text": "Später" }]
  }
}

Der Callback (Bürger antwortet)

Wenn der Bürger tippt oder schreibt, ruft die Plattform deine globale Service-Callback-URL auf. Envelope:

{
  "message": {
    "content": {
      "messageType": "choiceResponse",         // oder "processChatMessage"
      "messageContent": { "messageText": "Bezahlen" }  // gewählter Button-Text
    },
    "from": { "ecoId": "<TENANT>", "userId": "<sub>" },
    "messageId": "…"
  }
}
messageTypeBedeutung
choiceResponsemessageContent.messageText = der vom Bürger gewählte Button-Text.
processChatMessageNormaler Chat-Text des Nutzers (oft einfach ignorierbar).
Korreliere die Antwort über from.userId + deinen internen Status (z. B. „dieser Nutzer wartet auf eine Zahl-Entscheidung"). Buttons haben keine ID — du erkennst die Wahl nur am messageText.

PDF-Signatur

Du schickst ein PDF an die Plattform, der Bürger unterschreibt es direkt in der SuperApp, und du bekommst das signierte PDF zurück. Der Ablauf in vier Schritten:

PDF vorbereiten & senden

PDF füllen/flatten, Signatur-Kasten als Prozent-Koordinaten angeben, an /signature posten.

Bürger unterschreibt

Die SuperApp zeigt das PDF mit dem Signatur-Feld. Der Bürger unterschreibt.

Callback signatureResponse

Du bekommst signatureStatus: "signed" + eine mediaId.

Signiertes PDF laden

Über die mediaId das fertige PDF herunterladen und weiterverarbeiten.

Schritt 1 — Signatur-Request

Ein multipart/form-data-POST mit zwei Parts: signatureFile (das PDF) und signatureData (ein JSON-String).

POST <MPOWER_BASE>/auth/realms/<TENANT>/mpower/v1/users/{userId}/signature
# Content-Type: multipart/form-data; Authorization: Bearer <token>

# Part "signatureData" (JSON-String):
{
  "version": 3,
  "pageNumber": 1,
  "bottomLeftXCoordinate": 12,
  "bottomLeftYCoordinate": 3,
  "topRightXCoordinate": 39,
  "topRightYCoordinate": 5,
  "serviceUuid": "<DEINE_SID>",
  "messageText": "Bitte unterschreiben",
  "callbackUrl": "https://deine-app.de/api/webhooks/mpower-signature"
}
# → Antwort: { "messageId": "…", "instanceId": "…" }

⚠️ Die Koordinaten verstehen (häufigster Fehler)

Die vier Koordinaten sind ganzzahlige PROZENT (0–100) der Seitengröße, mit Ursprung unten-linksNICHT PDF-Punkte und keine Pixel. Übergibst du Punktwerte (z. B. 200), werden sie als 200 % gelesen → an den Rand gekappt, der Kasten verschwindet. Floats (z. B. 12.5) führen zu HTTP 400 (das Feld ist ein i32). Immer runden.
FeldBedeutung
pageNumberSeite, auf der unterschrieben wird (1-basiert).
bottomLeftX / YUntere-linke Ecke des Signatur-Kastens, in % der Seite (von unten-links).
topRightX / YObere-rechte Ecke, in % der Seite.

Umrechnung von Millimetern in Prozent (PDF-Punkt = 1/72 Zoll, 1 Zoll = 25,4 mm):

// X / Breite — direkt von links:
const MM = 72 / 25.4;                       // mm → pt
const pctX = Math.round(mmVonLinks * MM / seiteBreitePt * 100);

// Y — Ursprung ist UNTEN, also von oben umrechnen:
const pctY = Math.round((seiteHoehePt - mmVonOben * MM) / seiteHoehePt * 100);
AcroForm-Falle: Bei Formular-PDFs reicht flatten() nicht — es lässt ein leeres AcroForm-Dictionary zurück, und mPower zeigt dann keinen Signatur-Kasten an (außerdem überdecken die Formular-Widgets deinen Overlay-Text). Lösung: erst flatten, dann die Seiten in ein frisches PDFDocument kopieren — das entfernt das AcroForm vollständig.

Schritt 3 — Callback signatureResponse

{
  "message": {
    "content": {
      "messageType": "signatureResponse",
      "signatureStatus": "signed",
      "mediaContent": { "mediaId": "…", "fileName": "…",
                         "fileSize": 12345, "contentType": "application/pdf" }
    },
    "from": { "ecoId": "<TENANT>", "userId": "<sub>" }
  }
}
Korrelation: Da Query-Params nicht gespiegelt werden, gib dem PDF beim Senden einen sprechenden Dateinamen (z. B. <templateId>-<antragId>.pdf) — über mediaContent.fileName bzw. from.userId findest du den Antrag wieder.

Schritt 4 — Signiertes PDF herunterladen

GET <MPOWER_BASE>/v1/mpower/tenants/<TENANT>/media/{mediaId}/download
# Authorization: Bearer <token>
# → 301 Redirect auf eine presigned S3-URL.
Der Download antwortet mit 301 auf eine presigned S3-URL. fetch folgt dem Redirect automatisch und entfernt dabei den Authorization-Header cross-origin (so will es die Fetch-Spec) — S3 autorisiert über die Signatur in der URL. Du musst nichts Spezielles tun, nur den Redirect zulassen.

Payment

Payment löst eine echte Zahlung aus. Es läuft über einen eigenen Merchant-Client — nicht über deinen OIDC-Client. Das Token holst du genauso per client_credentials (siehe Grundlagen), aber mit den Merchant-Credentials.

DIE wichtigste Payment-Regel: merchantId === merchantServiceUUID === die client_id deines Payment-Merchant-Clients — beide Felder bekommen denselben Wert, und das ist NICHT die OIDC-sID dieser MiniApp, sondern der separate Payment-Client (Credentials von 1DE). tenantId = Tenant deiner Merchant-Credentials, nicht der mPower-Tenant.

Schritt 1 — Transaktion anstoßen

POST <PAYMENT_BASE>/mpay-merchant/create/transaction
# Authorization: Bearer <merchant_token>
{
  "version": 1,
  "idempotencyId": "<UUID>",            // echte UUID, gegen Doppelzahlung
  "userId": "<sub>",
  "merchantId": "<MERCHANT_ID>",
  "merchantServiceUUID": "<MERCHANT_ID>",
  "merchantName": "Stadt-Service",
  "merchantCallback": "https://deine-app.de/api/webhooks/payment?applicationId=42",
  "transactionTimeout": 10,
  "amount": 1000,                       // 10,00 € — in CENT (Ganzzahl!)
  "tenantId": "<MERCHANT_TENANT>",
  "currency": "EUR",
  "paymentContent": [[{ "key": "Antrag", "value": "10,00 €" }]]
}
FeldAchtung
amountIn Cent als Ganzzahl. 10,00 € = 1000. Niemals Dezimal.
idempotencyIdEchte UUID. Schützt vor Doppelbuchung bei Retries.
merchantCallbackDein Webhook für das Ergebnis. Query-Params werden hier gespiegelt (anders als bei mPower).

Schritt 2 — Ergebnis-Callback

Das Ergebnis kommt asynchron an deine merchantCallback-URL, sobald der Bürger gezahlt (oder abgebrochen) hat.

{
  "transactionId": "…",
  "status": "finished",
  "transactionStatus": "finished",
  "message": "Payment complete.",
  "cardGatewayType": "credit_stripe"
}
Erfolg = der Status enthält finished bzw. completenicht „success" oder „paid" (das ist empirisch verifiziert). Prüfe also auf finished/complete, nicht auf andere Wörter.

End-to-End: Formular → Signatur → Zahlung

So greifen die drei mPower-Teile in einem typischen Behörden-Flow ineinander:

Formular ausfüllen └─ PDF füllen → Signatur-Koordinaten (%) → mPower /signature (Abschnitt Signatur) ↓ Bürger unterschreibt in der SuperApp Callback signatureResponse "signed" → mediaId per /media/download laden ↓ Status: awaiting_payment mPower choiceRequest "Bezahlen" (Abschnitt Chat) ↓ Bürger tippt "Bezahlen" Callback choiceResponse "Bezahlen" → Payment create/transaction (Abschnitt Payment) ↓ Bürger zahlt Payment-Webhook status "finished" → fertig (z. B. Brief + "Danke" in den Chat)

Eine bewährte Status-Maschine dazu:

draft → ready → awaiting_signature → awaiting_payment → paying → sent

Discovery — Store & Auffindbarkeit

Beim Anlegen wird deine MiniApp als Service registriert. Über zwei Flags steuerst du die Sichtbarkeit:

  • searchable — im Store auffindbar.
  • webFlowEnabled — WebFlow aktiv.

Über die sID ist deine MiniApp per Deeplink aus anderen MiniApps und vom KI-Agenten der SuperApp erreichbar.

Deploy & Domain

Deine MiniApp ist eine normale Web-App — hoste sie, wo du willst (Vercel, eigener Server, Container …). Pflicht:

miniApp.json ausliefern

Unter /miniApp.json erreichbar.

Redirect-URI beim IDP registrieren

https://<deine-domain>/api/auth/callback. Wird beim Anlegen gesetzt; bei Domain-Wechsel neu registrieren, sonst scheitert der OIDC-Callback.

Startseite nicht cachen

no-store — sonst sieht der Nutzer Updates erst nach Force-Close der SuperApp.

Brauchst du eine *.temmuz.uk-Subdomain (Cloudflare, proxied)? Frag deinen 1DE-Ansprechpartner.

Auto-Deploy auf eine eigene Subdomain (am einfachsten)

Du musst gar nicht selbst hosten: Lade dein Projekt als ZIP hoch — im Dashboard bei deiner MiniApp oder per MCP-Tool deploy_miniapp. Wir bauen es als eigenen Container und schalten es live auf <name>-<code>.temmuz.uk (mit HTTPS).

Projekt zippen

Next.js oder statisch. package.json im Root, ohne node_modules, .next, .git (baut der Server). Max. 25 MB.

Hochladen

Dashboard → MiniApp → „ZIP hochladen & deployen", oder Agent: deploy_miniapp({ service_id, zip_base64 }).

Fertig

Nach 1–3 Min Build ist deine MiniApp unter der Subdomain live.

Aktualisieren = einfach neu deployen. Für Änderungen lädst du dasselbe Projekt erneut hoch (Dashboard) bzw. rufst deploy_miniapp mit derselben service_id auf — gleiche Subdomain, der Container wird ersetzt. Lege dafür KEINE neue MiniApp an (sonst Duplikate). create_miniapp ist nur einmal pro App nötig.
Für eine Standard-Next.js-App generieren wir automatisch ein Dockerfile (npm installnext buildnext start). Hat dein ZIP ein eigenes Dockerfile, nutzen wir deins. Kein package.json → wird als statische Seite ausgeliefert.

Im Browser testen (WebFlow)

Die nackte Subdomain im Browser zu öffnen reicht NICHT. Ohne WebFlow scheitert der Login (Silent SSO gibt es nur in der SuperApp). Zum Testen im Browser musst du WebFlow einschalten und dich mit dem Test-Account anmelden:

Innerhalb der SuperApp läuft das Login per Silent SSO automatisch. Zum Testen außerhalb der SuperApp (im normalen Browser):

WebFlow einschalten

Beim Anlegen den Schalter „WebFlow aktiv" setzen (Dashboard) — dann ist Web-Login möglich.

Subdomain öffnen & einloggen

Auf der IDP-Login-Seite mit dem Test-Account anmelden:

Test-IDP-AccountWert
E-Mailhello@kobil.com
PasswortTestAccount57428
Nach dem Test WebFlow wieder ausschalten! Im SuperApp-Betrieb muss WebFlow aus sein, damit der Silent-SSO-Flow greift. (Hinweis: das nachträgliche Umschalten an einem bestehenden Service ist derzeit nur über das SmartDashboard-UI bzw. beim Anlegen zuverlässig — eine API-Automatisierung dafür folgt.)

MCP für KI-Agenten

Binde deinen KI-Agenten (Claude, Cursor, …) direkt an, damit er mit deiner echten MiniApp-Config sofort entwickelt — Doku lesen, Config abrufen, Code generieren, sogar neue MiniApps anlegen.

ToolWirkung
get_docsDiese Doku (optional: nur ein Abschnitt).
list_my_miniappsDeine MiniApps.
get_miniapp_configOIDC-Config, client_secret, Redirect-URIs, Deeplink, miniApp.json, .env, Endpoints.
scaffold_miniappFertige Starter-Dateien (Next.js), prefilled.
create_miniappNeue MiniApp anlegen & veröffentlichen (optional mit Logo-Data-URI).
deploy_miniappProjekt (Next.js/statisch) als eigenen Container auf eine Subdomain hosten (ZIP base64).
delete_miniappEigene MiniApp löschen & Änderung veröffentlichen.

Verbindungsdaten

FeldWert
Endpointhttps://deutschlandappwebpage.temmuz.uk/mcp
TransportStreamable HTTP
Auth-Headerx-api-key: <DEIN_MCP_TOKEN>

Schritt 1 — Token holen: Im Dashboard unter „KI-Agent per MCP anbinden" einen Token erzeugen. Schritt 2 — Client einrichten (wähle deinen Agenten):

Schnellster Weg: eine Session, ein Befehl (Claude Code)

Kein Setup, keine Config-Datei. Der Befehl verbindet Claude Code nur für diese Session mit deiner MCP (Token einsetzen):

claude --strict-mcp-config --mcp-config '{"mcpServers":{"1de-partner":{"type":"http","url":"https://deutschlandappwebpage.temmuz.uk/mcp","headers":{"x-api-key":"<DEIN_MCP_TOKEN>"}}}}'
Nur für Claude Code (per --mcp-config inline). Ein reiner Chat-Prompt kann sich nicht verbinden — die MCP-Anbindung macht immer der Client. Für dauerhaftes Setup oder andere Agenten siehe unten.

Dauerhaft / andere Agenten

# Variante A — ein Befehl (Transport http + Custom-Header):
claude mcp add --transport http 1de-partner \
  https://deutschlandappwebpage.temmuz.uk/mcp \
  --header "x-api-key: <DEIN_MCP_TOKEN>"

# Variante B — projektweit per .mcp.json (ins Repo committen, Token via Env):
{
  "mcpServers": {
    "1de-partner": {
      "type": "http",
      "url": "https://deutschlandappwebpage.temmuz.uk/mcp",
      "headers": { "x-api-key": "${MCP_TOKEN}" }
    }
  }
}
# Prüfen:  claude mcp list   ·   in der Session:  /mcp

Sofort loslegen — der erste Prompt

Gib deinem Agenten als erstes diesen Auftrag. Er liest sich damit komplett ein, bevor er irgendetwas baut:

Du bist mein Entwickler für eine MiniApp im 1DE-/KOBIL-SuperApp-Ökosystem.

Lies dich ZUERST vollständig ein — rufe `get_docs` für ALLE Abschnitte auf und
verstehe: Was ist eine MiniApp, Schnellstart, miniApp.json, Design & Native Feel,
Authentifizierung (Silent SSO), Deeplinks, mPower (Chat, Signatur, Payment),
Discovery, Deploy — und wie man eine MiniApp anlegt (`create_miniapp`) und
deployt (`deploy_miniapp`).

WICHTIG zum Hosting: Soll auf 1DE gehostet werden, rufe `create_miniapp` OHNE `miniapp_url` auf —
es wird automatisch eine feste Subdomain vergeben und als URL/Redirect/Callback registriert.
Danach `deploy_miniapp` auf genau diese MiniApp → die URL stimmt immer (kein Mismatch). WebFlow bleibt aus.
Bei ÄNDERUNGEN/Updates: KEINE neue MiniApp anlegen! Dieselbe MiniApp per `deploy_miniapp` mit
derselben service_id erneut deployen (gleiche Subdomain, Container wird ersetzt). `create_miniapp` nur EINMAL.

Wenn du ALLES verstanden hast, frag NICHTS weiter ab, sondern melde dich bei mir:
„Ich bin bereit, deine MiniApp zu erstellen — was sollen wir bauen?"
und warte auf meine Idee. Erst danach legst du an, baust, und deployst.
Der Token bindet alle Tools an deinen Account — der Agent sieht nur deine MiniApps. Token kompromittiert? Im Dashboard einen neuen erzeugen, der alte wird sofort ungültig.

Referenz — Endpoints & Glossar

Glossar

BegriffBedeutung
sIDService-ID deiner MiniApp = OIDC client_id = serviceUuid für mPower.
Silent SSOLogin ohne Eintippen; Identität von der SuperApp.
Deeplink<SHARE_BASE><sID>, öffnet eine MiniApp als Overlay.
user_sessionDein eigenes signiertes Session-Cookie nach dem OIDC-Callback.

Endpoints

ZweckURL (Platzhalter aus deiner Config)
Authorize<ISSUER>/protocol/openid-connect/auth
Token<ISSUER>/protocol/openid-connect/token
JWKS<ISSUER>/protocol/openid-connect/certs
mPower Msg<MPOWER_BASE>/auth/realms/<TENANT>/mpower/v1/users/{userId}/message
Signatur<MPOWER_BASE>/…/users/{userId}/signature
Payment<PAYMENT_BASE>/mpay-merchant/create/transaction
Die echten Werte für deine MiniApp (inkl. client_secret) findest du im Dashboard — fertig vorbefüllt zum Kopieren.