Zum Inhalt springen
PageSpeed 100 als Auslieferungs-Standard
Auf dieser Seite

API

Alles, was Sie im Editor tun, läuft über eine offene Schnittstelle — dieselbe, die Sie selbst ansprechen können. Dieses Kapitel erklärt Basis-Adresse, Anmeldung und Fehlerformat und führt danach jeden Endpunkt auf, der Ihrem Konto offensteht.

Wofür die API da ist

Die Schnittstelle ist die Steuerebene von XICflow: Websites, Seiten, Bausteine, Medien, KI-Läufe, Domains, Anfragen und Abrechnung.

Der Editor arbeitet ausschließlich über diese Schnittstelle. Was Sie dort per Maus erledigen, können Sie deshalb auch aus einem eigenen Programm heraus tun — etwa Inhalte aus einem anderen System übernehmen, Anfragen abholen oder eine Veröffentlichung anstoßen.

Eckdaten der Schnittstelle
Basis-Adressehttps://api.xicflow.com/api
FormatJSON in UTF-8, auch im Fehlerfall. Ausnahmen sind der Bild-Upload (multipart/form-data), der CSV-Export, der Rechnungs-Download als PDF und die beiden Chat-Endpunkte, die einen Ereignisstrom (text/event-stream) liefern.
VersionDie Spezifikation trägt die Version 1.0.0. Die Adresse selbst enthält keine Versionsnummer; maßgeblich ist immer die maschinenlesbare Fassung.
Umfang115 Operationen auf 92 Pfaden, gegliedert in 19 Kategorien.
Trennung der KontenJede Ressource gehört zu genau einem Konto. Eine Kennung aus einem fremden Konto beantwortet die API mit 404.
RollenLesen steht allen Mitgliedern offen. Inhaltliche Änderungen verlangen mindestens „Bearbeiter“, das Anlegen und Löschen von Websites und Domains mindestens „Administrator“, Abrechnungsvorgänge die Rolle „Eigentümer“.

Aufrufe aus dem Browser sind auf zwei Herkünfte begrenzt

Für Anfragen aus einer Webseite heraus lässt die Schnittstelle nur xicflow.com und www.xicflow.com zu. Die öffentlichen Endpunkte für Kontaktformular und Site-Assistent sind davon ausgenommen, weil veröffentlichte Websites unter eigener Domain laufen. Ein Programm auf Ihrem Server ist von dieser Begrenzung nicht betroffen.

Anmelden und Token mitschicken

Ein Token entsteht bei der Anmeldung und wird danach bei jeder Anfrage im Kopfzeilenfeld „Authorization“ mitgeschickt.

  1. Rufen Sie POST /auth/login mit E-Mail und Passwort auf.

    Ein neues Konto legen Sie stattdessen über POST /auth/register an; auch dieser Aufruf liefert bereits ein Token.

  2. Nehmen Sie das Feld „token“ aus der Antwort.

    Das Feld „access_token“ enthält denselben Wert und existiert nur der Kompatibilität halber.

  3. Schicken Sie bei jeder weiteren Anfrage die Kopfzeile „Authorization: Bearer <token>“ mit.

  4. Beenden Sie die Sitzung über POST /auth/logout, wenn Sie das Token nicht mehr brauchen.

    Ein Token bleibt gültig, bis es widerrufen wird — einzeln über /auth/logout oder DELETE /auth/sessions/{id}, alle übrigen auf einmal über DELETE /auth/sessions.

Anfrage
curl -X POST https://api.xicflow.com/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"<E-Mail>","password":"<Passwort>"}'
Antwort
{
  "token": "<token>",
  "access_token": "<token>",
  "token_type": "bearer",
  "user": {
    "id": "<uuid>",
    "email": "<E-Mail>",
    "name": "<Name>",
    "site_role": "owner",
    "tenant_id": "<uuid>",
    "tenant": {
      "id": "<uuid>",
      "name": "<Kontoname>",
      "slug": "<slug>",
      "plan": "<Tarif>",
      "status": "active",
      "trial_ends_at": "<Zeitpunkt>"
    }
  }
}

Mit dem Token sind alle übrigen Endpunkte erreichbar:

Anfrage
curl https://api.xicflow.com/api/sites \
  -H "Authorization: Bearer <token>"

Ist für das Konto die Zwei-Faktor-Anmeldung aktiv und fehlt der Code, antwortet /auth/login nicht mit einem Token, sondern mit „totp_required“ und einem kurzlebigen „challenge_token“ (zehn Minuten gültig). Sie lösen es entweder über POST /auth/totp/challenge ein oder wiederholen den Login mit dem Feld „totp_code“. Ein Backup-Code wird an derselben Stelle angenommen.

Einige Endpunkte kommen ohne Token aus — Anmeldung und Registrierung, der Rückweg der Google-Anmeldung, die Passkey-Anmeldung, die Einlösung der Zwei-Faktor-Abfrage, das Kontaktformular veröffentlichter Websites, der eingebettete Site-Assistent, die Vorschau und Annahme einer Team-Einladung sowie der Stripe-Rückruf. In der Referenz weiter unten tragen sie die Kennzeichnung „ohne Token“.

Konventionen und Fehlerformat

Fehler kommen als JSON zurück. Je nach Ursache tragen sie ein Feld „error“ mit einem festen Schlüssel oder eine Feldliste unter „errors“.

Ungültige Eingaben (422)

Verletzt eine Anfrage die Feldregeln, nennt die Antwort jedes betroffene Feld einzeln.

422
{
  "message": "<Meldung>",
  "errors": {
    "<Feldname>": ["<Meldung zum Feld>"]
  }
}

Rolle reicht nicht (403)

„required“ nennt die nötige, „role“ die tatsächliche Rolle.

403
{
  "error": "forbidden",
  "message": "Ihre Rolle (…) erlaubt diese Aktion nicht.",
  "required": "editor",
  "role": "viewer"
}

Kontingent erschöpft (402)

Das Feld „resource“ nennt das betroffene Kontingent. Beim Editor-Chat lautet der Schlüssel stattdessen „chat_tokens_exhausted“.

402
{
  "error": "quota_exceeded",
  "resource": "ai_image",
  "plan": "<Tarif>",
  "remaining": 0,
  "upgrade": true,
  "message": "Dein monatliches Kontingent für KI-Bilder ist erschöpft. …"
}

Konto gesperrt (403)

Ist das Konto wegen offener Rechnungen gesperrt, antwortet jeder Endpunkt mit Token so — unabhängig davon, was angefragt wurde.

403
{
  "error": "account_suspended",
  "message": "Dein Konto ist wegen offener Rechnungen gesperrt. …"
}

Verwendete Statuscodes

Statuscodes und ihre Bedeutung in der XICflow-API
CodeBedeutung
200Erfolg.
201Angelegt.
202Angenommen, wird im Hintergrund verarbeitet — der Fortschritt läuft über GET /ai/generations/{generation}.
302Weiterleitung; kommt nur bei den beiden Endpunkten der Google-Anmeldung vor, die eine Browser-Navigation sind.
400Ungültige Anfrage.
401Kein oder ungültiges Token, falsche Zugangsdaten oder falscher Zwei-Faktor-Code.
402Kontingent erschöpft — Tarif erweitern oder aufladen.
403Kein Zugriff: Rolle reicht nicht oder Konto gesperrt.
404Nicht vorhanden — oder Ressource eines fremden Kontos.
409Konflikt: eine Vorbedingung ist nicht erfüllt.
410Nicht mehr gültig, etwa eine bereits eingelöste oder abgelaufene Einladung.
422Feldregeln verletzt.
429Zu viele Anfragen in kurzer Zeit.
500Serverfehler.
503Vorübergehend nicht verfügbar.

Grenzen je Minute

Empfindliche und teure Endpunkte sind gedrosselt. Ist die Grenze erreicht, antwortet die API mit 429.

Gezählt wird je angefangener Minute. Bei Endpunkten ohne Token zählt die Absender-Adresse, bei allen übrigen das angemeldete Konto. Ein allgemeines Limit über die gesamte Schnittstelle gibt es nicht — nur die hier genannten Endpunkte sind begrenzt.

Anfragen je Minute nach Endpunkt
EndpunkteJe Minute
Passwort ändern, Zwei-Faktor aktivieren oder abschalten, Backup-Codes neu erzeugen, Datenexport6
Kontaktformular veröffentlichter Websites, Team-Einladung verschicken10
Anmeldung, Registrierung, Zwei-Faktor-Abfrage, Passkey-Anmeldung, Rückweg der Google-Anmeldung, Anzeigename ändern, alle anderen Sitzungen abmelden, Einladung ansehen und annehmen12
Einzelne Sitzung abmelden, Alt-Text per KI erzeugen, Chat des öffentlichen Site-Assistenten20
Alle KI-Endpunkte, Blog-Erzeugung, Veröffentlichen, Bild-Upload, Domain prüfen und binden, Wissensbasis neu aufbauen, Oberflächensprache setzen, alle kaufmännischen Vorgänge30
Konfiguration des öffentlichen Site-Assistenten60
Status einer Generierung abfragen120

