Référence de l'API publique
Exécuter un flow de canal API, poursuivre une session et récupérer sa sortie.
API publique du canal API
Base : origine du service Core, préfixe /public/v1/api.
La clé identifie le locataire et le canal ; aucun channel_id dans l'URL.
POST /execute est la seule écriture publique du canal API. Les lectures de conversations et l'API du widget ont leurs propres contrats.
Authentification
| Mode du canal | Clé | Appelant | Règle d'origine |
|---|---|---|---|
| Serveur | nx_live_ en production, nx_test_ en développement ou préproduction | Serveur, CI ou script | Ne pas envoyer Origin ; une requête qui l'envoie est refusée |
| Public | nx_pub_ | Navigateur, application mobile ou native | Si Origin est envoyé, il doit figurer dans les origines autorisées |
Note :
- Envoyez
Authorization: Bearer <clé>sur POST et GET. - Une clé widget ne peut pas appeler ces routes.
- Le canal doit être actif et relié à un flow.
- Un canal archivé renvoie 410, un canal non actif 409.
La publication des flows et des canaux est différée : la console ne permet pour le moment de créer des canaux API et widget qu'en développement. Ce mode exécute le brouillon ; les canaux de production existants exigent toujours une version publiée pour s'exécuter.
POST /public/v1/api/execute
Content-Type : application/json ou multipart/form-data.
Réponse : 200 application/json par défaut, 200 text/event-stream avec ?stream=true.
| Paramètre ou en-tête | Type | Règle |
|---|---|---|
Authorization | header | Obligatoire : Bearer <clé> du canal API. |
stream | query boolean | true : SSE ; false : JSON. Si absent, le champ stream du corps JSON s'applique (JSON par défaut). Le multipart renvoie du JSON par défaut. |
Idempotency-Key | header string | Facultatif, 1 à 255 caractères non blancs ; même valeur pour réessayer la même opération. |
Origin | header string | Clé serveur : interdit. Clé publique : si présent, doit être autorisé sur le canal. |
X-Naixus-Signature | header string | Obligatoire uniquement si la signature HMAC du canal serveur est activée. |
Corps JSON (application/json)
| Champ | Type | Règle |
|---|---|---|
payload | object | Facultatif, {} par défaut ; 10 000 caractères maximum après sérialisation JSON. Les champs métier suivent le schéma configuré sur le canal. |
payload.user_message | string | Entrée conversationnelle si présente ; utilisée pour répondre à un nœud Question en pause. |
session_id | string (UUID) | Facultatif ; absent : nouvelle session, présent : session existante du même canal. |
stream | boolean | Ancien champ facultatif ; le paramètre d'URL a priorité. |
curl -X POST 'https://api.example.com/public/v1/api/execute' \
-H 'Authorization: Bearer nx_live_votre_cle' \
-H 'Content-Type: application/json' \
-d '{"payload":{"user_message":"Résumez ma commande"}}'Corps multipart (multipart/form-data)
| Champ de formulaire | Type | Règle |
|---|---|---|
payload | chaîne JSON représentant un objet | Facultatif ; {} par défaut. payload.user_message doit être une chaîne si présent. |
session_id | string (UUID) | Facultatif ; conversation_id n'est pas accepté. |
| Champ de fichiers configuré sur le canal | fichiers | Facultatifs ; défaut docs. Envoi interdit si les fichiers sont désactivés. Nombre, taille et MIME selon la configuration du canal. |
Le multipart retourne du JSON par défaut et du SSE avec ?stream=true. Un mauvais nom de champ pour les fichiers est rejeté, pas ignoré. Pour un fichier, précisez le type MIME sur la partie multipart et laissez curl définir l'en-tête Content-Type avec sa boundary :
curl -N 'https://api.example.com/public/v1/api/execute?stream=true' \
-H 'Authorization: Bearer nx_live_votre_cle' \
-F 'docs=@cv.pptx;type=application/vnd.openxmlformats-officedocument.presentationml.presentation'Réponse JSON (200)
| Champ | Type | Signification |
|---|---|---|
run_id | string | null | Identifiant de l'exécution ; null si une session déjà en livechat évite l'automatisation. |
session_id | string | Identifiant stable de la session, à réutiliser pour les appels suivants et les fichiers générés. |
status | string | success, error, pending ; cancelled est réservé. Une erreur d'exécution peut avoir le statut HTTP 200. |
output | objet ou null | Sortie de l'exécution ; les champs ci-dessous existent lorsque output est un objet. |
output.result | valeur JSON ou null | Résultat propre au flow, pas nécessairement du texte pour l'utilisateur. |
output.error | valeur JSON ou null | Erreur d'exécution si status: "error". |
output.messages | tableau | Publications de cet appel uniquement, ordonnées ; chaque élément a id, role: "assistant", content. Pour les tours précédents, utiliser la lecture de conversation. |
output.metadata | objet | channel_id, flow_id, flow_name, flow_version, livechat_mode, environment, execution_order, started_at, completed_at ; les champs autres que channel_id peuvent être null. |
usage | objet ou null | Compteurs, dont total_nodes et duration_ms ; null sans exécution. |
error | objet ou null | null dans la réponse HTTP 200 ; les erreurs du flow sont dans output.error. |
{
"run_id": "9c1d2e3f-4a5b-6c7d-8e9f-0a1b2c3d4e5f",
"session_id": "b1f2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "success",
"output": {
"result": { "text": "Votre commande est en chemin." },
"error": null,
"messages": [{ "id": "pub_7f6d8e9a", "role": "assistant", "content": "Votre commande est en chemin." }],
"metadata": {
"channel_id": "6f1e2d3c-4b5a-6978-8f9e-0a1b2c3d4e5f",
"flow_id": "1a2b3c4d-5e6f-7890-abcd-ef1234567890",
"flow_name": "Commandes",
"flow_version": null,
"livechat_mode": null,
"environment": "dev",
"execution_order": ["trigger_from_channel", "agent"],
"started_at": "2026-08-04T10:00:00Z",
"completed_at": "2026-08-04T10:00:01Z"
}
},
"usage": { "total_nodes": 2, "duration_ms": 1000 },
"error": null
}Variantes : un transfert vers le livechat pendant l'appel renvoie pending (output.result, usage.duration_ms et completed_at éventuellement null). Si la session est déjà en livechat, run_id et usage valent null, output.messages vaut [] et output.metadata contient seulement channel_id et livechat_mode.
Réponse SSE (200 text/event-stream)
Chaque trame contient data: <objet JSON>\n\n ; l'objet porte le champ type (pas de champ SSE event:). La fin est la trame littérale data: [DONE]\n\n.
type | Champs | Signification |
|---|---|---|
data-run | data.run_id, data.session_id | Première trame ; run_id: null si le livechat évite l'exécution. |
text-start | id | Début d'une publication. |
text-delta | id, delta | Fragment de texte ; regrouper les fragments par id. |
text-end | id | Fin de la publication ; cet id apparaît dans output.messages[].id du JSON. |
data-status | data.status: "pending", data.output.messages, data.output.metadata.livechat_mode | En attente ; livechat_mode: null pour un nœud Question, livechat_waiting pour un transfert livechat. Le flux peut rester ouvert. |
finish | finishReason: "stop" | Fin normale, suivie de [DONE]. |
error | errorText | Erreur après le début du flux ; HTTP reste 200, aucun finish ne suit. |
data: {"type":"data-run","data":{"run_id":"9c1d2e3f-4a5b-6c7d-8e9f-0a1b2c3d4e5f","session_id":"b1f2c3d4-e5f6-7890-abcd-ef1234567890"}}
data: {"type":"text-start","id":"pub_7f6d8e9a"}
data: {"type":"text-delta","id":"pub_7f6d8e9a","delta":"Votre commande est en chemin."}
data: {"type":"text-end","id":"pub_7f6d8e9a"}
data: {"type":"finish","finishReason":"stop"}
data: [DONE]Poursuivre une session et répondre à un nœud Question
| Situation | Contrat |
|---|---|
| Nouvel appel | Omettre session_id. |
| Suite de la conversation | Renvoyer le session_id reçu ; ne pas le confondre avec run_id. |
| Nœud Question en pause | status: "pending", question dans output.messages, livechat_mode: null ; répondre avec le même session_id et payload.user_message. Le run_id ne change pas et les autres champs du payload ne sont pas nécessaires. |
| Session inconnue / autre locataire | 404 conversation_not_found. |
| Session d'un autre canal du même locataire | 403 conversation_forbidden. |
| Deux réponses simultanées | 409 resume_conflict (actuellement dans detail, avec retry_after_ms). |
À la reprise d'une Question, les autres champs du payload et les fichiers sont ignorés. Une question de clarification d'un Agent en pause (option Autoriser les questions de clarification activée) suit le même contrat : la réponse reprend la même étape Agent.
Fichiers générés
GET /public/v1/api/execute/{session_id}/artifacts/{artifact_id} : téléchargement d'un fichier produit par le flow. artifact_id figure dans output.result de /execute. La route n'existe pas pour l'API widget.
| Entrée | Type | Règle |
|---|---|---|
session_id | chemin string (UUID) | Session ayant produit le fichier ; pas le run_id. |
artifact_id | chemin string | Identifiant retourné dans le résultat du flow. |
Authorization | header | Même clé de canal que pour /execute. Signature HMAC non requise sur GET. |
| Statut | Réponse |
|---|---|
200 | Octets du fichier ; pour un PPTX : application/vnd.openxmlformats-officedocument.presentationml.presentation, avec Content-Disposition d'attachement. |
404 artifact_not_found | Fichier inconnu, expiré ou appartenant à un autre canal ou à une autre session ; conservation d'une heure. |
401, 403, 429 | Voir Erreurs et Limitation de débit. |
Réessais sans doublons
En-tête POST Idempotency-Key : 1 à 255 caractères non blancs, une valeur par opération. Un réessai doit conserver le même payload, les mêmes fichiers, la même session et le même format JSON/SSE.
| Réessai | Réponse |
|---|---|
| Identique, opération terminée | Résultat rejoué ; les publications SSE sont rejouées si le format est SSE. |
| Identique, opération en cours | 409 idempotency_in_progress. |
| Même clé, contenu différent | 409 idempotency_conflict. |
| Processus arrêté irrécupérablement | Peut aboutir à 503 request_abandoned après dix minutes. |
La déduplication de l'API ne garantit pas l'exécution unique des effets dans les outils externes.
Signature HMAC
| Propriété | Contrat |
|---|---|
| Portée | POST sur un canal serveur dont la signature est activée ; jamais les routes GET. |
| En-tête | X-Naixus-Signature: t=<secondes_unix>,v1=<hmac_sha256_hex_minuscule>. |
| Données signées | Octets exacts de <horodatage>. suivis du corps brut, avec le secret de signature du canal. |
| Tolérance temporelle | 300 secondes. |
Voir Signer les requêtes pour le calcul et la rotation du secret.
Erreurs
Format habituel : {"error":{"code":"<code>","message":"<message>"}}, avec X-Request-ID. resume_conflict utilise actuellement detail avec retry_after_ms ; http_error est un code de remplacement générique.
| HTTP | Codes et circonstances |
|---|---|
400 | payload_validation_error ou erreur de validation de fichier (dont file_field_mismatch). |
401 | invalid_api_key, signature_required, invalid_signature, signature_expired. |
403 | environment_mismatch, origin_not_allowed, conversation_forbidden. |
404 | conversation_not_found, channel_not_bound, artifact_not_found. |
409 | idempotency_conflict, idempotency_in_progress, channel_inactive, resume_conflict. |
410 | channel_archived. |
413 / 415 | file_too_large / invalid_mime_type. |
422 | validation_error (corps JSON invalide ou champs non conformes). |
429 | rate_limit_exceeded, avec Retry-After en secondes. |
503 | signing_secret_unavailable, request_abandoned. |
Une erreur d'exécution du flow peut aussi renvoyer HTTP 200 avec status: "error" et output.error.
Limitation de débit
| Compteur | Valeur par défaut | Plage / portée |
|---|---|---|
| Canal API ou Webchat | 3000/minute | Configurable de 1 à 100000 ; partagé par toutes les clés du canal. |
Clé publique nx_pub_, par IP | 60/minute | Configurable de 0 (désactivé) jusqu'à la limite du canal ; pas de sous-limite IP pour les clés serveur. |
| Pré-authentification, par IP | Limite de protection distincte | Routes /public/* ; non incluse dans les compteurs de trafic par canal. |
En-têtes de réponse : X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset décrivent le compteur le plus restrictif. Le refus est 429 rate_limit_exceeded avec Retry-After en secondes. OPTIONS n'est pas débité. En cas d'indisponibilité de Redis, le quota du canal laisse passer les requêtes.
Mesures : Observe affiche les requêtes authentifiées et les 429 des dernières 24 heures (filtrables par canal), y compris celles sans exécution. Ces mesures sont indisponibles si Redis ne peut pas être lu ; Home renvoie vers Observe lorsqu'il y a des rejets.
Annexe : CORS et identifiants des requêtes
| Sujet | Contrat |
|---|---|
| Pré-vérification | OPTIONS /public/v1/api/execute (et OPTIONS sur la route de téléchargement) sans clé ni exécution ; aucune signature HMAC. |
| CORS | Clé publique : Origin doit être autorisé s'il est présent. Clé serveur : ne pas envoyer Origin. |
X-Request-ID | En-tête facultatif de la requête ; repris s'il est valide, sinon généré. Présent dans les réponses JSON, SSE et d'erreur. Identifie la requête HTTP, pas la session ni l'exécution. |