JavaScript und fetch
Der Einsendungs-Endpunkt im Detail: Body-Formate, Header, CORS, Antworten und Idempotenz.
Jeder Code, der eine HTTP-Anfrage senden kann, kann an Ikiform senden. Sende JSON, FormData oder urlencoded Daten an https://ikiform.com/f/<formId> und lies eine JSON-Antwort. Das SDK verpackt das in einer Funktion, ist aber optional. Für eine Schritt-für-Schritt-Einrichtung auf einem bestimmten Stack siehe Anleitungen nach Plattform.
Mit fetch
const response = await fetch("https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx", {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify({
name: "Ada Lovelace",
email: "ada@example.com",
message: "Hello",
}),
});
const result = await response.json();
if (!result.ok) console.error(result.error.code, result.error.fields);Ausprobieren
curl https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx \
-H "Content-Type: application/json" \
-d '{"name":"Ada Lovelace","email":"ada@example.com","message":"Hello from the Ikiform docs."}'Gib deine eigene Formular-ID ein, um das als echten Request zu senden.
Endpunkte
| Methode | Pfad | Was er macht |
|---|---|---|
POST | /f/<formId> | Eine Einsendung erstellen |
OPTIONS | /f/<formId> | CORS-Preflight, immer 204 |
GET | /f/<formId>/schema | Die öffentliche Felddefinition des Formulars, siehe shadcn/ui |
GET | /f/<formId>/thanks | Die gehostete Dankeseite |
GET | /f/<formId>/challenge | Der Frame der Ikiform-Menschlichkeitsprüfung, vom SDK verwendet |
Wenn du /f/<formId> selbst in einem Browser-Tab öffnest, ist das ein GET, der mit 404 not_found beantwortet wird. Das ist so gewollt: Der Endpunkt nimmt nur Posts an.
Body-Formate
| Content-Type | Struktur | Hinweise |
|---|---|---|
application/json und +json-Typen | Ein JSON-Objekt | Werte können Strings, Zahlen, Booleans, Arrays und Objekte sein, höchstens 3 Ebenen tief verschachtelt, das oberste Objekt mitgezählt |
application/x-www-form-urlencoded | Name-Wert-Paare | Wiederholte Namen und name[] werden zu Arrays |
multipart/form-data | Name-Wert-Paare | Wie urlencoded; echte Dateien werden abgelehnt |
| Alles andere | 415 unsupported_media_type |
Bodies müssen UTF-8 sein. Ein anderes charset als utf-8 bekommt 415 unsupported_charset, und Bytes, die kein gültiges UTF-8 sind, bekommen denselben Code. Ein JSON-Array oder ein fehlerhafter Body bekommt 400 invalid_body.
Header
Request-Header
| Header | Pflicht | Wirkung |
|---|---|---|
Content-Type | Ja | Wählt den Body-Parser, siehe oben |
Accept | Nein | application/json erzwingt eine JSON-Antwort, siehe JSON oder eine Weiterleitung |
Idempotency-Key | Nein | Macht erneute Versuche sicher, bis zu 255 Zeichen, siehe Idempotenz |
Authorization | Nein | Bearer ik_sk_... oder Bearer ik_pub_..., siehe Von einem Server |
Origin, Referer | Von Browsern gesendet | Wird mit den erlaubten Domains des Formulars abgeglichen |
Response-Header
| Header | Wann | Wert |
|---|---|---|
X-Request-Id | Jede Antwort | req_..., in Fehler-Bodies als request_id wiederholt |
Retry-After | 429 | Sekunden, bis der nächste Post erlaubt ist |
Location | 303 Browser-Erfolg | Deine Weiterleitung oder die gehostete Dankeseite |
Access-Control-Allow-Origin | Wenn die Anfrage einen Origin hat | Der eigene Origin der Anfrage |
Access-Control-Expose-Headers | Mit CORS | X-Request-Id, Retry-After, damit Browser-Code beide lesen kann |
Cache-Control | Erfolg | no-store |
CORS
Der Einsendungs-Endpunkt akzeptiert Cross-Origin-Posts von jeder Website. Preflights sind immer erfolgreich und geben den Origin der Anfrage zurück. Es werden keine Cookies oder Zugangsdaten verwendet, also schützt nicht CORS dein Formular, sondern die erlaubten Domains. Sind erlaubte Domains gesetzt, wird ein Post von einer anderen Website je nach Einstellung des Formulars als Spam gespeichert oder abgelehnt. Siehe Erlaubte Domains.
OPTIONS /f/frm_xxxxxxxxxxxxxxxx HTTP/1.1
Origin: https://example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Accept, Idempotency-Key, Authorization
Access-Control-Max-Age: 86400
Vary: Origin/api/v1 ist anders: Sie sendet keine CORS-Header und beantwortet Browser-Preflights mit 405, sodass ein Secret Key nie von einer Webseite aus genutzt werden kann.Antworten
Erfolg ist 201 mit der neuen Einsendungs-ID. Fehler verwenden überall dasselbe Format, mit Feldfehlern nach Feld-ID, wenn die Validierung fehlschlägt. Alle Codes stehen unter Fehler.
{ "ok": true, "id": "sub_01k7v2c9t3e8m5q4x6z0a1b2c3" }201. Spam wird separat gespeichert und erreicht nie deine Webhooks oder deinen Posteingang.Idempotenz
Sende einen Idempotency-Key-Header oder ein _idempotency-Feld, um erneute Versuche sicher zu machen. Schlüssel sind bis zu 255 Zeichen lang und gelten 24 Stunden lang für das Formular. Werden beide gesendet, gewinnt der Header.
| Erneuter Versuch mit | Ergebnis |
|---|---|
| Demselben Schlüssel und denselben Feldern | Die erste Antwort wird erneut abgespielt. Es wird keine zweite Einsendung erstellt. |
| Demselben Schlüssel und anderen Feldern | 422 idempotency_mismatch |
| Demselben Schlüssel, während die erste Anfrage noch läuft | 409 idempotency_in_progress |
Posts, die fehlschlagen, bevor die Einsendung gespeichert ist, etwa bei Validierungsfehlern, behalten den Schlüssel nicht, sodass du die Daten korrigieren und es mit demselben Schlüssel erneut versuchen kannst. Eine sichere Retry-Schleife:
const key = crypto.randomUUID();
async function send(attempt = 1) {
const response = await fetch("https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx", {
method: "POST",
headers: { "Content-Type": "application/json", "Idempotency-Key": key },
body: JSON.stringify({ email: "ada@example.com" }),
}).catch(() => null);
if (response && response.status < 500 && response.status !== 429) return response.json();
if (attempt === 3) throw new Error("Ikiform is unreachable");
const wait = Number(response?.headers.get("Retry-After")) || attempt * 2;
await new Promise((resolve) => setTimeout(resolve, wait * 1000));
return send(attempt + 1);
}Anleitungen nach Plattform
Frameworks
- Next.jsEine Client-Komponente oder eine Server Action.
- ReactLade-, Fehler- und Erfolgszustände.
- VueEine Single-File-Komponente.
- NuxtPosts vor der Hydration und danach mit
$fetch. - SvelteEine Svelte-5-Komponente und eine Server Action.
- SvelteKitEine vorgerenderte Seite mit Progressive Enhancement.
- AstroEin Formular ohne JavaScript, optional erweitert.
- GatsbyEin statisches Formular oder eine Gatsby Function.
- Reines JavaScript
fetchmit Inline-Fehlern.
Statische Website-Generatoren
- HugoEin Partial und ein Shortcode für Inhaltsdateien.
- JekyllEin Include und die Einrichtung für GitHub Pages.
- EleventyEin Shortcode für Nunjucks, Liquid und Markdown.