API-Grundlagen.
Mailan hat zwei Hälften und zwei Arten von Zugängen. Einsendungen kommen über einen öffentlichen Endpunkt herein, den jeder mit dem Access-Key deines Formulars aufrufen darf. Alles, was Daten wieder ausliest, braucht einen geheimen API-Key. Diese Seite beschreibt, was beide Hälften teilen: Basis-URL, Antwortformat, Status-Codes und Limits.
Basis-URL
Alle API-Routen liegen unterhalb von /api. Beim gehosteten Dienst ist das https://mailan.email/api, in deiner eigenen Installation deine Domain mit demselben Pfad. Einzige Ausnahme ist der Health-Check: Er liegt in der Wurzel, außerhalb des Präfixes, damit ein Uptime-Monitor nichts von /api wissen muss.
Access-Key und API-Key
Die beiden sind nicht austauschbar. Der Access-Key identifiziert ein Formular und darf im HTML einer öffentlichen Seite stehen — mit ihm lässt sich nur eine Einsendung für genau dieses Formular anlegen. Der API-Key gehört zu deinem Konto, liest deine Daten und muss auf einem Server bleiben.
| Eigenschaft | Access-Key | API-Key |
|---|---|---|
| Geltungsbereich | Ein Formular | Das ganze Konto |
| Geheim | Nein — es ist bewusst öffentlich | Ja — wie ein Passwort behandeln |
| Übertragen als | URL-Segment oder Feld access_key | Header Authorization: Bearer |
| Erlaubt | Eine Einsendung anlegen | Formulare und Einsendungen lesen |
| Wo zu finden | Dashboard → Formular → Einstellungen | Dashboard → API-Keys |
Ein API-Key wird genau einmal angezeigt, direkt nach dem Anlegen: Gespeichert wird nur sein Hash, er lässt sich also nicht erneut anzeigen. Keys sehen aus wie mln_live_… und können jederzeit widerrufen werden; ein widerrufener Key antwortet wie ein unbekannter mit 401.
Antwortformat
Alles unter /api/v1 antwortet in derselben Hülle: ein Erfolgs-Flag plus die Nutzdaten in data. Fehler tragen das Flag und stattdessen eine Nachricht. Der Submit-Endpunkt ist bewusst flacher — er antwortet Browsern wie Programmen und liefert success und message direkt.
Status-Codes
Wert den Status-Code aus, nicht die Nachricht: Der Wortlaut richtet sich an Menschen und kann sich ändern, die Codes nicht.
| Code | Bedeutung | Was zu tun ist |
|---|---|---|
200 |
Angenommen bzw. erfolgreich gelesen. | Nichts. |
303 |
Einsendung gespeichert, der Browser wird zum Ziel weitergeleitet. | Nur bei klassischen Formular-Posts. Mit Accept: application/json bekommst du stattdessen JSON. |
400 |
Der Request-Body war nicht lesbar oder ein Wert ungültig. | Content-Type und Feldnamen prüfen. |
401 |
Fehlender, unbekannter oder widerrufener API-Key. | Authorization-Header prüfen, notfalls neuen Key anlegen. |
403 |
Captcha fehlgeschlagen, Herkunft nicht erlaubt oder Formular gesperrt. | Die Nachricht lesen und die erlaubten Domains des Formulars prüfen. |
404 |
Unbekannter Access-Key oder eine Einsendung, die dir nicht gehört. | Fremde Ressourcen sehen aus wie fehlende — das ist Absicht. |
413 |
Ein Upload hat das Größenlimit überschritten. | Die Datei vor dem Senden prüfen; der Server bricht mitten im Datenstrom ab. |
429 |
Rate-Limit oder Monatskontingent überschritten. | Warten und später erneut versuchen. Einsendungen nicht blind wiederholen. |
500 |
Auf unserer Seite ist etwas schiefgegangen. | Mit Backoff erneut versuchen; die Einsendung kann trotzdem gespeichert sein. |
Rate-Limits und Kontingente
Drei Limits stehen nebeneinander. Zwei schützen den Submit-Endpunkt, eines die Lese-API; darüber liegt das monatliche Einsendungs-Kontingent deines Tarifs. Die Zahlen unten sind die Vorgaben des gehosteten Dienstes — in deiner eigenen Installation sind es Umgebungsvariablen.
| Limit | Vorgabe | Umgebungsvariable |
|---|---|---|
| Einsendungen pro Formular und Minute | 20 |
RATELIMIT_SUBMIT_PER_MINUTE |
| Einsendungen pro IP und Minute | 10 |
RATELIMIT_SUBMIT_PER_IP_PER_MINUTE |
| Lese-Anfragen pro Key und Minute | 120 |
RATELIMIT_API_PER_MINUTE |
| Einsendungen pro Monat | Laut deinem Tarif | Tarif-Einstellung |
Jede Überschreitung wird mit 429 beantwortet. Die Submit-Limits arbeiten mit einem gleitenden Fenster, das Budget füllt sich also laufend auf statt schlagartig zur vollen Minute.
Erlaubte Domains
Ein Formular lässt sich auf die Domains beschränken, auf denen es eingebunden ist. Ist die Liste leer, wird jede Herkunft akzeptiert; sobald sie Einträge hat, wird eine Einsendung von woanders mit 403 beantwortet. Dieselbe Liste entscheidet auch, welche Weiterleitungsziele akzeptiert werden — genau das verhindert, dass der Endpunkt zum offenen Redirect wird.
Server-zu-Server-Anfragen senden keinen Origin-Header und werden davon nie blockiert — die Beschränkung schützt gegen ein kopiertes Formular auf einer fremden Seite, nicht gegen ein Programm.