curl --request POST \
--url https://api.zelinqa.ai/v1/sessions/{session_id}/next \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"state_version": 0
}
'{
"request_id": "req_1002",
"session_id": "ses_01J8Z",
"decision_id": "dec_7f2a",
"action": "ask",
"stop_reason": null,
"candidates": [
{
"rank": 1,
"question_id": "q_budget",
"text": "Quel budget souhaitez-vous consacrer au canapé ?",
"type": "open",
"choices": [],
"target_ids": [
"annual_budget"
]
},
{
"rank": 2,
"question_id": "q_delai",
"text": "À quelle période souhaitez-vous être livré ?",
"type": "single_choice",
"choices": [
{
"choice_id": "choice_1m",
"label": "Dans le mois"
},
{
"choice_id": "choice_3m",
"label": "Dans les trois mois"
},
{
"choice_id": "choice_later",
"label": "Plus tard"
}
],
"target_ids": [
"delivery_window"
]
}
],
"progress": {
"objective": {
"computed_status": "in_progress",
"progress": 0.34,
"client_override": null,
"effective_status": "in_progress"
},
"sub_objectives": [
{
"id": "so_besoin",
"order_position": 0,
"completion_role": "blocking",
"computed_status": "covered",
"progress": 1,
"client_override": null,
"effective_status": "covered"
},
{
"id": "so_budget",
"order_position": 1,
"completion_role": "blocking",
"computed_status": "in_progress",
"progress": 0.15,
"client_override": null,
"effective_status": "in_progress"
},
{
"id": "so_livraison",
"order_position": 2,
"completion_role": "contributing",
"computed_status": "not_started",
"progress": 0,
"client_override": null,
"effective_status": "not_started"
}
]
},
"turn_count": 2,
"turns_remaining": 8,
"warnings": [],
"degraded": false,
"degraded_reasons": [],
"versions": {
"state_version": 4,
"engine_version": "1.0.0",
"api_version": "1.0"
}
}Comprendre le tour précédent et proposer les questions suivantes
Route principale du runtime. En un seul appel, le moteur résout la question réellement posée et son outcome, applique les mises à jour du client, réduit l’état, recalcule les progressions, puis classe les questions éligibles.
Le client n’a pas à savoir quelle candidate son agent a utilisée : si
decision_id, question_id ou outcome sont absents, NBQ les résout depuis
la décision en attente, le texte de l’agent, la réponse structurée et le
contexte. Une reformulation de la question par l’agent hôte reste
rattachable.
Au premier appel d’une session neuve, previous_turn est absent.
curl --request POST \
--url https://api.zelinqa.ai/v1/sessions/{session_id}/next \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"state_version": 0
}
'{
"request_id": "req_1002",
"session_id": "ses_01J8Z",
"decision_id": "dec_7f2a",
"action": "ask",
"stop_reason": null,
"candidates": [
{
"rank": 1,
"question_id": "q_budget",
"text": "Quel budget souhaitez-vous consacrer au canapé ?",
"type": "open",
"choices": [],
"target_ids": [
"annual_budget"
]
},
{
"rank": 2,
"question_id": "q_delai",
"text": "À quelle période souhaitez-vous être livré ?",
"type": "single_choice",
"choices": [
{
"choice_id": "choice_1m",
"label": "Dans le mois"
},
{
"choice_id": "choice_3m",
"label": "Dans les trois mois"
},
{
"choice_id": "choice_later",
"label": "Plus tard"
}
],
"target_ids": [
"delivery_window"
]
}
],
"progress": {
"objective": {
"computed_status": "in_progress",
"progress": 0.34,
"client_override": null,
"effective_status": "in_progress"
},
"sub_objectives": [
{
"id": "so_besoin",
"order_position": 0,
"completion_role": "blocking",
"computed_status": "covered",
"progress": 1,
"client_override": null,
"effective_status": "covered"
},
{
"id": "so_budget",
"order_position": 1,
"completion_role": "blocking",
"computed_status": "in_progress",
"progress": 0.15,
"client_override": null,
"effective_status": "in_progress"
},
{
"id": "so_livraison",
"order_position": 2,
"completion_role": "contributing",
"computed_status": "not_started",
"progress": 0,
"client_override": null,
"effective_status": "not_started"
}
]
},
"turn_count": 2,
"turns_remaining": 8,
"warnings": [],
"degraded": false,
"degraded_reasons": [],
"versions": {
"state_version": 4,
"engine_version": "1.0.0",
"api_version": "1.0"
}
}Autorisations
Clé d'intégration préfixée nbq_live_, envoyée dans
Authorization: Bearer nbq_live_… et résolue par l'authorizer Lambda de
l'API Gateway publique. L'authorizer valide la clé, puis injecte en amont
du service les headers de contexte x-tenant-id, x-nbq-id et x-scopes —
x-scopes étant la liste des scopes de la clé séparés par des virgules,
par exemple runtime,configuration:read.
Ces headers ne sont jamais acceptés depuis le client : toute valeur entrante
est écrasée. Une clé absente ou invalide produit 401 au niveau de la
passerelle ; une clé valide sans le scope requis produit 403 avec le code
insufficient_scope.
En-têtes
Clé unique par mutation logique, choisie par l'appelant.
Même clé et même corps renvoient exactement la réponse d'origine, sans
rejouer l'effet : aucun retry ne double turn_count, un outcome, un
événement, un feedback ou une publication. Même clé avec un corps différent
produit 409 idempotency_key_reused.
Les enregistrements sont isolés par tenant et par opération, et sont purgés après 24 heures. Passé ce délai, la même clé est traitée comme neuve.
8 - 128Paramètres de chemin
Identifiant opaque de session attribué par NBQ à la création.
1 - 128Corps
Version lue par le client avant cette mutation, en contrôle optimiste.
x >= 0Observation du dernier échange. Absent au premier appel d'une session neuve.
decision_id, question_id et outcome sont des aides optionnelles,
jamais des identifiants que le client devrait fabriquer. Lorsqu'ils manquent,
NBQ résout la candidate utilisée depuis la décision en attente,
assistant_text, la réponse structurée et le contexte — ce qui permet à
l'agent hôte de reformuler librement les questions. Une valeur explicite du
client reste prioritaire sur l'inférence et est validée.
Show child attributes
Show child attributes
Contexte apparu depuis le dernier appel NBQ. Le client choisit un résumé compact ou le delta ordonné des messages ; il ne renvoie jamais l'historique déjà traité.
- Option 1
- Option 2
Show child attributes
Show child attributes
Mises à jour explicites du système appelant, prioritaires sur l'inférence.
Show child attributes
Show child attributes
Contraintes valables pour cet appel uniquement. Elles sont appliquées avant le calcul du classement, jamais en filtrant un top 3 déjà constitué.
Show child attributes
Show child attributes
Réponse
Décision calculée, ou arrêt explicite si aucune question n'existe.
Aucun score de sélection n'est exposé : le classement est porté par rank.
Un score brut n'a pas de sens métier hors du moteur et ne doit pas devenir
une dépendance des intégrations.
Invariants garantis par le moteur, non exprimés en JSON Schema pour rester générables en SDK, et couverts par les tests de contrat (NBQ-313) :
action: askimpliquedecision_idnon nul,stop_reasonnul et au moins un candidat ;action: stopimpliquedecision_idnul,stop_reasonrenseigné etcandidatesvide.
Non nul quand action vaut ask. À renvoyer dans le tour suivant si disponible.
stop n'est produit que lorsqu'aucune question identifiable
n'existe. Une limite de tours atteinte, un objectif déjà atteint ou une
éligibilité normale vide ne coupent pas la conversation : le moteur
propose encore la meilleure question disponible et le signale dans
warnings. La décision d'arrêter appartient à l'appelant.
ask, stop Unique cause d'arrêt dur : aucune question identifiable ne subsiste après
application des exclusions dures — question inactive, sous-objectif exclu par
le client, contrainte stricte de l'appel. Les autres situations terminales
remontent par warnings, la conversation restant décidée par l'appelant.
no_question_available Ordonnées par pertinence décroissante, rang 1 en premier. Lorsque plusieurs candidats sont demandés, le moteur simule la couverture apportée par le premier avant de choisir le suivant : deux variantes demandant la même information ne sont pas retournées ensemble.
10Show child attributes
Show child attributes
Show child attributes
Show child attributes
x >= 0Vaut 0 lorsque la limite souple est atteinte ou dépassée.
x >= 0Conditions d'arrêt réunies, sans que NBQ interrompe la conversation.
max_turns_reached: la limite souple est atteinte ou dépassée ;objective_achieved: les conditions de réussite sont satisfaites ;eligibility_exhausted_fallback: plus aucune question n'était éligible normalement, la proposition est un repli — elle porte tout de même unquestion_idvalide et respecte les exclusions dures ;constraints_relaxed: une préférenceprefera dû être élargie.
max_turns_reached, objective_achieved, eligibility_exhausted_fallback, constraints_relaxed Vrai lorsque la compréhension du tour a été effectuée en mode réduit.
missing_user_text, summary_only_context, semantic_service_unavailable, unresolved_previous_turn La version de configuration épinglée par la session n'est pas exposée : le client ne la choisit pas et ne doit pas s'y adosser.
Show child attributes
Show child attributes