Lange Läufe und Wiederholungen

Bauen und Veröffentlichen dauern zu lange für eine einzelne Antwort. Diese Endpunkte quittieren sofort und arbeiten im Hintergrund weiter.

  1. Der Aufruf antwortet mit 202 und einer „generation_id“.

    So arbeiten POST /ai/build, POST /sites/{site}/publish und POST /sites/{site}/blog/generate.

  2. Fragen Sie GET /ai/generations/{generation} ab, bis „status“ nicht mehr queued oder running lautet.

    Dieser Endpunkt ist mit 120 Abfragen je Minute großzügig bemessen, sekündliches Nachfragen ist also vorgesehen.

  3. Bei „succeeded“ steht das Ergebnis im Feld „output“, bei „failed“ die Ursache im Feld „error“.

Ein fehlgeschlagener Lauf wird nicht von selbst wiederholt

Bau und Veröffentlichung laufen bewusst genau einmal, weil ein zweiter Anlauf nicht dasselbe Ergebnis liefern würde. Steht „failed“, stoßen Sie den Vorgang selbst erneut an. Auch sonst kennt die Schnittstelle keine Wiederholungsschlüssel: wird dieselbe erzeugende Anfrage zweimal geschickt, entsteht ein zweiter Datensatz.

Zwei Endpunkte antworten nicht mit einem fertigen Dokument, sondern mit einem laufenden Ereignisstrom: der Editor-Assistent unter POST /ai/chat und der Assistent veröffentlichter Websites unter POST /public/assistant/{siteSlug}/chat. Beide senden Ereignisse als text/event-stream, beginnend mit „start“ und endend mit „done“ oder „error“.

Referenz aller Endpunkte

Jeder Eintrag lässt sich aufklappen und zeigt dann Zweck, Parameter, Aufbau der Anfrage und mögliche Antworten.

Diese Liste ist erzeugt, nicht abgeschrieben

Sie entsteht beim Bau der Seite aus derselben Spezifikation, die auch die Schnittstelle selbst ausliefert. Kommt ein Endpunkt hinzu, steht er nach dem nächsten Bau hier — dafür bleiben Kurztexte, Feldhinweise und die besonderen Antwortbeschreibungen auch in der englischen Fassung deutsch; übersetzt sind lediglich die wiederkehrenden Standardantworten. Endpunkte des Betreibers sind nicht enthalten.

Auth

Registrierung, Login, Sitzungen, 2FA/TOTP, Passkeys, OAuth.

POST /auth/register Konto registrieren ohne Token

Legt Nutzer + eigenen Tenant (Owner) an und liefert ein Bearer-Token. 14-Tage-Trial.

Parameter

Parameter von POST /auth/register
NameOrtTypPflichtHinweis
emailRumpfstring (email)jaE-Mail (wird normalisiert, +alias entfernt).
passwordRumpfstringjaMindestens 10 Zeichen.
nameRumpfstringjaAnzeigename.

Anfrage · application/json

{
  "email": "<email>",
  "password": "<string>",
  "name": "<string>"
}

Antworten

  • 200 Token + Nutzerprofil ({token, access_token, token_type, user}).
  • 422 E-Mail bereits vergeben oder ungültige Eingabe.
POST /auth/login Login (Passwort, optional 2FA) ohne Token

Liefert {token, user}. Bei aktivem TOTP ohne totp_code stattdessen {totp_required:true, challenge_token, expires_in}.

Parameter

Parameter von POST /auth/login
NameOrtTypPflichtHinweis
emailRumpfstring (email)ja
passwordRumpfstringja
totp_codeRumpfstringneinOptionaler 6-stelliger TOTP- oder Backup-Code.

Anfrage · application/json

{
  "email": "<email>",
  "password": "<string>",
  "totp_code": "<string>"
}

Antworten

  • 200 {token,user} oder {totp_required,challenge_token,expires_in}.
  • 401 Ungültige Zugangsdaten oder 2FA-Code.
  • 403 Konto gesperrt.
  • 429 Zu viele 2FA-Fehlversuche.
POST /auth/totp/challenge 2FA per Challenge-Token einlösen ohne Token

Parameter

Parameter von POST /auth/totp/challenge
NameOrtTypPflichtHinweis
challenge_tokenRumpfstringja48-stelliges Token aus der Login-Antwort.
codeRumpfstringjaTOTP- oder Backup-Code.

Anfrage · application/json

{
  "challenge_token": "<string>",
  "code": "<string>"
}

Antworten

  • 200 {token,user}.
  • 401 Ungültig/abgelaufen.
  • 429 Zu viele Versuche.
POST /auth/passkey/login/options Passkey-Login: Optionen anfordern ohne Token

Parameter

Parameter von POST /auth/passkey/login/options
NameOrtTypPflichtHinweis
emailRumpfstring (email)neinOptional — schränkt allowCredentials ein.

Anfrage · application/json

{
  "email": "<email>"
}

Antworten

  • 200 WebAuthn-publicKey-Request-Optionen (flach).
POST /auth/passkey/login/verify Passkey-Login: Antwort verifizieren ohne Token

Parameter

Parameter von POST /auth/passkey/login/verify
NameOrtTypPflichtHinweis
idRumpfstringjaCredential-ID (base64url).
responseRumpfobjectjaWebAuthn-Assertion: clientDataJSON, authenticatorData, signature.

Anfrage · application/json

{
  "id": "<string>",
  "response": {}
}

Antworten

  • 200 {token,user}.
  • 401 Challenge abgelaufen / Passkey unbekannt.
  • 403 Konto gesperrt.
GET /auth/oauth/{provider}/redirect Google-SSO starten (302) ohne Token

Parameter

Parameter von GET /auth/oauth/{provider}/redirect
NameOrtTypPflichtHinweis
providerPfadstringjaOAuth-Provider, aktuell nur "google".
returnAbfragestringneinRückkehr-URL nach erfolgreichem Login.

Antworten

  • 302 Weiterleitung (Browser-Navigation)
  • 404 Unbekannter Provider.
GET /auth/oauth/{provider}/callback Google-SSO-Callback (302 mit Token-Fragment) ohne Token

Der State wird gegen das beim Redirect gesetzte Cookie geprüft. Im Fehlerfall ebenfalls 302, aber mit #error=… (state_missing, state_mismatch, no_code, exchange_failed, no_sub, email_unverified, account_disabled).

Parameter

Parameter von GET /auth/oauth/{provider}/callback
NameOrtTypPflichtHinweis
providerPfadstringjaOAuth-Provider, aktuell nur "google".
stateAbfragestringneinCSRF-State.
codeAbfragestringneinAuthorization-Code.

Antworten

  • 302 Redirect ins Frontend mit #token=…&provider=…(&new=1) im Fragment.
POST /auth/oauth/{provider}/callback SSO-Callback als form_post (302, identisch zu GET) ohne Token

Alias derselben Verarbeitung für Provider mit response_mode=form_post. State und Code werden weiterhin aus der Query gelesen.

Parameter

Parameter von POST /auth/oauth/{provider}/callback
NameOrtTypPflichtHinweis
providerPfadstringjaOAuth-Provider, aktuell nur "google".
stateAbfragestringneinCSRF-State.
codeAbfragestringneinAuthorization-Code.

Antworten

  • 302 Redirect ins Frontend mit #token=… im Fragment.
GET /me Aktuelles Nutzerprofil

Antworten

  • 200 Nutzerprofil inkl. tenant (plan/status/trial_ends_at).
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
POST /auth/logout Aktuelles Token widerrufen

Antworten

  • 200 {ok:true}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
POST /auth/change-password Passwort ändern

Widerruft alle anderen Sessions. new_password braucht Bestätigung (new_password_confirmation).

Parameter

Parameter von POST /auth/change-password
NameOrtTypPflichtHinweis
current_passwordRumpfstringja
new_passwordRumpfstringjaMindestens 10 Zeichen, confirmed.
new_password_confirmationRumpfstringnein

Anfrage · application/json

{
  "current_password": "<string>",
  "new_password": "<string>",
  "new_password_confirmation": "<string>"
}

Antworten

  • 200 {ok:true}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 422 Aktuelles Passwort falsch.
GET /auth/sessions Aktive Sitzungen auflisten

Alle Bearer-Token des angemeldeten Nutzers, zuletzt genutzte zuerst. Die eigene Sitzung ist mit current:true markiert.

Antworten

  • 200 {sessions:[{id, device, last_used_at, created_at, current}]}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
DELETE /auth/sessions Alle anderen Sitzungen abmelden

Widerruft jedes Token außer dem aktuell verwendeten.

