Skip to content
PageSpeed 100 as the delivery default
On this page

API

Everything you do in the editor runs through an open interface — the same one you can address yourself. This chapter explains the base address, signing in and the error format, and then lists every endpoint that is open to your account.

What the API is for

The interface is the control plane of XICflow: websites, pages, blocks, media, AI runs, domains, requests and billing.

The editor works exclusively through this interface. Whatever you do there with the mouse you can therefore also do from a program of your own — for instance take content over from another system, collect requests or trigger a publish.

Key facts about the interface
Base addresshttps://api.xicflow.com/api
FormatJSON in UTF-8, including for errors. The exceptions are the image upload (multipart/form-data), the CSV export, the invoice download as PDF and the two chat endpoints, which return an event stream (text/event-stream).
VersionThe specification carries version 1.0.0. The address itself contains no version number; the machine-readable version is always authoritative.
Scope115 operations across 92 paths, grouped into 19 categories.
Account separationEvery resource belongs to exactly one account. The API answers an ID from another account with 404.
RolesReading is open to every member. Content changes require at least “Editor”, creating and deleting websites and domains at least “Administrator”, and billing actions the “Owner” role.

Browser calls are limited to two origins

For requests coming from a web page, the interface only allows xicflow.com and www.xicflow.com. The public endpoints for the contact form and the site assistant are exempt, because published websites run under their own domain. A program on your own server is not affected by this limit.

Signing in and sending the token

A token is created when you sign in and is then sent with every request in the “Authorization” header.

  1. Call POST /auth/login with your email address and password.

    To create a new account, use POST /auth/register instead; that call already returns a token as well.

  2. Take the “token” field from the response.

    The “access_token” field holds the same value and exists only for compatibility.

  3. Send the header “Authorization: Bearer <token>” with every further request.

  4. End the session via POST /auth/logout once you no longer need the token.

    A token stays valid until it is revoked — individually via /auth/logout or DELETE /auth/sessions/{id}, or all the others at once via DELETE /auth/sessions.

Request
curl -X POST https://api.xicflow.com/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"<E-Mail>","password":"<Passwort>"}'
Response
{
  "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>"
    }
  }
}

With the token in hand, every other endpoint is within reach:

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

If two-factor sign-in is active for the account and the code is missing, /auth/login does not return a token but “totp_required” together with a short-lived “challenge_token” (valid for ten minutes). You either redeem it via POST /auth/totp/challenge or repeat the login with the “totp_code” field. A backup code is accepted in the same place.

A few endpoints work without a token — sign-in and registration, the return leg of Google sign-in, passkey sign-in, redeeming the two-factor challenge, the contact form of published websites, the embedded site assistant, previewing and accepting a team invitation, and the Stripe callback. In the reference further down they carry the label “no token”.

Conventions and error format

Errors come back as JSON. Depending on the cause they carry an “error” field with a fixed key, or a list of fields under “errors”.

Invalid input (422)

If a request violates the field rules, the response names every affected field individually.

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

Role is not sufficient (403)

“required” names the role that is needed, “role” the one you actually have.

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

Quota used up (402)

The “resource” field names the quota concerned. For the editor chat the key reads “chat_tokens_exhausted” instead.

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

Account suspended (403)

If the account is suspended because of unpaid invoices, every endpoint that needs a token answers like this, no matter what was requested.

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

Status codes in use

Status codes and their meaning in the XICflow API
CodeMeaning
200Success.
201Created.
202Accepted and processed in the background — progress runs through GET /ai/generations/{generation}.
302Redirect; occurs only on the two Google sign-in endpoints, which are browser navigations.
400Invalid request.
401Missing or invalid token, wrong credentials or wrong two-factor code.
402Quota used up — upgrade the plan or top up.
403No access: role is insufficient or the account is suspended.
404Does not exist — or belongs to another account.
409Conflict: a precondition is not met.
410No longer valid, for example an invitation that was already redeemed or has expired.
422Field rules violated.
429Too many requests in a short time.
500Server error.
503Temporarily unavailable.

Per-minute limits

Sensitive and expensive endpoints are throttled. Once the limit is reached, the API answers with 429.

Counting happens per started minute. On endpoints without a token the sending address is counted, on all others the signed-in account. There is no blanket limit across the whole interface — only the endpoints listed here are capped.

Requests per minute by endpoint
EndpointsPer minute
Change password, enable or disable two-factor, regenerate backup codes, data export6
Contact form of published websites, sending a team invitation10
Sign-in, registration, two-factor challenge, passkey sign-in, return leg of Google sign-in, changing the display name, signing out all other sessions, previewing and accepting an invitation12
Signing out a single session, generating alt text with AI, chat of the public site assistant20
All AI endpoints, blog generation, publishing, image upload, verifying and binding a domain, rebuilding the knowledge base, setting the interface language, all commercial actions30
Configuration of the public site assistant60
Polling the status of a generation120

Long runs and retries

Building and publishing take too long for a single response. These endpoints acknowledge immediately and carry on in the background.

  1. The call answers with 202 and a “generation_id”.

    This applies to POST /ai/build, POST /sites/{site}/publish and POST /sites/{site}/blog/generate.

  2. Poll GET /ai/generations/{generation} until “status” is no longer queued or running.

    This endpoint is generously capped at 120 requests per minute, so polling once a second is expected.

  3. On “succeeded” the result sits in the “output” field, on “failed” the cause sits in “error”.

A failed run is not repeated automatically

Building and publishing deliberately run exactly once, because a second attempt would not produce the same result. If it says “failed”, start the process again yourself. The interface has no idempotency keys either: sending the same creating request twice produces a second record.

Two endpoints do not answer with a finished document but with a running event stream: the editor assistant at POST /ai/chat and the assistant of published websites at POST /public/assistant/{siteSlug}/chat. Both send events as text/event-stream, starting with “start” and ending with “done” or “error”.

