CodeB eForms Server von Aloaha

API REST-API: Formulare und E-Rechnungen aus Ihrer eigenen Software.

Jedes Formular des Servers lässt sich aus anderen Anwendungen nutzen: Formulare auflisten, Felder lesen, Daten prüfen, ein ausgefülltes PDF erhalten, absenden oder aus strukturierten Daten eine ZUGFeRD- / XRechnung-E-Rechnung erstellen. Die API ist als OpenAPI 3.1 beschrieben und mit Bearer-Tokens Ihrer OpenID-Connect-Server geschützt.

Eine Einsendung über die API wird genau wie eine aus dem Webformular verarbeitet: versiegeltes PDF, optionale Serversignatur, E-Mails, E-Rechnung.

Auf einen Blick

  • Basis-URL: https://<Ihr Server>/api/v1 (auf Servern ohne URLs ohne Dateiendung: /api.ashx/v1).
  • Beschreibung: OpenAPI 3.1 unter /api/v1/openapi auf jedem Server und als Download. Importieren Sie sie in Postman, Swagger UI oder einen Codegenerator.
  • Format: JSON (UTF-8). PDFs kommen als Base64 in der JSON-Antwort oder mit Accept: application/pdf als Datei.
  • Fehler: Problem Details nach RFC 9457 (application/problem+json).

Anmeldung

Jeder Aufruf außer /, /health, /openapi und /field-types braucht ein Access Token eines der OpenID-Connect-Server, die auf dem Formularserver eingerichtet sind (standardmäßig phone.codeb.io, www.aloaha.com und phone.aloaha.com):

Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6…
  • JWT-Tokens werden lokal geprüft: RS256-Signatur gegen die veröffentlichten Schlüssel des Servers, Aussteller, Ablauf und Zielgruppe (Audience). Die Audience ist die Client-ID des Formularservers; ein Administrator kann weitere Client-IDs zulassen (Einstellungen, REST-API).
  • Undurchsichtige Tokens werden per Token-Introspection beim ausstellenden Server geprüft. Sind mehrere Server eingerichtet, nennen Sie ihn im Header X-OIDC-Issuer: phone.codeb.io.
  • Rollen kommen aus dem Claim role des Tokens, wie bei der Anmeldung im Designer: admin und user sehen die Formulare ihrer Gruppe (Hostname des Anmeldeservers), guest nur freigegebene Formulare. Absenden erfordert user oder admin, außer der Administrator lässt Gäste zu.
  • GET /api/v1/me zeigt, für welchen Benutzer, welche Rolle und Gruppe ein Token steht.

Ein Bearer-Token erhalten

Die API nimmt die Access Tokens an, die die OpenID-Connect-Server bei der Anmeldung ausstellen (RS256-JWTs, eine Stunde gültig). Ihre Anwendung erhält eines mit dem Standardverfahren Authorization Code Flow mit PKCE; das kann jede OAuth-2.0- / OpenID-Connect-Bibliothek. Unten steht phone.codeb.io für den Anmeldeserver, den Sie verwenden.

