Aktuell gibt es viele unterschiedliche Möglichkeiten um ein Evalanche-Formular in eine Webseite zu integrieren. Alle Varianten haben spezifische Vor- und Nachteile (siehe auch Einbinden von Webformularen). Die neue SmartForms API (REST) soll eine weitere Möglichkeit schaffen, welche größtmögliche Flexibilität bietet und einfach zu nutzen ist.
Hierbei übernimmt ein JavaScript in der Website oder Landingpage das Abholen der Formularkonfiguration, die Darstellung, Validierung der Daten und Übertragung zu Evalanche. Die Konfiguration kann in Evalanche erfolgen und muss nicht auf der Website oder Landingpage durchgeführt werden.
Grundlegendes Vorgehen:
-
Formularkonfiguration abfragen: Durch einen Get-Request (JSON-Format) kann eine Formular- und Feld-Konfiguration per API abgefragt werden. Im Anschluss übernimmt ein eigenes JavaScript in der Website die Darstellung.
- Formulardaten übermitteln: Durch einen Post-Request (JSON-Format) der ausgefüllten Formulardaten erfolgt das Absenden, welches entweder eine Erfolgs-Meldung oder eine Fehlermeldung beinhaltet. Hier finden Sie das Schema welchem die eingehenden Daten entsprechen müssen. (https://scnem.com/api/form/v1/schema)
Über die API kann eine beliebige Webseite per JavaScript die Formular- und Felder-Konfiguration eines beliebigen Evalanche-Formulars via GET-Request, also durch den Aufruf einer bestimmten URL (Endpunkt), als JSON-Objekt beziehen.
Aus der Formular- und Felder-Konfiguration kann mittels JavaScript eine individuelle, an die Webseite angepasste Darstellung des Formulars erzeugt werden.
Zusammen mit einem in der Konfig enthaltenen Sicherheits-Tokens, kann das Formular dann via POST-Request, ebenfalls im JSON-Format, wieder an den Endpunkt zurück geschickt werden. Der Sicherheits-Token wird aus diversen Daten des GET-Requests erzeugt, sodass der POST-Request zum Absenden des Formulars nur von demjenigen durchgeführt werden kann, welcher auch die Konfiguration abgefragt hat. Dies ersetzt die analogen Techniken CSRF-Token und Captcha.
Auf den POST-Request, der beim Absenden übermittelt wird, antwortet die API mit einer ausführlichen Antwort ob die Eintragung erfolgreich war oder es zu Fehlern gekommen ist. Die Fehlercodes ermöglichen eine einfache Darstellung des Validierungs-Ergebnisses.
Protokoll | HTTP |
Stil | REST |
Daten-Codierung | JSON |
Endpunkt | https://DOMAIN/api/form/v1/<form-id>[/<profile-sid>] |
Einstellungen beim Formular aktivieren (CORS)
Formulare, auf die via Formular API (Rest) zugegriffen werden soll, müssen in der Konfiguration die Option "Formular API aktivieren" aktiviert haben. Wenn von einer externen Webseite auf das Formular zugegriffen werden soll, muss die Domain dieser Webseite (origin) ebenfalls in der Formular-Konfiguration im Feld "erlaubte Domains" eingetragen werden. Hierbei darf kein Protokoll, wie etwa http:// angegeben werden (z.B.: sc-networks.com), mehrere Domains müssen mit einem Komma getrennt eingetragen werden.
Die API antwortet nur, wenn sowohl die Formular-Konfiguration (wie beschrieben) korrekt ist und der Request einen "Origin-Header" besitzt, welcher zu der Konfigurierten Domain passt.
Beispiel JavaScript für Website oder Landingpage
Folgendes Beispiel dient lediglich dem Verständnis und für Tests der API und sollte in dieser Form nicht produktiv eingesetzt werden. Hierzu sollten individuelle Anpassungen und Überarbeitungen im Vorfeld noch erfolgen.
Folgende Formular-Funktionen werden zur Zeit unterstützt:
- Formular Titel
- Alle Feld-Typen
- Felder-Reihenfolge in Zeilen und Spalten
- Pflichtfelder
- Default-Werte für Formular-Felder
- Vorausgefüllte Werte bei bekanntem Profil
- Vollständige Formular-Validierung und Darstellung der Fehlermeldungen aus der Formular-Konfiguration.
- Formular-Limits
Beispiel Code zur Veranschaulichung: SmartForm_Client.zip
Vorgehen zum Testen:
- In einem Evalanche-Account muss ein Formular erstellt werden. Es kann auch ein bereits existierendes verwendet werden.
- In der Formular-Konfiguration muss zunächst die API aktiviert und die Domain (CORS) freigegeben werden (siehe oben).
- Im Quelltext der Datei: Formular-API-202012.html muss die Variable "formId" mit der SID des Evalanche-Formulars befüllt werden. Die SID eines Formulars finden Sie in der Integrations-URL des Formulas hinter "sid=". Die SID hat folgendes Format: "xxxxx.xxxxx" z.b. "dlthr.1fkppep" (Zeile 207)
- Im Quelltext muss ebenfalls die Interface-Domain (ohne Protokoll) in der Variablen "interfaceDomain" festgelegt werden. (Zeile 213)
- Optional: Soll es eine Möglichkeit der Vorausfüllung geben, muss die Variable "profileUid" mit einer Profil-UID befüllt werden. (Zeile 210)
- Optional: Um die Formular-Konfig als JSON zu prüfen, kann diese über eine Unix-Console mit folgendem Befehl abgerufen werden:
curl -H "Origin: https://INTERFACE_DOMAIN" https://INTERFACE_DOMAIN/api/form/v1/FORM_SID
(Die Variablen INTERFACE_DOMAIN und FORM_SID müssen mit Ihren Daten ersetzt werden.)
Abruf der Formularkonfiguration
Der Abruf einer Formular-Konfiguration erfolgt mittels eines GET
-Requests, z.B. aus einem JavaScript innerhalb der Website.
Die abgerufenen Daten dienen der korrekten Darstellung und Konfiguration des Formulars und entsprechen den Konfigurationen, welche im Evalanche-Objekt hinterlegt sind.
-
token:
Eindeutiger Token zur Validierung für ein Absenden der Formular-Daten
-
form:
- action: Action-URL des Formulars
- title: Titel des Formulars (Erscheinungsbild)
- shortdesc_html: Kurztext des Formulars (Erscheinungsbild)
- language: Sprache des Formulars (Konfiguration)
- translation: diverse Validierungs-Texte (Erscheinungsbild)
- tracking: Externe-Tracking-Daten (Konfiguration)
- limit: Formular-Limit (Konfiguration)
-
fields:
- label: Label des Feldes
- required: Bool, ob Feld ein Pflichtfeld ist
- name: Name des Feldes
- sort: Position des Feldes
- translation: diverse Validierungs-Fehler-Texte
- hidden: Bool, ob Feld sichtbar oder versteckt angezeigt wird
- readonly: Bool, ob ein Feld bestehende Werte überschreiben darf oder nicht
- default_value: Default-Wert
- type: Feld-Typ (ggfs. mit Auflistung der möglichen Optionen)
-
profile (optional, sofern Formular vorausgefüllt wird):
- data: Daten des angegebenen Profils
{
"token": "abcdefgh1234",
"form": {
"action": "https:\/\/evalanche\/art_resource.php?sid=6m.38t18m",
"title": "Newsletter Anmeldung",
"shortdesc_html": ">h1<Newsletter Anmeldung>\/h1<",
"language": "",
"translation": {
"preface_validation": "Bitte korrigieren Sie folgende Fehler",
"duplicate_validation": "Sie sind bereits eingetragen",
"missing_validation": "Markierte Pflichtfelder nicht ausgef\u00fcllt",
"failed_validation": "Die Anmeldung ist fehlgeschlagen",
"submit": "Abschicken"
},
"tracking": {
"link": "",
"campaign": ""
},
"limit": {
"entry": {
"active": false,
"max_entry": 0,
"redirect": "",
"limit_active": false
},
"time": {
"start": {
"active": false,
"timestamp": 1598614860,
"redirect": "https://heise.de",
"limit_active": false
},
"end": {
"active": false,
"timestamp": 0,
"redirect": "",
"limit_active": false
}
}
}
},
"fields": [
{
"label": "Anrede",
"required": 0,
"name": "form_SALUTATION",
"pool_attribute_id": int,
"sort": 0,
"translation": {
"validation_error": ""
},
"hidden": false,
"readonly": false,
"default_value": "",
"widget_id": 2,
"auto_display": false,
"write_protection": false,
"type": "select",
"options": [
{
"key": 0,
"value": "-"
},
{
"key": 1,
"value": "Frau"
},
{
"key": 2,
"value": "Herr"
},
{
"key": 3,
"value": "Familie"
},
{
"key": 4,
"value": "Firma"
}
]
},
{
"label": "Vorname",
"required": 0,
"name": "form_FIRSTNAME",
"pool_attribute_id": int,
"sort": 1,
"translation": {
"validation_error": ""
},
"hidden": false,
"readonly": false,
"default_value": "",
"widget_id": 22,
"auto_display": false,
"write_protection": false,
"type": "text",
"options": []
},
{
"label": "Name",
"required": 0,
"name": "form_NAME",
"pool_attribute_id": int,
"sort": 2,
"translation": {
"validation_error": ""
},
"hidden": false,
"readonly": false,
"default_value": "",
"widget_id: 22,
"auto_display": false,
"write_protection": false,
"type": "text",
"options": []
},
{
"label": "eMail",
"required": 1,
"name": "form_EMAIL",
"pool_attribute_id": int,
"sort": 3,
"translation": {
"validation_error": "Keine g\u00fcltige eMail-Adresse"
},
"hidden": false,
"readonly": false,
"default_value": "",
"widget_id" 22,
"auto_display": false,
"write_protection": false,
"type": "text",
"options": []
},
{
"label": "Firma",
"required": 0,
"name": "form_COMPANY",
"pool_attribute_id": int,
"sort": 4,
"translation": {
"validation_error": ""
},
"hidden": false,
"readonly": false,
"default_value": "",
"widget_id": 22,
"auto_display": false,
"write_protection": false,
"type": "text",
"options": []
}
],
"profile": {
"uid": "6d6b454c95b8ace7373ba4740d91b5c3",
"data": {
"form_SALUTATION": {
"pool_attribute_id": 649263,
"value": [
2
]
},
"form_FIRSTNAME": {
"pool_attribute_id": 649264,
"value": "Max"
},
"form_NAME": {
"pool_attribute_id": 649265,
"value": "Mustermann"
},
"form_EMAIL": {
"pool_attribute_id": 649266,
"value": "max@mustermann.de"
},
"form_COMPANY": {
"pool_attribute_id": 649267,
"value": "Musterfirma"
},
"form_ADDRESS": {
"pool_attribute_id": 649268,
"value": "Musterstra\u00dfe"
},
"form_STREETNUMBER": {
"pool_attribute_id": 649269,
"value": "555"
},
"form_ZIPCODE": {
"pool_attribute_id": 649270,
"value": "55555"
},
"form_CITY": {
"pool_attribute_id": 649271,
"value": "Musterdorf"
}
}
}
}
Formular-Daten übertragen
Die Übertragung von Formular-Daten erfolgt mittels eines POST
-Requests an den Endpunkt.
Diese Methode ermöglicht ein flexibleres Absenden via JS ohne die Formular-Action via Submit ausführen zu müssen.
-
token:
Eindeutiger Token zum Validieren der Formular-Daten (siehe GET-Request)
-
profile_uid:
Die verschlüsselte User-ID oder null
-
data:
Die Formular-Daten als Liste von Dictionaries mit den Feldnamen im Formular inkl. "form_"-Prefix (vgl. HTML Ausgabe des Formulars)
-
options:
- force_new_profile: Erzwingt die Erzeugung eines neuen Profils
- allow_empty_profile: Leere Profile werden erlaubt
- presets: Dictionary von Defaults für die Vorbelegung (gleiches Format wie in "data")
{
"token": "abcdefgh1234",
"profile_uid": null,
"data": [{
"field_name": "form_EMAIL",
"value": "some-email@some-domain.de"
},{
"field_name": "form_NAME",
"value": "Some-name"
},{
"field_name": "form_FIRSTNAME",
"value": "Some-first-name"
},{
"field_name": "form_INTEREST",
"value": [
462096,
462097
]
},{
"field_name": "form_ANSWER",
"value": "462101"
},{
"field_name": "form_BOOL",
"value": "1"
}],
"options": {
"force_new_profile": false,
"allow_empty_profile": false
}
}
Ergebnis im Erfolgsfall
{
"result": {
"profile": {
"uid": "88625be2dc052aa347fe4ecd80da1fb2",
"data": {
"form_SALUTATION": {
"pool_attribute_id": 36,
"value": [
1
]
},
"form_FIRSTNAME": {
"pool_attribute_id": 37,
"value": "Some-first-name"
},
"form_NAME": {
"pool_attribute_id": 38,
"value": "Some-name"
},
"form_EMAIL": {
"pool_attribute_id": 39,
"value": "some-email@some-domain.de"
},
"form_COMPANY": {
"pool_attribute_id": 40,
"value": ""
},
"form_INTEREST": {
"pool_attribute_id": 69,
"value": [7, 8]
}
}
},
"redirection_url": "https://scnem.com/html/default_confirmation.html"
}
}
Hinweis
Bitte beachten Sie, dass die Bestätigungsseite (redirection_url) nach dem Absenden des Smartforms vom Client aufgerufen werden muss, um eventuell nachfolgende Evalanche-Prozesse anzustoßen.
Ergebnis im Fehlerfall
{
"error": {
"code": 102,
"validation_error_attributes": [],
"mandatory_error_attributes": [
"form_EMAIL"
],
"subscription_limit_redirection": null
}
}
Fehlercodes
Sollte beim Submit ein Fehler auftreten, so wird ein Result mit einem der folgenden Fehlercodes zurückgeliefert:
- 101 Kein Profil vorhanden (bei Eindeutigkeitskriterium "Profil-Id" und fehlender Profil-UID im Request)
- 102 Datenvalidierung fehlgeschlagen (Fehlende Pflichtfelder oder invalidate Daten)
- 103 Login-Valdierung fehlgeschlagen (bei Permissiontype "nur Login")
- 104 Profil-Eindeutigkeitsfehler (Bei neuen Profilen mit gleicher Mailadresse eines bereits bestehenden Profils im Pool und Option "Aktualisierung verhindern")
- 105 Verstoss gegen das Eintragungslimit
- 106 Pflichtfeld Verletzung
- 107 Request invalide/Token ungültig
- 108 Profil leer
Sicherheit
Da es sich bei dieser API um eine öffentliche API handelt, wurden Maßnamen ergriffen um das Risiko von automatisierten Masseneintragungen zu senken. Es handelt sich dabei allerdings nur um Hindernisse, die eine mißbräuchliche Nutzung stark erschweren - eine absolute Sicherheit gibt es nicht.
Token
Bei jedem GET Request wird ein Token mitgeliefert. Dieses Token enthält verschlüsselte Informationen zu dem GET-Request sowie eine TTL (time to live).
Dieses Token muss bei einem folgenden Submit wieder mitgeschickt werden, um den Submit zu validieren. Solange die TTL nicht abgelaufen ist, ist der Token für mehrere POST-Requests gültig und verhält sich wie eine Art "Session-Token".
Folgende Dinge werden validiert
- Ist die TTL noch nicht erreicht (Ein Zufallswert von 100-300 Sekunden wird hier auf den Timestamp des GET-Requests addiert)
- Ist die IP des GET-Requests die gleiche wie die des POST
- Ist der User Agent des GET-Requests der gleiche wie der des POST
- Ist der genutzte Host im GET (also die Domain) die gleiche wie im POST
Schlägt die Validierung fehl, so wird kein expliziter Fehler erzeugt - es handelt sich dann um einen invaliden Request.
Widget-IDs
Folgende Widget-IDs können auftreten:
ID | Beschreibung |
1 | Texteingabe |
2 | Dropdown |
3 | Versteckte Eingabe |
4 | Texteingabe (Textarea) |
5 | Checkboxen |
6 | Dropdowns (Datum) |
7 | Dropdowns (Datum & Uhrzeit) |
8 | Texteingabe mit Trim |
9 | Radiobuttons |
10 | Nur anzeigen (Readonly) |
11 | Versteckte Eingabe (Dropdown) |
12 | Versteckte Eingabe (Mehrfach-Dropdown) |
13 | Texteingabe mit gr. Anfangsbuchstaben |
14 | Passwort-Eingabe |
15 | Passwort-Generator |
16 | Dropdowns (Datum in Zukunft) |
17 | Dropdowns (Datum & Uhrzeit in Zukunft) |
18 | Dropdowns (Mit Einschränkung anderer Felder) |
19 | Dropdowns (Datum unsichtbar) |
20 | Dropdowns (Datum & Uhrzeit unsichtbar) |
21 | Checkbox |
22 | Texteingabe (auch Leereingabe) |
23 | Texteingabe (Single selection) |
24 | Dropdown (mit Null-Option) |
25 | Radiobuttons (mit Null-Option) |
26 | Checkbox (unsichtbar) |
27 | Texteingabe (alles Kleinbuchstaben) |
28 | Texteingabe (alles Großbuchstaben) |
29 | Dropdowns (Datum in Vergangenheit) |
30 | Dropdowns (Datum & Uhrzeit in Vergangenheit) |
31 | Texteingabe (Textarea mit Leereingabe) |
32 | Checkboxen (nur anhängen) |
33 | Versteckt (aus Request) |
37 | Dropdowns (Datum & Uhrzeit mit strtotime) |
38 | Dropdowns (Datum mit strtotime) |
41 | Checkbox (invertiert) |
42 | Umkreissuche mit Dropdown |
43 | Dropdown mit Gruppen |
44 | Texteingabe (max. 45 gefiltert) |
45 | Texteingabe (max. 45 gefiltert, auch Leereingaben) |