Antworten

  • 200 {ok:true}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 429 Zu viele Anfragen (Rate-Limit)
DELETE /auth/sessions/{id} Einzelne Sitzung abmelden

Nur eigene Sitzungen; eine fremde ID trifft nichts und wird trotzdem mit 200 quittiert.

Parameter

Parameter von DELETE /auth/sessions/{id}
NameOrtTypPflichtHinweis
idPfadstringjaSitzungs-ID aus GET /auth/sessions.

Antworten

  • 200 {ok:true}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 429 Zu viele Anfragen (Rate-Limit)
GET /auth/totp/status 2FA-Status

Antworten

  • 200 {enabled, enabled_at, has_pending_secret, backup_codes_left}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
POST /auth/totp/setup 2FA einrichten (Pending-Secret)

Antworten

  • 200 {secret, provisioning_uri} (otpauth://).
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 422 Bereits aktiviert.
POST /auth/totp/enable 2FA aktivieren

Verifiziert den ersten Code und liefert die Backup-Codes EINMALIG im Klartext.

Parameter

Parameter von POST /auth/totp/enable
NameOrtTypPflichtHinweis
codeRumpfstringjaAktueller TOTP-Code.

Anfrage · application/json

{
  "code": "<string>"
}

Antworten

  • 200 {enabled:true, backup_codes[]}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 422 Ungültiger Code / kein Pending-Secret.
POST /auth/totp/disable 2FA deaktivieren

Parameter

Parameter von POST /auth/totp/disable
NameOrtTypPflichtHinweis
passwordRumpfstringja
codeRumpfstringjaTOTP- oder Backup-Code.

Anfrage · application/json

{
  "password": "<string>",
  "code": "<string>"
}

Antworten

  • 200 {enabled:false}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 422 Passwort oder Code falsch.
POST /auth/totp/regenerate-codes Backup-Codes neu erzeugen

Parameter

Parameter von POST /auth/totp/regenerate-codes
NameOrtTypPflichtHinweis
passwordRumpfstringja
codeRumpfstringja

Anfrage · application/json

{
  "password": "<string>",
  "code": "<string>"
}

Antworten

  • 200 {backup_codes[]}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 422 Validierungsfehler
POST /auth/passkey/register/options Passkey registrieren: Optionen

Antworten

  • 200 WebAuthn-publicKey-Create-Optionen (flach).
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
POST /auth/passkey/register/verify Passkey registrieren: verifizieren

Parameter

Parameter von POST /auth/passkey/register/verify
NameOrtTypPflichtHinweis
idRumpfstringjaCredential-ID (base64url).
responseRumpfobjectjaclientDataJSON + attestationObject.
nameRumpfstringneinOptionaler Anzeigename.

Anfrage · application/json

{
  "id": "<string>",
  "response": {},
  "name": "<string>"
}

Antworten

  • 200 {ok:true, id, credential_name}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 422 Challenge/Attestation ungültig.
GET /auth/passkeys Passkeys auflisten

Antworten

  • 200 {passkeys:[{id, credential_name, last_used_at, created_at}]}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
PUT /auth/passkeys/{id} Passkey umbenennen

Parameter

Parameter von PUT /auth/passkeys/{id}
NameOrtTypPflichtHinweis
idPfadstringjaCredential-ID.
nameRumpfstringja

Anfrage · application/json

{
  "name": "<string>"
}

Antworten

  • 200 {ok:true}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
DELETE /auth/passkeys/{id} Passkey löschen

Parameter

Parameter von DELETE /auth/passkeys/{id}
NameOrtTypPflichtHinweis
idPfadstringjaCredential-ID.

Antworten

  • 200 {ok:true}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
GET /auth/oauth/identities Verknüpfte OAuth-Identitäten

Antworten

  • 200 {providers:[…]}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
DELETE /auth/oauth/{provider} OAuth-Identität entkoppeln

Parameter

Parameter von DELETE /auth/oauth/{provider}
NameOrtTypPflichtHinweis
providerPfadstringjaOAuth-Provider, aktuell nur "google".

Antworten

  • 200 {ok:true}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 422 Letzter Zugang ohne gesetztes Passwort.

Konto

Eigenes Profil, Oberflächensprache und Datenexport (DSGVO Art. 20).

POST /account/profile Eigenen Anzeigenamen ändern

Parameter

Parameter von POST /account/profile
NameOrtTypPflichtHinweis
nameRumpfstringjaAnzeigename, max. 190 Zeichen (wird getrimmt).

Anfrage · application/json

{
  "name": "<string>"
}

Antworten

  • 200 {name}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 422 Validierungsfehler
  • 429 Zu viele Anfragen (Rate-Limit)
POST /account/locale Oberflächensprache setzen

Am Konto gespeichert und damit gerätübergreifend wirksam.

Parameter

Parameter von POST /account/locale
NameOrtTypPflichtHinweis
languageRumpfstringjade oder en.

Anfrage · application/json

{
  "language": "de"
}

Antworten

  • 200 {language}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 422 Validierungsfehler
  • 429 Zu viele Anfragen (Rate-Limit)
GET /account/data-export Eigene Daten exportieren (DSGVO Art. 20)

JSON-Download (Content-Disposition: attachment) mit Konto, Nutzern, Sites samt Seiten/Collections/Einträgen/Domains, Kontaktanfragen, Rechnungen und Medien-Metadaten des eigenen Kontos. Enthält bewusst keine Geheimnisse (Passwort-Hash, TOTP-Secret, Backup-Codes, Stripe-Referenzen). Rate-Limit 6/min.

Antworten

  • 200 {meta, account, users, sites, contact_submissions, invoices, assets}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 422 Kein Konto (Tenant) am Nutzer hinterlegt.
  • 429 Zu viele Anfragen (Rate-Limit)

Team

Mitglieder, Rollen, Einladungen und Sitz-Kontingent eines Kontos.

GET /team Mitglieder, Einladungen und Sitze

seats.limit stammt aus dem Tarif; belegte Sitze = aktive Mitglieder plus offene, nicht abgelaufene Einladungen. Bei unbegrenzten Sitzen ist unlimited true und available null.

Antworten

  • 200 {members:[{id,name,email,role,is_owner,is_you,joined_at}], invitations:[{id,email,role,expires_at,expired}], seats:{used,limit,unlimited,available,plan}, your_role, roles}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 422 Kein Konto (Tenant) am Nutzer hinterlegt.
POST /team/invitations Mitglied einladen

Erfordert mindestens die Rolle admin; vergeben werden können nur Rollen unterhalb der eigenen. Eine bereits offene Einladung an dieselbe Adresse wird ersetzt. Die Einladung gilt 14 Tage; der Annahme-Link wird zusätzlich zurückgegeben, damit er auch ohne Mailzustellung weitergegeben werden kann. Rate-Limit 10/min.

Parameter

Parameter von POST /team/invitations
NameOrtTypPflichtHinweis
emailRumpfstring (email)jaAdresse ohne bestehendes XICflow-Konto. · max. 255 Zeichen
roleRumpfstringjaadmin|editor|viewer.

Anfrage · application/json

{
  "email": "<email>",
  "role": "admin"
}

Antworten

  • 201 {invitation:{id,email,role,expires_at,expired}, accept_url}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 403 Rolle reicht nicht (forbidden) oder Zielrolle zu hoch (role_too_high).
  • 422 already_member, email_taken, seat_limit_reached (mit limit) oder kein Tenant.
  • 429 Zu viele Anfragen (Rate-Limit)
DELETE /team/invitations/{invitation} Offene Einladung widerrufen

Erfordert mindestens die Rolle admin.

Parameter

Parameter von DELETE /team/invitations/{invitation}
NameOrtTypPflichtHinweis
invitationPfadstringjaEinladungs-UUID aus GET /team.

Antworten

  • 200 {ok:true}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 403 Rolle reicht nicht.
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Kein Tenant.
POST /team/members/{member}/role Rolle eines Mitglieds ändern

Die eigene Rolle und die des Konto-Eigentümers sind nicht änderbar. Änderbar sind nur Mitglieder, deren aktuelle UND neue Rolle unterhalb der eigenen liegen.

Parameter

Parameter von POST /team/members/{member}/role
NameOrtTypPflichtHinweis
memberPfadstringjaNutzer-UUID aus GET /team.
roleRumpfstringjaadmin|editor|viewer.

Anfrage · application/json

{
  "role": "admin"
}

Antworten

  • 200 {ok:true, role}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 403 Rolle reicht nicht.
  • 404 Mitglied nicht im eigenen Konto.
  • 422 cannot_change_owner, cannot_change_self oder kein Tenant.
DELETE /team/members/{member} Mitglied entfernen

Entfernt Zugang und Konto des Mitglieds und widerruft dessen Token. Eigentümer und eigenes Konto sind ausgenommen.

Parameter

Parameter von DELETE /team/members/{member}
NameOrtTypPflichtHinweis
memberPfadstringjaNutzer-UUID aus GET /team.

Antworten

  • 200 {ok:true}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 403 Rolle reicht nicht.
  • 404 Mitglied nicht im eigenen Konto.
  • 422 cannot_remove_owner, cannot_remove_self oder kein Tenant.
GET /public/team/invitation/{token} Einladung vorab ansehen (ohne Anmeldung) ohne Token

Löst den Einmal-Token auf, damit die Annahme-Seite Team und Rolle anzeigen kann. Rate-Limit 12/min.

Parameter

Parameter von GET /public/team/invitation/{token}
NameOrtTypPflichtHinweis
tokenPfadstringjaEinmal-Token aus dem Einladungslink.

Antworten

  • 200 {email, role, team, expires_at}.
  • 404 Token unbekannt (invalid).
  • 410 Bereits angenommen (already_accepted) oder abgelaufen (expired).
  • 429 Zu viele Anfragen (Rate-Limit)
POST /public/team/accept Einladung annehmen (ohne Anmeldung) ohne Token

Legt das Konto mit der eingeladenen Rolle an, löst den Token ein und liefert direkt ein Bearer-Token. Die E-Mail stammt aus der Einladung und gilt damit als bestätigt. Rate-Limit 12/min.

Parameter

Parameter von POST /public/team/accept
NameOrtTypPflichtHinweis
tokenRumpfstringjaEinmal-Token aus dem Einladungslink.
nameRumpfstringjaAnzeigename, max. 255 Zeichen.
passwordRumpfstringjaMindestens 10 Zeichen.

Anfrage · application/json

{
  "token": "<string>",
  "name": "<string>",
  "password": "<string>"
}

Antworten

  • 200 {token, access_token, token_type, user:{id,name,email,role,tenant_id}}.
  • 404 Token unbekannt (invalid).
  • 409 Für diese E-Mail existiert bereits ein Konto (email_taken).
  • 410 Bereits angenommen oder abgelaufen.
  • 422 Validierungsfehler
  • 429 Zu viele Anfragen (Rate-Limit)

Sites

CRUD der Websites eines Kontos plus Veröffentlichung.

GET /sites Sites des Kontos auflisten

Antworten

  • 200 {data:[Site]} inkl. theme, domains, pages_count.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
POST /sites Site anlegen

Parameter

Parameter von POST /sites
NameOrtTypPflichtHinweis
nameRumpfstringja
slugRumpfstringjaKleinbuchstaben/Ziffern/Bindestrich, je Konto eindeutig.
theme_idRumpfstring (uuid)neinOptionales Theme (UUID, eigen oder System).
default_localeRumpfstringneinDefault "de".
localesRumpfarrayneinAktive Sprachen, z. B. ["de","en"].
companyRumpfobjectneinFirmenstammdaten.
brandingRumpfobjectnein
trust_barRumpfobjectnein
xictraq_idRumpfstringneinXICTRAQ-Property für Analytics/Monitoring.
contact_endpointRumpfstringnein
contact_recipientRumpfstringnein
google_verificationRumpfstringnein
settingsRumpfobjectnein

Anfrage · application/json

{
  "name": "<string>",
  "slug": "<string>",
  "theme_id": "<uuid>",
  "default_locale": "<string>",
  "locales": [],
  "company": {},
  "branding": {},
  "trust_bar": {},
  "xictraq_id": "<string>",
  "contact_endpoint": "<string>",
  "contact_recipient": "<string>",
  "google_verification": "<string>",
  "settings": {}
}

Antworten

  • 201 {data:Site}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 422 Slug vergeben / ungültig.
GET /sites/{site} Site abrufen

Parameter

Parameter von GET /sites/{site}
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.

Antworten

  • 200 {data:Site} inkl. pages, theme, domains.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
PUT /sites/{site} Site aktualisieren

status und primary_domain_id sind bewusst NICHT hierüber setzbar (Publish- bzw. Domain-Flow).

Parameter

Parameter von PUT /sites/{site}
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.
nameRumpfstringnein
slugRumpfstringnein
theme_idRumpfstring (uuid)nein
default_localeRumpfstringnein
localesRumpfarraynein
companyRumpfobjectnein
brandingRumpfobjectnein
settingsRumpfobjectnein

Anfrage · application/json

{
  "name": "<string>",
  "slug": "<string>",
  "theme_id": "<uuid>",
  "default_locale": "<string>",
  "locales": [],
  "company": {},
  "branding": {},
  "settings": {}
}

Antworten

  • 200 {data:Site}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Slug vergeben.
DELETE /sites/{site} Site löschen

Parameter

Parameter von DELETE /sites/{site}
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.

Antworten

  • 200 {deleted:true}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
POST /sites/{site}/publish Site veröffentlichen (asynchron)

Reiht einen Publish-Job ein und antwortet sofort. Status via GET /ai/generations/{generation_id}.

Parameter

Parameter von POST /sites/{site}/publish
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.
labelRumpfstringneinOptionales Versionslabel.
notesRumpfstringneinOptionale Notiz.

Anfrage · application/json

{
  "label": "<string>",
  "notes": "<string>"
}

Antworten

  • 202 {generation_id, status:"queued"}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
GET /sites/{site}/regions Seiten-IDs der Header-/Footer-Regionen

Header und Footer sind eigene System-Seiten (type=system) und tauchen daher nicht in GET /sites/{site}/pages auf. Dieser Endpunkt liefert ihre Seiten-IDs als Anker für den blockbasierten Header-/Footer-Editor; fehlende Regionsseiten werden beim ersten Aufruf angelegt.

Parameter

Parameter von GET /sites/{site}/regions
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.

Antworten

  • 200 {data:{header, footer}} — je Region eine Seiten-UUID.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)