Reference of all endpoints

Every entry can be expanded and then shows purpose, parameters, the shape of the request and the possible responses.

This list is generated, not transcribed

It is produced when the page is built, from the same specification the interface itself serves. When an endpoint is added it appears here after the next build — in exchange, short texts, field notes and the endpoint-specific response descriptions stay German in the English version; only the recurring standard responses are translated. Operator endpoints are not included.

Auth

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

POST /auth/register Konto registrieren no token

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

Parameters

Parameters of POST /auth/register
NameInTypeRequiredNote
emailBodystring (email)yesE-Mail (wird normalisiert, +alias entfernt).
passwordBodystringyesMindestens 10 Zeichen.
nameBodystringyesAnzeigename.

Request · application/json

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

Responses

  • 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) no token

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

Parameters

Parameters of POST /auth/login
NameInTypeRequiredNote
emailBodystring (email)yes
passwordBodystringyes
totp_codeBodystringnoOptionaler 6-stelliger TOTP- oder Backup-Code.

Request · application/json

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

Responses

  • 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 no token

Parameters

Parameters of POST /auth/totp/challenge
NameInTypeRequiredNote
challenge_tokenBodystringyes48-stelliges Token aus der Login-Antwort.
codeBodystringyesTOTP- oder Backup-Code.

Request · application/json

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

Responses

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

Parameters

Parameters of POST /auth/passkey/login/options
NameInTypeRequiredNote
emailBodystring (email)noOptional — schränkt allowCredentials ein.

Request · application/json

{
  "email": "<email>"
}

Responses

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

Parameters

Parameters of POST /auth/passkey/login/verify
NameInTypeRequiredNote
idBodystringyesCredential-ID (base64url).
responseBodyobjectyesWebAuthn-Assertion: clientDataJSON, authenticatorData, signature.

Request · application/json

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

Responses

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

Parameters

Parameters of GET /auth/oauth/{provider}/redirect
NameInTypeRequiredNote
providerPathstringyesOAuth-Provider, aktuell nur "google".
returnQuerystringnoRückkehr-URL nach erfolgreichem Login.

Responses

  • 302 Redirect (browser navigation)
  • 404 Unbekannter Provider.
GET /auth/oauth/{provider}/callback Google-SSO-Callback (302 mit Token-Fragment) no 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).

Parameters

Parameters of GET /auth/oauth/{provider}/callback
NameInTypeRequiredNote
providerPathstringyesOAuth-Provider, aktuell nur "google".
stateQuerystringnoCSRF-State.
codeQuerystringnoAuthorization-Code.

Responses

  • 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) no token

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

Parameters

Parameters of POST /auth/oauth/{provider}/callback
NameInTypeRequiredNote
providerPathstringyesOAuth-Provider, aktuell nur "google".
stateQuerystringnoCSRF-State.
codeQuerystringnoAuthorization-Code.

Responses

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

Responses

  • 200 Nutzerprofil inkl. tenant (plan/status/trial_ends_at).
  • 401 Not authenticated (missing or invalid bearer token)
POST /auth/logout Aktuelles Token widerrufen

Responses

  • 200 {ok:true}.
  • 401 Not authenticated (missing or invalid bearer token)
POST /auth/change-password Passwort ändern

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

Parameters

Parameters of POST /auth/change-password
NameInTypeRequiredNote
current_passwordBodystringyes
new_passwordBodystringyesMindestens 10 Zeichen, confirmed.
new_password_confirmationBodystringno

Request · application/json

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

