Demandes
Créer un formulaire et une demande en un seul appel
Un agent au téléphone avec une cliente apprend qu’elle doit encore envoyer deux fiches de paie, payer des frais de 40 EUR et réserver un appel. Il envoie le formulaire et la demande dans le même appel, et Formstep s’occupe du reste.
Quand l’utiliser
Une demande pointe d’ordinaire vers un formulaire que quelqu’un a créé dans l’éditeur et publié. Quand les questions dépendent du dossier,
l’appelant les envoie avec la demande : requests.create accepte form à la place de formId. Formstep
crée un formulaire ordinaire à partir des blocs, le publie et crée la demande en une seule étape : soit les deux existent, soit aucun.
Nous l’appelons un formulaire inline.
Continuez d’utiliser formId pour un formulaire que vous envoyez à beaucoup de personnes sous la même forme et que vous voulez
concevoir à la main dans l’éditeur. Utilisez form quand une automatisation décide de ce qu’il faut demander.
L’appel
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"}}'Tout le reste de la demande garde son sens : recipient, prefill, context, readonly,
delivery, les rappels, l’expiration, callbackUrl, test et idempotencyKey sont vérifiés
par rapport au nouveau formulaire exactement comme pour un formulaire créé à la main. La réponse ajoute le formulaire, avec les clés sous
lesquelles ses réponses reviennent :
{
"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" }
]
}
}Pour préremplir une question à choix dans le même appel, envoyez des clés d’option, comme pour tout formulaire. La clé d’une option est
dérivée de son libellé : Self-employed devient self_employed. Un libellé à la place d’une clé échoue avec
INVALID_PREFILL_VALUE, qui liste les clés valides.
L’objet form
| Champ | Ce que ça fait |
|---|---|
| name | Obligatoire, de 1 à 100 caractères. Le nom affiché dans le tableau de bord et dans l’onglet du navigateur, le même pour chaque destinataire. Personnalisez avec prefill et context, jamais avec le nom. |
| blocks | Obligatoire, de 1 à 200 blocs, dans l’ordre où le formulaire les affiche. Les blocs des colonnes d’une ligne et les champs d’un groupe répétable comptent aussi. |
| language | La langue de l’interface du formulaire. Par défaut : l’anglais. |
| logo, cover, emoji | Votre identité visuelle, envoyée avec chaque demande. logo : { "type": "icon", "name": "HeartIcon" } ou { "type": "image", "url": "https://…" }. cover : { "type": "color", "color": "#0f4c81" } ou { "type": "image", "url": "https://…", "offsetY": 50 }. emoji : un emoji à côté du nom. Voir plus bas. |
| theme | Une apparence par mode de couleur : { "light": "solarized-light", "dark": "dracula" }. Chaque mode prend l’id d’un préréglage, gratuit sur tous les plans, ou un objet de thème complet tel que le prend l’outil MCP formTheme_set, ce qui demande le plan Pro. |
| settings | Le comportement du formulaire que règle la page des paramètres : l’identité visuelle, un domaine d’e-mail vérifié (emailDomainId), les e-mails au propriétaire et au répondant avec leur texte, le calendrier des relances, l’e-mail d’invitation, la redirection et la conservation. Champs par clé : respondentNotificationTo est la clé d’une question e-mail, redirectQueryParams associe un paramètre à une clé de champ. Le texte des e-mails est du texte brut avec des repères {{key}}. Aucune barrière de mot de passe ou de connexion, et aucun réglage de lien de partage comme la protection anti-robots ou les modifications après envoi : une demande porte son propre lien. Toute autre clé est refusée. |
| translations | Le formulaire dans d’autres langues, avec un sélecteur de langue pour le destinataire : { "de": { "Your name": "Ihr Name" } }, chaque texte du formulaire ayant pour clé le texte tel que les blocs l’ont écrit. Voir plus bas. |
Les blocs
Un bloc prend les paramètres de l’outil editor_insert* correspondant du serveur MCP,
sans formId ni after, plus une key facultative. Sans elle, la clé est dérivée du titre : « Full
name » devient full_name. Un paramètre que le bloc ne connaît pas est refusé plutôt qu’ignoré.
| Catégorie | Types |
|---|---|
| Questions | text, contact, number, date, time, radio, checkbox, select, switch, rating, linearScale, matrix, ranking, pictureChoice, file, signature, decision |
| Documents | documents, pour montrer des fichiers que le destinataire lit ou signe |
| Paiements et rendez-vous | payment, scheduleAppointment |
| Contenu | header, paragraph, image (URL dans src), embedded, table (cells la remplit), list, row (columns : les blocs de chaque colonne, de 2 à 6 colonnes, et widths en pourcentage). Une key facultative permet à la logique d’afficher ou de masquer le bloc. |
| Structure | pageDivider, repeatingGroup (fields : les questions membres sous forme de blocs, chacune avec sa clé), hiddenField (key obligatoire : c’est la clé de context), calculatedField (son name est sa clé), logic |
Le texte de header et paragraph, les éléments de liste et les cellules de tableau acceptent bold, italic,
, struck<u>underlined</u>, , code$$equation$$,
text, <span color=“red” background=“yellow” font=“font-georgia” size=“1.25”>…</span>
avec les couleurs, polices et tailles de la barre d’outils de l’éditeur, et {{key}}, qui affiche la valeur du champ
portant cette clé. Les marques s’imbriquent ; un marqueur sans son pendant reste du texte. Une colonne d’une ligne accepte tout bloc sauf
pageDivider, logic, hiddenField, calculatedField, repeatingGroup, row et scheduleAppointment. Un bloc decision prend son
title et ses labels pour approuver, refuser et demander des modifications, dans la langue du formulaire.
Les blocs se désignent entre eux par leur clé, jamais par un id d’élément : un bloc logic prend sa rule comme
editor_insertLogic, avec des clés de champ là où il attend des ids, des libellés d’option comme valeurs de condition et des
noms de page pour setNextPage.
Paiements
Un bloc payment prend amount et currency, ou amountFromField : la clé d’un champ caché
ou d’une question numérique. Avec un champ caché, chaque demande passe son propre montant dans context, si bien qu’un seul
formulaire facture à chaque client son propre montant :
{
"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 }
}Une question numérique qui fixe le montant doit être obligatoire et avoir un min supérieur à 0, pour que personne n’arrive au
checkout avec un montant vide, nul ou négatif.
Le formulaire encaisse par le compte Stripe par défaut de l’espace de travail, ou par celui que connection désigne. Une
personne connecte Stripe une fois pour l’espace de travail ; une
automatisation ne le peut pas. Sans compte utilisable, l’appel échoue et vous indique où le connecter.
Rendez-vous
Un bloc scheduleAppointment prend eventType, le titre ou l’id d’un type d’événement de la connexion
Cal.com de l’espace de travail, et connection quand l’espace de travail en a
plusieurs. Formstep recherche le type d’événement au moment où la demande est créée. prefill: { name, email } désigne les
questions dont les réponses remplissent la réservation.
Votre identité visuelle
Une automatisation ne peut pas inventer votre identité visuelle, alors vous la lui donnez une fois et elle l’envoie avec chaque demande :
logo, cover et emoji à côté des blocs, et theme pour les couleurs et la typographie.
| Champ | Valeur |
|---|---|
| logo | Une icône de l’éditeur, { "type": "icon", "name": "HeartIcon" }, ou votre propre image, { "type": "image", "url": "https://…/logo.png" }. |
| cover | Une couleur unie, { "type": "color", "color": "#0f4c81" }, ou une image, { "type": "image", "url": "https://…/cover.jpg", "offsetY": 50 }, où offsetY, de 0 à 100, choisit la partie visible d’une image haute. |
| emoji | Un emoji, affiché à côté du nom du formulaire. |
Chaque image, y compris le src d’un bloc image, doit être un JPEG, PNG ou WebP public. Formstep récupère chacune une fois à
la création du formulaire et en garde sa propre copie : le formulaire et les PDF de ses soumissions survivent ainsi à la source. Une URL
impossible à récupérer fait échouer l’appel avec INLINE_FORM_IMAGE_UNREACHABLE, qui nomme le champ. Sans identité visuelle,
le formulaire ressemble à un nouveau formulaire créé depuis le tableau de bord.
Traductions
translations publie le formulaire dans d’autres langues en une fois, et le destinataire obtient le sélecteur de langue d’un
formulaire traduit :
{ "de": { "Your name": "Ihr Name", "Order for **{{customer}}**": "Bestellung für **{{customer}}**" } }. Chaque texte du
formulaire doit y figurer, avec pour clé le texte exactement tel que les blocs l’ont écrit : titres de question, options, textes
indicatifs, en-têtes, paragraphes, éléments de liste, cellules de tableau, noms de groupe et libellés de bouton. Les marques et
{{key}} restent comme dans la source. Un texte manquant fait échouer l’appel avec
INLINE_FORM_TRANSLATION_MISSING, qui liste les textes à ajouter. Le texte des e-mails n’est pas traduit.
Une définition, un formulaire
Un appel ultérieur avec le même objet form réutilise le même formulaire, et la réponse indique “reused”: true.
Cent demandes avec une même définition donnent un seul formulaire, avec un seul ensemble de réponses à exporter. Modifier un bloc, le nom,
l’identité visuelle ou une traduction crée un nouveau formulaire ; les demandes déjà envoyées gardent le formulaire avec lequel elles ont
été créées. Un formulaire fermé ou dépublié n’est pas réutilisé : l’appel suivant avec la même définition en crée un nouveau.
Personnalisez avec prefill et context
Placez le nom du client, le numéro de facture ou le montant dans prefill et context, jamais dans le nom du
formulaire, un titre ou un montant fixe. Une définition qui change à chaque client crée un nouveau formulaire par client. Définissez
key sur chaque question : une clé dérivée suit le titre, donc une question renommée répond sous une nouvelle clé. Un espace
de travail crée au plus 300 nouveaux formulaires inline par jour ; au-delà, un appel qui créerait un nouveau formulaire échoue avec
RATE_LIMITED, tandis que les appels qui réutilisent un formulaire continuent de fonctionner.
Quand un appel crée un nouveau formulaire alors qu’un formulaire inline ouvert a les mêmes types de blocs dans le même ordre, la réponse
nomme ce formulaire dans form.similarForm. Le plus souvent, un nom ou un titre modifié en est la cause. Pour lire toutes les
réponses à un formulaire inline, listez ses soumissions au lieu de lire chaque demande.
Dans le tableau de bord
Un formulaire inline appartient à sa demande : il vit donc sur la page de la demande plutôt que sur la page Formulaires. La page liste les
réponses par clé de champ, et Aperçu ouvre le formulaire tel que le destinataire l’a vu, rempli avec ses réponses. Un
lien vers l’éditeur ou les réponses d’un formulaire inline ouvre à la place la page Demandes filtrée sur ce formulaire. Les agents voient
toujours les formulaires inline dans form_list, et l’API refuse de les modifier.
Un formulaire inline n’a pas de lien de partage, et on ne peut pas en ajouter : ses demandes sont le seul moyen d’y accéder, et le callback transporte toutes les réponses. Il n’a pas non plus d’intégrations.
Comme il n’a pas de page propre, un formulaire inline n’est jamais supprimé à la main. Il disparaît avec sa dernière demande : quand vous supprimez une demande, ou que la période de conservation du formulaire la supprime, et qu’aucune autre demande n’utilise encore le formulaire, le formulaire est supprimé lui aussi.
Quand l’appel est refusé
Chaque refus est une VALIDATION_ERROR dont votre automatisation peut lire le details.reason pour choisir la
suite. Rien n’est créé.
| Motif | Que faire |
|---|---|
| FORM_SOURCE_MISSING / FORM_SOURCE_AMBIGUOUS | Envoyez exactement l’un des deux : formId ou form. |
| INLINE_FORM_INVALID | Un bloc ou un champ de form ne respecte pas son schéma. details.issues les nomme un par un. |
| INLINE_FORM_DUPLICATE_KEY | Deux blocs aboutissent à la même clé. Donnez à l’un d’eux sa propre clé. |
| INLINE_FORM_UNKNOWN_KEY | Une règle de logique, amountFromField ou un prefill de rendez-vous désigne une clé qu’aucun bloc ne porte. |
| INLINE_FORM_AMOUNT_MISSING | Passez un nombre positif pour le champ du montant dans context. |
| INLINE_FORM_CONNECTION_MISSING | Stripe ou Cal.com n’est pas connecté. details.connectUrl est la page qu’une personne ouvre une fois pour le connecter. |
| INLINE_FORM_EVENT_TYPE_NOT_FOUND | Aucun type d’événement Cal.com ne correspond. L’erreur liste ceux qui existent. |
| INLINE_FORM_IMAGE_UNREACHABLE | Une URL d’image n’est pas un JPEG, PNG ou WebP public. details.field la nomme. Utilisez une URL que tout le monde peut ouvrir, ou retirez l’image. |
| INLINE_FORM_TRANSLATION_MISSING | Une traduction omet des textes du formulaire. details.missing les liste, tels qu’écrits dans les blocs. |
| INLINE_FORM_PUBLISH_ISSUES | La publication a refusé le formulaire, par exemple à cause d’un type d’événement qu’on ne peut pas réserver depuis un formulaire. |
Depuis un agent
Sur le serveur MCP, request_create accepte le même form. Avant de créer un formulaire avec un paiement ou un
rendez-vous, un agent lit workspaceConnection_list : l’outil montre les comptes Stripe et Cal.com connectés et, quand l’un
manque, le lien qu’une personne doit ouvrir une fois. scheduler_listEventTypes liste les types d’événement qu’un rendez-vous
peut désigner, et paymentConnection_setDefault change le compte Stripe par défaut. Avec l’API REST, ces trois outils
s’appellent connections.list, scheduler.listEventTypes et paymentConnections.setDefault.