Formstepdocs
Zur AppApp

Anfragen

Formular und Request in einem Aufruf erstellen

Ein Agent erfährt im Telefonat mit einer Kundin, dass sie noch zwei Gehaltsabrechnungen hochladen, eine Gebühr von 40 EUR bezahlen und ein Gespräch buchen muss. Er sendet Formular und Request im selben Aufruf, und Formstep übernimmt den Rest.


Wann Sie es nutzen

Ein Request verweist normalerweise auf ein Formular, das jemand im Editor gebaut und veröffentlicht hat. Hängen die Fragen vom Einzelfall ab, schickt der Aufrufer sie stattdessen mit: requests.create nimmt form anstelle von formId. Formstep baut aus den Blöcken ein gewöhnliches Formular, veröffentlicht es und erstellt den Request in einem Schritt, sodass entweder beides existiert oder keines von beiden. Wir nennen das ein Inline-Formular.

Nutzen Sie weiterhin formId für ein Formular, das Sie vielen Personen in derselben Form senden und von Hand im Editor gestalten möchten. Nutzen Sie form, wenn eine Automation entscheidet, was gefragt wird.

Der Aufruf

requests.create mit einem Formular
bash
curl -X POST https://api.formstep.io/api/v1 \
  -H "Authorization: Bearer $FORMSTEP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"method":"requests.create","params":{
        "form":{
          "name":"Documents and fee for your mortgage application",
          "logo":{"type":"image","url":"https://acme.example/logo.png"},
          "cover":{"type":"color","color":"#0f4c81"},
          "emoji":"🏦",
          "blocks":[
            {"type":"paragraph","content":"Upload the two documents and pay the processing fee."},
            {"type":"file","key":"payslips","title":"Your last two payslips","maxFiles":2},
            {"type":"payment","key":"fee","title":"Processing fee","amount":40,"currency":"EUR"},
            {"type":"scheduleAppointment","key":"call","title":"Pick a time for our call","eventType":"15 min call"}]},
        "recipient":{"email":"ada@example.com","name":"Ada"},
        "delivery":"email",
        "idempotencyKey":"call-8841"}}'

Alles andere am Request behält seine Bedeutung: recipient, prefill, context, readonly, delivery, Erinnerungen, Ablauf, callbackUrl, test und idempotencyKey werden gegen das neue Formular genauso geprüft wie gegen eines, das von Hand gebaut wurde. Die Antwort enthält zusätzlich das Formular, mit den Schlüsseln, unter denen seine Antworten zurückkommen:

Antwort, gekürzt
json
{
  "id": "kd7...",
  "status": "pending",
  "url": "https://form.formstep.io/r/rq_...",
  "form": {
    "id": "j58...",
    "name": "Documents and fee for your mortgage application",
    "reused": false,
    "fields": [
      { "key": "payslips", "type": "file" },
      { "key": "fee", "type": "payment" },
      { "key": "call", "type": "schedule-appointment" }
    ]
  }
}

Um eine Auswahlfrage im selben Aufruf vorauszufüllen, senden Sie Optionsschlüssel, wie bei jedem Formular. Der Schlüssel einer Option wird aus ihrem Label abgeleitet, aus Self-employed wird also self_employed. Ein Label statt eines Schlüssels schlägt mit INVALID_PREFILL_VALUE fehl, und der Fehler listet die gültigen Schlüssel.

Das Formularobjekt

FeldWas es tut
nameErforderlich, 1 bis 100 Zeichen. Der Name im Dashboard und im Browser-Tab, für jede empfangende Person gleich. Personalisieren Sie über prefill und context, nie über den Namen.
blocksErforderlich, 1 bis 200 Blöcke, in der Reihenfolge, in der das Formular sie zeigt. Die Blöcke in den Spalten einer Zeile und die Felder einer wiederholenden Gruppe zählen mit.
languageDie Oberflächensprache des Formulars. Standard: Englisch.
logo, cover, emojiIhre Marke, mit jedem Request gesendet. logo: { "type": "icon", "name": "HeartIcon" } oder { "type": "image", "url": "https://…" }. cover: { "type": "color", "color": "#0f4c81" } oder { "type": "image", "url": "https://…", "offsetY": 50 }. emoji: ein Emoji neben dem Namen. Siehe unten.
themeEin Aussehen pro Farbmodus: { "light": "solarized-light", "dark": "dracula" }. Jeder Modus nimmt eine Preset-ID, in jedem Plan kostenlos, oder ein ganzes Theme-Objekt, wie es das MCP-Tool formTheme_set nimmt; das braucht den Pro-Plan.
settingsDas Formularverhalten, das die Einstellungsseite festlegt: Branding, eine verifizierte E-Mail-Domain (emailDomainId), E-Mails an die Inhaber und an die antwortende Person samt Text, der Erinnerungsplan, die Einladungs-E-Mail, die Weiterleitung und die Aufbewahrung. Felder per Schlüssel: respondentNotificationTo ist der Schlüssel einer E-Mail-Frage, redirectQueryParams ordnet einem Parameter einen Feldschlüssel zu. E-Mail-Text ist reiner Text mit {{key}}-Platzhaltern. Keine Sperre per Passwort oder Anmeldung und keine Einstellung des Freigabelinks wie Bot-Schutz oder Bearbeiten nach dem Absenden: Eine Anfrage bringt ihren eigenen Link mit. Jeder andere Schlüssel wird abgelehnt.
translationsDas Formular in weiteren Sprachen, mit einer Sprachauswahl für die empfangende Person: { "de": { "Your name": "Ihr Name" } }, jeder Text des Formulars unter dem Text, wie die Blöcke ihn geschrieben haben. Siehe unten.

Blöcke

Ein Block nimmt die Parameter des passenden editor_insert*-Tools auf dem MCP-Server, ohne formId und after, plus einen optionalen key. Ohne ihn wird der Schlüssel aus dem Titel abgeleitet, aus „Full name” wird also full_name. Einen Parameter, den der Block nicht kennt, lehnt Formstep ab, statt ihn stillschweigend zu verwerfen.

ArtTypen
Fragentext, contact, number, date, time, radio, checkbox, select, switch, rating, linearScale, matrix, ranking, pictureChoice, file, signature, decision
Dokumentedocuments, um Dateien zu zeigen, die die empfangende Person liest oder unterschreibt
Zahlungen und Buchungenpayment, scheduleAppointment
Inhaltheader, paragraph, image (src-URL), embedded, table (cells füllt sie), list, row (columns: die Blöcke jeder Spalte, 2 bis 6 Spalten, und widths in Prozent). Mit einem optionalen key kann Logik den Block ein- oder ausblenden.
StrukturpageDivider, repeatingGroup (fields: die zugehörigen Fragen als Blöcke, jede mit ihrem key), hiddenField (key erforderlich: er ist der context-Schlüssel), calculatedField (sein name ist sein Schlüssel), logic

Text in header und paragraph, Listenpunkte und Tabellenzellen verstehen bold, italic, struck, <u>underlined</u>, code, $$equation$$, text, <span color=“red” background=“yellow” font=“font-georgia” size=“1.25”>…</span> mit den Farben, Schriften und Größen der Editor-Werkzeugleiste, und {{key}}, das den Wert des Felds mit diesem Schlüssel zeigt. Auszeichnungen lassen sich verschachteln; ein Zeichen ohne Gegenstück bleibt Text. Eine Spalte einer Zeile nimmt jeden Block außer pageDivider, logic, hiddenField, calculatedField, repeatingGroup, row und scheduleAppointment. Ein decision-Block nimmt seinen title und seine labels für Zustimmen, Ablehnen und Änderungen in der Sprache des Formulars.

Blöcke verweisen über den Schlüssel aufeinander, nie über die Element-ID: Ein logic-Block nimmt seine rule so wie editor_insertLogic, mit Feldschlüsseln dort, wo IDs erwartet werden, Optionslabels als Bedingungswerten und Seitennamen für setNextPage.

Zahlungen

Ein payment-Block nimmt amount und currency, oder amountFromField: den Schlüssel eines versteckten Felds oder einer Zahlenfrage. Mit einem versteckten Feld übergibt jeder Request seinen eigenen Betrag in context, sodass ein einziges Formular jeder Person ihren eigenen Betrag berechnet:

