Créer un formulaire web
Créer un formulaire web et ses champs, le modifier, lui faire créer une fiche à chaque envoi, le faire remplir par sa page publique ou une invitation par email, et faire valider ses listes de fiches.
Un formulaire web est un modèle de formulaire : ses champs, sa mise en page, sa page publique. Chaque envoi d'un visiteur en crée une réponse, une instance du formulaire. L'API crée et modifie le formulaire ; les réponses naissent des envois, sur la page publique.
1Créer le formulaire et ses champs
Le formulaire et tous ses champs partent d'un seul appel :
POST https://staging-api.docage.com/Forms
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9…
Content-Type: application/json
{
"Name": "Demande de rappel",
"IsTemplate": true,
"Fields": [
{ "Type": "header", "Subtype": "h2", "Name": "Titre", "Label": "Être rappelé" },
{ "Type": "text", "Subtype": "text", "Name": "Nom", "Label": "Nom", "Required": true, "RowIndex": 1, "ColumnWidth": 6 },
{ "Type": "text", "Subtype": "email", "Name": "Email", "Label": "Email", "Required": true, "RowIndex": 1, "ColumnWidth": 6 },
{ "Type": "radio-group", "Name": "Moment", "Label": "Quand vous rappeler ?", "Required": true, "Values": [
{ "Label": "Le matin", "Value": "matin" },
{ "Label": "L'après-midi", "Value": "apres-midi" }
] },
{ "Type": "textarea", "Name": "Message", "Label": "Votre message" },
{ "Type": "checkbox", "Name": "Accord", "Label": "Consentement", "Required": true, "Values": [
{ "Label": "J'accepte d'être rappelé", "Value": "oui" }
] }
]
}curl -X POST "https://staging-api.docage.com/Forms" \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9…" \
-H "Content-Type: application/json" \
-d '{
"Name": "Demande de rappel",
"IsTemplate": true,
"Fields": [{"Type": "header", "Subtype": "h2", "Name": "Titre", "Label": "Être rappelé"}, {"Type": "text", "Subtype": "text", "Name": "Nom", "Label": "Nom", "Required": true, "RowIndex": 1, "ColumnWidth": 6}, {"Type": "text", "Subtype": "email", "Name": "Email", "Label": "Email", "Required": true, "RowIndex": 1, "ColumnWidth": 6}, {"Type": "radio-group", "Name": "Moment", "Label": "Quand vous rappeler ?", "Required": true, "Values": [{"Label": "Le matin", "Value": "matin"}, {"Label": "L'\''après-midi", "Value": "apres-midi"}]}, {"Type": "textarea", "Name": "Message", "Label": "Votre message"}, {"Type": "checkbox", "Name": "Accord", "Label": "Consentement", "Required": true, "Values": [{"Label": "J'\''accepte d'\''être rappelé", "Value": "oui"}]}]
}'using HttpClient client = new();
using HttpRequestMessage request = new(HttpMethod.Post, "https://staging-api.docage.com/Forms");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
request.Content = new StringContent("""
{
"Name": "Demande de rappel",
"IsTemplate": true,
"Fields": [
{
"Type": "header",
"Subtype": "h2",
"Name": "Titre",
"Label": "Être rappelé"
},
{
"Type": "text",
"Subtype": "text",
"Name": "Nom",
"Label": "Nom",
"Required": true,
"RowIndex": 1,
"ColumnWidth": 6
},
{
"Type": "text",
"Subtype": "email",
"Name": "Email",
"Label": "Email",
"Required": true,
"RowIndex": 1,
"ColumnWidth": 6
},
{
"Type": "radio-group",
"Name": "Moment",
"Label": "Quand vous rappeler ?",
"Required": true,
"Values": [
{
"Label": "Le matin",
"Value": "matin"
},
{
"Label": "L'après-midi",
"Value": "apres-midi"
}
]
},
{
"Type": "textarea",
"Name": "Message",
"Label": "Votre message"
},
{
"Type": "checkbox",
"Name": "Accord",
"Label": "Consentement",
"Required": true,
"Values": [
{
"Label": "J'accepte d'être rappelé",
"Value": "oui"
}
]
}
]
}
""", Encoding.UTF8, "application/json");
using HttpResponseMessage response = await client.SendAsync(request);
string result = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
throw new HttpRequestException(result);const response = await fetch("https://staging-api.docage.com/Forms", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"Name": "Demande de rappel",
"IsTemplate": true,
"Fields": [{"Type": "header", "Subtype": "h2", "Name": "Titre", "Label": "Être rappelé"}, {"Type": "text", "Subtype": "text", "Name": "Nom", "Label": "Nom", "Required": true, "RowIndex": 1, "ColumnWidth": 6}, {"Type": "text", "Subtype": "email", "Name": "Email", "Label": "Email", "Required": true, "RowIndex": 1, "ColumnWidth": 6}, {"Type": "radio-group", "Name": "Moment", "Label": "Quand vous rappeler ?", "Required": true, "Values": [{"Label": "Le matin", "Value": "matin"}, {"Label": "L'après-midi", "Value": "apres-midi"}]}, {"Type": "textarea", "Name": "Message", "Label": "Votre message"}, {"Type": "checkbox", "Name": "Accord", "Label": "Consentement", "Required": true, "Values": [{"Label": "J'accepte d'être rappelé", "Value": "oui"}]}]
})
});
const text = await response.text();
if (!response.ok) throw new Error(text);
const result = text ? JSON.parse(text) : null;La réponse est l'identifiant du formulaire, en chaîne JSON.
IsTemplate:true. Sans lui, la fiche serait une réponse : elle n'aurait pas de page publique.- Chaque champ a un
Type(ci-dessous), unName— son nom technique, sous lequel la réponse garde la saisie —, unLabel— le texte que voit le visiteur — et, au besoin,Required. - La mise en page suit une grille de 12 colonnes :
ColumnWidthest la largeur du champ (12 d'office, toute la ligne) ; les champs qui portent le mêmeRowIndex, supérieur à 0, partagent une ligne. - Une option se donne par son libellé et sa valeur :
{ "Label": "Le matin", "Value": "matin" }. Le visiteur voit le libellé, la réponse garde la valeur.
Les types de champ
Type |
Ce que le visiteur fait |
|---|---|
text |
Il saisit une ligne ; Subtype : text, email ou tel. |
textarea |
Il saisit un texte sur plusieurs lignes. |
number |
Il saisit un nombre, borné par Min et Max. |
date |
Il choisit une date ; Subtype time pour une heure, datetime-local pour une date et une heure. |
select |
Il choisit dans une liste ; Multiple à true : plusieurs valeurs. |
radio-group, button-group |
Il choisit une option ; Multiple à true sur button-group : plusieurs. |
checkbox-group |
Il coche une ou plusieurs options. |
checkbox |
Il coche une case : son texte est le Label de son unique option. |
tags, country, rating, date-range |
Il donne des étiquettes, un pays, une note, un intervalle de dates. |
file |
Il dépose un fichier ; Multiple à true : plusieurs. |
header, paragraph |
Il lit : un titre (Subtype h1, h2 ou h3) ou un paragraphe, dont le texte est le Label. |
step |
Il avance d'étape en étape : les champs qui suivent une étape lui appartiennent ; l'indicateur paraît dès deux étapes. |
Nommer les champs
Donnez à chaque champ un nom unique, fait de lettres et de chiffres, sans accent, sans espace et sans _ : Prenom,
EmailPro. Un nom qui ne suit pas cette forme est réécrit, à la création comme à la modification — « Prénom » devient « Prenom »,
un nom vide prend celui de son libellé, un doublon reçoit un numéro ; un nom qui porte un _ (Contact_LastName) désigne une
donnée d'une fiche et reste tel quel. Relisez les noms après chaque écriture : ce sont eux que lisent les réponses, les conditions
et les calculs.
2Modifier le formulaire
Relisez d'abord ses champs (GET https://staging-api.docage.com/Forms/{id}), puis renvoyez la liste entière :
PUT https://staging-api.docage.com/Forms/33333333-0000-4000-8000-000000000003
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9…
Content-Type: application/json
{
"Fields": [ … ],
"RedirectionUrl": "https://www.example.com/merci"
}Fields remplace la liste en base : un champ absent est supprimé. RedirectionUrl est la page ouverte après l'envoi.
| Code | Ce qu'il dit |
|---|---|
400 |
Le corps est vide. |
403 |
Vous n'avez pas le droit de modifier le formulaire, ou il est à la corbeille. |
404 |
Le formulaire est introuvable, ou vous ne le voyez pas. |
409 |
Un champ est mal configuré, ou c'est un champ système verrouillé : le message dit lequel. |
422 |
Une valeur est refusée : le message dit laquelle. |
Les réponses déjà reçues ne changent pas : chacune garde les champs du jour de son envoi.
3Créer une fiche à chaque envoi
Un champ de création fait créer une fiche à chaque envoi, rattachée à la réponse :
{ "Type": "create-contact", "Name": "Contact", "Label": "Vos coordonnées" }Sans Fields, le visiteur voit les saisies que prévoit le type de fiche (le prénom, le nom, l'email… d'un contact).
Type |
La fiche créée |
|---|---|
create-contact |
Un nouveau contact. |
create-document |
Un document, rempli des réponses. |
create-mail |
Un email, envoyé à l'envoi du formulaire ; KeepAsDraft à true : gardé en brouillon. |
create-card |
Une carte de pipeline : DefinitionId (le type de carte) et PipelineId (un pipeline de ce type), StageId facultatif. |
create-custom-object |
Un objet personnalisé : DefinitionId (son type). |
CreationTemplateId: le modèle dont la fiche est tirée ; vide, le modèle par défaut des préférences, sinon aucun.LinkedTo: le nom du champcreate-contactauquel une carte ou un email se rattache ; vide, le seul du formulaire.IsIterableàtrue: le visiteur peut en remplir plusieurs, une fiche par itération.
Un champ de création ne se pose que dans un formulaire web, jamais dans un sous-formulaire ; son nom ne porte ni espace, ni _,
ni ., ni crochet, et deux champs de création ne portent pas le même nom. Sinon, l'enregistrement est refusé (409, avec le
motif). La réponse dit les fiches créées : voir Lire les réponses d'un formulaire.
Un champ « Paiement » (payment) fait de même régler une somme à chaque envoi : voir
Faire régler une somme.
4Le faire remplir
GET https://staging-api.docage.com/Forms/33333333-0000-4000-8000-000000000003
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9…curl "https://staging-api.docage.com/Forms/33333333-0000-4000-8000-000000000003" \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9…"using HttpClient client = new();
using HttpRequestMessage request = new(HttpMethod.Get, "https://staging-api.docage.com/Forms/33333333-0000-4000-8000-000000000003");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
using HttpResponseMessage response = await client.SendAsync(request);
string result = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
throw new HttpRequestException(result);const response = await fetch("https://staging-api.docage.com/Forms/33333333-0000-4000-8000-000000000003", {
headers: {
Authorization: `Bearer ${token}`
}
});
const text = await response.text();
if (!response.ok) throw new Error(text);
const result = text ? JSON.parse(text) : null;IntegrationLink est l'adresse de sa page publique, sur l'application de votre marque (https://staging-app.docage.com/Forms/Form?formId=…) :
- partagez-la, ou mettez-la dans un email — voir Envoyer un email ;
- intégrez-la à votre site, dans un cadre : la page s'y affiche.
ViewCount et SubmitCount comptent les affichages et les envois de la page.
Un formulaire se remplit aussi dans un parcours : l'action « Formulaire » (Type 0) d'un participant le désigne par son FormId
(POST https://staging-api.docage.com/TransactionActions), et le participant le remplit à son tour, sur sa page.
Inviter une personne par email
L'API compose l'email qui invite une personne — un contact ou un utilisateur — à remplir le formulaire, pré-rempli de ses données :
PUT https://staging-api.docage.com/Forms/CreateFormInvitationMail/33333333-0000-4000-8000-000000000003/%7B%22TypeName%22%3A%22Contact%22%2C%22Id%22%3A%2200000000-0000-4000-8000-000000000201%22%7D
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9…curl -X PUT "https://staging-api.docage.com/Forms/CreateFormInvitationMail/33333333-0000-4000-8000-000000000003/%7B%22TypeName%22%3A%22Contact%22%2C%22Id%22%3A%2200000000-0000-4000-8000-000000000201%22%7D" \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9…"using HttpClient client = new();
using HttpRequestMessage request = new(HttpMethod.Put, "https://staging-api.docage.com/Forms/CreateFormInvitationMail/33333333-0000-4000-8000-000000000003/%7B%22TypeName%22%3A%22Contact%22%2C%22Id%22%3A%2200000000-0000-4000-8000-000000000201%22%7D");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
using HttpResponseMessage response = await client.SendAsync(request);
string result = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
throw new HttpRequestException(result);const response = await fetch("https://staging-api.docage.com/Forms/CreateFormInvitationMail/33333333-0000-4000-8000-000000000003/%7B%22TypeName%22%3A%22Contact%22%2C%22Id%22%3A%2200000000-0000-4000-8000-000000000201%22%7D", {
method: "PUT",
headers: {
Authorization: `Bearer ${token}`
}
});
const text = await response.text();
if (!response.ok) throw new Error(text);
const result = text ? JSON.parse(text) : null;Le dernier segment de l'adresse est la personne, en JSON encodé : {"TypeName":"Contact","Id":"…"}, où TypeName vaut Contact
ou DocageUser. L'email part du modèle d'invitation choisi dans les réglages d'emails du formulaire, sinon de celui de la
plateforme ; son lien ouvre la page publique, pré-remplie. C'est un brouillon, que rien n'envoie : la réponse donne son
identifiant et son nom (Id, Name) ; relisez-le, puis envoyez-le par POST https://staging-api.docage.com/Mails/Send/{id}.
| Code | Ce qu'il dit |
|---|---|
400 |
La personne est illisible, ou n'est ni un contact ni un utilisateur. |
404 |
Le formulaire ou la personne est introuvable, ou vous ne le voyez pas. |
422 |
Le formulaire n'est pas un modèle de formulaire web, ou le modèle d'email d'invitation de ses réglages n'existe plus, ou vous n'y avez pas accès. |
5Faire valider les listes de fiches
Un champ à options dont la liste vient de fiches ou d'un tableur (sa Source) ne la montre au visiteur qu'une fois son
exposition validée par un administrateur de l'organisation du formulaire : la page publique compose alors la liste avec les
droits de lecture de cet administrateur. Jusque-là, elle reste vide.
GET https://staging-api.docage.com/Forms/33333333-0000-4000-8000-000000000003/Exposure
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9…curl "https://staging-api.docage.com/Forms/33333333-0000-4000-8000-000000000003/Exposure" \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9…"using HttpClient client = new();
using HttpRequestMessage request = new(HttpMethod.Get, "https://staging-api.docage.com/Forms/33333333-0000-4000-8000-000000000003/Exposure");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
using HttpResponseMessage response = await client.SendAsync(request);
string result = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
throw new HttpRequestException(result);const response = await fetch("https://staging-api.docage.com/Forms/33333333-0000-4000-8000-000000000003/Exposure", {
headers: {
Authorization: `Bearer ${token}`
}
});
const text = await response.text();
if (!response.ok) throw new Error(text);
const result = text ? JSON.parse(text) : null;La réponse dit, pour chacun de ces champs (Fields), l'état de sa validation — Status : None, Pending (demandée) ou
Approved — et si vous pouvez la donner vous-même (CanApprove).
- Administrateur de l'organisation :
POST https://staging-api.docage.com/Forms/{id}/Exposure/Approvevalide toutes les listes qui ne le sont pas. - Sinon, demandez-la à l'un des administrateurs que liste
GET https://staging-api.docage.com/Forms/ExposureApprovers:POST https://staging-api.docage.com/Forms/{id}/Exposure/Request, avec{ "ApproverId": "…" }; il en est prévenu dans l'application.
Une validation vaut pour une liste précise : changer la source du champ — type de fiche, filtre, tableur, colonnes — la fait tomber,
et elle ne vaut plus quand l'administrateur qui l'a donnée perd son rôle. Les mêmes routes valent pour les champs d'un document
(GET https://staging-api.docage.com/Documents/{id}/Exposure) et pour les zones posées sur les documents d'un parcours (GET https://staging-api.docage.com/Transactions/{id}/Exposure).
| Code | Ce qu'il dit |
|---|---|
400 |
La demande ne désigne aucun administrateur. |
403 |
Vous voyez le formulaire sans pouvoir le modifier, ou vous n'êtes pas administrateur de son organisation. |
404 |
Le formulaire est introuvable, ou vous ne le voyez pas. |
422 |
La personne choisie n'est pas administrateur de l'organisation du formulaire. |
Les pièges
- Un champ d'un
Typeinconnu est perdu, sans erreur : relisez le formulaire après chaque écriture. - Une propriété que l'écriture ne sait pas lire est ignorée sans erreur, comme pour toute fiche — voir Créer et modifier.
- Un formulaire système ne se modifie pas (
403) : tirez-en une copie parPOST https://staging-api.docage.com/Forms/Duplicate, avec la liste de ses identifiants ; la réponse associe à chacun l'identifiant de sa copie. - Les options tirées d'une liste de fiches ou d'un tableur restent vides sur la page publique tant que leur exposition n'est pas validée (étape 5).
TransactionTemplateId, le modèle de parcours pour lequel le formulaire est écrit (ses champs en citent les participants), est un modèle de parcours actif de votre organisation, ou de la plateforme, que vous voyez : sinon l'écriture est refusée (422). Un participant renommé dans ce modèle l'est aussi dans le formulaire.- Ce qu'un envoi déclenche — les fiches des champs de création, un paiement — ne part que d'un envoi sur la page publique.