Documentation API

Référence de l'API

Les sept routes, une par une : ce que vous envoyez, ce que vous recevez, et pour chaque paramètre s'il est pris en charge, ignoré ou refusé.

Toutes les routes sont sous https://app.netaix.fr/v1 et demandent une clé (voir Authentification). Une description lisible par une machine est disponible : openapi.json.

GET /v1/models

GET https://app.netaix.fr/v1/models

Aucun paramètre. Rend la liste des niveaux Netaix puis celle des modèles que la clé peut appeler. Le détail de la réponse et la façon de l'utiliser sont dans Modèles et routage.

POST /v1/chat/completions

POST https://app.netaix.fr/v1/chat/completions

La route principale. Elle suit le format d'OpenAI pour la requête comme pour la réponse.

Paramètres

Les champs inconnus sont acceptés sans erreur, comme le fait l'API d'origine. La colonne « État » dit ce que la passerelle en fait réellement : un paramètre marqué « ignoré » est accepté mais n'a aucun effet, ce qu'il valait mieux écrire que laisser découvrir.

ChampTypeÉtatDétail
modelchaîne, requisPris en chargeUn niveau netaix-* ou un identifiant de modèle. 200 caractères au plus.
messagestableau, requisPris en charge200 messages au plus. Rôles system, user, assistant, tool. Le contenu peut être une chaîne ou une liste de blocs.
streambooléenPris en chargeDéfaut false. Voir le flux.
temperaturenombre, 0 à 2Pris en chargeTransmis au modèle.
max_tokensentier, 1 à 128000Pris en chargeTransmis au modèle.
toolstableauPris en chargeUn tour d'inférence. Voir les outils.
tool_choicechaîne ou objetPris en chargeTransmis avec tools.
top_pnombre, 0 à 1Accepté, ignoréValidé puis non transmis au modèle.
response_formatobjetAccepté, ignoréAucun mode JSON imposé. Pour obtenir du JSON, demandez-le dans la consigne, ou utilisez tools dont le schéma, lui, est transmis.
n, stop, seed, logprobs, presence_penalty, frequency_penaltydiversAccepté, ignoréUne seule réponse est rendue, sans séquence d'arrêt côté passerelle.
stream_optionsobjetAccepté, inutileLe bloc usage est déjà envoyé sur le dernier fragment de tout flux.

Réponse

200, sans flux
{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "created": 1793664000,
  "model": "mistral-large-latest",
  "choices": [{
    "index": 0,
    "message": {"role": "assistant", "content": "..."},
    "finish_reason": "stop"
  }],
  "usage": {
    "prompt_tokens": 1240,
    "completion_tokens": 318,
    "total_tokens": 1558,
    "prompt_tokens_details": {"cached_tokens": 980},
    "cache_write_tokens": 0
  }
}
ChampCe qu'il porte
modelLe modèle réellement servi, même quand vous avez demandé un niveau.
finish_reasonstop, ou tool_calls quand le modèle demande un outil.
usage.prompt_tokensJetons d'entrée hors part relue depuis le cache du fournisseur.
usage.prompt_tokens_details.cached_tokensPart d'entrée relue depuis le cache du fournisseur.
usage.cache_write_tokensJetons écrits dans le cache du fournisseur. Ajout Netaix, hors norme OpenAI.

Le flux

Avec "stream": true, la réponse est un flux d'événements serveur (text/event-stream). Chaque ligne utile commence par data: et porte un objet chat.completion.chunk. Le flux se termine par data: [DONE].

Extrait de flux
data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1793664000,"model":"gpt-4.1","choices":[{"index":0,"delta":{"role":"assistant","content":"Bon"},"finish_reason":null}]}

data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1793664001,"model":"gpt-4.1","choices":[{"index":0,"delta":{"content":"jour"},"finish_reason":null}]}

data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1793664002,"model":"gpt-4.1","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":18,"completion_tokens":2,"total_tokens":20,"prompt_tokens_details":{"cached_tokens":0},"cache_write_tokens":0}}