ein Formular, ein Betrag pro Request
json
{
  "form": {
    "name": "Pay your invoice",
    "blocks": [
      { "type": "hiddenField", "key": "invoice_total" },
      { "type": "payment", "key": "invoice", "title": "Invoice", "currency": "EUR", "amountFromField": "invoice_total" }
    ]
  },
  "recipient": { "email": "ada@example.com" },
  "context": { "invoice_total": 1200 }
}

Eine Zahlenfrage, die den Betrag festlegt, muss ein Pflichtfeld sein und ein min über 0 haben, damit niemand mit einem leeren, null oder negativen Betrag in den Checkout gelangt.

Das Formular rechnet über das Standard-Stripe-Konto des Workspace ab, oder über das Konto, das connection nennt. Eine Person verbindet Stripe einmal für den Workspace; eine Automation kann das nicht. Ohne nutzbares Konto schlägt der Aufruf fehl und sagt Ihnen, wo Sie es verbinden.

Buchungen

Ein scheduleAppointment-Block nimmt eventType, den Titel oder die ID eines Ereignistyps der Cal.com-Verbindung des Workspace, und connection, wenn der Workspace mehrere hat. Formstep sucht den Ereignistyp heraus, wenn der Request erstellt wird. prefill: { name, email } nennt die Fragen, deren Antworten die Buchung ausfüllen.

Ihre Marke

Eine Automation kann Ihren Auftritt nicht erfinden, also geben Sie ihn ihr einmal mit, und sie sendet ihn mit jedem Request: logo, cover und emoji neben den Blöcken, und theme für Farben und Schrift.

FeldNimmt
logoEin Icon aus dem Builder, { "type": "icon", "name": "HeartIcon" }, oder Ihr eigenes Bild, { "type": "image", "url": "https://…/logo.png" }.
coverEine Vollfarbe, { "type": "color", "color": "#0f4c81" }, oder ein Bild, { "type": "image", "url": "https://…/cover.jpg", "offsetY": 50 }, wobei offsetY von 0 bis 100 den sichtbaren Teil eines hohen Bildes wählt.
emojiEin Emoji, angezeigt neben dem Formularnamen.

Jedes Bild, einschließlich des src eines image-Blocks, muss ein öffentliches JPEG, PNG oder WebP sein. Formstep lädt jedes einmal, wenn das Formular erstellt wird, und behält eine eigene Kopie, sodass das Formular und die PDFs seiner Einreichungen die Quelle überdauern. Eine URL, die sich nicht laden lässt, lässt den Aufruf mit INLINE_FORM_IMAGE_UNREACHABLE fehlschlagen und nennt das Feld. Ohne Marke sieht das Formular aus wie ein neues Formular aus dem Dashboard.

Übersetzungen

translations veröffentlicht das Formular sofort in weiteren Sprachen, und die empfangende Person erhält die Sprachauswahl eines übersetzten Formulars: { "de": { "Your name": "Ihr Name", "Order for **{{customer}}**": "Bestellung für **{{customer}}**" } }. Jeder Text des Formulars muss enthalten sein, unter dem Text genau so, wie die Blöcke ihn geschrieben haben: Fragetitel, Optionen, Platzhalter, Überschriften, Absätze, Listenpunkte, Tabellenzellen, Gruppennamen und Schaltflächenbeschriftungen. Auszeichnungen und {{key}} bleiben wie in der Quelle. Fehlt ein Text, schlägt der Aufruf mit INLINE_FORM_TRANSLATION_MISSING fehl, das die fehlenden Texte auflistet. E-Mail-Texte werden nicht übersetzt.

Eine Definition, ein Formular

Ein späterer Aufruf mit demselben form-Objekt nutzt dasselbe Formular erneut, und die Antwort enthält “reused”: true. Hundert Requests mit einer Definition ergeben ein Formular, mit einem Satz Antworten zum Exportieren. Ändern Sie einen Block, den Namen, die Marke oder eine Übersetzung, entsteht ein neues Formular; bereits gesendete Requests behalten das Formular, mit dem sie erstellt wurden. Ein Formular, das Sie für Einreichungen schließen oder zurückziehen, wird nicht erneut genutzt: Der nächste Aufruf mit derselben Definition erstellt ein neues.