Seiten & Blöcke

Seiten (bilingual) und ihre Inhaltsblöcke.

GET /sites/{site}/pages Seiten einer Site

Parameter

Parameter von GET /sites/{site}/pages
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.

Antworten

  • 200 {data:[Page]} inkl. translations.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
POST /sites/{site}/pages Seite anlegen

Bilingual: translations je Locale ({locale,title,slug,…}).

Parameter

Parameter von POST /sites/{site}/pages
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.
slugRumpfstringja
pathRumpfstringjaBeginnt mit "/", nur [a-z0-9/-].
typeRumpfstringneinpage|post|landing|legal|system.
statusRumpfstringneindraft|published|scheduled|archived.
templateRumpfstringnein
parent_idRumpfstring (uuid)nein
sort_orderRumpfintegernein
is_homeRumpfbooleannein
is_noindexRumpfbooleannein
seoRumpfobjectnein
translationsRumpfarrayjaPflicht, min. 1 Eintrag mit locale/title/slug.

Anfrage · application/json

{
  "slug": "<string>",
  "path": "<string>",
  "type": "<string>",
  "status": "<string>",
  "template": "<string>",
  "parent_id": "<uuid>",
  "sort_order": 0,
  "is_home": false,
  "is_noindex": false,
  "seo": {},
  "translations": []
}

Antworten

  • 201 {data:Page}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Pfad vergeben / ungültig.
GET /pages/{page} Seite abrufen

Parameter

Parameter von GET /pages/{page}
NameOrtTypPflichtHinweis
pagePfadstringjaSeiten-UUID.

Antworten

  • 200 {data:Page} inkl. translations, sections, blocks.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
PUT /pages/{page} Seite aktualisieren

Parameter

Parameter von PUT /pages/{page}
NameOrtTypPflichtHinweis
pagePfadstringjaSeiten-UUID.
slugRumpfstringnein
pathRumpfstringnein
typeRumpfstringnein
statusRumpfstringnein
is_homeRumpfbooleannein
is_noindexRumpfbooleannein
seoRumpfobjectnein
published_atRumpfstring (date-time)nein
translationsRumpfarrayneinUpsert je Locale.

Anfrage · application/json

{
  "slug": "<string>",
  "path": "<string>",
  "type": "<string>",
  "status": "<string>",
  "is_home": false,
  "is_noindex": false,
  "seo": {},
  "published_at": "<date-time>",
  "translations": []
}

Antworten

  • 200 {data:Page}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Validierungsfehler
DELETE /pages/{page} Seite löschen

Parameter

Parameter von DELETE /pages/{page}
NameOrtTypPflichtHinweis
pagePfadstringjaSeiten-UUID.

Antworten

  • 200 {deleted:true}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
PUT /pages/{page}/reorder-blocks Blöcke neu sortieren

blocks: Liste von Block-IDs (Position = sort_order) oder Objekten {id,section_id,sort_order} für sektionsübergreifendes Verschieben.

Parameter

Parameter von PUT /pages/{page}/reorder-blocks
NameOrtTypPflichtHinweis
pagePfadstringjaSeiten-UUID.
blocksRumpfarrayjaIDs oder {id,section_id,sort_order}-Objekte.