Responses

  • 200 {ok:true}.
  • 401 Not authenticated (missing or invalid 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.

Responses

  • 200 {sessions:[{id, device, last_used_at, created_at, current}]}.
  • 401 Not authenticated (missing or invalid bearer token)
DELETE /auth/sessions Alle anderen Sitzungen abmelden

Widerruft jedes Token außer dem aktuell verwendeten.

Responses

  • 200 {ok:true}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 429 Too many requests (rate limit)
DELETE /auth/sessions/{id} Einzelne Sitzung abmelden

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

Parameters

Parameters of DELETE /auth/sessions/{id}
NameInTypeRequiredNote
idPathstringyesSitzungs-ID aus GET /auth/sessions.

Responses

  • 200 {ok:true}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 429 Too many requests (rate limit)
GET /auth/totp/status 2FA-Status

Responses

  • 200 {enabled, enabled_at, has_pending_secret, backup_codes_left}.
  • 401 Not authenticated (missing or invalid bearer token)
POST /auth/totp/setup 2FA einrichten (Pending-Secret)

Responses

  • 200 {secret, provisioning_uri} (otpauth://).
  • 401 Not authenticated (missing or invalid bearer token)
  • 422 Bereits aktiviert.
POST /auth/totp/enable 2FA aktivieren

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

Parameters

Parameters of POST /auth/totp/enable
NameInTypeRequiredNote
codeBodystringyesAktueller TOTP-Code.

Request · application/json

{
  "code": "<string>"
}

Responses

  • 200 {enabled:true, backup_codes[]}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 422 Ungültiger Code / kein Pending-Secret.
POST /auth/totp/disable 2FA deaktivieren

Parameters

Parameters of POST /auth/totp/disable
NameInTypeRequiredNote
passwordBodystringyes
codeBodystringyesTOTP- oder Backup-Code.

Request · application/json

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

Responses

  • 200 {enabled:false}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 422 Passwort oder Code falsch.
POST /auth/totp/regenerate-codes Backup-Codes neu erzeugen

Parameters

Parameters of POST /auth/totp/regenerate-codes
NameInTypeRequiredNote
passwordBodystringyes
codeBodystringyes

Request · application/json

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

Responses

  • 200 {backup_codes[]}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 422 Validation error
POST /auth/passkey/register/options Passkey registrieren: Optionen

Responses

  • 200 WebAuthn-publicKey-Create-Optionen (flach).
  • 401 Not authenticated (missing or invalid bearer token)
POST /auth/passkey/register/verify Passkey registrieren: verifizieren

Parameters

Parameters of POST /auth/passkey/register/verify
NameInTypeRequiredNote
idBodystringyesCredential-ID (base64url).
responseBodyobjectyesclientDataJSON + attestationObject.
nameBodystringnoOptionaler Anzeigename.

Request · application/json

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

Responses

  • 200 {ok:true, id, credential_name}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 422 Challenge/Attestation ungültig.
GET /auth/passkeys Passkeys auflisten

Responses

  • 200 {passkeys:[{id, credential_name, last_used_at, created_at}]}.
  • 401 Not authenticated (missing or invalid bearer token)
PUT /auth/passkeys/{id} Passkey umbenennen

Parameters

Parameters of PUT /auth/passkeys/{id}
NameInTypeRequiredNote
idPathstringyesCredential-ID.
nameBodystringyes

Request · application/json

{
  "name": "<string>"
}

Responses

  • 200 {ok:true}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
DELETE /auth/passkeys/{id} Passkey löschen

Parameters

Parameters of DELETE /auth/passkeys/{id}
NameInTypeRequiredNote
idPathstringyesCredential-ID.

Responses

  • 200 {ok:true}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
GET /auth/oauth/identities Verknüpfte OAuth-Identitäten

Responses

  • 200 {providers:[…]}.
  • 401 Not authenticated (missing or invalid bearer token)
DELETE /auth/oauth/{provider} OAuth-Identität entkoppeln

Parameters

Parameters of DELETE /auth/oauth/{provider}
NameInTypeRequiredNote
providerPathstringyesOAuth-Provider, aktuell nur "google".

Responses

  • 200 {ok:true}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 422 Letzter Zugang ohne gesetztes Passwort.

Konto

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

POST /account/profile Eigenen Anzeigenamen ändern

Parameters

Parameters of POST /account/profile
NameInTypeRequiredNote
nameBodystringyesAnzeigename, max. 190 Zeichen (wird getrimmt).

Request · application/json

{
  "name": "<string>"
}

Responses

  • 200 {name}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 422 Validation error
  • 429 Too many requests (rate limit)
POST /account/locale Oberflächensprache setzen

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

Parameters

Parameters of POST /account/locale
NameInTypeRequiredNote
languageBodystringyesde oder en.

Request · application/json

{
  "language": "de"
}

Responses

  • 200 {language}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 422 Validation error
  • 429 Too many requests (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.

Responses

  • 200 {meta, account, users, sites, contact_submissions, invoices, assets}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 422 Kein Konto (Tenant) am Nutzer hinterlegt.
  • 429 Too many requests (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.

Responses

  • 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 Not authenticated (missing or invalid 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.

Parameters

Parameters of POST /team/invitations
NameInTypeRequiredNote
emailBodystring (email)yesAdresse ohne bestehendes XICflow-Konto. · max. 255 Zeichen
roleBodystringyesadmin|editor|viewer.

Request · application/json

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

Responses

  • 201 {invitation:{id,email,role,expires_at,expired}, accept_url}.
  • 401 Not authenticated (missing or invalid 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 Too many requests (rate limit)
DELETE /team/invitations/{invitation} Offene Einladung widerrufen

Erfordert mindestens die Rolle admin.

Parameters

Parameters of DELETE /team/invitations/{invitation}
NameInTypeRequiredNote
invitationPathstringyesEinladungs-UUID aus GET /team.

Responses

  • 200 {ok:true}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 403 Rolle reicht nicht.
  • 404 Not found (does not exist, or belongs to another account)
  • 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.

Parameters

Parameters of POST /team/members/{member}/role
NameInTypeRequiredNote
memberPathstringyesNutzer-UUID aus GET /team.
roleBodystringyesadmin|editor|viewer.

Request · application/json

{
  "role": "admin"
}

Responses

  • 200 {ok:true, role}.
  • 401 Not authenticated (missing or invalid 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.

Parameters

Parameters of DELETE /team/members/{member}
NameInTypeRequiredNote
memberPathstringyesNutzer-UUID aus GET /team.

Responses

  • 200 {ok:true}.
  • 401 Not authenticated (missing or invalid 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) no token

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

Parameters

Parameters of GET /public/team/invitation/{token}
NameInTypeRequiredNote
tokenPathstringyesEinmal-Token aus dem Einladungslink.

Responses

  • 200 {email, role, team, expires_at}.
  • 404 Token unbekannt (invalid).
  • 410 Bereits angenommen (already_accepted) oder abgelaufen (expired).
  • 429 Too many requests (rate limit)
POST /public/team/accept Einladung annehmen (ohne Anmeldung) no 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.

Parameters

Parameters of POST /public/team/accept
NameInTypeRequiredNote
tokenBodystringyesEinmal-Token aus dem Einladungslink.
nameBodystringyesAnzeigename, max. 255 Zeichen.
passwordBodystringyesMindestens 10 Zeichen.

Request · application/json

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

Responses

  • 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 Validation error
  • 429 Too many requests (rate limit)

Sites

CRUD der Websites eines Kontos plus Veröffentlichung.

GET /sites Sites des Kontos auflisten

Responses

  • 200 {data:[Site]} inkl. theme, domains, pages_count.
  • 401 Not authenticated (missing or invalid bearer token)
POST /sites Site anlegen

Parameters

Parameters of POST /sites
NameInTypeRequiredNote
nameBodystringyes
slugBodystringyesKleinbuchstaben/Ziffern/Bindestrich, je Konto eindeutig.
theme_idBodystring (uuid)noOptionales Theme (UUID, eigen oder System).
default_localeBodystringnoDefault "de".
localesBodyarraynoAktive Sprachen, z. B. ["de","en"].
companyBodyobjectnoFirmenstammdaten.
brandingBodyobjectno
trust_barBodyobjectno
xictraq_idBodystringnoXICTRAQ-Property für Analytics/Monitoring.
contact_endpointBodystringno
contact_recipientBodystringno
google_verificationBodystringno
settingsBodyobjectno

Request · 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": {}
}

Responses

  • 201 {data:Site}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 422 Slug vergeben / ungültig.
GET /sites/{site} Site abrufen

Parameters

Parameters of GET /sites/{site}
NameInTypeRequiredNote
sitePathstringyesSite-UUID.

Responses

  • 200 {data:Site} inkl. pages, theme, domains.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
PUT /sites/{site} Site aktualisieren

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

Parameters

Parameters of PUT /sites/{site}
NameInTypeRequiredNote
sitePathstringyesSite-UUID.
nameBodystringno
slugBodystringno
theme_idBodystring (uuid)no
default_localeBodystringno
localesBodyarrayno
companyBodyobjectno
brandingBodyobjectno
settingsBodyobjectno

Request · application/json

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

Responses

  • 200 {data:Site}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
  • 422 Slug vergeben.
DELETE /sites/{site} Site löschen

Parameters

Parameters of DELETE /sites/{site}
NameInTypeRequiredNote
sitePathstringyesSite-UUID.

Responses

  • 200 {deleted:true}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
POST /sites/{site}/publish Site veröffentlichen (asynchron)

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

Parameters

Parameters of POST /sites/{site}/publish
NameInTypeRequiredNote
sitePathstringyesSite-UUID.
labelBodystringnoOptionales Versionslabel.
notesBodystringnoOptionale Notiz.

Request · application/json

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

Responses

  • 202 {generation_id, status:"queued"}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
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.

Parameters

Parameters of GET /sites/{site}/regions
NameInTypeRequiredNote
sitePathstringyesSite-UUID.

Responses

  • 200 {data:{header, footer}} — je Region eine Seiten-UUID.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)

Seiten & Blöcke

Seiten (bilingual) und ihre Inhaltsblöcke.

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

Parameters

Parameters of GET /sites/{site}/pages
NameInTypeRequiredNote
sitePathstringyesSite-UUID.

Responses

  • 200 {data:[Page]} inkl. translations.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
POST /sites/{site}/pages Seite anlegen

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

Parameters

Parameters of POST /sites/{site}/pages
NameInTypeRequiredNote
sitePathstringyesSite-UUID.
slugBodystringyes
pathBodystringyesBeginnt mit "/", nur [a-z0-9/-].
typeBodystringnopage|post|landing|legal|system.
statusBodystringnodraft|published|scheduled|archived.
templateBodystringno
parent_idBodystring (uuid)no
sort_orderBodyintegerno
is_homeBodybooleanno
is_noindexBodybooleanno
seoBodyobjectno
translationsBodyarrayyesPflicht, min. 1 Eintrag mit locale/title/slug.

Request · 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": []
}

Responses

  • 201 {data:Page}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
  • 422 Pfad vergeben / ungültig.
GET /pages/{page} Seite abrufen

Parameters

Parameters of GET /pages/{page}
NameInTypeRequiredNote
pagePathstringyesSeiten-UUID.

Responses

  • 200 {data:Page} inkl. translations, sections, blocks.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
PUT /pages/{page} Seite aktualisieren

Parameters

Parameters of PUT /pages/{page}
NameInTypeRequiredNote
pagePathstringyesSeiten-UUID.
slugBodystringno
pathBodystringno
typeBodystringno
statusBodystringno
is_homeBodybooleanno
is_noindexBodybooleanno
seoBodyobjectno
published_atBodystring (date-time)no
translationsBodyarraynoUpsert je Locale.

Request · application/json

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

Responses

  • 200 {data:Page}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
  • 422 Validation error
DELETE /pages/{page} Seite löschen

Parameters

Parameters of DELETE /pages/{page}
NameInTypeRequiredNote
pagePathstringyesSeiten-UUID.

Responses

  • 200 {deleted:true}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
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.

Parameters

Parameters of PUT /pages/{page}/reorder-blocks
NameInTypeRequiredNote
pagePathstringyesSeiten-UUID.
blocksBodyarrayyesIDs oder {id,section_id,sort_order}-Objekte.

Request · application/json

{
  "blocks": []
}

Responses

  • 200 {data:[Section]} inkl. sortierter Blöcke.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
  • 422 Validation error
POST /pages/{page}/blocks Block hinzufügen

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

Parameters

Parameters of POST /pages/{page}/blocks
NameInTypeRequiredNote
pagePathstringyesSeiten-UUID.
typeBodystringnoblock_types.key (alternativ block_type_id).
block_type_idBodystring (uuid)noAlternativ zu type.
section_idBodystring (uuid)noZiel-Section (sonst erste/neue).
propsBodyobjectnoBlock-Eigenschaften gemäß Schema.
contentBodyobjectno
sort_orderBodyintegerno
is_visibleBodybooleanno

Request · application/json

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

Responses

  • 201 {data:Block}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
  • 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.

Parameters

Parameters of PUT /pages/{page}/blocks
NameInTypeRequiredNote
pagePathstringyesSeiten-UUID.
blocksBodyarrayyesPflicht (darf leer sein — leert dann die Seite). Elemente: {id?, type, props?, content?}; type ist ein block_types.key.

Request · application/json

{
  "blocks": []
}

Responses

  • 200 {ok:true, blocks:[{id,type}], count}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
  • 422 Validation error
PUT /blocks/{block} Block aktualisieren

Parameters

Parameters of PUT /blocks/{block}
NameInTypeRequiredNote
blockPathstringyesBlock-UUID.
propsBodyobjectno
contentBodyobjectno
block_type_idBodystring (uuid)noOptionaler Typwechsel.
typeBodystringno
section_idBodystring (uuid)no
sort_orderBodyintegerno
is_visibleBodybooleanno

Request · application/json

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

Responses

  • 200 {data:Block}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
  • 422 Validation error
DELETE /blocks/{block} Block löschen

Parameters

Parameters of DELETE /blocks/{block}
NameInTypeRequiredNote
blockPathstringyesBlock-UUID.

Responses

  • 200 {deleted:true}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)

Theme

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

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

Parameters

Parameters of GET /sites/{site}/theme
NameInTypeRequiredNote
sitePathstringyesSite-UUID.

Responses

  • 200 {data:Theme} mit tokens.
  • 401 Not authenticated (missing or invalid 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.

Parameters

Parameters of PUT /sites/{site}/theme
NameInTypeRequiredNote
sitePathstringyesSite-UUID.
nameBodystringno
tokensBodyobjectyesDesign-Tokens (colors, colorsDark, fonts, gradients, hero, sectionStyle, headerStyle …).

Request · application/json

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

Responses

  • 200 {data:Theme}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
  • 422 Validation error

Medien

Bild-Uploads je Site.

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

Parameters

Parameters of GET /sites/{site}/media
NameInTypeRequiredNote
sitePathstringyesSite-UUID.
qQuerystringnoVolltextsuche über Dateiname, Alt-Text und Titel (case-insensitiv).

Responses

  • 200 {data:[Asset]} (neueste zuerst) mit url, path, alt, title, width, height, bytes, mime.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
POST /sites/{site}/media Bild hochladen

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

Parameters

Parameters of POST /sites/{site}/media
NameInTypeRequiredNote
sitePathstringyesSite-UUID.
fileBodystring (binary)yesBilddatei.
altBodystringnoOptionaler Alt-Text (BFSG).

Request · multipart/form-data

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

Responses

  • 201 {url, path, bytes, mime, width, height, asset_id}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
  • 422 Ungültige Datei.
PATCH /sites/{site}/media/{asset} Alt-Text/Titel eines Assets setzen

Parameters

Parameters of PATCH /sites/{site}/media/{asset}
NameInTypeRequiredNote
sitePathstringyesSite-UUID.
assetPathstringyesAsset-UUID.
altBodystringnoAlt-Text (BFSG).
titleBodystringnoOptionaler Titel.

Request · application/json

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

Responses

  • 200 {data:Asset}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
  • 422 Validation error
DELETE /sites/{site}/media/{asset} Asset löschen

Parameters

Parameters of DELETE /sites/{site}/media/{asset}
NameInTypeRequiredNote
sitePathstringyesSite-UUID.
assetPathstringyesAsset-UUID.

Responses

  • 200 {deleted:true}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
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.

Parameters

Parameters of POST /sites/{site}/media/{asset}/describe
NameInTypeRequiredNote
sitePathstringyesSite-UUID.
assetPathstringyesAsset-UUID.

Responses

  • 200 {alt, title}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 402 Quota used up — upgrade or top up required
  • 404 Not found (does not exist, or belongs to another account)
  • 429 Too many requests (rate limit)

Block-Typen

Globaler Katalog verfügbarer Blocktypen inkl. Schema.

GET /block-types Block-Typ-Katalog

Parameters

Parameters of GET /block-types
NameInTypeRequiredNote
allQuerybooleanno1 = auch deaktivierte Typen zeigen.

Responses

  • 200 {data:[BlockType]} mit key, category, schema, default_props, preview_svg.
  • 401 Not authenticated (missing or invalid bearer token)

CMS

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

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

Parameters

Parameters of GET /sites/{site}/collections
NameInTypeRequiredNote
sitePathstringyesSite-UUID.

Responses

  • 200 {data:[Collection]} mit name, fields-Schema, Eintragszahl.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
POST /sites/{site}/collections Collection anlegen

Parameters

Parameters of POST /sites/{site}/collections
NameInTypeRequiredNote
sitePathstringyesSite-UUID.
nameBodystringyesAnzeigename.
slugBodystringnoURL-Segment (optional; aus name abgeleitet).
fieldsBodyarraynoFeld-Definitionen [{key,label,type}].

Request · application/json

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

Responses

  • 201 {data:Collection}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
  • 422 Validation error
GET /collections/{collection} Collection abrufen

Parameters

Parameters of GET /collections/{collection}
NameInTypeRequiredNote
collectionPathstringyesCollection-UUID.

Responses

  • 200 {data:Collection}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
PUT /collections/{collection} Collection ändern

Parameters

Parameters of PUT /collections/{collection}
NameInTypeRequiredNote
collectionPathstringyesCollection-UUID.
nameBodystringno
fieldsBodyarraynoFeld-Definitionen.

Request · application/json

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

Responses

  • 200 {data:Collection}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
  • 422 Validation error
DELETE /collections/{collection} Collection löschen

Parameters

Parameters of DELETE /collections/{collection}
NameInTypeRequiredNote
collectionPathstringyesCollection-UUID.

Responses

  • 200 {deleted:true}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
GET /collections/{collection}/entries Einträge einer Collection

Parameters

Parameters of GET /collections/{collection}/entries
NameInTypeRequiredNote
collectionPathstringyesCollection-UUID.

Responses

  • 200 {data:[Entry]} mit Feldwerten.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
POST /collections/{collection}/entries Eintrag anlegen

Parameters

Parameters of POST /collections/{collection}/entries
NameInTypeRequiredNote
collectionPathstringyesCollection-UUID.
dataBodyobjectyesFeldwerte gemäß Collection-Schema.

Request · application/json

{
  "data": {}
}

Responses

  • 201 {data:Entry}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
  • 422 Validation error
PUT /entries/{entry} Eintrag ändern

Parameters

Parameters of PUT /entries/{entry}
NameInTypeRequiredNote
entryPathstringyesEntry-UUID.
dataBodyobjectnoFeldwerte.

Request · application/json

{
  "data": {}
}

Responses

  • 200 {data:Entry}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
  • 422 Validation error
DELETE /entries/{entry} Eintrag löschen

Parameters

Parameters of DELETE /entries/{entry}
NameInTypeRequiredNote
entryPathstringyesEntry-UUID.

Responses

  • 200 {deleted:true}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)

Versionen

Snapshots einer Site: sichern und wiederherstellen.

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

Parameters

Parameters of GET /sites/{site}/versions
NameInTypeRequiredNote
sitePathstringyesSite-UUID.

Responses

  • 200 {data:[SiteVersion]} (neueste zuerst) mit label, created_at, Auslöser.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
POST /sites/{site}/versions Version sichern (Snapshot)

Parameters

Parameters of POST /sites/{site}/versions
NameInTypeRequiredNote
sitePathstringyesSite-UUID.
labelBodystringnoOptionales Versionslabel.

Request · application/json

{
  "label": "<string>"
}

Responses

  • 201 {data:SiteVersion}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
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.

Parameters

Parameters of POST /sites/{site}/versions/{version}/restore
NameInTypeRequiredNote
sitePathstringyesSite-UUID.
versionPathstringyesVersions-UUID.

Responses

  • 200 {ok:true, restored}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)

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).

Parameters

Parameters of GET /sites/{site}/activity
NameInTypeRequiredNote
sitePathstringyesSite-UUID.

Responses

  • 200 {data:[Activity]} mit type, summary, created_at.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)

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.