1. Anwendung einmalig registrieren

  • Registrieren Sie Ihre Anwendung beim Anmeldeserver als OIDC-Client (das erledigt ein Administrator des CodeB-Servers unter /oidc-clients.html, oder fragen Sie uns unter info@aloaha.com). Sie wählen eine Client-ID (z. B. my-app) und die Redirect-URI, zu der die Anmeldung zurückkehrt (z. B. http://localhost:8765/callback für ein Skript). Die Redirect-URI muss Zeichen für Zeichen übereinstimmen. Mit Client-Secret ist der Client vertraulich, ohne ist er öffentlich und nutzt nur PKCE.
  • Auf dem Formularserver lässt ein Administrator die Client-ID zu: Settings → REST API → Other applications allowed. Tokens für die eigene Client-ID des Formularservers werden ohnehin angenommen.

2. Anmelden und Code erhalten

Erzeugen Sie ein PKCE-Paar und öffnen Sie die Autorisierungs-URL im Browser. Die Person meldet sich an (Passwort, Passkey oder EU Digital Identity Wallet), und der Browser kehrt mit ?code=… zu Ihrer Redirect-URI zurück.

VERIFIER=$(openssl rand -base64 48 | tr -d '=+/' | cut -c1-64)
CHALLENGE=$(printf '%s' "$VERIFIER" | openssl dgst -sha256 -binary | openssl base64 | tr '+/' '-_' | tr -d '=')

# diese URL im Browser öffnen (eine Zeile)
https://phone.codeb.io/oauth2/v1/authorize?response_type=code&client_id=my-app
  &redirect_uri=http%3A%2F%2Flocalhost%3A8765%2Fcallback&scope=openid%20profile%20email
  &state=xyz&nonce=abc&code_challenge=$CHALLENGE&code_challenge_method=S256

Auch wenn unter der Redirect-URI nichts antwortet, steht der Code in der Adresszeile des Browsers. Er gilt wenige Minuten und nur einmal.

3. Code gegen Tokens tauschen

curl -X POST https://phone.codeb.io/oauth2/v1/token \
  -d grant_type=authorization_code -d client_id=my-app \
  -d redirect_uri=http://localhost:8765/callback \
  -d code=$CODE -d code_verifier=$VERIFIER
# vertraulicher Client: zusätzlich  -d client_secret=$SECRET

{ "access_token": "eyJhbGciOiJSUzI1NiIs…", "token_type": "Bearer", "expires_in": 3600,
  "id_token": "eyJ…", "refresh_token": "…" }

4. API aufrufen, bei Bedarf erneuern

curl -H "Authorization: Bearer $ACCESS_TOKEN" https://forms.example.com/api/v1/me

# nach einer Stunde: neue Tokens mit dem Refresh Token (es wechselt bei jeder Nutzung)
curl -X POST https://phone.codeb.io/oauth2/v1/token \
  -d grant_type=refresh_token -d client_id=my-app -d refresh_token=$REFRESH_TOKEN

Das Token handelt für die angemeldete Person: Ihre role bestimmt, welche Formulare die API zeigt (siehe oben). Für einen Hintergrundjob melden Sie sich einmal mit einem eigenen Konto an und halten das Token mit dem Refresh Token aktuell.

Der ganze Ablauf als Skript

Python 3, nur Standardbibliothek: öffnet den Browser, empfängt den Code auf localhost und gibt das Access Token aus.

import base64, hashlib, http.server, json, secrets, urllib.parse, urllib.request, webbrowser

ISSUER, CLIENT_ID = "https://phone.codeb.io", "my-app"
REDIRECT = "http://localhost:8765/callback"
verifier = secrets.token_urlsafe(48)
challenge = base64.urlsafe_b64encode(hashlib.sha256(verifier.encode()).digest()).rstrip(b"=").decode()
state = secrets.token_urlsafe(16)
webbrowser.open(ISSUER + "/oauth2/v1/authorize?" + urllib.parse.urlencode({
    "response_type": "code", "client_id": CLIENT_ID, "redirect_uri": REDIRECT,
    "scope": "openid profile email", "state": state, "nonce": secrets.token_urlsafe(16),
    "code_challenge": challenge, "code_challenge_method": "S256"}))

class Callback(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        q = urllib.parse.parse_qs(urllib.parse.urlparse(self.path).query)
        assert q.get("state") == [state], "state mismatch"
        self.server.code = q["code"][0]
        self.send_response(200); self.end_headers(); self.wfile.write(b"Angemeldet. Sie koennen diesen Tab schliessen.")
    def log_message(self, *a): pass

srv = http.server.HTTPServer(("localhost", 8765), Callback)
srv.handle_request()
body = urllib.parse.urlencode({"grant_type": "authorization_code", "client_id": CLIENT_ID,
    "redirect_uri": REDIRECT, "code": srv.code, "code_verifier": verifier}).encode()
tokens = json.load(urllib.request.urlopen(ISSUER + "/oauth2/v1/token", body))
print(tokens["access_token"])

Endpunkte

Alle Pfade relativ zu /api/v1.

MethodePfadWas er tut
GET/formsFormulare, die das Token nutzen darf; Filter ?released=true und ?q=.
GET/forms/{formId}Einstellungen, Seitenzahl, Links zur PDF- und HTML-Fassung.
GET/forms/{formId}/fieldsAlle Felder: Typ, Name zum Absenden, Position, Pflicht, Prüfregel, Auswahlwerte.
GET/forms/{formId}/schemaJSON Schema der Werte, für Codegeneratoren und KI-Agenten.
GET/forms/{formId}/pdfDas leere freigegebene PDF-Formular.
POST/forms/{formId}/validatePrüft Werte, ohne abzusenden.
POST/forms/{formId}/fillAusgefülltes PDF ohne Einsendung, ohne E-Mails (wie Speichern im Webformular).
POST/forms/{formId}/submissionsSendet das Formular ab: versiegeltes PDF, E-Mails, E-Rechnung.
POST/einvoicesZUGFeRD- / Factur-X- / XRechnung-Rechnung aus strukturierten Daten.
GET/field-types, /validation-rules, /meFeldtypen, Prüfregeln, Identität des Tokens.

Formulare und Felder lesen

Listen Sie die freigegebenen Formulare auf und lesen Sie dann die Felder eines Formulars. Jedes Eingabefeld hat einen submitName: Das ist der Schlüssel beim Absenden. Optionsfelder teilen sich den Namen ihrer Gruppe; Auswahllisten nennen ihre options.

curl -H "Authorization: Bearer $TOKEN" https://forms.example.com/api/v1/forms?released=true
curl -H "Authorization: Bearer $TOKEN" https://forms.example.com/api/v1/forms/zugferd/fields?inputOnly=true

Feldtypen: textfield, dropdown, checkbox und radio nehmen Werte auf; text, image, line und button dienen nur dem Layout. Positionen sind in Punkt angegeben, gemessen wie im Editor.

Ausfüllen und absenden

Senden Sie die Werte als Objekt aus submitName und Wert. Kontrollkästchen nehmen true oder false, Auswahllisten und Optionsgruppen einen ihrer Werte. Der Server prüft zuerst Pflichtfelder, Auswahlwerte, Länge und Prüfregeln; ist etwas falsch, antwortet er mit 422 und einer Fehlerliste und sendet nichts ab.

curl -X POST https://forms.example.com/api/v1/forms/contactrequest/submissions \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"values": {"Name": "Erika Muster", "Email": "erika@example.com", "Message": "Bitte rufen Sie mich zurück.", "Consent": true}}'

Antwort (201):

{
  "submissionId": "0b6c1f2e9d4a4c51a3f0d2b7e8c91a44",
  "formId": "contactrequest",
  "status": "submitted",
  "pdf": { "fileName": "contactrequest.pdf", "size": 84211, "sha256": "…", "eInvoice": false, "data": "JVBERi0xLjc…" }
}
  • /fill liefert nur das ausgefüllte PDF: nichts wird versiegelt, keine E-Mail verschickt, Pflichtfelder dürfen leer bleiben.
  • Formulare mit Anmeldepflicht erhalten die geprüfte Identität des Tokens, genau wie nach einer Anmeldung im Browser. Andere Formulare erhalten sie mit "useIdentity": true.
  • Unbekannte Feldnamen werden abgelehnt, damit Tippfehler nicht verloren gehen. Mit "ignoreUnknownFields": true werden sie stattdessen übersprungen. Weggelassene Felder behalten ihren Vorgabewert, wie im Browser.
  • Absenden erfordert die Rolle user oder admin; außerdem begrenzt der Server die Zahl der API-Einsendungen pro Tag.

E-Rechnungen (ZUGFeRD / XRechnung)

POST /einvoices nimmt eine Rechnung als strukturierte Daten, füllt das Rechnungsformular des Servers aus und sendet es ab. Die Antwort ist ein PDF/A-3 mit eingebettetem XML nach EN 16931 (ZUGFeRD / Factur-X; mit Käuferreferenz (Leitweg-ID) für XRechnung). Zeilensummen, Umsatzsteuer und Gesamtbetrag werden berechnet, wenn Sie sie weglassen. Datumsangaben im ISO-Format (2026-10-11), Beträge mit Punkt.

curl -X POST https://forms.example.com/api/v1/einvoices \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -H "Accept: application/pdf" \
  -o rechnung-2026-0042.pdf -d '{
  "invoice": { "number": "2026-0042", "date": "2026-10-11", "currency": "EUR", "dueDate": "2026-10-25", "taxPercent": 19 },
  "seller":  { "name": "Example Supplies GmbH", "street": "Musterstraße 1", "postCode": "10115", "town": "Berlin",
               "country": "DE", "email": "billing@example.com", "vatId": "DE123456789" },
  "buyer":   { "name": "Example Hotel AG", "street": "Seestraße 1", "postCode": "12345", "town": "Musterstadt",
               "country": "DE", "email": "accounts@example.com" },
  "payment": { "iban": "DE02120300000000202051", "bic": "BYLADEM1001" },
  "items":   [ { "name": "Beratung (Stunden)", "quantity": 4, "netPrice": 120 },
               { "name": "Reisekostenpauschale", "netPrice": 80 } ]
}'

"action": "preview" liefert die ausgefüllte Rechnung, ohne sie zu versenden. Die Rechnung geht per E-Mail an die Adressen in den Daten, wie beim Rechnungs-Webformular.

Vollständige Referenz der E-Rechnungs-API: jedes Feld mit seinem Geschäftsbegriff nach EN 16931, Rechen- und Steuerregeln, Checkliste XRechnung und Fehler.

Fehler und Grenzen

Jeder Fehler ist ein Problem-Details-Objekt mit type, title, status und detail; Prüffehler enthalten zusätzlich eine Liste der Felder.

StatusCodeBedeutung
400invalid_jsonDer Inhalt ist kein JSON-Objekt.
401invalid_token, invalid_requestToken fehlt, ist abgelaufen, für eine andere Anwendung ausgestellt oder von einem unbekannten Server.
403insufficient_scope, local_accountErforderlicher Scope fehlt oder der Name gehört zu einem lokalen Konto.
404form_not_foundUnbekanntes Formular oder Formular einer anderen Gruppe.
409form_not_releasedDas Formular ist noch nicht freigegeben.
422validation_failedWerte fehlen oder sind ungültig; siehe errors.
403role_requiredAbsenden erfordert die Rolle user oder admin.
404not_foundUnbekannter API-Pfad.
405method_not_allowedFalsche HTTP-Methode (GET oder POST) für diesen Pfad.
413 / 415too_large, unsupported_media_typeInhalt größer als 10 MB oder kein JSON.
422not_an_invoice_form, too_many_itemsDas gewählte Formular hat keine Rechnungspositionen oder weniger als die Rechnung.
429rate_limited, daily_limitZu viele Anfragen (standardmäßig 120 pro Minute und Benutzer) oder Tagesgrenze der API-Einsendungen erreicht; Retry-After abwarten.
502form_processing_failedDas Formular konnte nicht verarbeitet werden (z. B. Mailserver nicht erreichbar).
500server_errorFehler auf dem Server; Details stehen im Serverprotokoll.
503api_disabled, issuer_unavailable, loopback_not_configuredAPI abgeschaltet, Anmeldeserver nicht erreichbar oder interne Adresse des Servers nicht eingestellt.

Was die API abdeckt

Wir haben die API mit den Schnittstellen verbreiteter Formular-Baukästen und PDF-Dienste verglichen. Diese bieten typischerweise: Formulare und ihre Fragen auflisten, Einsendungen lesen und anlegen, Webhooks bei neuen Einsendungen sowie PDF-Formulardaten füllen oder auslesen. Die API des CodeB eForms Server deckt ab:

  • Formulare und Felder, mit Feldtypen, Positionen, Prüfregeln und einem JSON Schema je Formular.
  • Einsendungen mit der vollständigen Verarbeitung des Webformulars: versiegeltes und optional signiertes PDF, E-Mails und Regeln für Anhänge.
  • PDF ausfüllen ohne Einsendung sowie das leere PDF-Formular.
  • E-Rechnungen (ZUGFeRD / Factur-X / XRechnung) aus strukturierten Daten, was Formular-Baukästen meist nicht können.
  • Sicherheit nach Standard: OAuth-2.0-Bearer-Tokens Ihrer eigenen OpenID-Connect-Server, keine zusätzlichen API-Schlüssel.

Der Server speichert eingesandte Daten bewusst nicht, daher gibt es keinen Endpunkt, der frühere Einsendungen auflistet. Benachrichtigungen über neue Einsendungen (Webhooks) sind geplant.

Fragen und Antworten

Wie erhalte ich ein Token für die API?

Melden Sie sich mit dem Authorization-Code-Flow (mit PKCE) bei einem der OpenID-Connect-Server an, die auf dem Formularserver eingerichtet sind, zum Beispiel phone.codeb.io, und verwenden Sie das Access Token. Tokens für die Client-ID des Formularservers werden angenommen; ein Administrator kann die Client-IDs weiterer Anwendungen zulassen.

Gibt es eine OpenAPI- oder Swagger-Beschreibung?

Ja. Jeder Server veröffentlicht OpenAPI 3.1 unter /api/v1/openapi, und Sie können sie auf dieser Seite herunterladen. Importieren Sie sie in Postman, Swagger UI oder einen Codegenerator.

Kann ich über die API ZUGFeRD- oder XRechnung-Rechnungen erstellen?

Ja. POST /api/v1/einvoices nimmt Verkäufer, Käufer, Positionen und Umsatzsteuer als JSON und liefert ein PDF/A-3 mit eingebettetem XML nach EN 16931. Mit Käuferreferenz (Leitweg-ID) erfüllt es XRechnung.

Unterscheidet sich eine Einsendung über die API von einer im Browser?

Nein. Die API übergibt die Werte an dieselbe Verarbeitung wie das Webformular; versiegeltes PDF, Signatur, E-Mails und E-Rechnung sind gleich.

Kann ich eingesandte Formulare auflisten?

Nein. Der Server speichert eingesandte Daten nicht; das Ergebnis geht an die eingerichteten Empfänger und an den Aufrufer zurück. Benachrichtigungen über neue Einsendungen sind geplant.

Die API ausprobieren

Fragen Sie nach Testzugangsdaten für unseren Online-Formularserver und testen Sie die API mit Ihren eigenen Formularen.

Stand: