Formular-ID

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

Formular-ID
Felder
Body
Idempotenzschlüssel
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

MethodePfadWas er macht
POST/f/<formId>Eine Einsendung erstellen
OPTIONS/f/<formId>CORS-Preflight, immer 204
GET/f/<formId>/schemaDie öffentliche Felddefinition des Formulars, siehe shadcn/ui
GET/f/<formId>/thanksDie gehostete Dankeseite
GET/f/<formId>/challengeDer 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-TypeStrukturHinweise
application/json und +json-TypenEin JSON-ObjektWerte können Strings, Zahlen, Booleans, Arrays und Objekte sein, höchstens 3 Ebenen tief verschachtelt, das oberste Objekt mitgezählt
application/x-www-form-urlencodedName-Wert-PaareWiederholte Namen und name[] werden zu Arrays
multipart/form-dataName-Wert-PaareWie urlencoded; echte Dateien werden abgelehnt
Alles andere415 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

HeaderPflichtWirkung
Content-TypeJaWählt den Body-Parser, siehe oben
AcceptNeinapplication/json erzwingt eine JSON-Antwort, siehe JSON oder eine Weiterleitung
Idempotency-KeyNeinMacht erneute Versuche sicher, bis zu 255 Zeichen, siehe Idempotenz
AuthorizationNeinBearer ik_sk_... oder Bearer ik_pub_..., siehe Von einem Server
Origin, RefererVon Browsern gesendetWird mit den erlaubten Domains des Formulars abgeglichen

Response-Header

HeaderWannWert
X-Request-IdJede Antwortreq_..., in Fehler-Bodies als request_id wiederholt
Retry-After429Sekunden, bis der nächste Post erlaubt ist
Location303 Browser-ErfolgDeine Weiterleitung oder die gehostete Dankeseite
Access-Control-Allow-OriginWenn die Anfrage einen Origin hatDer eigene Origin der Anfrage
Access-Control-Expose-HeadersMit CORSX-Request-Id, Retry-After, damit Browser-Code beide lesen kann
Cache-ControlErfolgno-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.

Preflight
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
Die REST API unter /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" }
Ein Post, der als Spam bewertet wird, bekommt trotzdem 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 mitErgebnis
Demselben Schlüssel und denselben FeldernDie erste Antwort wird erneut abgespielt. Es wird keine zweite Einsendung erstellt.
Demselben Schlüssel und anderen Feldern422 idempotency_mismatch
Demselben Schlüssel, während die erste Anfrage noch läuft409 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:

retry.js
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

Statische Website-Generatoren

Website-Baukästen