Parameters

Parameters of POST /ai/plan
NameInTypeRequiredNote
site_idBodystringyesSite-UUID (36 Zeichen).
briefBodystringyesGeschäfts-Briefing (3–8000 Zeichen).
langBodystringnode|en.

Request · application/json

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

Responses

  • 200 {generation_id, blueprint:{sitemap,skeletons}, assistant_text, usage}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 402 Quota used up — upgrade or top up required
  • 404 Site nicht gefunden.
  • 422 Validation error
  • 429 Too many requests (rate limit)
POST /ai/build Site bauen (asynchron)

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

Parameters

Parameters of POST /ai/build
NameInTypeRequiredNote
site_idBodystringyes
briefBodystringnoAlternativ zu blueprint.
blueprintBodyobjectnoBlueprint aus /ai/plan.
langBodystringnode|en.

Request · application/json

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

Responses

  • 202 {generation_id, status:"queued"}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 402 Quota used up — upgrade or top up required
  • 404 Not found (does not exist, or belongs to another account)
  • 422 Weder brief noch blueprint.
  • 429 Too many requests (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.

Parameters

Parameters of POST /ai/chat
NameInTypeRequiredNote
site_idBodystringyes
messageBodystringyes1–8000 Zeichen.
conversation_idBodystringno
historyBodyarraynoBisherige Turns (max. 40).
langBodystringnode|en.
page_idBodystringnoAktuell geöffnete Seite (Kontext).
block_idBodystringnoAktuell markierter Block (Kontext).

Request · application/json

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

Responses

  • 200 Server-sent events stream (text/event-stream): events start, delta, tool_call_*, pending_action, done, error
  • 401 Not authenticated (missing or invalid bearer token)
  • 402 Chat-Token-Kontingent erschöpft.
  • 404 Not found (does not exist, or belongs to another account)
  • 422 Validation error
  • 429 Too many requests (rate limit)
POST /ai/chat/{pendingAction}/apply Vorgeschlagene Mutation bestätigen

Parameters

Parameters of POST /ai/chat/{pendingAction}/apply
NameInTypeRequiredNote
pendingActionPathstringyesID der Pending-Mutation aus dem Chat-Stream.

Responses

  • 200 Ergebnis der ausgeführten Aktion.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Nicht gefunden / abgelaufen / kein Zugriff.
  • 422 Validation error
POST /ai/image Bild generieren (Gemini)

Parameters

Parameters of POST /ai/image
NameInTypeRequiredNote
site_idBodystringyes
promptBodystringyesBildbeschreibung (3–2000 Zeichen).
altBodystringyesAlt-Text (Pflicht, BFSG).
aspectBodystringno1:1|4:3|16:9|3:4|9:16 (Default 16:9).
premiumBodybooleannoHöhere Qualität (teurer).

Request · application/json

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

Responses

  • 200 Generiertes Asset (url/alt/…).
  • 401 Not authenticated (missing or invalid bearer token)
  • 402 Quota used up — upgrade or top up required
  • 404 Not found (does not exist, or belongs to another account)
  • 422 Validation error
  • 429 Too many requests (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.

Parameters

Parameters of POST /ai/rewrite
NameInTypeRequiredNote
site_idBodystringyesSite-UUID (36 Zeichen).
textBodystringyesAusgangstext (1–6000 Zeichen).
commandBodystringyesshorten|lengthen|bullets|professional|simplify|rephrase|fix.
langBodystringnoZielsprache; ohne Angabe die Standardsprache der Site. · max. 5 Zeichen

Request · application/json

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

Responses

  • 200 {text, command, generation_id, usage}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 402 Quota used up — upgrade or top up required
  • 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.

Parameters

Parameters of POST /ai/brand-extract
NameInTypeRequiredNote
urlBodystringyesÖffentliche http(s)-Adresse. · max. 300 Zeichen
site_idBodystringnoOptional — ordnet den Lauf einer Site zu (36 Zeichen).

Request · application/json

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

Responses

  • 200 {brand:{name,tagline,industry,tone,brand_voice,colors:{primary,accent},summary}, source_url, usage}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 402 Quota used up — upgrade or top up required
  • 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.

Parameters

Parameters of GET /ai/generations/{generation}
NameInTypeRequiredNote
generationPathstringyesGenerierungs-UUID.

Responses

  • 200 {id, kind, status, output, error}; status queued|running|succeeded|failed.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)

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.

Parameters

Parameters of POST /sites/{site}/blog/topics
NameInTypeRequiredNote
sitePathstringyesSite-UUID.
countBodyintegernoAnzahl Vorschläge, 1–8 (Vorgabe 5).

Request · application/json

{
  "count": 1
}

Responses

  • 200 {topics:[{title, angle, category, tags}]}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 402 Quota used up — upgrade or top up required
  • 404 Not found (does not exist, or belongs to another account)
  • 422 Validation error
  • 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.

Parameters

Parameters of POST /sites/{site}/blog/generate
NameInTypeRequiredNote
sitePathstringyesSite-UUID.
topicBodystringyesThema (3–200 Zeichen).
categoryBodystringnoOptionale Kategorie. · max. 60 Zeichen
tagsBodyarraynoBis zu 6 Schlagwörter à 40 Zeichen.
statusBodystringnodraft (Vorgabe) | scheduled | published.
publish_atBodystring (date)noPflicht bei status=scheduled; frühestens heute.

Request · application/json

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

Responses

  • 202 {generation_id, status:"queued"}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 402 Quota used up — upgrade or top up required
  • 404 Not found (does not exist, or belongs to another account)
  • 422 Validation error
  • 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

Parameters

Parameters of GET /sites/{site}/assistant
NameInTypeRequiredNote
sitePathstringyesSite-UUID.

Responses

  • 200 {enabled, settings, knowledge, chat_tokens, embed}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
PUT /sites/{site}/assistant Assistent an/aus + Einstellungen

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

Parameters

Parameters of PUT /sites/{site}/assistant
NameInTypeRequiredNote
sitePathstringyesSite-UUID.
enabledBodybooleanno
settingsBodyobjectnoname, greeting, placeholder, persona, primary, accent, show_branding.

Request · application/json

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

Responses

  • 200 {enabled, settings, knowledge, embed}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 403 Plan reicht nicht (ai_chat).
  • 404 Not found (does not exist, or belongs to another account)
POST /sites/{site}/assistant/reindex RAG-Wissensbasis neu aufbauen

Parameters

Parameters of POST /sites/{site}/assistant/reindex
NameInTypeRequiredNote
sitePathstringyesSite-UUID.

Responses

  • 200 {ok:true, knowledge}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
  • 500 Neuaufbau fehlgeschlagen.

Assistent (öffentlich)

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

GET /public/assistant Erreichbarkeits-Probe des Widget-Gates no token

Responses

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

Responses

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

Parameters

Parameters of GET /public/assistant/{siteSlug}/config
NameInTypeRequiredNote
siteSlugPathstringyesSlug der veröffentlichten Site.

Responses

  • 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) no 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.

