Questionnaires
Guide each visitor to the answer that fits them.
Every answer carries weights towards one or more profiles. The profile with the highest total decides which result page is shown — a page built in the editor, like any other.
Questionnaires
Every answer carries weights towards one or more profiles. The profile with the highest total decides which result page is shown — a page built in the editor, like any other.
A questionnaire is made of four objects. Understand them, and you can build any questionnaire you like.
The test
Its title, its slug, its introduction page. It starts out inactive: a half-built questionnaire would give wrong results.
The profiles
The possible outcomes. Each one points to the page shown to whoever gets it, and can also be awarded by overall score.
The questions
Single or multiple choice, in order. An inactive question can still be edited, but is no longer asked.
The weights
Carried by each answer, towards one or more profiles. They are the only input to the calculation.
1 — Create the test
It starts out inactive. You switch it on once profiles, questions and weights are in place.
POST /api/agent/v1/questionnaires/creer/
{
"titre": "Which kind of support suits you?",
"slug": "which-support",
"description": "Eight questions, two minutes.",
"page_de_presentation": 118
}
→ 201 { "questionnaire": { "id": 4, "actif": false } }
2 — Declare the profiles
Each profile points to the page shown to whoever gets it. The first two are reached through weights; the third through an overall score, which catches the undecided.
POST /api/agent/v1/questionnaires/4/profils/
{ "nom": "Self-reliant", "slug": "self-reliant",
"description": "Knows where they are going, wants a tool.",
"page_de_resultat": 120 }
POST /api/agent/v1/questionnaires/4/profils/
{ "nom": "Supported", "slug": "supported",
"page_de_resultat": 121 }
POST /api/agent/v1/questionnaires/4/profils/
{ "nom": "Still thinking", "slug": "still-thinking",
"page_de_resultat": 122,
"attribue_par_score": true,
"score_min": 0, "score_max": 6 }
3 — Ask a question and set its weights
Weights are what the calculation is made of. One answer can feed several profiles with different strengths — which is what keeps a questionnaire from being black and white.
POST /api/agent/v1/questionnaires/4/questions/
{
"texte": "Where are you with your current website?",
"type": "single",
"rang": 1,
"reponses": [
{ "texte": "I don't have one yet",
"poids": { "supported": 3, "still-thinking": 2 } },
{ "texte": "I have one, it no longer suits me",
"poids": { "self-reliant": 2, "supported": 2 } },
{ "texte": "I have one and want to run it myself",
"poids": { "self-reliant": 4 } }
]
}
4 — A multiple-choice question
The weights of every ticked answer add up. Useful for questions about usage, where several answers can be true at once.
POST /api/agent/v1/questionnaires/4/questions/
{
"texte": "What do you need to manage? (several answers)",
"type": "multiple",
"rang": 2,
"reponses": [
{ "texte": "An online store",
"poids": { "self-reliant": 1, "supported": 2 } },
{ "texte": "Appointments",
"poids": { "supported": 2 } },
{ "texte": "Online courses",
"poids": { "supported": 3 } },
{ "texte": "None of these for now",
"poids": { "still-thinking": 3 } }
]
}
5 — Settle two profiles that are too close
When two profiles finish neck and neck, the heavier one is not always the right call. A combination describes that case: “if Self-reliant and Supported are within 2 points of each other, show Supported”.
POST /api/agent/v1/questionnaires/4/combinaisons/
{
"titre": "Self-reliant or supported",
"profil_parent": "self-reliant",
"profil_prefere": "supported",
"profil_alternatif": "self-reliant",
"criteres": [
{ "profil_a": "self-reliant",
"profil_b": "supported",
"comparaison": "~=",
"tolerance": 2 }
]
}
→ « ~= » without a tolerance is REFUSED: the
criterion would amount to strict equality
6 — Build the result page
The result page is an ordinary page. Tokens in it are replaced at render time with the values of that attempt. Nothing that identifies the visitor appears there: the address of a result travels by email.
PUT /api/agent/v1/blocs/604/contenu/
{
"type": "TEXT",
"texte": "<h1>[%profil%]</h1>
<p>[%profil_description%]</p>
<p>Your score: [%score%]</p>"
}
Available tokens:
[%profil%] name of the profile obtained
[%profil_description%] its description
[%profil_prefere%] profile chosen by a combination
[%score%] overall score
[%test%] title of the questionnaire
7 — Switch it on, and only then
Activation is a separate, deliberate step. An active questionnaire with incomplete weights raises no alarm: it answers — and it answers wrong.
PATCH /api/agent/v1/questionnaires/4/
{ "actif": true }
Full review before activation:
GET /api/agent/v1/questionnaires/4/
→ profiles, questions, answers, weights and
combinations, in a single call
A badly built questionnaire throws no error: it answers, and it answers wrong. Three refusals close the cases the database would happily accept — a weight aimed at another test's profile, a reversed score range no value could ever fall into, and a closeness comparison with no tolerance.
The calculation never changes — weights that add up — but there are three ways to draw a result from it. They can be combined: nothing stops you from awarding some profiles by weight and others by score band.
The profile with the highest total wins. This is the most common form: the point is not to grade the respondent but to steer them to the answer that concerns them. A sales qualification questionnaire, a guide to choosing between several offers.
POST /api/agent/v1/questionnaires/4/profils/
{ "nom": "Self-reliant", "slug": "self-reliant",
"page_de_resultat": 120 }
POST /api/agent/v1/questionnaires/4/questions/
{ "texte": "How do you work today?",
"type": "single",
"reponses": [
{ "texte": "On my own, with my own tools",
"poids": { "self-reliant": 4 } },
{ "texte": "With an agency",
"poids": { "supported": 4 } }
] }
→ the highest total decides which page is shown
The total is compared against bands. The profile is no longer a category but a LEVEL: digital maturity, readiness, exposure to a risk. The bands must cover the whole range without overlapping — a score that falls into none of them would lead to no page at all.
POST /api/agent/v1/questionnaires/5/profils/
{ "nom": "Beginner level", "slug": "beginner",
"attribue_par_score": true,
"score_min": 0, "score_max": 10,
"page_de_resultat": 130 }
POST /api/agent/v1/questionnaires/5/profils/
{ "nom": "Advanced level", "slug": "advanced",
"attribue_par_score": true,
"score_min": 11, "score_max": 25,
"page_de_resultat": 131 }
→ a reversed range is REFUSED: no score
could ever reach it
When two totals are close, the higher one is not always telling the truth: a one-point gap out of twenty is noise, not a preference. A combination describes that case and imposes the profile to keep. That is what separates an honest questionnaire from one that decides by chance.
POST /api/agent/v1/questionnaires/4/combinaisons/
{
"titre": "Self-reliant or supported",
"profil_parent": "self-reliant",
"profil_prefere": "supported",
"profil_alternatif": "self-reliant",
"criteres": [
{ "profil_a": "self-reliant",
"profil_b": "supported",
"comparaison": "~=",
"tolerance": 2 }
]
}
Comparisons: > < >= <= == ~=
« ~= » requires a tolerance — without one, the
criterion would amount to strict equality,
and would never settle anything
There are two, and the choice is not cosmetic: with multiple choice, the weights of every ticked answer add up, which changes the scale of the totals. A questionnaire that mixes both needs weights calibrated accordingly.
An inactive question can still be edited but is no longer asked. That is how you remove a question from a live questionnaire without skewing the attempts already recorded.