Anfrage · application/json

{
  "blocks": []
}

Antworten

  • 200 {data:[Section]} inkl. sortierter Blöcke.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Validierungsfehler
POST /pages/{page}/blocks Block hinzufügen

props werden gegen block_types.schema validiert (unbekannte Props -> 422).

Parameter

Parameter von POST /pages/{page}/blocks
NameOrtTypPflichtHinweis
pagePfadstringjaSeiten-UUID.
typeRumpfstringneinblock_types.key (alternativ block_type_id).
block_type_idRumpfstring (uuid)neinAlternativ zu type.
section_idRumpfstring (uuid)neinZiel-Section (sonst erste/neue).
propsRumpfobjectneinBlock-Eigenschaften gemäß Schema.
contentRumpfobjectnein
sort_orderRumpfintegernein
is_visibleRumpfbooleannein

Anfrage · application/json

{
  "type": "<string>",
  "block_type_id": "<uuid>",
  "section_id": "<uuid>",
  "props": {},
  "content": {},
  "sort_order": 0,
  "is_visible": false
}

Antworten

  • 201 {data:Block}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Unbekannter Typ / Props verletzen das Schema.
PUT /pages/{page}/blocks Alle Blöcke einer Seite ersetzen (Autosave)

Vollständiger Abgleich: Blöcke mit bekannter id werden aktualisiert, Einträge ohne id neu angelegt, alle nicht gesendeten Blöcke der Seite gelöscht. Die Reihenfolge im Array bestimmt die Reihenfolge auf der Seite. Blöcke mit unbekanntem oder deaktiviertem type werden übersprungen. Fehlt content, bleiben vorhandene Übersetzungen erhalten. Maximal 400 Blöcke je Aufruf.

Parameter

Parameter von PUT /pages/{page}/blocks
NameOrtTypPflichtHinweis
pagePfadstringjaSeiten-UUID.
blocksRumpfarrayjaPflicht (darf leer sein — leert dann die Seite). Elemente: {id?, type, props?, content?}; type ist ein block_types.key.

Anfrage · application/json

{
  "blocks": []
}

Antworten

  • 200 {ok:true, blocks:[{id,type}], count}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Validierungsfehler
PUT /blocks/{block} Block aktualisieren

Parameter

Parameter von PUT /blocks/{block}
NameOrtTypPflichtHinweis
blockPfadstringjaBlock-UUID.
propsRumpfobjectnein
contentRumpfobjectnein
block_type_idRumpfstring (uuid)neinOptionaler Typwechsel.
typeRumpfstringnein
section_idRumpfstring (uuid)nein
sort_orderRumpfintegernein
is_visibleRumpfbooleannein

Anfrage · application/json

{
  "props": {},
  "content": {},
  "block_type_id": "<uuid>",
  "type": "<string>",
  "section_id": "<uuid>",
  "sort_order": 0,
  "is_visible": false
}

Antworten

  • 200 {data:Block}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Validierungsfehler
DELETE /blocks/{block} Block löschen

Parameter

Parameter von DELETE /blocks/{block}
NameOrtTypPflichtHinweis
blockPfadstringjaBlock-UUID.

Antworten

  • 200 {deleted:true}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)

Theme

Design-Tokens je Site (Copy-on-Write für System-Themes).

GET /sites/{site}/theme Theme der Site

Parameter

Parameter von GET /sites/{site}/theme
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.

Antworten

  • 200 {data:Theme} mit tokens.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Kein Theme verfügbar.
PUT /sites/{site}/theme Theme aktualisieren

Copy-on-Write: ein geteiltes System-Theme wird beim ersten Schreiben geklont.

Parameter

Parameter von PUT /sites/{site}/theme
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.
nameRumpfstringnein
tokensRumpfobjectjaDesign-Tokens (colors, colorsDark, fonts, gradients, hero, sectionStyle, headerStyle …).

Anfrage · application/json

{
  "name": "<string>",
  "tokens": {}
}

Antworten

  • 200 {data:Theme}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Validierungsfehler

Medien

Bild-Uploads je Site.

GET /sites/{site}/media Mediathek einer Site

Parameter

Parameter von GET /sites/{site}/media
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.
qAbfragestringneinVolltextsuche über Dateiname, Alt-Text und Titel (case-insensitiv).

Antworten

  • 200 {data:[Asset]} (neueste zuerst) mit url, path, alt, title, width, height, bytes, mime.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
POST /sites/{site}/media Bild hochladen

multipart/form-data. Nur Rasterformate (jpeg/png/webp/gif), max. 8 MB; SVG ist bewusst ausgeschlossen.

Parameter

Parameter von POST /sites/{site}/media
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.
fileRumpfstring (binary)jaBilddatei.
altRumpfstringneinOptionaler Alt-Text (BFSG).

Anfrage · multipart/form-data

{
  "file": "<binary>",
  "alt": "<string>"
}

Antworten

  • 201 {url, path, bytes, mime, width, height, asset_id}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Ungültige Datei.
PATCH /sites/{site}/media/{asset} Alt-Text/Titel eines Assets setzen

Parameter

Parameter von PATCH /sites/{site}/media/{asset}
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.
assetPfadstringjaAsset-UUID.
altRumpfstringneinAlt-Text (BFSG).
titleRumpfstringneinOptionaler Titel.

Anfrage · application/json

{
  "alt": "<string>",
  "title": "<string>"
}

Antworten

  • 200 {data:Asset}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Validierungsfehler
DELETE /sites/{site}/media/{asset} Asset löschen

Parameter

Parameter von DELETE /sites/{site}/media/{asset}
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.
assetPfadstringjaAsset-UUID.

Antworten

  • 200 {deleted:true}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
POST /sites/{site}/media/{asset}/describe Alt-Text/Titel per KI-Vision erzeugen

Claude-Vision analysiert das Bild und schlägt Alt-Text + Titel vor. Rate-Limit 20/min.

Parameter

Parameter von POST /sites/{site}/media/{asset}/describe
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.
assetPfadstringjaAsset-UUID.

Antworten

  • 200 {alt, title}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 402 Kontingent erschöpft — Upgrade oder Aufladen nötig
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 429 Zu viele Anfragen (Rate-Limit)

Block-Typen

Globaler Katalog verfügbarer Blocktypen inkl. Schema.

GET /block-types Block-Typ-Katalog

Parameter

Parameter von GET /block-types
NameOrtTypPflichtHinweis
allAbfragebooleannein1 = auch deaktivierte Typen zeigen.

Antworten

  • 200 {data:[BlockType]} mit key, category, schema, default_props, preview_svg.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)

CMS

Strukturierte Inhalts-Collections und ihre Einträge je Site.

GET /sites/{site}/collections Collections einer Site

Parameter

Parameter von GET /sites/{site}/collections
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.

Antworten

  • 200 {data:[Collection]} mit name, fields-Schema, Eintragszahl.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
POST /sites/{site}/collections Collection anlegen

Parameter

Parameter von POST /sites/{site}/collections
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.
nameRumpfstringjaAnzeigename.
slugRumpfstringneinURL-Segment (optional; aus name abgeleitet).
fieldsRumpfarrayneinFeld-Definitionen [{key,label,type}].

Anfrage · application/json

{
  "name": "<string>",
  "slug": "<string>",
  "fields": []
}

Antworten

  • 201 {data:Collection}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Validierungsfehler
GET /collections/{collection} Collection abrufen

Parameter

Parameter von GET /collections/{collection}
NameOrtTypPflichtHinweis
collectionPfadstringjaCollection-UUID.

Antworten

  • 200 {data:Collection}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
PUT /collections/{collection} Collection ändern

Parameter

Parameter von PUT /collections/{collection}
NameOrtTypPflichtHinweis
collectionPfadstringjaCollection-UUID.
nameRumpfstringnein
fieldsRumpfarrayneinFeld-Definitionen.

Anfrage · application/json

{
  "name": "<string>",
  "fields": []
}

Antworten

  • 200 {data:Collection}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Validierungsfehler
DELETE /collections/{collection} Collection löschen

Parameter

Parameter von DELETE /collections/{collection}
NameOrtTypPflichtHinweis
collectionPfadstringjaCollection-UUID.

Antworten

  • 200 {deleted:true}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
GET /collections/{collection}/entries Einträge einer Collection

Parameter

Parameter von GET /collections/{collection}/entries
NameOrtTypPflichtHinweis
collectionPfadstringjaCollection-UUID.

Antworten

  • 200 {data:[Entry]} mit Feldwerten.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
POST /collections/{collection}/entries Eintrag anlegen

Parameter

Parameter von POST /collections/{collection}/entries
NameOrtTypPflichtHinweis
collectionPfadstringjaCollection-UUID.
dataRumpfobjectjaFeldwerte gemäß Collection-Schema.

