Guide de l'API Figen pour ROMEO#
Ce guide s'adresse aux développeurs qui branchent ROMEO sur l'API de Figen. Il se lit dans l'ordre :
l'essentiel en une page, un premier appel, la façon de marquer un modèle, puis les parcours un par un, avec
leurs commandes curl. Tous les exemples sont fictifs. Version du guide : API v1, novembre 2026.
1. L'essentiel en une page#
Ce que fait l'API#
Deux choses.
Contrôler les modèles. Inovéa dépose ses modèles de documents réglementaires : ce sont les modèles de base. Chaque cabinet peut en adapter une copie, le modèle du cabinet. L'API compare cette copie au modèle de base et dit ce qui a été supprimé ou modifié dans les mentions obligatoires.
Générer les documents. ROMEO envoie les données d'un dossier. L'API rend le document en Markdown et en HTML, rédige les commentaires libres quand le modèle en prévoit, puis contrôle le rendu.
Tout se passe de serveur à serveur, avec une clé d'API. Aucun utilisateur d'Inovéa ne se connecte chez Figen. Les textes circulent en Markdown ; le HTML est accepté en entrée et converti. Jamais de Word.
Les trois règles#
- Figen contrôle et alerte, ROMEO décide. L'API dit l'état d'un modèle et détaille ses alertes. Bloquer un cabinet ou le laisser continuer reste votre décision. Figen ne corrige jamais un modèle.
- Rien de vos clients n'est conservé. Le document généré part dans la réponse. Il ne reste chez nous qu'une ligne de journal, sans contenu.
/v1ne casse jamais sans préavis. Vous êtes prévenus avant tout changement, chaque évolution est consignée dans le journal des changements, et une rupture passe par une nouvelle version.
Le vocabulaire#
| Mot | Sens |
|---|---|
| Modèle de base | Le modèle déposé par Inovéa. Il est versionné et fait référence. |
| Modèle du cabinet | La copie adaptée par un cabinet (un CIF). cif_id est l'identifiant du cabinet, choisi par ROMEO. |
| Mention obligatoire | Un passage que le cabinet ne peut ni supprimer ni dénaturer. Dans le modèle, une marque de clause la délimite. |
| Zone libre | Tout ce qui n'est pas dans une clause. Le cabinet peut l'adapter. |
| Commentaire | Un texte libre, rédigé par l'IA au moment de la génération ou fourni par ROMEO. Dans le modèle, une marque de bloc IA dit où il se place. |
| Contrôle | La comparaison d'un texte avec sa référence. Il rend un statut et des alertes. |
| Alerte | Un écart constaté. Elle est bloquante ou vaut simple information. |
| Dérive | L'état d'un modèle de cabinet qui était valide quand le modèle de base a été republié. Il attend une revalidation. |
Ce guide dit mention, cabinet, modèle et commentaire. Dans les marques, les champs et les codes de
l'API, les mêmes choses s'appellent clause, cif, gabarit et bloc ou ia.
Où trouver quoi#
| Adresse | Contenu |
|---|---|
/guide |
Ce guide, suivi du journal des changements de l'API. |
/docs |
La référence complète des routes et de leurs schémas. |
/openapi.json |
La même référence, au format OpenAPI. |
2. Premier appel en deux minutes#
Il vous faut curl, jq (version 1.6 ou plus récente : le parcours 4.6 utilise son option --rawfile) et
deux variables d'environnement. L'adresse vous est remise avec votre clé.
export ROMEO_URL="…" # adresse de l'API, sans barre oblique à la fin
export ROMEO_CLE="…" # votre clé : ne l'écrivez ni dans un dépôt, ni dans une adresse
Premier appel, sans clé. /v1/sante est la seule route de /v1 qui n'en demande pas.
curl -sS "$ROMEO_URL/v1/sante"
{"statut": "ok", "service": "inovea-romeo", "version": "0.1.0",
"revision": "a653dd83277e562295e158df51fd88bae0c38a17", "environnement": "recette",
"base_de_donnees": "ok", "ia": {"mode": "bedrock", "modele": "claude-opus-5-5"},
"heure": "2026-11-10T09:00:00Z"}
revision identifie le code servi : elle change à chaque mise à jour du service, citez-la dans vos
questions. Si la base de données ne répond pas, l'API répond 503 avec "statut": "degrade". ia.mode vaut bedrock
ou factice : regardez-le avant vos essais. En mode factice, les jugements et les rédactions sont simulés et
signés "modele_ia": "factice" : de quoi tester l'enchaînement des appels, pas juger de la qualité d'un avis.
Deuxième appel, avec la clé :
curl -sS "$ROMEO_URL/v1/moi" -H "Authorization: Bearer $ROMEO_CLE"
{"cle": {"nom": "ROMEO recette", "prefixe": "romeo_rec_ab12cd", "creee_le": "…",
"derniere_utilisation": "…"},
"environnement": "recette", "ia": {"mode": "bedrock", "modele": "claude-opus-5-5"}}
La réponse nomme la clé, sans jamais la répéter, et dit dans quel environnement elle travaille. recette est
l'environnement de test. creee_le et derniere_utilisation sont des dates ; prévoyez aussi null : c'est
ce que rend la clé de développement d'un service lancé en local.
Toutes les autres routes de /v1 attendent le même en-tête. Sans clé reconnue, l'API répond 401, avec une
erreur de la forme décrite en partie 9. Pour lire une réponse à l'écran, ajoutez | jq à la commande. Dans
les corps JSON que vous envoyez, un champ inconnu est refusé (400 requete_invalide) : une faute de frappe
ne passe pas inaperçue. Seuls donnees et blocs portent des clés libres.
3. Le modèle de document#
Un modèle est un texte Markdown qui suit quelques conventions. Elles disent à l'API ce qui se remplace, ce qui est obligatoire et ce qui se rédige.
Les conventions de marquage#
| Convention | Syntaxe | Rôle |
|---|---|---|
| Variable | {{ org_orias }}, {{ product.name }} |
Remplacée par une donnée à la génération. |
| Condition, boucle | {% if org_status_cif %}…{% endif %}, {% for product in products %}…{% endfor %} |
Syntaxe Jinja2 : un passage présent sous condition, ou répété. |
| Clause | <!-- clause: mediation -->…<!-- /clause --> |
Délimite une mention obligatoire. |
| Bloc IA | <!-- ia: justification_recommandation --> |
Emplacement d'un commentaire rédigé à la génération. Toujours hors d'une clause. |
| Note | <!-- note: … --> |
Consigne au conseiller. Ignorée au contrôle, retirée à la génération. |
Tout ce qui n'est pas dans une clause est une zone libre, que le cabinet peut adapter.
Une clause porte un identifiant (minuscules, chiffres et _, en commençant par une lettre) et trois attributs
facultatifs, séparés par une barre verticale :
<!-- clause: immatriculation | exigence: identique | titre: Immatriculation -->
exigencedit jusqu'où le cabinet peut toucher au texte. Avecsens, la valeur par défaut, il peut reformuler tant que le sens reste le même. Avecidentique, le texte se reprend mot pour mot.titredonne à la mention un libellé lisible dans les rapports.presencedit si le cabinet peut se passer de la mention. Sans cet attribut, elle est obligatoire. Avecpresence: facultative, le cabinet peut la retirer en entier, pas la dénaturer.
Exemple, inventé lui aussi : une section qui ne concerne que les cabinets exerçant une seconde activité.
<!-- clause: activite_credit | presence: facultative | titre: Activité de crédit -->
Le cabinet exerce aussi une activité d'intermédiaire en crédit, pour laquelle il est immatriculé à part.
<!-- /clause -->
Un cabinet qui n'exerce pas cette activité supprime la section : le contrôle le note pour information
(clause_facultative_retiree) et le modèle reste valide. Un cabinet qui la garde mais en change le sens
reçoit la même alerte bloquante que pour toute autre mention.
Un bloc IA peut porter sa propre consigne de rédaction : <!-- ia: cle | consigne: … -->.
Les variables acceptent des filtres de mise en forme :
| Filtre | Valeur reçue | Texte rendu |
|---|---|---|
date |
2026-12-15 |
15 décembre 2026 |
date("court") |
2026-12-15 |
15/12/2026 |
euros |
1234.5 |
1 234,50 € |
pct |
3.5 |
3,5 % |
ouinon |
true |
Oui |
S'y ajoutent nombre et les filtres courants de Jinja2, par exemple {{ org_orias | default("néant") }} ou
{{ vigilance | join(", ") }}. Même sans filtre, un booléen rendu par une variable s'écrit « Oui » ou
« Non », jamais « True ».
Un mini-modèle, fictif#
Le modèle ci-dessous est inventé pour ce guide. Il sert dans tous les parcours ; enregistrez-le dans un
fichier modele.md pour les rejouer.
# Rapport de conseil
{{ org_name }} a préparé ce rapport pour {{ client_first_name }}.
<!-- note: Adaptez cette présentation à votre cabinet. -->
Notre cabinet accompagne des particuliers dans la gestion de leur patrimoine depuis 2009.
<!-- clause: immatriculation | exigence: identique | titre: Immatriculation -->
{{ org_name }} est immatriculé au registre des intermédiaires sous le numéro {{ org_orias }}.
<!-- /clause -->
{% if org_status_cif %}
<!-- clause: mediation | titre: Médiation -->
En cas de désaccord, écrivez d'abord au cabinet. Sans réponse satisfaisante sous deux mois, vous pouvez
saisir gratuitement le médiateur : {{ org_mediator_name }}.
<!-- /clause -->
{% endif %}
## Notre recommandation
<!-- ia: justification_recommandation | consigne: Expliquer en quelques phrases le choix proposé. -->
Ce qu'il faut y voir :
- Le paragraphe de présentation est une zone libre. Le cabinet l'adapte comme il veut, et la note qui le précède ne sortira jamais dans un document.
immatriculationest une mention à reprendre mot pour mot. Le moindre changement de texte lève une alerte bloquante, sans appel à l'IA.mediationest une mention dont le sens doit être conservé. Le cabinet peut la reformuler ; si le texte change, un juge dit si le sens a tenu.- La condition
{% if org_status_cif %}entoure la mention de médiation. Quand la donnée vaut faux, la mention est écartée et dite non applicable : le document reste conforme. Placée à l'intérieur de la clause, la même condition laisserait une mention vide, et une alerte bloquante (clause_vide_au_rendu). - Cette condition fait partie de ce qui est contrôlé. Un cabinet qui la retire, la change, ou en ajoute une
autour d'une mention reçoit une alerte bloquante (
condition_modifiee), même si le texte de la mention n'a pas bougé : entourée d'une condition fausse, la mention disparaîtrait du document. - Le bloc IA sera remplacé par un commentaire, rédigé par l'IA ou fourni par ROMEO.
Pourquoi des commentaires HTML#
Les marques de clause, de bloc IA et de note sont des commentaires HTML, pour trois raisons.
- Ils sont invisibles au rendu. Le cabinet voit son modèle comme le client verra le document.
- Ils survivent au Markdown comme au HTML. La même marque vaut dans les deux formats que l'API accepte en entrée.
- Ils permettent de recontrôler un document après coup. Un document généré garde ses marques de clause
(option
conserver_marques), toujours invisibles. S'il est retouché avant signature, l'API retrouve chaque mention.
Si un éditeur de texte retire les marques, le contrôle ne tombe pas pour autant. L'API cherche le texte de
chaque mention dans tout le document. Retrouvé à l'identique, il donne une simple information
(marque_absente). Retrouvé avec des changements, il est traité comme une mention modifiée. Introuvable, la
mention est tenue pour supprimée.
Une limite connue de l'entrée en HTML : dans un tableau, une ligne qui porte une balise Jinja ou une cellule
qui porte un filtre ({{ montant | euros }}) ne survit pas au passage par un éditeur HTML, parce que la
barre verticale y sépare les cellules. Le Markdown reste donc le format de référence des modèles. Au dépôt
d'un modèle de base, contenu_markdown vous rend ce que l'API a compris. Pour le modèle d'un cabinet, il se
lit dans son détail (GET /v1/cifs/{cif_id}/modeles/{code}).
Ce que le contrôle tient pour identique#
La comparaison ignore ce qui ne change pas le fond : la typographie (apostrophes, guillemets, tirets), les espaces, le gras et l'italique, les notes, l'espacement à l'intérieur des expressions Jinja. Deux textes qui ne diffèrent que par cela sont identiques pour le contrôle.
Les données attendues à la génération#
ROMEO envoie un objet JSON à plat pour les valeurs simples (org_name, client_first_name,
profile_risk_label…). S'y ajoutent products, une liste d'objets dont les clés sont celles des variables
product.* sans le préfixe, puis totals, remuneration, vigilance (une liste de phrases) et les
drapeaux de condition (org_status_cif, org_status_miobsp, realestateActive, personType…). Le modèle
lit ce JSON tel quel.
Une valeur mal formée est refusée : 400 requete_invalide, avec le chemin de la clé dans details. C'est
le cas de products qui n'est pas une liste d'objets, ou d'un booléen là où le catalogue attend un texte.
GET /v1/catalogue-variables liste les variables, leurs groupes, les drapeaux de condition et les blocs IA
connus : près de 400 variables, une trentaine de drapeaux, une quinzaine de blocs IA. L'exemple n'en montre
qu'un extrait.
curl -sS "$ROMEO_URL/v1/catalogue-variables" -H "Authorization: Bearer $ROMEO_CLE"
{"variables": [{"cle": "org_orias", "libelle": "N° ORIAS de l'organisation", "type": "text",
"groupe": "cabinet", "source": "figen"}],
"groupes": [{"id": "cabinet", "libelle": "Cabinet"}], "drapeaux": ["org_status_cif", "personType"],
"blocs_ia": [{"cle": "justification_recommandation", "libelle": "…", "description": "…"}]}
Avec ?code=, la réponse porte en plus modele : ce que ce modèle utilise, mention par mention. Pour le
mini-modèle, une fois déposé au parcours 4.1 (?code=rapport-exemple) :
{"modele": {"code": "rapport-exemple", "version": 1, "variables": ["org_name", "…"],
"par_clause": {"immatriculation": ["org_name", "org_orias"], "mediation": ["org_mediator_name"]},
"variables_inconnues": [], "blocs_ia": ["justification_recommandation"]}}
Une variable hors catalogue dans un modèle de base n'est pas refusée : elle est signalée dans
variables_inconnues.
4. Les parcours#
Les sept parcours se suivent. Rejoués dans l'ordre avec le mini-modèle de la partie 3, ils donnent les
résultats décrits. Ils utilisent le code rapport-exemple, pour ne pas toucher aux modèles d'Inovéa, qui
portent des codes comme der-conseiller ou rapport-conseil. Le cabinet fictif s'appelle CIF-0042, le
conseiller u-1234. Jouez-les sur l'environnement de test : /v1 n'a pas de route pour retirer un modèle de
base, le modèle d'exemple y restera.
4.1 Déposer un modèle de base#
ROMEO → PUT /v1/modeles-de-base/{code} le texte du modèle, son type, son profil, son libellé
ROMEO ← 201 version créée, mentions, variables, anomalies, impact
Le code du modèle est le vôtre : c'est vous qui le choisissez, dans l'adresse.
jq -Rs '{type: "rapport_conseil", profil: "conseiller", libelle: "Rapport de conseil (exemple)",
contenu: ., format: "markdown", notes_version: "Première version",
personnalisable: true, publier: true}' modele.md \
| curl -sS -X PUT "$ROMEO_URL/v1/modeles-de-base/rapport-exemple" \
-H "Authorization: Bearer $ROMEO_CLE" -H "Content-Type: application/json" \
--data-binary @-
{"code": "rapport-exemple", "type": "rapport_conseil", "profil": "conseiller", "libelle": "…",
"personnalisable": true, "version": 1, "statut": "publiee", "inchange": false, "simulation": false,
"contenu_markdown": "…",
"clauses": [{"id": "immatriculation", "titre": "Immatriculation", "exigence": "identique",
"facultative": false, "lignes": [8, 10], "variables": ["org_name", "org_orias"]},
{"id": "mediation", "titre": "Médiation", "exigence": "sens",
"facultative": false, "lignes": [13, 16], "variables": ["org_mediator_name"]}],
"variables": ["org_name", "…"], "variables_inconnues": [],
"blocs_ia": [{"cle": "justification_recommandation", "consigne": "…", "ligne": 21}],
"notes": [{"texte": "…", "ligne": 5}], "anomalies": [],
"impact": {"modeles_cif": 0, "restent_valides": 0, "a_corriger": []}}
À lire dans cette réponse :
201annonce une nouvelle version. Si le contenu est celui de la dernière version, l'API répond200avec"inchange": true: aucune nouvelle version n'est créée. Redéposer le contenu d'une version plus ancienne en crée une nouvelle. Une version déposée ne change plus.inchangene parle que du contenu.type,profiletlibellesont remplacés à chaque dépôt, même avec"inchange": true.personnalisable, s'il est omis, garde sa valeur enregistrée (trueà la création).clausesest ce que l'API a compris de vos marques. Vérifiez que toutes vos mentions obligatoires y sont.anomaliesrelève les défauts de forme. Un simpleavertissementn'empêche pas le dépôt. Une anomalie de gravitéerreurle refuse :400 gabarit_invalide, rien n'est stocké.personnalisabledit si les cabinets ont le droit d'adapter ce modèle.publierdécide si la version est publiée ou reste en brouillon ("statut": "brouillon").- Un brouillon n'a aucun effet sur les cabinets, et son
impactn'est qu'une projection. Pour le publier, redéposez le même contenu avecpublier: true:"inchange": true, mais"statut": "publiee". - Tant qu'un modèle de base n'a aucune version publiée, le dépôt d'un cabinet, les trois routes de
/v1/documentset le contrôle qui ne précise pasreference.versionrépondent404 introuvable.
Les valeurs admises pour type, profil et format sont dans la partie 9. Pour relire ce qui est déposé :
curl -sS "$ROMEO_URL/v1/modeles-de-base" -H "Authorization: Bearer $ROMEO_CLE"
{"modeles": [{"code": "rapport-exemple", "type": "rapport_conseil", "profil": "conseiller", "libelle": "…",
"personnalisable": true, "version": 1, "statut": "publiee", "publiee_le": "…", "nb_clauses": 2,
"modeles_cif": {"valide": 0, "alertes": 0, "derivant": 0}}]}
modeles_cif compte les modèles de cabinet par état. GET /v1/modeles-de-base/{code} rend le détail de la
version publiée courante (à défaut, du dernier brouillon), et ?version=1 celui d'une version précise. Le
paramètre ne s'écrit pas sans valeur : ?version= rend 400. La forme est celle du dépôt, sans impact,
avec en plus "versions": [{"version": 1, "statut": "publiee", "cree_le": "…", "notes_version": "…"}].
4.2 Déposer le modèle d'un cabinet et lire le contrôle#
ROMEO → POST /v1/controles facultatif : contrôle à blanc pendant la saisie
ROMEO → PUT /v1/cifs/{cif_id}/modeles/{code} dépôt du modèle du cabinet
ROMEO ← statut du modèle et contrôle complet dans la même réponse
ROMEO montre le rapport au cabinet et décide de bloquer ou non
Le cabinet part du modèle de base et l'adapte. Ici, il touche à la mention de médiation :
sed 's/saisir gratuitement le médiateur/saisir le médiateur, à vos frais/' modele.md > modele-cabinet.md
Pendant la saisie, ROMEO peut demander un contrôle à blanc. Le modèle du cabinet ne change pas d'état :
jq -Rs '{reference: {code: "rapport-exemple"}, contenu: ., format: "markdown", mode: "modele"}' \
modele-cabinet.md \
| curl -sS -X POST "$ROMEO_URL/v1/controles" \
-H "Authorization: Bearer $ROMEO_CLE" -H "Content-Type: application/json" \
--data-binary @-
La réponse est un contrôle, avec "id": null et "enregistre": false. Le dépôt, lui, enregistre le modèle
et son contrôle. cif_id est votre identifiant du cabinet. Aucun appel préalable ne crée le cabinet : le
premier dépôt suffit.
jq -Rs '{contenu: ., format: "markdown"}' modele-cabinet.md \
| curl -sS -X PUT "$ROMEO_URL/v1/cifs/CIF-0042/modeles/rapport-exemple" \
-H "Authorization: Bearer $ROMEO_CLE" -H "Content-Type: application/json" \
--data-binary @-
{"cif_id": "CIF-0042", "code": "rapport-exemple", "version": 1, "statut": "alertes", "inchange": false,
"base": {"version_controlee": 1, "version_validee": null, "version_courante": 1},
"controle": {
"id": "ctl_…", "enregistre": true, "cree_le": "…", "statut": "alertes",
"resume": {"bloquantes": 1, "informations": 0, "clauses_attendues": 2, "clauses_intactes": 1,
"clauses_reformulees": 0},
"alertes": [{"code": "clause_alteree", "gravite": "bloquante", "niveau": "paragraphe",
"message": "La mention « Médiation » a été modifiée et son sens n'est plus celui du modèle de base.",
"clause_id": "mediation", "titre": "Médiation",
"attendu": {"texte": "… vous pouvez\nsaisir gratuitement le médiateur : …", "lignes": [14, 15]},
"constate": {"texte": "… vous pouvez\nsaisir le médiateur, à vos frais : …", "lignes": [14, 15]},
"diff": [{"op": "egal", "texte": "… vous pouvez\nsaisir"}, {"op": "supprime", "texte": " gratuitement"},
{"op": "egal", "texte": " le médiateur"}, {"op": "ajoute", "texte": ", à vos frais"},
{"op": "egal", "texte": " : {{ org_mediator_name }}."}],
"variable": null,
"jugement": {"verdict": "sens_altere", "justification": "La saisine du médiateur n'est plus gratuite.",
"modele_ia": "claude-opus-5-5", "depuis_cache": true}}],
"rapport_markdown": "…", "rapport_html": "…", "modele_annote": "…"}}
Cet exemple montre une IA branchée. Sur un service lancé en local, l'IA est simulée (ia.mode vaut
factice, partie 2) : vous lirez "modele_ia": "factice" et une justification convenue.
À lire dans cette réponse :
statutest l'état du modèle du cabinet :validesans alerte bloquante,alertessinon. C'est sur lui que ROMEO décide.baseporte partout trois numéros de version du modèle de base :version_controlee, celle du dernier contrôle ;version_validee, la dernière sur laquelle le modèle du cabinet a été valide (nulls'il ne l'a jamais été) ;version_courante, la version publiée.controledit pourquoi : le rapport prêt à afficher au cabinet (rapport_html) et, pour chaque alerte, ce qui était attendu, ce qui est constaté, la différence mot à mot et l'avis du juge. La partie 5 détaille ces champs.depuis_cachevaut icitrue: le contrôle à blanc qui précède a déjà fait juger ce passage.
Si le modèle de base n'est pas personnalisable, le dépôt est refusé : 409 modele_non_personnalisable. Si
un modèle de base passe à personnalisable: false après coup, la génération utilise le modèle de base pour
tous les cabinets, même ceux dont le modèle était valide, et le dit ("repli_sur_base": true). Leur modèle
est gardé : il resservira si le modèle de base redevient personnalisable.
Le cabinet corrige et redépose. Cette fois, il n'adapte que la zone libre :
sed 's/depuis 2009/depuis plus de quinze ans/' modele.md > modele-cabinet.md
Rejouez le PUT ci-dessus. Le modèle passe à "statut": "valide". Le contrôle garde une alerte
zone_libre_modifiee, de gravité information : elle renseigne, elle ne bloque pas.
Pour relire l'état de tous les modèles d'un cabinet :
curl -sS "$ROMEO_URL/v1/cifs/CIF-0042/modeles" -H "Authorization: Bearer $ROMEO_CLE"
{"cif_id": "CIF-0042", "modeles": [{"code": "rapport-exemple", "type": "rapport_conseil", "libelle": "…",
"utilise": "modele_cif", "suspendu": false, "statut": "valide", "version": 2,
"base": {"version_controlee": 1, "version_validee": 1, "version_courante": 1},
"dernier_controle": {"id": "ctl_…", "statut": "valide",
"resume": {"bloquantes": 0, "informations": 1, "…": "…"}, "cree_le": "…"},
"maj_le": "…"}]}
Tous les modèles de base publiés figurent dans cette liste ; un modèle resté en brouillon n'y est pas.
utilise dit lequel servirait à générer : modele_cif quand le modèle du cabinet est valide,
modele_de_base quand le cabinet n'a rien déposé (statut vaut alors null), que son modèle n'est pas
valide, ou que le modèle de base n'est plus personnalisable : son modèle est suspendu ("suspendu": true).
Trois autres routes complètent le parcours.
GET /v1/cifs/{cif_id}/modeles/{code}rend le détail d'un modèle et son dernier contrôle : la forme de la réponse du dépôt, pluscontenu_markdown,suspenduetmaj_le.GET /v1/controles/{id}relit un contrôle enregistré.DELETE /v1/cifs/{cif_id}/modeles/{code}fait revenir le cabinet au modèle de base et répond{"cif_id": "CIF-0042", "code": "rapport-exemple", "supprime": true}. Le modèle du cabinet, ses versions et ses contrôles sont supprimés :GET /v1/controles/{id}répond ensuite404. Ne le jouez pas maintenant : la suite se sert du modèle déposé.
4.3 Mettre à jour un modèle de base#
1. PUT /v1/modeles-de-base/{code}, simulation: true anomalies et impact, rien n'est stocké
2. PUT /v1/modeles-de-base/{code}, publier: true nouvelle version ; les modèles de cabinet valides
passent à « derivant » et sont recontrôlés
3. GET /v1/cifs/{cif_id}/modeles/{code} le contrôle joint dit ce qu'il reste à corriger
4. POST …/revalider 200 : retour à « valide » ; 409 : il reste à corriger
Inovéa raccourcit le délai de la mention de médiation :
sed 's/sous deux mois/sous un mois/' modele.md > modele-v2.md
Simuler d'abord. Le même PUT, avec simulation: true, analyse le texte et mesure l'effet sur les
modèles des cabinets. Rien n'est stocké.
jq -Rs '{type: "rapport_conseil", profil: "conseiller", libelle: "Rapport de conseil (exemple)",
contenu: ., format: "markdown", notes_version: "Délai de médiation ramené à un mois",
personnalisable: true, publier: true, simulation: true}' modele-v2.md \
| curl -sS -X PUT "$ROMEO_URL/v1/modeles-de-base/rapport-exemple" \
-H "Authorization: Bearer $ROMEO_CLE" -H "Content-Type: application/json" \
--data-binary @-
La réponse a la même forme qu'au dépôt, avec "simulation": true. Le champ à regarder est impact :
{"impact": {"modeles_cif": 1, "restent_valides": 0,
"a_corriger": [{"cif_id": "CIF-0042", "bloquantes": 1, "controle_id": null}]}}
Un modèle de cabinet est concerné, et il ne resterait pas valide : sa mention de médiation annonce encore
deux mois. Vous savez qui prévenir avant de publier. En simulation, controle_id vaut null : aucun
contrôle n'est enregistré. Après la publication, il désigne le contrôle stocké.
Publier ensuite. Rejouez la commande en passant simulation à false. L'API crée la version 2. Les
modèles de cabinet qui étaient valides passent à derivant et sont recontrôlés aussitôt contre la nouvelle
version. Avec "revalidation_automatique": true dans la requête, ceux qui n'ont aucune alerte bloquante
redeviennent valide sans autre appel.
Lire la dérive. Le détail du modèle du cabinet porte ce nouveau contrôle, qui dit ce qu'il reste à corriger :
curl -sS "$ROMEO_URL/v1/cifs/CIF-0042/modeles/rapport-exemple" -H "Authorization: Bearer $ROMEO_CLE"
{"cif_id": "CIF-0042", "code": "rapport-exemple", "version": 2, "statut": "derivant", "…": "…",
"controle": {"id": "ctl_…", "statut": "alertes", "resume": {"bloquantes": 1, "…": "…"}, "…": "…"},
"contenu_markdown": "…", "maj_le": "…"}
Dans la liste des modèles du cabinet (GET /v1/cifs/CIF-0042/modeles), base montre l'écart,
{"version_controlee": 2, "version_validee": 1, "version_courante": 2}, et utilise vaut modele_de_base.
Lever la dérive. ROMEO demande la revalidation :
curl -sS -X POST "$ROMEO_URL/v1/cifs/CIF-0042/modeles/rapport-exemple/revalider" \
-H "Authorization: Bearer $ROMEO_CLE"
Si le contrôle joint est sans alerte bloquante, l'API répond 200 avec la forme du dépôt, et le modèle
redevient valide. Ici, la mention de médiation du cabinet annonce encore deux mois : l'API répond 409.
{"erreur": {"code": "revalidation_impossible", "message": "…",
"details": [{"controle_id": "ctl_…", "bloquantes": 1}]}}
Le cabinet doit reprendre son modèle et le redéposer. Le parcours 4.4 montre ce qui se passe en attendant, puis lève la dérive.
4.4 Générer un document simple#
ROMEO → POST /v1/documents/verifier-donnees facultatif : ce qui manque, sans générer
ROMEO → POST /v1/documents code du modèle, cabinet, conseiller, données
ROMEO ← markdown, html, modèle utilisé, conformité, durée
Les données du dossier, fictives, dans un fichier donnees.json :
{"org_name": "Cabinet Dupont Patrimoine", "org_orias": "00000000", "org_status_cif": true,
"org_mediator_name": "Médiateur fictif du patrimoine", "client_first_name": "Camille"}
Vérifier les données. Cet appel fait une génération à blanc, sans IA, et dit ce qui manque. Son corps
ne porte que code, cif_id et donnees : il n'accepte pas options. Essayez-le en retirant une donnée :
jq 'del(.org_orias) | {code: "rapport-exemple", cif_id: "CIF-0042", donnees: .}' donnees.json \
| curl -sS -X POST "$ROMEO_URL/v1/documents/verifier-donnees" \
-H "Authorization: Bearer $ROMEO_CLE" -H "Content-Type: application/json" \
--data-binary @-
{"complet": false,
"manquantes": [{"cle": "org_orias", "libelle": "…", "dans_clauses": ["immatriculation"], "bloquante": true}],
"alertes": [{"code": "variable_non_resolue", "gravite": "bloquante", "niveau": "variable", "message": "…",
"clause_id": "immatriculation", "variable": "org_orias", "…": "…"}],
"conditions_non_renseignees": [], "inconnues": []}
bloquante vaut vrai parce que la donnée manque dans une mention obligatoire. libelle vaut null pour une
variable hors catalogue. conditions_non_renseignees liste les drapeaux de condition absents, inconnues
les clés envoyées que ni le catalogue ni le modèle ne connaissent. alertes a la forme des alertes de la
génération : c'est ce qu'elle relèverait avec ces données, sans dépendre de l'IA (clause_vide_au_rendu,
par exemple, pour une mention que les données laissent vide).
complet: true veut dire : aucune variable ne manque, et aucune de ces alertes n'est bloquante. Cela ne
garantit pas un document conforme : les commentaires, rédigés ou fournis, ne sont jugés qu'à la
génération.
Générer. Le modèle porte un bloc IA. Pour un rendu immédiat, on demande ici de ne pas le rédiger
(blocs_ia: false) ; le parcours 4.5 s'en occupe.
jq '{code: "rapport-exemple", cif_id: "CIF-0042", conseiller_id: "u-1234", donnees: .,
options: {formats: ["markdown", "html"], blocs_ia: false, reference_romeo: "DOC-1"}}' donnees.json \
| curl -sS -X POST "$ROMEO_URL/v1/documents" \
-H "Authorization: Bearer $ROMEO_CLE" -H "Content-Type: application/json" \
--data-binary @- > reponse.json
jq -r .markdown reponse.json > document.md
jq -r .html reponse.json > document.html
jq 'del(.markdown, .html)' reponse.json
{"id": "doc_…", "code": "rapport-exemple", "markdown": "…", "html": "…",
"modele": {"origine": "modele_de_base", "version_base": 2, "version_cif": null,
"etat_modele_cif": "derivant", "repli_sur_base": true},
"conformite": {"statut": "conforme",
"alertes": [{"code": "bloc_ia_indisponible", "gravite": "information", "…": "…"}],
"variables_non_resolues": [], "conditions_non_renseignees": [],
"clauses_presentes": ["immatriculation", "mediation"], "clauses_non_applicables": []},
"blocs_ia": [{"cle": "justification_recommandation", "statut": "indisponible", "…": "…"}],
"produits_enrichis": [], "duree_ms": 2140}
À lire dans cette réponse :
modeledit quel modèle a servi, et pourquoi. Ici le modèle du cabinet dérive depuis le parcours 4.3. Seul un modèlevalidesert à générer : l'API s'est repliée sur le modèle de base (repli_sur_base) et le dit.conformite.statutvautconformes'il n'y a aucune alerte bloquante. Chaque mention obligatoire est soit présente, soit non applicable parce qu'une condition l'écarte.- Une donnée absente laisse dans le document le marqueur
[À compléter : nom]et figure dansvariables_non_resolues. Dans une mention obligatoire, c'est une alerte bloquante. - Le commentaire non rédigé laisse
[Bloc à rédiger : justification_recommandation]et une alerte d'information. htmlest le format d'affichage. Markdown et HTML gardent les marques de clause, invisibles, pour un contrôle ultérieur. En HTML, les marqueurs[À compléter : …]et[Bloc à rédiger : …]sont entourés de<mark class="a-completer">.
Les options de la requête, toutes facultatives :
| Option | Effet |
|---|---|
formats |
Formats rendus : markdown, html. Par défaut, ["markdown"] seul : demandez html pour l'affichage. Un format non demandé revient à null dans la réponse, il n'en est pas absent. |
si_modele_non_valide |
Que faire si le modèle du cabinet n'est pas valide. modele_de_base, la valeur par défaut : générer avec le modèle de base et le dire. generer : générer avec le modèle du cabinet malgré ses alertes. refuser : répondre 422 modele_non_valide. |
conserver_marques |
Garder les marques de clause dans le document, pour pouvoir le recontrôler. Vrai par défaut. |
blocs_ia |
Rédiger par l'IA les commentaires que ROMEO ne fournit pas. Vrai par défaut ; à faux, ils restent à rédiger. |
verifier_blocs |
Soumettre au juge les commentaires fournis par ROMEO (parcours 4.5). Faux par défaut. |
enrichir_produits |
Compléter, pour chaque produit qui porte un isin, les données absentes à partir du référentiel. Une valeur envoyée par ROMEO n'est jamais écrasée. Les ISIN complétés sont listés dans produits_enrichis. Vrai par défaut. |
reference_romeo |
Votre référence du document. Elle est reprise dans le journal. |
cif_id est facultatif : un consultant n'a pas de modèle propre, le modèle de base sert alors directement.
Lever la dérive, pour finir. Le cabinet repart de la nouvelle version du modèle de base et y reporte son adaptation :
sed 's/depuis 2009/depuis plus de quinze ans/' modele-v2.md > modele-cabinet.md
Rejouez le PUT du parcours 4.2. Le modèle du cabinet redevient valide, contrôlé contre la version 2, et
c'est lui qui sert aux générations suivantes.
4.5 L'aller-retour du rapport de conseil#
Un rapport de conseil contient un commentaire libre. Le conseiller doit pouvoir le relire avant qu'il n'entre dans le document. D'où un aller-retour en deux appels :
ROMEO API Figen
1. POST /v1/documents/blocs → rédige les commentaires (l'appel qui attend l'IA)
← blocs : cle, libelle, statut, texte, modele_ia
2. le conseiller relit et corrige les textes dans ROMEO
3. POST /v1/documents, avec blocs → insère les textes validés, rend le document
← markdown, html, conformité (sans appel à l'IA, donc vite)
Rédiger les commentaires. Le corps est celui de POST /v1/documents, et vous pouvez l'envoyer tel quel :
blocs, formats et les autres options du rendu y sont acceptés, puis ignorés. Toute autre clé est refusée
(400 requete_invalide). Rien n'est stocké.
jq '{code: "rapport-exemple", cif_id: "CIF-0042", conseiller_id: "u-1234", donnees: .}' donnees.json \
| curl -sS -X POST "$ROMEO_URL/v1/documents/blocs" \
-H "Authorization: Bearer $ROMEO_CLE" -H "Content-Type: application/json" \
--data-binary @-
{"code": "rapport-exemple",
"blocs": [{"cle": "justification_recommandation", "libelle": "…", "statut": "redige",
"texte": "…", "modele_ia": "claude-opus-5-5"}],
"duree_ms": 8200}
Le rédacteur ne s'appuie que sur les données envoyées et n'invente aucun chiffre. ROMEO affiche chaque
texte au conseiller, qui le corrige.
Générer le document final. ROMEO renvoie les textes validés dans blocs, clé par clé :
jq --arg texte "Texte relu et validé par le conseiller." \
'{code: "rapport-exemple", cif_id: "CIF-0042", conseiller_id: "u-1234", donnees: .,
blocs: {justification_recommandation: $texte},
options: {formats: ["markdown", "html"], reference_romeo: "DOC-2"}}' donnees.json \
| curl -sS -X POST "$ROMEO_URL/v1/documents" \
-H "Authorization: Bearer $ROMEO_CLE" -H "Content-Type: application/json" \
--data-binary @-
Dans la réponse, chaque commentaire de blocs_ia porte son texte et un statut. Vérifiez que chaque texte
envoyé revient avec "statut": "fourni" : c'est la preuve qu'il est dans le document.
{"blocs_ia": [{"cle": "justification_recommandation", "statut": "fourni",
"texte": "Texte relu et validé par le conseiller.", "…": "…"}], "…": "…"}
| Statut | Sens |
|---|---|
redige |
Rédigé par l'IA. |
fourni |
Texte envoyé par ROMEO, inséré dans le document. |
indisponible |
Non rédigé : le document porte [Bloc à rédiger : cle] et l'alerte bloc_ia_indisponible. |
Un commentaire que ROMEO ne fournit pas est rédigé par l'IA si blocs_ia est vrai, sinon laissé à rédiger.
Un texte fourni vide n'est jamais rédigé à sa place par l'IA : le commentaire sort indisponible, avec son
marqueur « à rédiger ». Une clé de blocs qui ne correspond à aucun commentaire du document lève l'alerte
d'information bloc_fourni_inconnu : ce texte n'est pas dans le document.
Le texte fourni est lu comme du Markdown : paragraphes, listes, gras et liens sont rendus. Un titre devient
un paragraphe en gras, une image est remplacée par son texte, le HTML s'affiche comme du texte, et aucune
marque ne peut y être posée. Dans le document, chaque commentaire est encadré par <!-- ia-debut: cle -->
et <!-- ia-fin: cle --> ; en HTML, il est en plus dans un <div class="bloc-ia" data-cle="cle">. Avec
conserver_marques: false, ces repères disparaissent.
Avec "verifier_blocs": true, l'API soumet les textes fournis au juge, qui cherche une contradiction avec
une mention obligatoire ou une promesse interdite : alerte ajout_contradictoire, ou ajout_a_juger si le
juge n'a pas pu se prononcer. Les deux sont bloquantes.
Régler le délai d'attente. Un relais (Cloudflare) placé devant l'environnement de test coupe tout appel
à 100 secondes. Réglez votre client sur 95 secondes au plus. Une coupure, délai dépassé ou code 524, n'est
pas un refus de l'API : POST /v1/documents/blocs ne stocke rien, vous pouvez le relancer. Les commentaires
d'un même document sont rédigés de front : la durée est celle du plus long, pas leur somme.
4.6 Contrôler un document retouché avant signature#
Un conseiller retouche parfois le document final. Avant la signature, ROMEO peut vérifier que les mentions obligatoires ont tenu.
ROMEO → POST /v1/controles, mode « document » le modèle et les données d'origine, le texte retouché
ROMEO ← un contrôle mêmes alertes que pour un modèle
Reprenons le document du parcours 4.4 et retirons un mot de la mention de médiation :
sed 's/saisir gratuitement/saisir/' document.md > document-retouche.md
Figen n'a pas gardé le document d'origine. La référence se reconstruit donc à partir du modèle et des
données : avec reference.donnees, l'API rend d'abord le modèle avec ces données, puis compare.
jq -n --slurpfile donnees donnees.json --rawfile retouche document-retouche.md \
'{reference: {code: "rapport-exemple", donnees: $donnees[0]},
contenu: $retouche, format: "markdown", mode: "document"}' \
| curl -sS -X POST "$ROMEO_URL/v1/controles" \
-H "Authorization: Bearer $ROMEO_CLE" -H "Content-Type: application/json" \
--data-binary @-
La réponse est un contrôle, comme au parcours 4.2 : une alerte sur mediation, son diff, l'avis du juge. Si
le document a été retouché en HTML, envoyez-le avec "format": "html".
reference n'accepte pas cif_id : un document généré avec le modèle d'un cabinet est comparé au modèle de
base. Les zones libres adaptées par le cabinet et le commentaire inséré ressortent alors comme des passages
modifiés, en simple information (zone_libre_modifiee) quand le juge les tient pour neutres.
ROMEO peut aussi fournir lui-même le document d'origine, s'il l'a gardé. La référence devient alors
{"contenu": "…", "format": "markdown"}. type_document est facultatif ; avec reference.code, il vaut
par défaut le type du modèle de base.
4.7 Suivre ce qui change#
L'API ne rappelle pas ROMEO. C'est ROMEO qui vient lire le fil des changements d'état, à son rythme.
ROMEO → GET /v1/evenements premier appel
ROMEO ← evenements, suivant ROMEO garde la valeur de « suivant »
ROMEO → GET /v1/evenements?depuis=… appels suivants : seulement ce qui est nouveau
curl -sS "$ROMEO_URL/v1/evenements?limite=1" -H "Authorization: Bearer $ROMEO_CLE"
{"evenements": [{"id": 1, "cree_le": "…", "type": "base_publiee", "code": "rapport-exemple", "cif_id": null,
"details": {"version": 1, "revalidation_automatique": false}}],
"suivant": "1"}
Les événements viennent du plus ancien au plus récent, limite par appel : 100 par défaut, 1000 au plus.
Vos numéros différeront si d'autres modèles ont déjà été déposés. Gardez suivant et passez-le dans depuis
à l'appel suivant. Quand il n'y a rien de nouveau, la liste est vide et suivant ne change pas.
SUIVANT=1 # la valeur de « suivant » que vous venez de recevoir
curl -sS "$ROMEO_URL/v1/evenements?depuis=$SUIVANT" -H "Authorization: Bearer $ROMEO_CLE"
| Type d'événement | Ce qui s'est passé |
|---|---|
base_publiee |
Une version d'un modèle de base a été publiée. |
modele_cif_valide |
Le modèle d'un cabinet est valide. |
modele_cif_alertes |
Le modèle d'un cabinet porte au moins une alerte bloquante. |
modele_cif_derivant |
Le modèle d'un cabinet dérive : son modèle de base a changé. |
modele_cif_revalide |
La dérive d'un modèle de cabinet a été levée. |
modele_cif_supprime |
Un cabinet est revenu au modèle de base. |
details précise l'événement : version et revalidation_automatique pour base_publiee ; controle_id,
bloquantes et version_base pour un modèle de cabinet, plus sa version après un dépôt ou un appel à
revalider ; version seule pour modele_cif_supprime. Après une publication avec
revalidation_automatique, un modèle resté sans alerte bloquante donne directement modele_cif_revalide,
avec "automatique": true, sans modele_cif_derivant avant.
Le journal des générations a ses filtres, tous facultatifs : cif_id, conseiller_id, depuis et limite
(100 par défaut, 1000 au plus). Ici, depuis est une date ou une date et heure ISO 8601 (2026-11-10,
2026-11-10T09:00:00Z), pas un curseur, et les lignes viennent de la plus récente à la plus ancienne. Le
journal ne contient aucun document, aucune donnée de client :
curl -sS "$ROMEO_URL/v1/journal?cif_id=CIF-0042&limite=20" -H "Authorization: Bearer $ROMEO_CLE"
{"generations": [{"id": "doc_…", "cree_le": "…", "code": "rapport-exemple", "cif_id": "CIF-0042",
"conseiller_id": "u-1234", "modele": {}, "statut": "conforme", "nb_alertes": 0,
"reference_romeo": "DOC-2", "duree_ms": 2140}]}
5. Lire un contrôle#
Les états#
Un contrôle est valide s'il n'a aucune alerte bloquante, alertes sinon. Un document généré suit la même
règle : conforme ou alertes. Le modèle d'un cabinet connaît trois états :
| État | Sens |
|---|---|
valide |
Contrôlé sans alerte bloquante contre la version courante du modèle de base. |
alertes |
Au moins une alerte bloquante. |
derivant |
Il était valide, le modèle de base a été republié. Il a été recontrôlé contre la nouvelle version (le contrôle joint dit ce qu'il reste à corriger) et attend une revalidation. |
Seul un modèle valide sert à générer ; sinon l'option si_modele_non_valide décide (parcours 4.4). Un
modèle valide peut porter des alertes d'information : elles disent ce que le cabinet a changé sans que cela
pose de problème.
Les codes d'alerte#
Une alerte est bloquante ou vaut information. Seules les bloquantes font passer un modèle à alertes.
Son niveau dit sur quoi elle porte : clause, paragraphe, variable, zone_libre ou document.
Voici les codes à ce jour ; d'autres pourront s'ajouter (partie 8). Au contrôle d'un modèle, ou d'un document
retouché :
| Code | Gravité | Niveau | Libellé | Quoi faire |
|---|---|---|---|---|
clause_supprimee |
bloquante | clause | Mention obligatoire supprimée | Remettre la mention telle qu'elle figure dans le modèle de base. |
clause_alteree |
bloquante | paragraphe | Mention obligatoire dont le sens a changé | Reprendre la rédaction du modèle de base, ou reformuler sans en changer la portée. |
clause_non_identique |
bloquante | paragraphe | Mention à reprendre mot pour mot, modifiée | Rétablir le texte exact du modèle de base : cette mention ne se reformule pas. |
clause_a_juger |
bloquante | paragraphe | Mention modifiée, jugement indisponible | Relancer le contrôle plus tard : le juge n'a pas pu se prononcer et, dans le doute, le modèle reste bloqué. |
variable_retiree |
bloquante | variable | Variable retirée d'une mention obligatoire | Remettre la variable dans la mention : sans elle, l'information ne figurerait plus dans les documents. |
condition_modifiee |
bloquante | clause | Condition modifiée dans ou autour d'une mention obligatoire | Rétablir les conditions et les boucles du modèle de base, dans la mention comme autour d'elle : entourée d'une condition fausse, une mention disparaîtrait du document. |
jinja_invalide |
bloquante | document | Syntaxe du modèle invalide : aucun document ne peut être généré | Corriger la syntaxe à la ligne indiquée : tant qu'elle est fausse, aucun document ne peut être généré avec ce modèle. Un commentaire jamais fermé lève aussi cette alerte : une marque à laquelle il manque -->, par exemple. |
ajout_contradictoire |
bloquante | zone_libre | Ajout qui contredit une mention obligatoire | Retirer ou corriger l'ajout. |
ajout_a_juger |
bloquante | zone_libre | Passage ajouté ou modifié, jugement indisponible | Relancer le contrôle plus tard : tant que le passage n'a pas pu être jugé, le modèle reste bloqué. |
jinja_ajoute |
bloquante | clause ou document | Variable, condition ou instruction ajoutée par le cabinet | Retirer ce qui a été ajouté : une mention n'admet que les variables du modèle de base, et seules des conditions ou des boucles peuvent être ajoutées ailleurs. |
mise_en_forme_masquante |
bloquante | clause | Mise en forme qui masque ou modifie une mention | Retirer de la mention le texte barré, le HTML, l'image, le code ou les caractères invisibles : elle doit s'afficher telle qu'elle est écrite. |
rendu_divergent |
bloquante | clause ou document | Mention qui ne s'afficherait pas comme elle a été contrôlée | Repartir du modèle de base autour de cette mention : un élément placé hors d'elle en modifie ou en empêche l'affichage. |
bloc_ia_modifie |
bloquante | document | Commentaire à rédiger ajouté, retiré ou modifié | Rétablir les commentaires à rédiger et leurs consignes tels qu'ils sont dans le modèle de base. |
clause_reformulee |
information | paragraphe | Mention reformulée, sens conservé | Rien à faire : la reformulation est acceptée. |
clause_facultative_retiree |
information | clause | Mention facultative retirée | Rien à faire : le cabinet peut retirer cette mention quand elle ne le concerne pas. |
marque_absente |
information | clause | Marque de clause absente, texte retrouvé | Rien d'obligatoire ; remettre les marques facilite les contrôles suivants. |
clause_deplacee |
information | clause | Mention déplacée | Rien à faire ; vérifier que l'ordre reste logique à la lecture. |
clause_inconnue |
information | clause | Clause inconnue du modèle de base | Vérifier l'identifiant : il n'existe pas dans le modèle de base. |
zone_libre_modifiee |
information | zone_libre | Zone libre modifiée | Rien à faire : le cabinet est libre d'adapter ces passages. |
marques_abimees |
information | document | Marques abîmées | Corriger les marques signalées. Le contrôle a été mené malgré tout. Si une marque n'est plus fermée par --> (<!-- /clause seul, par exemple), s'y ajoute jinja_invalide, bloquante. |
À la génération d'un document :
| Code | Gravité | Niveau | Libellé | Quoi faire |
|---|---|---|---|---|
variable_non_resolue |
bloquante dans une clause, information ailleurs | variable | Donnée manquante à la génération | Compléter la donnée et régénérer ; bloquante si elle se trouve dans une mention obligatoire. |
clause_vide_au_rendu |
bloquante | clause | Mention obligatoire vide après rendu | Envoyer les données qui alimentent cette mention : une condition l'a vidée, elle sortirait vide dans le document. |
condition_non_renseignee |
information | variable | Condition non renseignée, tenue pour fausse | Envoyer la donnée de condition, vraie ou fausse, pour lever le doute. |
bloc_ia_indisponible |
information | document | Commentaire non rédigé | Rédiger le commentaire à la main, ou relancer la rédaction. |
bloc_fourni_inconnu |
information | document | Texte fourni pour un commentaire que le document ne porte pas | Vérifier la clé du commentaire : le texte n'a pas été inséré dans le document. |
Ce que contient un contrôle#
| Champ | Contenu |
|---|---|
statut |
valide ou alertes. |
resume |
Le nombre d'alertes bloquantes et d'informations, et le compte des mentions : clauses_attendues, clauses_intactes, clauses_reformulees. |
alertes |
La liste des alertes, détaillée ci-dessous. |
rapport_markdown, rapport_html |
Le rapport en français, lisible tel quel par un conseiller : une ligne de synthèse, une section par alerte bloquante, puis les informations. Dans le Markdown, le diff s'écrit ~~supprimé~~ et **ajouté**. |
modele_annote |
Le texte contrôlé, où chaque passage en cause est encadré par une marque d'alerte. |
La marque d'alerte du modèle annoté s'écrit <!-- alerte: code | clause: id -->…<!-- /alerte -->.
Chaque alerte porte :
| Champ | Contenu |
|---|---|
code, gravite, niveau |
Voir les tableaux ci-dessus. |
message |
La phrase à montrer telle quelle. |
clause_id, titre |
La mention concernée et son libellé, s'il y en a un. |
attendu, constate |
Le texte du modèle de base et celui du texte contrôlé, avec leurs lignes. |
diff |
La différence mot à mot : une suite d'opérations egal, supprime, ajoute. |
variable |
La variable en cause, pour les alertes de niveau variable. |
jugement |
L'avis du juge, quand il a été consulté : verdict, justification, modele_ia, depuis_cache. |
Le juge : son rôle, ses limites#
Le contrôle commence toujours par une comparaison mot à mot, sans IA. Le juge n'intervient qu'ensuite, et seulement sur les passages modifiés. Une mention intacte ne lui est jamais soumise.
| Passage modifié | Verdict | Alerte |
|---|---|---|
Mention d'exigence sens |
sens_conserve |
clause_reformulee, information |
Mention d'exigence sens |
sens_altere |
clause_alteree, bloquante |
Mention d'exigence sens |
indisponible |
clause_a_juger, bloquante |
| Zone libre ajoutée ou modifiée | neutre |
zone_libre_modifiee, information |
| Zone libre ajoutée ou modifiée | contradictoire |
ajout_contradictoire, bloquante |
| Zone libre ajoutée ou modifiée | indisponible |
ajout_a_juger, bloquante |
Certains écarts ne se discutent pas, et le juge n'est pas consulté : une mention supprimée, une mention
d'exigence identique modifiée, une variable retirée d'une mention, une condition modifiée. L'alerte est
bloquante d'office.
Ce que le contrôle garantit sans l'IA#
Un modèle n'est jamais valide parce que le juge a été convaincu, absent ou contourné. Ces règles sont
appliquées par le code, avant tout jugement, et bloquent d'office :
- Ce qui est en commentaire est absent. Un texte de mention mis en commentaire est une mention supprimée, et ce que le contrôle tient pour absent n'est jamais dans le document généré.
- Une mention doit s'afficher comme elle a été contrôlée (
rendu_divergent). Le contrôle rend le modèle du cabinet avec des données d'épreuve et compare, mention par mention, le texte qui s'afficherait à celui qu'il a examiné. Un élément placé hors de la mention qui la cache, la remplace ou en change une valeur est ainsi repéré, quelle que soit l'astuce. - Le cabinet n'ajoute pas d'instructions au modèle (
jinja_ajoute). Dans une mention, seules les variables et conditions du modèle de base sont admises. Ailleurs, le cabinet peut ajouter des conditions et des boucles, rien d'autre : une instruction qui redéfinirait une variable changerait le contenu d'une mention sans y toucher. - Pas de mise en forme qui masque (
mise_en_forme_masquante) : texte barré, HTML brut, image, code ou caractères invisibles dans une mention ; et, partout dans le modèle, HTML brut, bloc de code ou caractères invisibles que le modèle de base ne porte pas. Dans un modèle ou un document envoyé en HTML, ce que l'éditeur a rendu invisible (attributhidden,display:none…) est traité de même. - Les commentaires à rédiger sont ceux du modèle de base (
bloc_ia_modifie) : un cabinet ne peut ni en ajouter, ni en retirer, ni en changer la consigne. - Un passage non jugé bloque (
clause_a_juger,ajout_a_juger) : si le juge ne peut pas se prononcer sur une mention modifiée ou sur un passage ajouté, le modèle n'est pas validé.
Ces garanties portent sur ce que l'API rend. Pour qu'elles vaillent jusqu'à la signature, affichez et
faites signer le HTML que l'API fournit (html) : c'est lui qui fait référence. Un document retouché se
recontrôle avant signature (parcours 4.6). L'API ne lit pas vos feuilles de style : une mention cachée par
une classe CSS de votre côté lui échappe.
Les champs Markdown rendus par l'API (markdown, modele_annote, contenu_markdown) reprennent des
textes écrits par des cabinets ou venus de vos données. Affichez-les avec un rendu qui n'interprète pas le
HTML brut, ou utilisez le HTML que l'API fournit (html, rapport_html), déjà neutralisé.
Ce que vous pouvez attendre d'un jugement :
- Il est justifié. Chaque verdict vient avec une justification d'une ou deux phrases et le nom du modèle
d'IA qui l'a rendu (
modele_ia). - Il est mémorisé. Une même paire de textes n'est jugée qu'une fois. Si elle revient, l'avis sort de la
mémoire et la réponse le dit :
"depuis_cache": true. - Il est rejouable. Le même modèle redéposé reçoit le même avis. Deux cabinets qui font la même modification reçoivent la même réponse.
- Dans le doute, il bloque. Si le juge ne peut pas se prononcer sur une mention modifiée ou sur un passage ajouté, le modèle n'est pas validé. Un avis indisponible n'est pas mémorisé : relancer le contrôle suffit.
Ses limites, pour être clairs. Le juge donne un avis sur le sens d'un texte. Il peut se tromper : sa justification est là pour qu'un humain puisse le vérifier. Et il ne décide de rien. Il alerte, ROMEO décide.
6. Ce que nous proposons de plus simple, et pourquoi#
Sur huit points, l'API fait un choix plus simple que ce qu'on attend souvent d'un service de ce genre. Pour chacun : l'idée de départ, notre proposition, et ce que vous y gagnez.
| Idée | Ce que vous imaginiez peut-être | Ce que nous proposons | Pourquoi |
|---|---|---|---|
| Vos identifiants plutôt que les nôtres | Créer chaque modèle et chaque cabinet chez Figen, recevoir un identifiant Figen, le stocker dans ROMEO et tenir la correspondance. | Les adresses portent vos clés : le code du modèle, votre cif_id, votre conseiller_id, votre reference_romeo. |
Aucune table de correspondance à tenir de votre côté. Un PUT sur votre clé crée ou met à jour, et redéposer le même contenu ne crée pas de nouvelle version (inchange). |
| Des réponses immédiates plutôt que des rappels | Déposer un modèle, puis attendre que Figen rappelle ROMEO quand le contrôle est prêt. | Le contrôle est dans la réponse du dépôt. Les changements d'état survenus entre deux appels se lisent dans /v1/evenements, quand vous le voulez. |
ROMEO n'a pas de point d'entrée à exposer ni de rappel perdu à rattraper. Un seul sens de circulation, facile à tester. |
| Simuler avant de publier | Publier la nouvelle version d'un modèle de base, puis découvrir combien de cabinets se retrouvent en dérive. | simulation: true sur le dépôt : la réponse donne les anomalies et l'effet sur les modèles des cabinets, sans rien stocker. |
Inovéa sait qui sera touché avant de publier, et peut prévenir les cabinets concernés. |
| Se replier sur le modèle de base | Refuser de générer tant que le modèle du cabinet porte une alerte. | Par défaut, la génération se replie sur le modèle de base et le dit (repli_sur_base). Avec si_modele_non_valide, ROMEO peut préférer refuser, ou générer malgré les alertes. |
Un conseiller n'est jamais bloqué devant son client parce que le modèle de son cabinet attend une correction. Le document sort quand même, avec les mentions dans la rédaction d'Inovéa. |
| Contrôler à blanc pendant la saisie | Déposer le modèle pour connaître ses alertes, corriger, redéposer. | POST /v1/controles contrôle n'importe quel texte sans le déposer. |
ROMEO peut montrer les alertes dans son éditeur, avant le dépôt. Le cabinet corrige au fil de l'eau et l'historique de ses dépôts reste propre. |
| Rédiger les commentaires à part | Un seul appel qui rédige le commentaire et rend le document. | Deux appels : POST /v1/documents/blocs rédige, POST /v1/documents rend. |
Les temps de réponse sont maîtrisés : le rendu ne dépend pas de l'IA et répond vite (parcours 4.5). ROMEO sait quand afficher une attente, et le conseiller relit le commentaire avant qu'il n'entre dans le document. |
| Vérifier les données sans générer | Générer le document pour découvrir qu'il manque une donnée. | POST /v1/documents/verifier-donnees dit ce qui manque, dans quelles mentions, et si c'est bloquant. |
ROMEO peut signaler au conseiller les champs à compléter avant de lancer la génération. L'appel se fait sans IA. |
| Des mentions qu'un cabinet peut retirer | Un modèle par combinaison de statuts, ou des sections laissées en zone libre pour que chaque cabinet enlève celles qui ne le concernent pas. | presence: facultative sur la clause : le cabinet peut la retirer en entier, pas la dénaturer. |
Les modèles d'un groupement contiennent des sections qu'un cabinet doit retirer quand elles ne le concernent pas, par exemple un statut qu'il n'a pas. Il fallait le permettre sans ouvrir la porte à leur réécriture : retirée, la section est signalée pour information ; gardée, elle est contrôlée comme les autres. |
7. Données et confidentialité#
Ce qui est stocké#
| Donnée | Ce que nous gardons |
|---|---|
| Clés d'API | Le nom, le préfixe et un hachage SHA-256 de la clé, avec ses dates. Jamais la clé elle-même. |
| Modèles de base | Chaque version, avec son contenu, ses mentions et ses variables. Une version ne change plus. |
| Modèles des cabinets | Chaque version déposée, son statut et la version de base sur laquelle elle a été validée. Un DELETE supprime le modèle du cabinet, ses versions et ses contrôles. |
| Contrôles | Le statut, le résumé, les alertes, le rapport et le modèle annoté. |
| Jugements | Le verdict, sa justification et le modèle d'IA, pour ne pas juger deux fois la même modification. |
| Journal des générations | Une ligne sans contenu : identifiant, qui, quand, modèle et versions, statut, empreinte. |
| Événements | Le fil des changements d'état. |
| Référentiel produits | Un extrait du référentiel des fonds et contrats, par ISIN. |
Ce qui ne l'est pas#
- Les documents générés. Ils partent dans la réponse et ne sont pas gardés.
- Les données de vos clients. Les
donneesenvoyées servent au rendu, puis disparaissent. - Les essais. Un contrôle à blanc (
POST /v1/controles), un dépôt avecsimulation: trueet une rédaction de commentaires (POST /v1/documents/blocs) n'enregistrent ni le texte envoyé ni leur résultat. Seuls les avis du juge sur un passage de modèle sont mémorisés : empreintes des deux textes, verdict et justification, laquelle peut citer quelques mots du modèle. - Les avis du juge sur un document. Quand le texte jugé est un document généré ou un commentaire
(contrôle d'un document retouché, option
verifier_blocs), il peut contenir des données de client : rien n'est mémorisé, et l'avis n'existe que dans la réponse.
Où#
La machine et la base de données sont en France ; les modèles d'IA traitent dans l'Union européenne, pas
seulement en France. Le modèle utilisé est Claude Opus, appelé par Amazon Bedrock (région eu-west-3).
Ce que voit l'IA#
- Au contrôle : les passages modifiés et, pour y confronter les zones libres, les mentions obligatoires du modèle de base. Un texte déposé sans aucun changement ne donne lieu à aucun appel à l'IA.
- À la rédaction d'un commentaire : les données envoyées pour ce document, et le document déjà rendu, qui
sert de contexte. Si vous ne voulez pas d'IA sur un document, passez
blocs_iaà faux, ou fournissez vous-mêmes les textes dansblocs.
Vos modèles#
Les modèles d'Inovéa sont confidentiels. Aucune page publique n'en montre une ligne : un modèle ne se lit que par des appels à l'API, avec une clé, et ce guide n'utilise que des exemples inventés. Les essais et les démonstrations se font sur des données fictives.
À confirmer#
- La durée de conservation des modèles, des contrôles et du journal, et les modalités de suppression.
8. Nos engagements#
Versions, préavis, journal des changements#
- Une API versionnée. Toutes les routes portent le préfixe
/v1. Aucune rupture n'y sera introduite : un changement incompatible passe par une nouvelle version de l'API. Ajouter un champ à une réponse ou un code d'alerte n'est pas une rupture : décidez surgravite(bloquanteouinformation), et traitez un code que vous ne connaissez pas encore selon sa gravité. - Un préavis. Vous êtes prévenus avant tout changement de l'API. Le délai de préavis et le canal d'annonce sont à confirmer.
- Un journal des changements. Chaque évolution de
/v1est consignée dansCHANGELOG-API.md, remis avec ce guide. Sur le service, il se lit à la fin de la page/guide.
Environnement de test et temps de réponse#
- Une plateforme de test. Vous disposez d'un environnement de test et de cette documentation.
L'adresse vous est remise avec votre clé ;
/v1/moirappelle dans quel environnement une clé travaille. Les essais s'y font sur des données fictives. L'adresse de production est à confirmer. - Des temps de réponse maîtrisés. Le rendu d'un document est immédiat, la rédaction par l'IA est plus
lente : c'est pour cela que les deux sont séparés (parcours 4.5). Les réponses de génération portent leur
durée (
duree_ms). Le relais placé devant l'environnement de test coupe tout appel à 100 secondes (parcours 4.5). Les temps de réponse garantis, la disponibilité du service et le maintien de cette limite en production sont à confirmer.
9. Référence rapide#
Les routes#
Authentification : Authorization: Bearer suivi de la clé, sur tout /v1 sauf /v1/sante.
| Méthode | Route | Rôle |
|---|---|---|
GET |
/v1/sante |
État du service, mode de l'IA, base de données. Sans clé. Répond aussi à HEAD, sans corps. |
GET |
/v1/moi |
À qui appartient la clé, environnement. |
GET |
/v1/catalogue-variables?code= |
Variables et blocs IA ; avec code, ce que ce modèle utilise. |
GET |
/v1/modeles-de-base |
Liste des modèles de base et compte des modèles de cabinet par état. |
PUT |
/v1/modeles-de-base/{code} |
Déposer une version (analyse, anomalies, impact). simulation: true ne stocke rien. |
GET |
/v1/modeles-de-base/{code}?version= |
Détail d'une version ; sans version, la version publiée courante. |
PUT |
/v1/cifs/{cif_id}/modeles/{code} |
Déposer le modèle d'un cabinet. La réponse contient le contrôle. |
GET |
/v1/cifs/{cif_id}/modeles |
État de tous les modèles d'un cabinet, et lequel servirait à générer. |
GET |
/v1/cifs/{cif_id}/modeles/{code} |
Détail et dernier contrôle. |
POST |
/v1/cifs/{cif_id}/modeles/{code}/revalider |
Lever la dérive si le dernier contrôle est sans alerte bloquante. |
DELETE |
/v1/cifs/{cif_id}/modeles/{code} |
Revenir au modèle de base : le modèle du cabinet, ses versions et ses contrôles sont supprimés. |
POST |
/v1/controles |
Contrôle à blanc de n'importe quel texte. Rien n'est stocké. |
GET |
/v1/controles/{id} |
Relire un contrôle stocké. |
POST |
/v1/documents |
Générer un document et contrôler le rendu. |
POST |
/v1/documents/blocs |
Rédiger seulement les commentaires libres, pour relecture dans ROMEO. |
POST |
/v1/documents/verifier-donnees |
Dire ce qui manque dans les données, sans générer. |
GET |
/v1/journal |
Journal des générations, sans contenu. Filtres : cif_id, conseiller_id, depuis (une date), limite. |
GET |
/v1/evenements?depuis= |
Fil des changements d'état. depuis est le curseur suivant ; limite borne la réponse. |
Les schémas complets sont dans /docs et /openapi.json. Un paramètre d'adresse (?code=, ?version=,
?depuis=) se donne avec une valeur ou s'omet. Les adresses s'écrivent sans barre finale : /v1/moi/ rend
404 introuvable.
Les valeurs admises#
| Champ | Valeurs |
|---|---|
type |
der, lettre_mission, mandat_courtage, rapport_conseil, declaration_adequation, mandat_rto, autre |
profil |
conseiller, consultant, tous |
format |
markdown (par défaut), html |
mode d'un contrôle |
modele (par défaut), document |
si_modele_non_valide |
modele_de_base (par défaut), generer, refuser |
| Statut d'un commentaire | redige, fourni, indisponible |
code d'un modèle |
2 à 63 caractères : minuscules sans accent, chiffres et tirets, sans tiret en tête |
cif_id, conseiller_id |
1 à 64 caractères : lettres sans accent, chiffres, ., _ et - |
Clé d'un commentaire, dans blocs |
1 à 64 caractères : minuscules sans accent, chiffres et _, une lettre en tête |
Champs obligatoires : type, profil, libelle et contenu pour un modèle de base ; contenu pour le
modèle d'un cabinet ; contenu et reference (avec code ou contenu, jamais les deux) pour un contrôle ;
code pour les trois routes de /v1/documents. Tous les autres champs sont facultatifs.
Les limites#
| Quoi | Limite | Au-delà |
|---|---|---|
| Corps d'une requête | 2 Mo ; 32 niveaux d'imbrication | 413 corps_trop_grand ; 400 requete_invalide |
Texte d'un modèle ou d'un document (contenu) |
500 000 caractères | 413 corps_trop_grand |
donnees.products |
200 produits | 400 requete_invalide |
| Document rendu | 300 000 caractères | 422 generation_impossible |
libelle, notes_version, reference_romeo |
300, 2 000 et 128 caractères | 400 requete_invalide |
Les erreurs#
Toutes les erreurs ont la même forme :
{"erreur": {"code": "modele_non_personnalisable", "message": "…", "details": []}}
code est fait pour votre programme, message pour un humain, details précise quand il y a lieu.
| HTTP | Code d'erreur | Quand |
|---|---|---|
400 |
requete_invalide |
Corps ou paramètres mal formés : JSON illisible, champ obligatoire absent, champ inconnu, valeur non admise, donnée mal formée. details nomme chaque champ refusé (champ, emplacement, message). |
400 |
gabarit_invalide |
Modèle refusé pour sa forme : au dépôt d'un modèle de base, une anomalie de gravité erreur. details liste les anomalies. Rien n'est stocké. |
400 |
format_incoherent |
Le format annoncé contredit le contenu : du Markdown annoncé html, par exemple. |
401 |
cle_absente, cle_invalide |
En-tête Authorization absent ou mal formé ; clé inconnue ou révoquée. |
404 |
introuvable |
Adresse, modèle de base, version, modèle de cabinet ou contrôle inconnu. details dit lequel (ressource). |
405 |
methode_non_permise |
Méthode HTTP non prévue sur cette adresse. |
409 |
modele_non_personnalisable |
Un cabinet dépose un modèle alors que le modèle de base ne l'autorise pas. |
409 |
revalidation_impossible |
Revalidation demandée alors que le dernier contrôle porte une alerte bloquante, ou un passage que le juge n'a pas pu juger. details donne le contrôle et le nombre d'alertes bloquantes. |
409 |
depots_simultanes |
Le même modèle est modifié par plusieurs appels à la fois : rejouez l'appel. |
413 |
corps_trop_grand |
Corps de plus de 2 Mo, ou texte de plus de 500 000 caractères. |
422 |
modele_non_valide |
Génération demandée avec si_modele_non_valide: "refuser" alors que le modèle du cabinet n'est pas valide. |
422 |
generation_impossible |
Le modèle ne peut pas être rendu avec ces données : un document de plus de 300 000 caractères, par exemple. details dit pourquoi. |
500 |
erreur_interne |
Défaut du service. details porte l'identifiant de la requête, à nous transmettre. |
503 |
service_degrade |
/v1/sante seulement, quand la base de données ne répond pas. |
Dans tous les cas, message dit ce qui ne va pas. Le 503 de /v1/sante garde le corps habituel de la
route, avec "statut": "degrade", et y ajoute l'objet erreur. Une réponse qui vient du relais, et non de
l'API, ne suit pas cette forme : une coupure (délai dépassé ou code 524, parcours 4.5), par exemple.
Chaque réponse porte un en-tête X-Request-Id : le vôtre si vous en envoyez un (1 à 64 lettres sans accent,
chiffres, ., _ ou -), sinon celui que l'API crée. Gardez-le, et joignez-le à toute question.
Journal des changements de l'API#
Toute évolution de /v1 est consignée ici, la plus récente en premier. Aucune rupture n'est introduite dans
/v1 : un changement incompatible passe par une nouvelle version de l'API, annoncée à l'avance.
v1 : corrections du 10 novembre 2026 (recette)#
Corrections faites après une relecture de l'API du point de vue d'un développeur client, avant toute mise en production. Les champs ajoutés ne retirent rien. Les corrections qui refusent ou changent ce qui passait à tort sont marquées « à vérifier de votre côté ».
Documents#
POST /v1/documents/verifier-donnees: la réponse porte un nouveau champalertes, de la même forme queconformite.alertesd'un document. Il liste ce que la génération relèverait avec ces données (variable_non_resolue,clause_vide_au_rendu,condition_non_renseignee), hors alertes des commentaires à rédiger.completsuit désormais cette règle :complet: trueveut dire que générer maintenant avec ce corps ne lèvera aucune alerte bloquante due aux données. Avant,completpouvait valoirtruealors qu'une mention obligatoire sortait vide (clause_vide_au_rendu).POST /v1/documents/blocs: à vérifier de votre côté. La route accepte le corps complet dePOST /v1/documents(blocset toutes les options, qu'elle ignore si elle ne les lit pas) et refuse désormais toute autre clé,400 requete_invalide, comme les autres routes. Avant, une clé inconnue, donc une faute de frappe, passait sans rien dire.POST /v1/documents,/v1/documents/blocs,/v1/documents/verifier-donnees, etreference.donneesdePOST /v1/controles: à vérifier de votre côté. Une donnée dont la forme contredit le catalogue de variables est refusée,400 requete_invalide, etdetails[].champdonne son chemin (donnees.products.0.name) :productsqui n'est pas une liste d'objets,totals,suitabilityouremunerationqui n'est pas un objet, une liste ou un objet pour une valeur simple, un booléen pour autre chose qu'un oui/non. Avant, la valeur était rendue telle quelle ("org_orias": falses'écrivait « Non »). Restent admis : un nombre pour un texte, un texte pour un montant, une liste de phrases pour un texte, une clé hors catalogue, etnull, qui vaut absent.POST /v1/documents, champblocs: à vérifier de votre côté. Un commentaire renvoyé vide (chaîne vide ou faite de blancs) dit que le conseiller l'a vidé : il reste à rédiger (statut: "indisponible", marqueur[Bloc à rédiger : cle], alertebloc_ia_indisponible), sans appel à l'IA ni au juge pour cette clé. Avant, l'API le faisait rédiger par l'IA (statut: "redige").nullest désormais admis et vaut non fourni : le commentaire est rédigé comme si la clé n'était pas envoyée (avant :400 requete_invalide).
Modèles de base et modèles des cabinets#
PUT /v1/modeles-de-base/{code}: à vérifier de votre côté.personnalisableomis ne vauttruequ'à la création du modèle ; au redépôt, il garde sa valeur enregistrée. Avant, un redépôt qui ne le répétait pas remettaittrue.PUT /v1/modeles-de-base/{code}:inchangeest précisé, sans changer de sens.inchange: true: aucune nouvelle version n'a été créée, le contenu est celui de la dernière version.type,profil,libelleetpersonnalisablesuivent quand même ce dépôt, et un brouillon redéposé avecpublier: trueest publié : la réponse montre l'état d'après l'appel.- Modèle de cabinet suspendu : à vérifier de votre côté. Quand un modèle de base passe à
personnalisable: false, les modèles déjà déposés par les cabinets sont gardés mais ne servent plus à générer : le modèle de base sert, quelle que soit l'optionsi_modele_non_valide, sans refus. La génération le dit parmodele.repli_sur_base: true(modele.etat_modele_cifreste l'état réel du modèle du cabinet). Avant, ces modèles continuaient de servir. Si la base redevient personnalisable, ils resservent tels quels. GET /v1/cifs/{cif_id}/modelesetGET /v1/cifs/{cif_id}/modeles/{code}(ainsi que la réponse derevalider) : nouveau champsuspendu. Dans la liste,utilisevaut alorsmodele_de_base.- Message de
400 gabarit_invalideau dépôt d'un modèle de base : accord corrigé (« 2 anomalies de forme qui empêchent de l'accepter »).
Service#
HEAD /v1/sante:200, ou503si la base ne répond pas, sans corps, pour les sondes de surveillance.GET /v1/sante: nouveau champrevision, l'identifiant de la révision du code servie. Il change à chaque mise à jour du service ; rien d'autre ne change dans la réponse.
v1 : version initiale (novembre 2026, recette)#
Première version de l'API, ouverte sur l'environnement de test. La date de mise en production est à confirmer.
Service#
GET /v1/sante: état du service, mode de l'IA, base de données (sans clé) ;503avecstatut: "degrade"si la base ne répond pas.GET /v1/moi: à qui appartient la clé, environnement.GET /v1/catalogue-variables?code=: variables et blocs IA ; aveccode, ce qu'un modèle utilise.
Modèles de base#
GET /v1/modeles-de-base: liste des modèles de base et compte des modèles de cabinet par état.PUT /v1/modeles-de-base/{code}: déposer une version (analyse, anomalies, impact sur les modèles des cabinets) ;simulation: truene stocke rien.GET /v1/modeles-de-base/{code}?version=: détail d'une version.- Marquage : une clause peut porter
presence: facultative(le cabinet peut la retirer en entier, pas la dénaturer) ; chaque clause des réponses portefacultative.
Modèles des cabinets#
PUT /v1/cifs/{cif_id}/modeles/{code}: déposer le modèle d'un cabinet ; la réponse contient le contrôle.GET /v1/cifs/{cif_id}/modeles: état de tous les modèles d'un cabinet, et lequel servirait à générer.GET /v1/cifs/{cif_id}/modeles/{code}: détail et dernier contrôle.POST /v1/cifs/{cif_id}/modeles/{code}/revalider: lever la dérive si le dernier contrôle est sans alerte bloquante ; sinon409 revalidation_impossible.DELETE /v1/cifs/{cif_id}/modeles/{code}: revenir au modèle de base.
Contrôles#
POST /v1/controles: contrôle à blanc de n'importe quel texte, rien n'est stocké.GET /v1/controles/{id}: relire un contrôle stocké.
Documents#
POST /v1/documents: générer un document et contrôler le rendu.POST /v1/documents/blocs: rédiger seulement les commentaires libres d'un document, pour relecture dans ROMEO.POST /v1/documents/verifier-donnees: dire ce qui manque dans les données, sans générer.
Suivi#
GET /v1/journal: journal des générations, sans contenu.GET /v1/evenements?depuis=: fil des changements d'état.
Conventions#
- Authentification par
Authorization: Bearersur tout/v1, sauf/v1/sante. - Erreurs de la forme
{"erreur": {"code": "…", "message": "…", "details": […]}}, avec les codes HTTP 400, 401, 404, 405, 409, 413, 422, 500 ou 503. - Codes d'erreur :
requete_invalide,gabarit_invalide,format_incoherent(400) ;cle_absente,cle_invalide(401) ;introuvable(404) ;methode_non_permise(405) ;modele_non_personnalisable,revalidation_impossible,depots_simultanes(409) ;corps_trop_grand(413) ;modele_non_valide,generation_impossible(422) ;erreur_interne(500) ;service_degrade(503, sur/v1/sante). - États d'un modèle de cabinet :
valide,alertes,derivant. Seul un modèlevalidesert à générer ; sinon l'optionsi_modele_non_validedécide. - Statuts d'un bloc de commentaire :
redige,fourni,indisponible.
Codes d'alerte#
Les codes d'alerte sont décrits dans le guide (partie 5) : gravité, libellé et quoi faire. Un code peut s'ajouter sans changer de version : un client décide sur gravite.
- Au contrôle :
clause_supprimee,clause_alteree,clause_non_identique,clause_a_juger,variable_retiree,condition_modifiee,jinja_invalide,jinja_ajoute,mise_en_forme_masquante,rendu_divergent,bloc_ia_modifie,ajout_a_juger,ajout_contradictoire,clause_reformulee,clause_facultative_retiree,marque_absente,clause_deplacee,clause_inconnue,zone_libre_modifiee,marques_abimees. - À la génération :
variable_non_resolue,clause_vide_au_rendu,condition_non_renseignee,bloc_ia_indisponible,bloc_fourni_inconnu.