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/openapiauf 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/pdfals 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
roledes Tokens, wie bei der Anmeldung im Designer:adminundusersehen die Formulare ihrer Gruppe (Hostname des Anmeldeservers),guestnur freigegebene Formulare. Absenden erfordertuseroderadmin, außer der Administrator lässt Gäste zu. GET /api/v1/mezeigt, 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/callbackfü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.
| Methode | Pfad | Was er tut |
|---|---|---|
| GET | /forms | Formulare, die das Token nutzen darf; Filter ?released=true und ?q=. |
| GET | /forms/{formId} | Einstellungen, Seitenzahl, Links zur PDF- und HTML-Fassung. |
| GET | /forms/{formId}/fields | Alle Felder: Typ, Name zum Absenden, Position, Pflicht, Prüfregel, Auswahlwerte. |
| GET | /forms/{formId}/schema | JSON Schema der Werte, für Codegeneratoren und KI-Agenten. |
| GET | /forms/{formId}/pdf | Das leere freigegebene PDF-Formular. |
| POST | /forms/{formId}/validate | Prüft Werte, ohne abzusenden. |
| POST | /forms/{formId}/fill | Ausgefülltes PDF ohne Einsendung, ohne E-Mails (wie Speichern im Webformular). |
| POST | /forms/{formId}/submissions | Sendet das Formular ab: versiegeltes PDF, E-Mails, E-Rechnung. |
| POST | /einvoices | ZUGFeRD- / Factur-X- / XRechnung-Rechnung aus strukturierten Daten. |
| GET | /field-types, /validation-rules, /me | Feldtypen, 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…" }
}
/fillliefert 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": truewerden sie stattdessen übersprungen. Weggelassene Felder behalten ihren Vorgabewert, wie im Browser. - Absenden erfordert die Rolle
useroderadmin; 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.
| Status | Code | Bedeutung |
|---|---|---|
| 400 | invalid_json | Der Inhalt ist kein JSON-Objekt. |
| 401 | invalid_token, invalid_request | Token fehlt, ist abgelaufen, für eine andere Anwendung ausgestellt oder von einem unbekannten Server. |
| 403 | insufficient_scope, local_account | Erforderlicher Scope fehlt oder der Name gehört zu einem lokalen Konto. |
| 404 | form_not_found | Unbekanntes Formular oder Formular einer anderen Gruppe. |
| 409 | form_not_released | Das Formular ist noch nicht freigegeben. |
| 422 | validation_failed | Werte fehlen oder sind ungültig; siehe errors. |
| 403 | role_required | Absenden erfordert die Rolle user oder admin. |
| 404 | not_found | Unbekannter API-Pfad. |
| 405 | method_not_allowed | Falsche HTTP-Methode (GET oder POST) für diesen Pfad. |
| 413 / 415 | too_large, unsupported_media_type | Inhalt größer als 10 MB oder kein JSON. |
| 422 | not_an_invoice_form, too_many_items | Das gewählte Formular hat keine Rechnungspositionen oder weniger als die Rechnung. |
| 429 | rate_limited, daily_limit | Zu viele Anfragen (standardmäßig 120 pro Minute und Benutzer) oder Tagesgrenze der API-Einsendungen erreicht; Retry-After abwarten. |
| 502 | form_processing_failed | Das Formular konnte nicht verarbeitet werden (z. B. Mailserver nicht erreichbar). |
| 500 | server_error | Fehler auf dem Server; Details stehen im Serverprotokoll. |
| 503 | api_disabled, , loopback_not_configured | API 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: