Trier 1 000 tickets pour 0,05 $ : le tuto API Decisions

OpenAI a ouvert un endpoint qui ne facture pas les tokens de sortie. J'y ai fait passer mes tickets pendant deux soirées.

Schéma de routage automatique de tickets support vers quatre services via une API de décision

Mardi 6 octobre, OpenAI a ouvert un endpoint que personne n'attendait : POST /v1/decisions. Ce n'est pas un modèle, ni un agent, ni un produit avec une page marketing. C'est une API qui ne sait répondre qu'à des questions à choix fermé — et qui ne facture pas les tokens de sortie. J'ai passé deux soirées à y faire passer mes tickets de support. Voici le code, les seuils, et ce que ça change sur la facture.

Ce que fait l'API Decisions — et ce qu'elle refuse de faire

Le principe tient en une phrase : vous envoyez un contexte (texte, image, ou les deux), vous posez des questions dont vous définissez vous-même la liste des réponses possibles, et vous récupérez une réponse typée par question. Pas de prose, pas de JSON à parser à la main, pas de modèle qui part en freestyle sur un champ que vous n'avez pas prévu.

La documentation officielle décrit trois formes de réponse, et il n'y en aura pas une quatrième :

  • predicate — une condition est-elle vraie ? Retourne une probabilité entre 0 et 1. Pas un booléen : une probabilité. C'est tout l'intérêt.
  • choice — une option parmi une liste fermée, avec un niveau de confiance et la distribution de probabilités sur chaque option.
  • score — une note sur des niveaux ordonnés, retournée comme moyenne pondérée par les probabilités des index de niveau.

Un seul modèle est branché dessus : gpt-6-luna. Pas de Sol, pas d'Astra, pas de fallback vers un modèle plus musclé pour les cas durs. Et une contrainte qui m'a coûté quarante minutes : les images doivent être des data URLs base64 inline. Les URLs HTTP hébergées et les file_id sont refusés sèchement.

Ce que l'endpoint ne fait pas : extraire des champs libres (restez sur Structured Outputs), appeler des fonctions (restez sur le function calling), ou expliquer son raisonnement. Vous n'aurez jamais de « pourquoi ». Vous aurez une probabilité, à vous d'en faire quelque chose.

Combien coûte l'API Decisions d'OpenAI en France

0,10 $ le million de tokens en entrée. Rien sur la sortie. Rien sur les lectures et écritures de cache. C'est confirmé par la doc et repris par plusieurs analyses du lancement. Deux majorations à connaître : au-delà de 272 000 tokens d'entrée, le prix unitaire de la requête entière double, et le traitement régional ajoute 10 %.

Le calcul pour 1 000, 10 000 et 1 million de tickets

Mes tickets réels font en moyenne 320 tokens. En ajoutant les instructions des trois questions, je tourne à ~500 tokens par appel. Ça donne :

  • 1 000 tickets : 0,5 M de tokens → 0,05 $. Cinq centimes.
  • 10 000 tickets : 0,50 $.
  • 1 million de tickets : 50 $, soit le prix d'un déjeuner pour classer un an de boîte support d'un gros e-commerçant.

Pour situer : j'avais monté le même tri d'emails en Batch API avec Luna il y a deux mois, à 3 € les 10 000. On passe à 0,50 $ pour le même volume — et sans attendre 24 h la fin du batch. C'est le vrai écart, et il vient d'une seule ligne de la grille tarifaire : la sortie est gratuite.

Le tuto : router trois décisions en un seul appel

Mon cas d'usage : une boîte de contact générique qui reçoit tout, du bug technique à la demande de devis, et une personne qui perd une heure par jour à distribuer. Objectif : un service cible, un drapeau « client en train de partir », et un niveau d'urgence. Trois décisions, un seul appel réseau — les questions indépendantes se cumulent dans la même requête.

Étape 1 — Vérifier les versions de SDK

C'est là que j'ai perdu mes premières dix minutes : l'endpoint existe mais mon SDK ne l'exposait pas. Il faut le client Python en 3.26.0 minimum, ou le JavaScript en 7.30.0.

pip install --upgrade "openai>=3.26.0"
# ou
npm i openai@^7.30.0

Étape 2 — La requête, en curl d'abord

Je teste toujours un endpoint neuf en curl avant de le câbler. Ça évite de chercher une erreur de schéma à travers trois couches d'abstraction.

curl https://api.openai.com/v1/decisions \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-6-luna",
    "input": "Bonjour, jai ete debite deux fois pour la commande #44871 et personne ne repond depuis mardi. Je vais faire opposition.",
    "questions": [
      {
        "type": "choice",
        "name": "service",
        "instructions": "Quel service doit traiter ce message ?",
        "choices": ["facturation", "livraison", "technique", "commercial"]
      },
      {
        "type": "predicate",
        "name": "risque_depart",
        "instructions": "Le client menace-t-il de partir, de faire opposition ou de laisser un avis negatif ?"
      },
      {
        "type": "score",
        "name": "urgence",
        "instructions": "Evalue le delai de traitement acceptable.",
        "levels": ["aucune urgence", "sous 5 jours", "sous 48h", "immediate"]
      }
    ]
  }'

Un avertissement honnête : les noms de champs pour les listes d'options (choices, levels) ont évolué entre la préversion limitée et la beta publique. Recopiez le schéma depuis la doc officielle plutôt que depuis un article — y compris celui-ci. Les trois types de réponse, eux, sont stables.

Étape 3 — Lire la réponse pour ce qu'elle est

Ce que je récupère sur ce ticket :

{
  "answers": [
    { "type": "choice", "name": "service", "value": "facturation",
      "confidence": 0.94,
      "probabilities": { "facturation": 0.94, "commercial": 0.03,
                         "livraison": 0.02, "technique": 0.01 } },
    { "type": "predicate", "name": "risque_depart", "probability": 0.88 },
    { "type": "score", "name": "urgence", "score": 2.61 }
  ]
}

Le champ qui vaut le détour, c'est probabilities. Un classifieur classique vous dit « facturation ». Celui-ci vous dit « facturation à 94 %, et si je me trompe c'est vers commercial ». Vous pouvez construire une logique de doute dessus, et c'est exactement ce qui manque à 90 % des pipelines de triage que je vois tourner en PME.

Étape 4 — Poser un seuil, pas une règle binaire

La partie que les gens sautent et qui fait la différence entre un tri utile et un tri qui agace l'équipe support.

svc, risk, urg = r.answers

if svc.confidence < 0.75:
    assign("file_humaine")          # le modele doute, on n'insiste pas
else:
    assign(svc.value)

if risk.probability > 0.80 or urg.score > 2.5:
    escalate(priority="P1")         # SLA 2 h, alerte Slack

Sur mes 200 tickets étiquetés à la main, le routage brut tombait juste 183 fois, soit 91,5 %. Les 17 ratés étaient presque tous des tickets qui mélangent deux sujets (« ma facture est fausse et l'appli plante »). En coupant à 0,75 de confiance, 12 tickets partent en file humaine et la précision sur le reste monte à 96 %. Échantillon modeste, endpoint en beta, à refaire sur vos données : c'est une méthode, pas un benchmark.

API Decisions vs Responses API : lequel pour router des tickets

OpenAI annonce « environ 10× plus rapide que la Responses API ». Mes mesures sur le même jeu de tickets, depuis Paris : médiane à 280 ms, p95 à 520 ms. En Responses API avec Structured Outputs sur le même modèle, des tests indépendants relèvent 1,46 s de médiane, et 2,33 s en activant le raisonnement moyen — ce qui recoupe ce que j'observe. Donc 5× plutôt que 10×, mais dans le bon ordre de grandeur.

Le vrai arbitrage n'est pas la latence, c'est la structure de coût. Si votre classifieur actuel tourne sans raisonnement, vous économisez 30 à 40 % en basculant. S'il tourne avec raisonnement, les tokens de réflexion se facturent en sortie et vous divisez la note par cinq. C'est la même logique que celle que j'avais détaillée sur la réduction de la facture de tokens des agents : le prix affiché par million ne dit rien, c'est le profil d'appel qui décide.

Un point que les analyses de lancement soulèvent à raison : si vous renvoyez plus de ~17 % de vos requêtes en secours vers la Responses API, l'économie s'évapore. Mesurez votre taux de repli avant de signer le ROI.

Côté concurrence, TypeSafe pousse Jev, un modèle de décision à 0,042 $ le million de tokens — 2,4× moins cher, mais texte uniquement et sans engagement de résidence des données. Aucun des deux n'a publié de comparaison de justesse. Si vous traitez du volume, testez les deux sur vos étiquettes.

Les trois trucs qui m'ont fait perdre du temps

Je ne vais pas vous vendre une soirée sans friction.

Les images. Mon idée de départ : faire analyser les photos de colis abîmés envoyées par les clients, directement depuis l'URL de notre bucket. Erreur 400. Il faut encoder en base64 inline. Sur des photos de smartphone à 4 Mo, l'encodage plus l'upload m'ont coûté 600 à 900 ms de plus par appel — soit davantage que l'inférence elle-même. Le « 10× plus rapide » ne survit pas aux images. J'ai fini par redimensionner à 1 024 px avant encodage, ce qui ramène la chose à ~250 ms de surcoût.

Les décisions en cascade. J'ai voulu enchaîner « est-ce une réclamation ? » puis « quel type de réclamation ? » dans une seule requête. Impossible : les questions d'un même appel sont indépendantes, elles ne se voient pas. Une décision qui dépend d'une autre, c'est un appel par étage. À 280 ms l'appel ça reste tenable, mais ça casse le schéma mental qu'on se fait de l'endpoint en lisant la doc.

Les limites non documentées. Nombre maximum d'options par question, nombre de questions par requête, RPM et TPM propres à l'endpoint : rien de publié. J'ai poussé à 12 options sans problème, mais je ne peux pas dimensionner un pic de charge sur une absence de documentation. Pour une boîte qui encaisse 5 000 tickets le lundi matin, c'est un vrai point de blocage avant la GA.

Comment brancher ça en prod sans casser votre support

La séquence que j'applique, et qui n'a rien de spécifique à cet endpoint :

  1. Shadow mode une semaine. L'API décide, vous enregistrez, mais c'est l'humain qui route. Vous comparez. Sans ce passage, vous ne connaîtrez jamais votre vraie précision ni votre taux de doute — et vous ne saurez pas où poser le seuil. La méthode des jeux d'évaluation que je décris dans le tuto évals et tests de non-régression s'applique telle quelle ici, avec un avantage : les réponses étant typées, la comparaison est triviale à automatiser.
  2. Calibrer le seuil sur votre coût d'erreur. Un ticket mal routé en interne coûte deux minutes. Un client en rupture envoyé dans la file « commercial » coûte un client. Les deux ne méritent pas le même seuil.
  3. Câbler la plomberie. Si vous codez, un worker qui lit l'IMAP et tape l'endpoint suffit. Si vous ne codez pas, un appel HTTP depuis Make ou n8n fait le travail — j'avais détaillé ce type de montage dans mes trois workflows n8n branchés sur un back-office.
  4. Garder la trace de la décision. Stockez probabilities avec le ticket. Le jour où le support vous dit « ça route n'importe comment », vous aurez les chiffres plutôt qu'une impression.

Ce dernier point mérite d'être pris au sérieux : faire lire tous vos emails entrants par un modèle, c'est une finalité à inscrire dans votre registre, et un sujet qui recoupe directement le trou RGPD des agents à mémoire pointé par la CNIL. La résidence européenne vous aide, elle ne vous dispense de rien.

Mon verdict après deux soirées

C'est le lancement le plus utile du DevDay 2026, dont j'avais décortiqué les annonces côté bureautique, et personne n'en parle parce qu'il n'a pas de nom marketing. Un endpoint qui ne facture pas sa sortie et qui rend des probabilités calibrées, ça remplace trois quarts des classifieurs maison que je croise chez mes clients — ceux qui demandent gentiment à un LLM de « répondre uniquement par le nom du service » et qui se cassent une fois sur cinquante parce que le modèle a ajouté un point final.

Pertinent pour vous si vous routez du volume : tickets, emails entrants, modération de commentaires, qualification de leads, tri de candidatures, contrôle de photos. À partir de quelques milliers d'éléments par mois, le gain de latence change l'expérience et le coût devient du bruit comptable.

Pas pour vous si vous traitez 50 messages par jour — le tri à la main reste moins cher que le temps d'intégration. Pas pour vous non plus s'il vous faut extraire des champs libres, générer une réponse, ou déclencher un outil : ce n'est pas le bon endpoint, et l'absence totale d'explication du modèle rendra vos audits internes pénibles.

Et attendez la GA si vous devez garantir un débit en pic. Sans RPM documenté sur /v1/decisions, mettre son triage support en dépendance dure d'une beta publique vieille de trois jours, c'est un pari. Montez le shadow mode maintenant, basculez la production quand les limites seront écrites.

FAQ

L'API Decisions d'OpenAI est-elle gratuite ?
Non, mais elle est atypique : seuls les tokens d'entrée sont facturés, à 0,10 $ le million. Les tokens de sortie, les lectures et les écritures de cache ne coûtent rien. Avec des tickets de 500 tokens instructions comprises, cela représente environ 0,05 $ les 1 000 décisions et 50 $ le million. Deux majorations existent : au-delà de 272 000 tokens d'entrée le prix unitaire de la requête double, et le traitement régional ajoute 10 %.
Peut-on utiliser l'API Decisions sans savoir coder ?
Oui, via un module HTTP dans un outil d'automatisation. Make, n8n ou Zapier savent tous envoyer un POST avec un corps JSON et récupérer un champ de la réponse. Vous devrez quand même écrire le schéma des questions à la main une fois, puis brancher la sortie sur votre logique de routage. Comptez une à deux heures pour un premier workflow qui tourne.
Quelle différence entre l'API Decisions et les Structured Outputs ?
Les Structured Outputs vous garantissent la forme d'un JSON que le modèle génère librement : vous pouvez y mettre des champs texte, des listes, des objets imbriqués. L'API Decisions ne génère rien : elle choisit dans une liste que vous avez fixée et renvoie une probabilité. Si vous avez besoin d'extraire un numéro de commande ou de rédiger un résumé, restez sur les Structured Outputs. Si vous avez juste besoin de trancher entre quatre services, Decisions est plus rapide et ne facture pas la sortie.
L'API Decisions est-elle compatible RGPD pour une entreprise française ?
La beta propose le Zero Data Retention et la résidence des données en Europe (EEE et Suisse), ce qui lève les deux objections les plus fréquentes. Ce n'est pas une mise en conformité automatique : faire analyser l'intégralité de vos emails entrants reste un traitement à inscrire dans votre registre, avec une finalité, une durée de conservation et une information des personnes concernées. Vérifiez aussi que l'option de résidence est bien activée sur votre organisation, elle n'est pas appliquée par défaut.
Faut-il attendre la disponibilité générale avant de passer en production ?
Pour un usage non critique — pré-tri, suggestion d'étiquette, tableau de bord — vous pouvez y aller maintenant en gardant un repli vers votre classifieur actuel. Pour un routage dont dépend votre SLA support, attendez : OpenAI ne publie pas encore de limites de débit propres à l'endpoint, ni le nombre maximum d'options par question. La GA est annoncée « dans les prochaines semaines ». Utilisez ce délai pour faire tourner le shadow mode et calibrer vos seuils.
Partager
Résumé vidéoen cours…