Parameters

Parameters of POST /public/assistant/{siteSlug}/chat
NameInTypeRequiredNote
messageBodystringyesBesucherfrage (max. 4000 Zeichen).
historyBodyarrayno
conversation_idBodystringno
langBodystringnode|en.

Request · text/plain

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

Responses

  • 200 Server-sent events stream (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) no 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.

Parameters

Parameters of POST /public/contact/{siteSlug}
NameInTypeRequiredNote
siteSlugPathstringyesSlug der veröffentlichten Site.
nameBodystringyes
emailBodystring (email)yes
phoneBodystringno
messageBodystringnoNachricht ODER url erforderlich.
urlBodystringno
websiteBodystringnoHoneypot — leer lassen.

Request · text/plain

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

Responses

  • 200 {ok:true} (immer, auch bei stillem Reject).
  • 429 Too many requests (rate limit)
GET /sites/{site}/submissions Eingänge einer Site

Parameters

Parameters of GET /sites/{site}/submissions
NameInTypeRequiredNote
sitePathstringyesSite-UUID.

Responses

  • 200 {data:[ContactSubmission]} (neueste zuerst, max. 500).
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
PATCH /submissions/{submission} Status setzen

Parameters

Parameters of PATCH /submissions/{submission}
NameInTypeRequiredNote
submissionPathstringyesSubmission-UUID.
statusBodystringyesnew|read|archived.

Request · application/json

{
  "status": "<string>"
}

Responses

  • 200 {data:ContactSubmission}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
  • 422 Validation error
DELETE /submissions/{submission} Eingang löschen

Parameters

Parameters of DELETE /submissions/{submission}
NameInTypeRequiredNote
submissionPathstringyesSubmission-UUID.

Responses

  • 200 {deleted:true}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
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.

Parameters

Parameters of GET /sites/{site}/submissions/export
NameInTypeRequiredNote
sitePathstringyesSite-UUID.

Responses

  • 200 CSV-Datei (Content-Disposition: attachment).
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)

Domains

Custom-Domains: anmelden, verifizieren, binden.

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

Parameters

Parameters of GET /sites/{site}/domains
NameInTypeRequiredNote
sitePathstringyesSite-UUID.

Responses

  • 200 {data:[Domain]} inkl. dns_instructions.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
POST /sites/{site}/domains Domain anmelden

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

Parameters

Parameters of POST /sites/{site}/domains
NameInTypeRequiredNote
sitePathstringyesSite-UUID.
hostBodystringyesReiner Hostname (kein Schema/Pfad).
is_primaryBodybooleanno
redirect_toBodystringnoOptionales Redirect-Ziel.

Request · application/json

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

Responses

  • 201 {data:Domain, bind}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 403 Custom-Domain-Limit erreicht.
  • 404 Not found (does not exist, or belongs to another account)
  • 422 Host bereits registriert / ungültig.