Anfrage · application/json

{
  "data": {}
}

Antworten

  • 201 {data:Entry}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Validierungsfehler
PUT /entries/{entry} Eintrag ändern

Parameter

Parameter von PUT /entries/{entry}
NameOrtTypPflichtHinweis
entryPfadstringjaEntry-UUID.
dataRumpfobjectneinFeldwerte.

Anfrage · application/json

{
  "data": {}
}

Antworten

  • 200 {data:Entry}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Validierungsfehler
DELETE /entries/{entry} Eintrag löschen

Parameter

Parameter von DELETE /entries/{entry}
NameOrtTypPflichtHinweis
entryPfadstringjaEntry-UUID.

Antworten

  • 200 {deleted:true}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)

Versionen

Snapshots einer Site: sichern und wiederherstellen.

GET /sites/{site}/versions Versionsverlauf einer Site

Parameter

Parameter von GET /sites/{site}/versions
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.

Antworten

  • 200 {data:[SiteVersion]} (neueste zuerst) mit label, created_at, Auslöser.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
POST /sites/{site}/versions Version sichern (Snapshot)

Parameter

Parameter von POST /sites/{site}/versions
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.
labelRumpfstringneinOptionales Versionslabel.

Anfrage · application/json

{
  "label": "<string>"
}

Antworten

  • 201 {data:SiteVersion}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
POST /sites/{site}/versions/{version}/restore Version wiederherstellen

Setzt die Site auf den Snapshot zurück. Der aktuelle Stand wird vorher automatisch als Version gesichert.

Parameter

Parameter von POST /sites/{site}/versions/{version}/restore
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.
versionPfadstringjaVersions-UUID.

Antworten

  • 200 {ok:true, restored}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)

Aktivität

Änderungsverlauf einer Site (KI-Läufe, Versionen, Hand-Edits).

GET /sites/{site}/activity Änderungsverlauf einer Site

Zusammengeführter Feed aus KI-Läufen, gesicherten Versionen und Hand-Edits (neueste zuerst).

Parameter

Parameter von GET /sites/{site}/activity
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.

Antworten

  • 200 {data:[Activity]} mit type, summary, created_at.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)

KI-Pipeline

KI-gestütztes Planen, Bauen, Chatten, Text-Überarbeitung, Bild- und Logo-Erzeugung.

POST /ai/plan Blueprint planen (Sitemap + Skeletons)

Zwei-Phasen-Plan (nur lesend, keine Writes). Zusätzlich auf 30/min pro Nutzer gedrosselt.

Parameter

Parameter von POST /ai/plan
NameOrtTypPflichtHinweis
site_idRumpfstringjaSite-UUID (36 Zeichen).
briefRumpfstringjaGeschäfts-Briefing (3–8000 Zeichen).
langRumpfstringneinde|en.

Anfrage · application/json

{
  "site_id": "<string>",
  "brief": "<string>",
  "lang": "<string>"
}

Antworten

  • 200 {generation_id, blueprint:{sitemap,skeletons}, assistant_text, usage}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 402 Kontingent erschöpft — Upgrade oder Aufladen nötig
  • 404 Site nicht gefunden.
  • 422 Validierungsfehler
  • 429 Zu viele Anfragen (Rate-Limit)
POST /ai/build Site bauen (asynchron)

Reiht einen Build-Job ein (Dutzende KI-Calls) und antwortet sofort. brief ODER blueprint nötig.

Parameter

Parameter von POST /ai/build
NameOrtTypPflichtHinweis
site_idRumpfstringja
briefRumpfstringneinAlternativ zu blueprint.
blueprintRumpfobjectneinBlueprint aus /ai/plan.
langRumpfstringneinde|en.

Anfrage · application/json

{
  "site_id": "<string>",
  "brief": "<string>",
  "blueprint": {},
  "lang": "<string>"
}

Antworten

  • 202 {generation_id, status:"queued"}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 402 Kontingent erschöpft — Upgrade oder Aufladen nötig
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Weder brief noch blueprint.
  • 429 Zu viele Anfragen (Rate-Limit)
POST /ai/chat Editor-Assistent (SSE-Streaming)

Interaktives Editieren via Tool-Calls. Antwort ist ein text/event-stream; Mutationen werden ggf. als pending_action zur Bestätigung ausgegeben.

Parameter

Parameter von POST /ai/chat
NameOrtTypPflichtHinweis
site_idRumpfstringja
messageRumpfstringja1–8000 Zeichen.
conversation_idRumpfstringnein
historyRumpfarrayneinBisherige Turns (max. 40).
langRumpfstringneinde|en.
page_idRumpfstringneinAktuell geöffnete Seite (Kontext).
block_idRumpfstringneinAktuell markierter Block (Kontext).

Anfrage · application/json

{
  "site_id": "<string>",
  "message": "<string>",
  "conversation_id": "<string>",
  "history": [],
  "lang": "<string>",
  "page_id": "<string>",
  "block_id": "<string>"
}

Antworten

  • 200 Server-Sent-Events-Strom (text/event-stream): Events start, delta, tool_call_*, pending_action, done, error
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 402 Chat-Token-Kontingent erschöpft.
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Validierungsfehler
  • 429 Zu viele Anfragen (Rate-Limit)
POST /ai/chat/{pendingAction}/apply Vorgeschlagene Mutation bestätigen

Parameter

Parameter von POST /ai/chat/{pendingAction}/apply
NameOrtTypPflichtHinweis
pendingActionPfadstringjaID der Pending-Mutation aus dem Chat-Stream.

Antworten

  • 200 Ergebnis der ausgeführten Aktion.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden / abgelaufen / kein Zugriff.
  • 422 Validierungsfehler
POST /ai/image Bild generieren (Gemini)

Parameter

Parameter von POST /ai/image
NameOrtTypPflichtHinweis
site_idRumpfstringja
promptRumpfstringjaBildbeschreibung (3–2000 Zeichen).
altRumpfstringjaAlt-Text (Pflicht, BFSG).
aspectRumpfstringnein1:1|4:3|16:9|3:4|9:16 (Default 16:9).
premiumRumpfbooleanneinHöhere Qualität (teurer).

Anfrage · application/json

{
  "site_id": "<string>",
  "prompt": "<string>",
  "alt": "<string>",
  "aspect": "<string>",
  "premium": false
}

Antworten

  • 200 Generiertes Asset (url/alt/…).
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 402 Kontingent erschöpft — Upgrade oder Aufladen nötig
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Validierungsfehler
  • 429 Zu viele Anfragen (Rate-Limit)
POST /ai/rewrite Textbaustein überarbeiten

Überarbeitet einen markierten Text nach festem Kommando. Vorhandene ==Hervorhebungs==-Marker und Markdown bleiben erhalten; die Sprache des Textes wird beibehalten. Verbraucht eine ai_text-Einheit.

Parameter

Parameter von POST /ai/rewrite
NameOrtTypPflichtHinweis
site_idRumpfstringjaSite-UUID (36 Zeichen).
textRumpfstringjaAusgangstext (1–6000 Zeichen).
commandRumpfstringjashorten|lengthen|bullets|professional|simplify|rephrase|fix.
langRumpfstringneinZielsprache; ohne Angabe die Standardsprache der Site. · max. 5 Zeichen

Anfrage · application/json

{
  "site_id": "<string>",
  "text": "<string>",
  "command": "shorten",
  "lang": "<string>"
}

Antworten

  • 200 {text, command, generation_id, usage}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 402 Kontingent erschöpft — Upgrade oder Aufladen nötig
  • 404 Site nicht gefunden.
  • 422 Ungültige Eingabe oder kein verwertbares Ergebnis.
  • 429 Rate-Limit oder Kontingentsperre belegt (busy).
  • 503 Textveredelung derzeit nicht verfügbar.
POST /ai/brand-extract Markenvorschlag aus bestehender Website

Ruft eine öffentliche http(s)-Adresse serverseitig ab, wertet Titel, Meta-Beschreibung, og:site_name, theme-color und einen Textauszug aus und leitet daraus einen Markenvorschlag ab. Nicht öffentlich erreichbare Ziele werden abgelehnt. Verbraucht eine ai_text-Einheit.

Parameter

Parameter von POST /ai/brand-extract
NameOrtTypPflichtHinweis
urlRumpfstringjaÖffentliche http(s)-Adresse. · max. 300 Zeichen
site_idRumpfstringneinOptional — ordnet den Lauf einer Site zu (36 Zeichen).

Anfrage · application/json

{
  "url": "<string>",
  "site_id": "<string>"
}

Antworten

  • 200 {brand:{name,tagline,industry,tone,brand_voice,colors:{primary,accent},summary}, source_url, usage}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 402 Kontingent erschöpft — Upgrade oder Aufladen nötig
  • 404 Site nicht gefunden (nur bei gesetzter site_id).
  • 422 Adresse ungültig/nicht erreichbar oder kein verwertbares Ergebnis.
  • 429 Rate-Limit oder Kontingentsperre belegt (busy).
  • 503 Marken-Analyse derzeit nicht verfügbar.