data: [DONE]
  • Le premier fragment de texte porte delta.role. Les suivants ne portent que delta.content.
  • Le dernier fragment porte finish_reason et le bloc usage, sans qu'il faille le demander.
  • Quand une recherche web a servi, un fragment supplémentaire porte un champ search_results de premier niveau, avec delta vide. C'est la convention employée par les fournisseurs qui exposent leurs sources ; un client strict l'ignore.
  • Une erreur survenue après le début du flux arrive sous la forme data: {"error": {...}}, suivie de data: [DONE]. Le code HTTP, lui, est déjà parti en 200 : votre code doit donc inspecter les fragments, pas seulement le statut.
Le piège du flux

Si vous écrivez votre propre lecteur plutôt que d'utiliser un SDK, traitez le cas du fragment d'erreur en cours de flux. Un lecteur qui ne regarde que le statut HTTP affichera une réponse tronquée comme une réponse complète.

Les outils

Envoyez vos définitions dans tools au format OpenAI. La passerelle fait un tour d'inférence et vous rend les tool_calls demandés par le modèle. Elle n'exécute pas vos outils : c'est votre code qui les exécute, puis renvoie le résultat dans un message de rôle tool au tour suivant. C'est le fonctionnement standard, en flux comme en bloc.

Réponse avec appel d'outil
{
  "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": null,
      "tool_calls": [{
        "id": "call_...",
        "type": "function",
        "function": {"name": "chercher_facture",
                     "arguments": "{\"numero\": \"F-2026-114\"}"}
      }]
    },
    "finish_reason": "tool_calls"
  }]
}

POST /v1/messages

POST https://app.netaix.fr/v1/messages

La même passerelle, au format de l'API d'Anthropic. Elle sert les clients écrits pour ce format, Claude Code et le SDK anthropic compris, usage agent inclus. Avec un SDK Anthropic, l'adresse de base est https://app.netaix.fr sans /v1 : le SDK ajoute le chemin lui-même.

Les deux routes sont servies par le même moteur : facturation, filtre des données sensibles, appels d'outils, comptage des jetons et comportement en cas d'erreur sont identiques sur /v1/chat/completions et ici. Le choix de la route est donc celui du format que parle votre client, pas celui des fonctionnalités disponibles.

ChampTypeÉtat
modelchaîne, requisPris en charge, niveaux compris. 200 caractères au plus.
messagestableau, requisPris en charge, 2 000 messages au plus. Blocs text, image, tool_use et tool_result transmis sans aplatissement.
systemchaîne ou liste de blocsPris en charge dans les deux formes. Examiné par le filtre des données sensibles comme les messages.
streambooléenPris en charge. Défaut false.
max_tokensentier, 1 à 128000Pris en charge. Défaut 4096.
temperaturenombre, 0 à 2Pris en charge, transmis au modèle.
top_pnombre, 0 à 1Pris en charge, transmis au modèle.
toolstableau, 256 au plusPris en charge. Un tour d'inférence : la passerelle rend les blocs tool_use, c'est votre code qui exécute les outils.
tool_choiceobjetPris en charge, transmis avec tools.
stop_sequencestableau, 16 au plusPris en charge, appliquées par la passerelle : le texte est coupé au premier motif rencontré et l'appel au modèle est refermé, pour ne pas payer la suite.
200, sans flux
{
  "id": "msg_...",
  "type": "message",
  "role": "assistant",
  "content": [
    {"type": "text", "text": "Je lis le fichier."},
    {"type": "tool_use", "id": "toolu_...",
     "name": "read_file", "input": {"path": "a.txt"}}
  ],
  "model": "claude-sonnet-4-5",
  "stop_reason": "tool_use",
  "stop_sequence": null,
  "usage": {
    "input_tokens": 1240,
    "output_tokens": 318,
    "cache_read_input_tokens": 980,
    "cache_creation_input_tokens": 0
  }
}
stop_reasonQuand
end_turnLe modèle a terminé sa réponse.
tool_useLe modèle demande un outil : exécutez-le et renvoyez un tool_result au tour suivant.
max_tokensLa réponse a atteint la borne demandée.
stop_sequenceUn de vos stop_sequences a été rencontré. Le motif vu est dans stop_sequence.

Le flux

Avec "stream": true, la réponse suit le protocole de flux d'Anthropic : chaque événement porte sa ligne event: puis sa ligne data:, ce qui permet à un SDK Anthropic de le lire sans adaptation.

Suite des événements en flux
message_start
ping
content_block_start        (un bloc text, ou un bloc tool_use)
content_block_delta        (text_delta, ou input_json_delta pour un outil)
content_block_stop
message_delta              (porte stop_reason, stop_sequence et usage)
message_stop
  • message_start et ping sont émis avant le premier appel au modèle : ils ne sont pas du contenu.
  • Les blocs sont indexés dans leur ordre d'apparition. Un appel d'outil émet ses arguments par fragments, en input_json_delta.
  • Une erreur survenue pendant le flux arrive sous la forme d'un événement error, le code HTTP étant déjà parti en 200 : votre code doit inspecter les événements, pas seulement le statut.

POST /v1/messages/count_tokens

POST https://app.netaix.fr/v1/messages/count_tokens

Rend une estimation du nombre de jetons d'entrée d'une requête /v1/messages. C'est la route qu'un client au format Anthropic appelle pour gérer sa fenêtre de contexte. Le corps est celui de /v1/messages ; max_tokens n'est pas nécessaire.

Réponse
{"input_tokens": 1284}
  • Le compte porte sur la consigne système, les messages, les arguments des appels d'outils rejoués et les définitions d'outils.
  • C'est une estimation faite par la passerelle, pas le compte exact d'un fournisseur : aucun modèle n'est appelé. Utilisez-la comme un ordre de grandeur, pas comme une valeur de facturation. Le compte réel d'un appel est dans le bloc usage de sa réponse.
  • L'appel n'est pas décompté en crédits. Il demande une clé et compte dans la limite de débit.

POST /v1/embeddings

POST https://app.netaix.fr/v1/embeddings

Transforme du texte en vecteurs, au format d'OpenAI.

ChampTypeÉtat
inputchaîne ou tableau de chaînes, requisPris en charge
modelchaînePris en charge. Par défaut, le modèle d'embeddings de la passerelle. Doit être un modèle d'embeddings du catalogue, sinon 404.
encoding_formatfloat ou base64Pris en charge. Tout autre valeur donne un 400.
dimensionsentierRefusé par un 400 : les modèles disponibles rendent des vecteurs de taille fixe, et l'ignorer en silence remplirait votre index de vecteurs de la mauvaise taille.
LimiteValeurCode de refus
Entrées par requête96too_many_inputs
Caractères par entrée32 000input_too_long
Caractères au total400 000request_too_large
Jetons déjà découpésnon acceptés, envoyez du texteinput_must_be_text
curl
curl https://app.netaix.fr/v1/embeddings \
  -H "Authorization: Bearer $NETAIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"input": ["Première phrase.", "Deuxième phrase."]}'
Réponse
{
  "object": "list",
  "model": "mistral-embed",
  "data": [
    {"object": "embedding", "index": 0, "embedding": [0.0123, -0.0456]},
    {"object": "embedding", "index": 1, "embedding": [0.0789, -0.0012]}
  ],
  "usage": {"prompt_tokens": 12, "total_tokens": 12}
}

Un vecteur dépend du modèle qui l'a produit. Si vous changez de modèle d'embeddings, il faut recalculer tout l'index : des vecteurs de deux modèles ne se comparent pas. Fixez donc model explicitement dès que vous constituez un index durable.

POST /v1/moderations

POST https://app.netaix.fr/v1/moderations

Rend un verdict de modération sur un texte, au format d'OpenAI. Le champ input accepte une chaîne ou une liste de blocs.

Réponse
{
  "id": "modr-...",
  "model": "omni-moderation-latest",
  "results": [{
    "flagged": false,
    "categories": {"violence": false, "hate": false},
    "category_scores": {"violence": 0.0002, "hate": 0.0001}
  }]
}
Important

Quand aucun verdict ne peut être produit, la route répond 503 avec le code moderation_unavailable, jamais un verdict « non signalé » par défaut. Votre code ne doit pas lire un 503 comme un contenu acceptable : c'est l'absence de verdict, pas un verdict favorable.

Cet appel n'est pas décompté en crédits. Il est compté dans le relevé de consommation de votre clé et soumis à la limite de débit, comme les autres routes.

La modération juge la nature du texte (violence, haine). Ce n'est pas le filtre des données sensibles, qui empêche une donnée confidentielle de sortir et s'applique, lui, aux quatre routes qui transmettent du texte : voir Filtre des données sensibles.

GET /v1/netaix/usage

GET https://app.netaix.fr/v1/netaix/usage

La consommation et les plafonds de la clé qui appelle, sans session ni mot de passe. C'est la route à utiliser pour afficher une jauge dans votre propre interface, ou pour qu'un traitement automatique sache qu'il approche de son plafond avant de se faire refuser.

Aucun paramètre : l'identité vient de la clé, jamais de la requête. Une clé ne lit que sa propre consommation, jamais celle d'une autre clé ni celle de l'organisation.

Réponse
{
  "object": "netaix.usage",
  "unite": "credits",
  "cle": {"prefixe": "...", "type": "personal_token"},
  "jour": {
    "debut": "2026-11-03T00:00:00Z",
    "consomme": 1240,
    "plafond": 5000,
    "restant": 3760,
    "part": 0.248,
    "alerte": false,
    "depasse": false
  },
  "cycle": {
    "debut": "2026-11-01T00:00:00Z",
    "consomme": 8120,
    "plafond": 20000,
    "restant": 11880,
    "part": 0.406,
    "alerte": false,
    "depasse": false
  },
  "verifie_a": "2026-11-03T09:14:22Z"
}
ChampCe qu'il porte
uniteToujours credits. Jamais des euros, jamais des jetons.
cle.prefixeLe début de votre clé, celui que l'application affiche pour vous permettre de la reconnaître. Jamais la clé entière.
cle.typepersonal_token pour un jeton d'accès personnel, workspace_key pour une clé d'organisation.
jour, cycleLes deux fenêtres de plafond de la clé. jour part de minuit, heure universelle ; cycle du début du cycle de facturation en cours.
debutLe début de la fenêtre, en heure universelle.
consommeLes crédits déjà consommés par cette clé dans la fenêtre.
plafondLe plafond réglé sur la clé pour cette fenêtre, ou null quand elle n'en a pas.
restant, partCe qui reste, et la part consommée entre 0 et 1. null tous les deux quand il n'y a pas de plafond : un plafond absent n'est pas un plafond à zéro.
alertetrue à partir de 80 % du plafond, tant qu'il n'est pas dépassé.
depassetrue quand la fenêtre est au plafond : les appels de cette clé sont refusés par un 429 jusqu'à sa réouverture.
verifie_aL'instant de la lecture, en heure universelle. Aucune valeur n'est mise en cache.

Ces chiffres sont calculés par la même fonction que celle qui refuse les appels au dépassement et que celle qui alimente le relevé de l'application. Ce que vous lisez ici est donc ce qui s'appliquera, pas une estimation parallèle.

Cette route est limitée à 30 requêtes par minute, et non 60 comme les autres. Elle n'est pas décomptée en crédits. Elle ne répond que pour une clé d'API : une instance d'agent ou une application cliente, qui n'ont pas de plafond de clé, reçoivent un 400 avec le code usage_not_available_for_this_credential.