POST /domains/{domain}/verify Domain-Besitz verifizieren (TXT)

Parameters

Parameters of POST /domains/{domain}/verify
NameInTypeRequiredNote
domainPathstringyesDomain-UUID.

Responses

  • 200 {verified:true, data:Domain}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
  • 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.

Parameters

Parameters of POST /domains/{domain}/bind
NameInTypeRequiredNote
domainPathstringyesDomain-UUID.

Responses

  • 200 {ok:true, state:"live", steps}.
  • 202 Angenommen — läuft weiter (DNS noch nicht aufgelöst / manueller Schritt).
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)
  • 409 Noch nicht verifiziert.
  • 422 Fehlerzustand.
DELETE /domains/{domain} Domain entfernen

Parameters

Parameters of DELETE /domains/{domain}
NameInTypeRequiredNote
domainPathstringyesDomain-UUID.

Responses

  • 200 {ok:true, detach}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 404 Not found (does not exist, or belongs to another account)

Nutzung

KI-Kontingente und Verbrauch des Kontos.

GET /usage KI-Kontingente & Verbrauch

Responses

  • 200 {plan, quotas, used, remaining, ai_credits, chat_tokens} (-1 = unbegrenzt).
  • 401 Not authenticated (missing or invalid bearer token)

Billing

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

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