GET /ai/generations/{generation} Status einer Generierung (Polling)

Fortschritt von Build/Publish. Großzügiger Limiter (120/min) für sekündliches Polling.

Parameter

Parameter von GET /ai/generations/{generation}
NameOrtTypPflichtHinweis
generationPfadstringjaGenerierungs-UUID.

Antworten

  • 200 {id, kind, status, output, error}; status queued|running|succeeded|failed.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)

Blog

KI-Blog je Site: Themenvorschläge und Beitrags-Erzeugung.

POST /sites/{site}/blog/topics Themenvorschläge für den Blog

Synchron. Verbraucht eine ai_text-Einheit.

Parameter

Parameter von POST /sites/{site}/blog/topics
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.
countRumpfintegerneinAnzahl Vorschläge, 1–8 (Vorgabe 5).

Anfrage · application/json

{
  "count": 1
}

Antworten

  • 200 {topics:[{title, angle, category, tags}]}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 402 Kontingent erschöpft — Upgrade oder Aufladen nötig
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Validierungsfehler
  • 429 Rate-Limit oder Kontingentsperre belegt (busy).
  • 503 Themenvorschläge derzeit nicht verfügbar.
POST /sites/{site}/blog/generate Blogbeitrag erzeugen (asynchron)

Reiht die Erzeugung ein und antwortet sofort. Fortschritt über GET /ai/generations/{generation}; bei status=succeeded trägt output {page_id, slug, title}. Der Beitrag entsteht als Seite mit type=post — Auflisten, Ändern und Löschen laufen über die Seiten-Endpunkte. Verbraucht eine ai_text-Einheit; schlägt der Lauf fehl, wird sie erstattet.

Parameter

Parameter von POST /sites/{site}/blog/generate
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.
topicRumpfstringjaThema (3–200 Zeichen).
categoryRumpfstringneinOptionale Kategorie. · max. 60 Zeichen
tagsRumpfarrayneinBis zu 6 Schlagwörter à 40 Zeichen.
statusRumpfstringneindraft (Vorgabe) | scheduled | published.
publish_atRumpfstring (date)neinPflicht bei status=scheduled; frühestens heute.

Anfrage · application/json

{
  "topic": "<string>",
  "category": "<string>",
  "tags": [],
  "status": "draft",
  "publish_at": "<date>"
}

Antworten

  • 202 {generation_id, status:"queued"}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 402 Kontingent erschöpft — Upgrade oder Aufladen nötig
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Validierungsfehler
  • 429 Rate-Limit oder Kontingentsperre belegt (busy).
  • 500 Start fehlgeschlagen (dispatch_failed) — verbrauchte Credits werden erstattet.

Assistent

Verwaltung des eingebetteten Site-Assistenten (RAG).

GET /sites/{site}/assistant Assistent-Status & Einstellungen

Parameter

Parameter von GET /sites/{site}/assistant
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.

Antworten

  • 200 {enabled, settings, knowledge, chat_tokens, embed}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
PUT /sites/{site}/assistant Assistent an/aus + Einstellungen

Aktivieren erfordert mindestens den Starter-Plan (Feature ai_chat).

Parameter

Parameter von PUT /sites/{site}/assistant
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.
enabledRumpfbooleannein
settingsRumpfobjectneinname, greeting, placeholder, persona, primary, accent, show_branding.

Anfrage · application/json

{
  "enabled": false,
  "settings": {}
}

Antworten

  • 200 {enabled, settings, knowledge, embed}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 403 Plan reicht nicht (ai_chat).
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
POST /sites/{site}/assistant/reindex RAG-Wissensbasis neu aufbauen

Parameter

Parameter von POST /sites/{site}/assistant/reindex
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.

Antworten

  • 200 {ok:true, knowledge}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 500 Neuaufbau fehlgeschlagen.

Assistent (öffentlich)

Widget-Endpunkte für veröffentlichte Sites (ohne Token).

GET /public/assistant Erreichbarkeits-Probe des Widget-Gates ohne Token

Antworten

  • 200 {ok:true, service:"xicflow-assistant"}.
GET /public/assistant/widget.js Eingebettetes Widget-Skript ohne Token

Antworten

  • 200 JavaScript (application/javascript).
  • 404 Skript nicht vorhanden.
GET /public/assistant/{siteSlug}/config Widget-Konfiguration (Branding) ohne Token

Parameter

Parameter von GET /public/assistant/{siteSlug}/config
NameOrtTypPflichtHinweis
siteSlugPfadstringjaSlug der veröffentlichten Site.

Antworten

  • 200 {enabled, name, greeting, placeholder, locale, colors, branding} (enabled:false wenn nicht freigeschaltet).
POST /public/assistant/{siteSlug}/chat Geerdete Q&A des Site-Assistenten (SSE) ohne Token

Read-only, an der veröffentlichten Wissensbasis geerdet. Body als text/plain-JSON (CORS-simpel): {message, history?, conversation_id?, lang?}. Abrechnung gegen den Chat-Token-Pool des Site-Tenants.

Parameter

Parameter von POST /public/assistant/{siteSlug}/chat
NameOrtTypPflichtHinweis
messageRumpfstringjaBesucherfrage (max. 4000 Zeichen).
historyRumpfarraynein
conversation_idRumpfstringnein
langRumpfstringneinde|en.

Anfrage · text/plain

{
  "message": "<string>",
  "history": [],
  "conversation_id": "<string>",
  "lang": "<string>"
}

Antworten

  • 200 Server-Sent-Events-Strom (text/event-stream): Events start, delta, tool_call_*, pending_action, done, error
  • 404 Assistent nicht verfügbar.
  • 422 Leere/zu lange Nachricht.

Kontaktanfragen

Formular-Eingänge veröffentlichter Sites.

POST /public/contact/{siteSlug} Formular-Eingang (öffentlich) ohne Token

Cross-Origin von veröffentlichten Sites (kein Token). Honeypot-Feld "website" muss leer bleiben; still-quittierend bei Spam/ungültig (kein Enumerationssignal). 10/min pro IP.

Parameter

Parameter von POST /public/contact/{siteSlug}
NameOrtTypPflichtHinweis
siteSlugPfadstringjaSlug der veröffentlichten Site.
nameRumpfstringja
emailRumpfstring (email)ja
phoneRumpfstringnein
messageRumpfstringneinNachricht ODER url erforderlich.
urlRumpfstringnein
websiteRumpfstringneinHoneypot — leer lassen.

Anfrage · text/plain

{
  "name": "<string>",
  "email": "<email>",
  "phone": "<string>",
  "message": "<string>",
  "url": "<string>",
  "website": "<string>"
}

Antworten

  • 200 {ok:true} (immer, auch bei stillem Reject).
  • 429 Zu viele Anfragen (Rate-Limit)
GET /sites/{site}/submissions Eingänge einer Site

Parameter

Parameter von GET /sites/{site}/submissions
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.

Antworten

  • 200 {data:[ContactSubmission]} (neueste zuerst, max. 500).
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
PATCH /submissions/{submission} Status setzen

Parameter

Parameter von PATCH /submissions/{submission}
NameOrtTypPflichtHinweis
submissionPfadstringjaSubmission-UUID.
statusRumpfstringjanew|read|archived.

Anfrage · application/json

{
  "status": "<string>"
}

Antworten

  • 200 {data:ContactSubmission}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Validierungsfehler
DELETE /submissions/{submission} Eingang löschen

Parameter

Parameter von DELETE /submissions/{submission}
NameOrtTypPflichtHinweis
submissionPfadstringjaSubmission-UUID.

Antworten

  • 200 {deleted:true}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
GET /sites/{site}/submissions/export Eingänge als CSV exportieren

text/csv (Semikolon-Delimiter + UTF-8-BOM, DE-Excel-tauglich). Custom-Formularfelder werden als zusätzliche Spalten ergänzt.

Parameter

Parameter von GET /sites/{site}/submissions/export
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.

Antworten

  • 200 CSV-Datei (Content-Disposition: attachment).
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)

Domains

Custom-Domains: anmelden, verifizieren, binden.

GET /sites/{site}/domains Domains der Site

Parameter

Parameter von GET /sites/{site}/domains
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.

Antworten

  • 200 {data:[Domain]} inkl. dns_instructions.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
POST /sites/{site}/domains Domain anmelden

Preview-Subdomains (*.xicflow.com) werden sofort verifiziert und gebunden.

Parameter

Parameter von POST /sites/{site}/domains
NameOrtTypPflichtHinweis
sitePfadstringjaSite-UUID.
hostRumpfstringjaReiner Hostname (kein Schema/Pfad).
is_primaryRumpfbooleannein
redirect_toRumpfstringneinOptionales Redirect-Ziel.