Erzeugt ein Aufruf ein neues Formular, obwohl ein offenes Inline-Formular dieselben Blocktypen in derselben Reihenfolge hat, nennt das Ergebnis des Aufrufs dieses Formular in form.similarForm. Meist war ein geänderter Name oder Titel der Grund. Um alle Antworten auf ein Inline-Formular zu lesen, listen Sie seine Einreichungen auf, statt jede Anfrage einzeln zu lesen.

Im Dashboard

Ein Inline-Formular gehört zu seiner Anfrage, deshalb steht es auf der Seite der Anfrage statt in der Formularliste. Die Seite listet die Antworten nach Feldschlüssel, und Vorschau öffnet das Formular so, wie die empfangende Person es gesehen hat, ausgefüllt mit ihren Antworten. Ein Link zum Editor oder zu den Einreichungen eines Inline-Formulars öffnet stattdessen die Anfragen-Seite, gefiltert auf dieses Formular. Agenten sehen Inline-Formulare weiterhin in form_list, und die API lehnt Änderungen an ihnen ab.

Ein Inline-Formular hat keinen Freigabelink, und Sie können keinen hinzufügen: Seine Requests sind der einzige Zugang, und der Callback trägt jede Antwort. Integrationen hat es ebenfalls keine.

Da es keine eigene Seite hat, wird ein Inline-Formular nie von Hand gelöscht. Es geht mit seinem letzten Request: Wenn Sie einen Request löschen oder der Aufbewahrungszeitraum des Formulars ihn entfernt und kein anderer Request das Formular noch verwendet, wird auch das Formular gelöscht.

Wenn der Aufruf abgelehnt wird

Jede Ablehnung ist ein VALIDATION_ERROR, auf dessen details.reason Ihre Automation verzweigen kann. Es wird nichts erstellt.

GrundWas zu tun ist
FORM_SOURCE_MISSING / FORM_SOURCE_AMBIGUOUSSenden Sie genau eines von formId und form.
INLINE_FORM_INVALIDEin Block oder ein Feld von form verletzt sein Schema. details.issues nennt jedes davon.
INLINE_FORM_DUPLICATE_KEYZwei Blöcke ergeben denselben Schlüssel. Geben Sie einem davon einen eigenen key.
INLINE_FORM_UNKNOWN_KEYEine Logikregel, amountFromField oder ein Buchungs-prefill nennt einen Schlüssel, den kein Block hat.
INLINE_FORM_AMOUNT_MISSINGÜbergeben Sie in context eine positive Zahl für das Betragsfeld.
INLINE_FORM_CONNECTION_MISSINGStripe oder Cal.com ist nicht verbunden. details.connectUrl ist die Seite, die eine Person einmal öffnet, um es zu verbinden.
INLINE_FORM_EVENT_TYPE_NOT_FOUNDKein Cal.com-Ereignistyp passt. Der Fehler listet die vorhandenen auf.
INLINE_FORM_IMAGE_UNREACHABLEEine Bild-URL ist kein öffentliches JPEG, PNG oder WebP. details.field nennt sie. Nutzen Sie eine URL, die jeder öffnen kann, oder lassen Sie das Bild weg.
INLINE_FORM_TRANSLATION_MISSINGEiner Übersetzung fehlen Texte, die das Formular hat. details.missing listet sie auf, so wie sie in den Blöcken stehen.
INLINE_FORM_PUBLISH_ISSUESDie Veröffentlichung hat das Formular abgelehnt, zum Beispiel wegen eines Ereignistyps, der sich nicht aus einem Formular buchen lässt.

Aus einem Agenten

Auf dem MCP-Server nimmt request_create dasselbe form. Bevor ein Agent ein Formular mit einer Zahlung oder einer Buchung baut, liest er workspaceConnection_list: Es zeigt die verbundenen Stripe- und Cal.com-Konten und, wenn eines fehlt, den Link, den eine Person einmal öffnen muss. scheduler_listEventTypes listet die Ereignistypen, die eine Buchung nennen kann, und paymentConnection_setDefault ändert das Standard-Stripe-Konto. Über die REST-API heißen dieselben drei connections.list, scheduler.listEventTypes und paymentConnections.setDefault.