Responses

  • 200 {publicKey, mode, currentPlan, hasSubscription, prices}.
  • 401 Not authenticated (missing or invalid bearer token)
GET /billing/plans Kaufbarer Katalog

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

Responses

  • 200 {currentPlan, currency, plans, creditPacks, creditBalance, chatTokenPacks, chatTokens}.
  • 401 Not authenticated (missing or invalid 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.

Parameters

Parameters of POST /billing/checkout
NameInTypeRequiredNote
targetBodystringnoplan|credits|chat_tokens.
planBodystringnostarter|pro|premium|agency (bei target=plan).
intervalBodystringnomonth|year (bei target=plan).
packBodystringnoPack-Key (bei credits/chat_tokens).

Request · application/json

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

Responses

  • 200 {sessionId, url} oder {switched:true, plan} bei In-Place-Upgrade.
  • 401 Not authenticated (missing or invalid bearer token)
  • 422 Kein Tenant / unbekanntes Paket / ungültige Eingabe.
POST /billing/portal Stripe-Kundenportal

Responses

  • 200 {url}.
  • 400 Kein Stripe-Konto.
  • 401 Not authenticated (missing or invalid bearer token)
GET /billing/subscription Aktuelle Abo-Details

Responses

  • 200 {active, status, plan, current_period_end, cancel_at_period_end, next_charge_amount, interval …}.
  • 401 Not authenticated (missing or invalid bearer token)
GET /billing/invoices Lokale GoBD-Rechnungen

Responses

  • 200 {invoices:[…]}.
  • 401 Not authenticated (missing or invalid bearer token)
GET /billing/invoices/{invoiceId}/pdf Rechnung als PDF herunterladen

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

Parameters

Parameters of GET /billing/invoices/{invoiceId}/pdf
NameInTypeRequiredNote
invoiceIdPathstringyesRechnungs-UUID aus GET /billing/invoices.

Responses

  • 200 PDF-Datei (application/pdf, Content-Disposition: attachment).
  • 401 Not authenticated (missing or invalid 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.

Parameters

Parameters of POST /billing/cancel
NameInTypeRequiredNote
immediateQuerybooleannotrue = sofort statt zum Periodenende.

Responses

  • 200 {ok:true, status, cancel_at_period_end, current_period_end}.
  • 400 Kein Tenant / keine Subscription.
  • 401 Not authenticated (missing or invalid bearer token)
  • 500 Server error
POST /billing/resume Geplante Kündigung zurücknehmen

Responses

  • 200 {ok:true, cancel_at_period_end:false}.
  • 400 Keine Subscription.
  • 401 Not authenticated (missing or invalid bearer token)
  • 500 Server error
GET /billing/addons Add-on-Katalog

Responses

  • 200 {addons}.
  • 401 Not authenticated (missing or invalid bearer token)
POST /billing/addons/checkout Add-ons buchen

Parameters

Parameters of POST /billing/addons/checkout
NameInTypeRequiredNote
addonsBodyarrayyesListe {key, quantity?} (extra_site, extra_seat, custom_domain, ki_generations, image_credit_pack).

Request · application/json

{
  "addons": []
}

Responses

  • 200 {sessionId, url}.
  • 401 Not authenticated (missing or invalid bearer token)
  • 422 Kein Tenant / unbekanntes Add-on.
POST /webhooks/stripe Stripe-Webhook (öffentlich, signaturverifiziert) no token

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

Responses

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

Webhook for new requests

XICflow calls an address of your choice by itself as soon as a form has been submitted on a published website.

You enter the target address per website in the “Automation webhook (URL)” field; only https addresses are accepted. The call happens in parallel with a five-second time limit — if the receiver does not answer, the request is still not lost, it is in the requests inbox in any case. There is no automatic retry.

If a signing secret is stored, every call carries the headers “X-XICflow-Timestamp” and “X-XICflow-Signature”. The receiver computes HMAC-SHA256 over the timestamp, a dot and the unchanged body, and compares the result with the value behind “sha256=”. The timestamp protects against a recorded call being replayed later.

Shape of the call

POST · Event form.submission

Fields of the webhook call
FieldTypeNote
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).
Body
{
  "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>"
  }
}

Machine-readable version

The same description as OpenAPI 3.1 — for tools that generate calls, types or a reference of their own from it.

The specification is freely available and needs no token. The version served by the interface itself is always authoritative; the copy next to this documentation is produced from the same source when the page is built.

Address of the specification
https://api.xicflow.com/api/openapi.json

You can load the file into a tool of your choice to try out calls or generate matching data types for your programming language. Signing in stays the same: a bearer token from /auth/login.

Frequently asked questions