Anfrage · application/json

{
  "host": "<string>",
  "is_primary": false,
  "redirect_to": "<string>"
}

Antworten

  • 201 {data:Domain, bind}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 403 Custom-Domain-Limit erreicht.
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Host bereits registriert / ungültig.
POST /domains/{domain}/verify Domain-Besitz verifizieren (TXT)

Parameter

Parameter von POST /domains/{domain}/verify
NameOrtTypPflichtHinweis
domainPfadstringjaDomain-UUID.

Antworten

  • 200 {verified:true, data:Domain}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 422 Noch nicht verifiziert (reason/checked).
POST /domains/{domain}/bind Domain binden (bis live)

Fährt die State-Machine (Plesk-Alias + LE + nginx-Map). Vorbedingung: verifiziert.

Parameter

Parameter von POST /domains/{domain}/bind
NameOrtTypPflichtHinweis
domainPfadstringjaDomain-UUID.

Antworten

  • 200 {ok:true, state:"live", steps}.
  • 202 Angenommen — läuft weiter (DNS noch nicht aufgelöst / manueller Schritt).
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)
  • 409 Noch nicht verifiziert.
  • 422 Fehlerzustand.
DELETE /domains/{domain} Domain entfernen

Parameter

Parameter von DELETE /domains/{domain}
NameOrtTypPflichtHinweis
domainPfadstringjaDomain-UUID.

Antworten

  • 200 {ok:true, detach}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Nicht gefunden (nicht vorhanden oder Ressource eines fremden Kontos)

Nutzung

KI-Kontingente und Verbrauch des Kontos.

GET /usage KI-Kontingente & Verbrauch

Antworten

  • 200 {plan, quotas, used, remaining, ai_credits, chat_tokens} (-1 = unbegrenzt).
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)

Billing

Stripe-Abos, Credit-/Token-Pakete, Add-ons, Rechnungen, Webhook.

GET /billing/config Stripe-Public-Key & aktueller Plan

Antworten

  • 200 {publicKey, mode, currentPlan, hasSubscription, prices}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
GET /billing/plans Kaufbarer Katalog

Abo-Tarife (Starter/Pro/Premium/Agentur), Credit- und Chat-Token-Pakete. Preise NETTO in Cent + EUR.

Antworten

  • 200 {currentPlan, currency, plans, creditPacks, creditBalance, chatTokenPacks, chatTokens}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
POST /billing/checkout Checkout starten (Abo / Credits / Chat-Tokens)

target steuert die Variante: plan (Default, mode=subscription) | credits | chat_tokens (mode=payment). Aktives Abo -> sofortiges In-Place-Upgrade mit Proration.

Parameter

Parameter von POST /billing/checkout
NameOrtTypPflichtHinweis
targetRumpfstringneinplan|credits|chat_tokens.
planRumpfstringneinstarter|pro|premium|agency (bei target=plan).
intervalRumpfstringneinmonth|year (bei target=plan).
packRumpfstringneinPack-Key (bei credits/chat_tokens).

Anfrage · application/json

{
  "target": "<string>",
  "plan": "<string>",
  "interval": "<string>",
  "pack": "<string>"
}

Antworten

  • 200 {sessionId, url} oder {switched:true, plan} bei In-Place-Upgrade.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 422 Kein Tenant / unbekanntes Paket / ungültige Eingabe.
POST /billing/portal Stripe-Kundenportal

Antworten

  • 200 {url}.
  • 400 Kein Stripe-Konto.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
GET /billing/subscription Aktuelle Abo-Details

Antworten

  • 200 {active, status, plan, current_period_end, cancel_at_period_end, next_charge_amount, interval …}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
GET /billing/invoices Lokale GoBD-Rechnungen

Antworten

  • 200 {invoices:[…]}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
GET /billing/invoices/{invoiceId}/pdf Rechnung als PDF herunterladen

Nur Rechnungen des eigenen Kontos. Der Dateiname ist die Rechnungsnummer.

Parameter

Parameter von GET /billing/invoices/{invoiceId}/pdf
NameOrtTypPflichtHinweis
invoiceIdPfadstringjaRechnungs-UUID aus GET /billing/invoices.

Antworten

  • 200 PDF-Datei (application/pdf, Content-Disposition: attachment).
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 404 Rechnung nicht gefunden, ohne PDF oder Datei nicht vorhanden (file_missing).
POST /billing/cancel Abo kündigen

Standard zum Periodenende; ?immediate=true kündigt sofort.

Parameter

Parameter von POST /billing/cancel
NameOrtTypPflichtHinweis
immediateAbfragebooleanneintrue = sofort statt zum Periodenende.

Antworten

  • 200 {ok:true, status, cancel_at_period_end, current_period_end}.
  • 400 Kein Tenant / keine Subscription.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 500 Serverfehler
POST /billing/resume Geplante Kündigung zurücknehmen

Antworten

  • 200 {ok:true, cancel_at_period_end:false}.
  • 400 Keine Subscription.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 500 Serverfehler
GET /billing/addons Add-on-Katalog

Antworten

  • 200 {addons}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
POST /billing/addons/checkout Add-ons buchen

Parameter

Parameter von POST /billing/addons/checkout
NameOrtTypPflichtHinweis
addonsRumpfarrayjaListe {key, quantity?} (extra_site, extra_seat, custom_domain, ki_generations, image_credit_pack).

Anfrage · application/json

{
  "addons": []
}

Antworten

  • 200 {sessionId, url}.
  • 401 Nicht authentifiziert (fehlendes oder ungültiges Bearer-Token)
  • 422 Kein Tenant / unbekanntes Add-on.
POST /webhooks/stripe Stripe-Webhook (öffentlich, signaturverifiziert) ohne Token

Kein Bearer-Token. Signatur über Stripe-Signature-Header; Idempotenz via stripe_events. Roh-Body erforderlich.

Antworten

  • 200 {received:true}.
  • 400 Signatur fehlt/ungültig.
  • 500 Kein Webhook-Secret konfiguriert.

Webhook für neue Anfragen

XICflow ruft von sich aus eine Adresse Ihrer Wahl auf, sobald auf einer veröffentlichten Website ein Formular abgeschickt wurde.

Die Zieladresse tragen Sie je Website im Feld „Automation-Webhook (URL)“ ein; nur https-Adressen werden angenommen. Der Aufruf geschieht nebenläufig mit fünf Sekunden Zeitlimit — antwortet der Empfänger nicht, geht die Anfrage trotzdem nicht verloren, sie steht in jedem Fall im Anfragen-Postfach. Eine automatische Wiederholung gibt es nicht.

Ist ein Signatur-Geheimnis hinterlegt, trägt jeder Aufruf die Kopfzeilen „X-XICflow-Timestamp“ und „X-XICflow-Signature“. Der Empfänger bildet dazu HMAC-SHA256 über den Zeitstempel, einen Punkt und den unveränderten Rumpf und vergleicht das Ergebnis mit dem Wert hinter „sha256=“. Der Zeitstempel schützt davor, dass ein mitgeschnittener Aufruf später erneut eingespielt wird.

Aufbau des Aufrufs

POST · Ereignis form.submission

Felder des Webhook-Aufrufs
FeldTypHinweis
eventstringWerte: form.submission
sitestringSlug der Site.
submitted_atstring (date-time)
submissionobject
submission.idstring (uuid)
submission.namestring
submission.emailstring
submission.phonestring
submission.messagestring
submission.urlstring
submission.fieldsobjectZusaetzliche Form-Builder-Felder.
submission.formstringKennung des ausgeloesten Formulars (aus dem Formular-Meta).
Rumpf
{
  "event": "form.submission",
  "site": "<string>",
  "submitted_at": "<date-time>",
  "submission": {
    "id": "<uuid>",
    "name": "<string>",
    "email": "<string>",
    "phone": "<string>",
    "message": "<string>",
    "url": "<string>",
    "fields": {},
    "form": "<string>"
  }
}

Maschinenlesbare Fassung

Dieselbe Beschreibung als OpenAPI 3.1 — für Werkzeuge, die daraus Aufrufe, Typen oder eine eigene Referenz erzeugen.

Die Spezifikation ist frei abrufbar und braucht kein Token. Verbindlich ist immer die Fassung der Schnittstelle selbst; die Kopie neben dieser Dokumentation entsteht beim Bau der Seite aus derselben Quelle.

Adresse der Spezifikation
https://api.xicflow.com/api/openapi.json

Sie können die Datei in ein Werkzeug Ihrer Wahl laden, um Aufrufe auszuprobieren oder passende Datentypen für Ihre Programmiersprache zu erzeugen. Die Anmeldung bleibt dieselbe: ein Bearer-Token aus /auth/login.

Häufige Fragen