Aller au contenu

Référence API

L’inférence passe par trois points d’accès, compatibles avec l’API OpenAI :

Point d’accèsUsage
POST /v1/chat/completionsComplétion : conversation, sortie structurée, outils, bases de connaissance
POST /v1/embeddingsVectorisation de texte
POST /v1/audio/transcriptionsTranscription audio (voir plus bas)

Les règles de conformité de votre organisation (pseudonymisation, longueur maximale, règles personnalisées) s’appliquent à chaque requête, et elles ne peuvent l’être qu’aux formats que Miraca sait lire. Les autres points d’accès de la norme OpenAI (/v1/responses, /v1/completions, génération d’images, synthèse vocale…) ne sont donc pas servis et répondent 404. Pour une complétion, utilisez /v1/chat/completions : les SDK OpenAI l’appellent par client.chat.completions.create.


Endpoint : POST https://api.miraca.fr/v1/chat/completions

ParamètreTypeDéfautDescription
modelstring—mistral-small (défaut) — voir Modèles & tarifs
messagesarray—Tableau [{role, content}] — rôles : system, user, assistant. Le content peut être une chaîne ou un tableau de parties (texte + fichiers joints — voir Fichiers dans le chat)
max_tokensinteger—Recommandé ≥ 300. Tokens alloués à la réponse (raisonnement inclus)
temperaturefloat0.70 = déterministe, 1 = créatif
top_pfloat1.0Nucleus sampling (alternative à temperature)
streambooleanfalseRéponse en streaming SSE
response_formatobject—Voir Sortie structurée
stopstring/array—Séquences d’arrêt
workspacestring—Slug d’un espace de travail : le modèle reçoit les outils workspace_*, un script run_code y lit les tableaux en cellules typées. Créé au premier usage ; piloté par /v1/workspaces/*
reasoning_effortstring—none, low, medium, high : combien le modèle réfléchit avant de répondre. Les niveaux acceptés dépendent du modèle (reasoning_efforts dans /v1/pricing) ; sur un modèle qui n’en propose pas, ou pour un niveau inconnu, la réponse est un 400 explicite. Posé, il prime sur miraca_niveau
miraca_niveauinteger ou string—Niveau de réflexion Miraca : 1 à 5, ou sa clé (direct, rapide, standard, approfondi, maximal). Un seul réglage que la plateforme traduit pour le modèle choisi (nombre de tours d’outils et raisonnement). Alias accepté : astrolabe_niveau. Valeur illisible : 400
tools_enabledstring[]—Outils à activer pour la requête (mode agent) : web_search et web_fetch (recherche web), kb:<slug> (bases de connaissance), connection:<slug> (connecteurs API), mcp:<slug> (serveur MCP tiers déclaré par l’organisation), mailbox:<slug> (boîtes mail), code (exécution de code), files (fichiers générés), agents (sous-agents). connection: et mcp: exigent le scope de clé connections. Pas de streaming, voir plus bas

262 144 tokens (entrée + sortie cumulés) — capacité de mistral-small (Mistral Small 4).

RepèreTokens approximatifs
1 mot français~1,3 token
1 page A4 (~400 mots)~520 tokens
262 144 tokens~200 000 mots / ~640 pages

mistral-small (Mistral Small 4) est un modèle avec raisonnement interne. La réponse inclut deux champs :

{
"id": "chatcmpl-…",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "La réponse finale à utiliser.",
"reasoning_content": "…réflexion interne du modèle (null si le modèle n'a pas raisonné)…"
},
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 42,
"completion_tokens": 318,
"total_tokens": 360
}
}
  • content — la réponse finale, directement exploitable.
  • reasoning_content — la chaîne de pensée interne du modèle (null si le modèle n’a pas généré de raisonnement). Non-standard OpenAI — ignoré par les SDK qui ne le supportent pas.

mistral-small est un modèle avec raisonnement interne (chain-of-thought) : il réfléchit avant de formuler sa réponse sur les tâches complexes. Quand ce raisonnement a lieu, il est exposé dans le champ reasoning_content du message.

Modereasoning_contentcontent
Chat libre (sans response_format)Présent si le modèle a raisonné, null sinonRéponse finale
json_object ou json_schemaToujours null (raisonnement désactivé)JSON contraint

Par défaut, le modèle décide lui-même s’il a besoin de raisonner : les tâches simples (reformulation, réponse directe) n’en déclenchent pas toujours.

Le paramètre reasoning_effort prend la main sur cette décision :

{ "model": "mistral-medium", "reasoning_effort": "none", "messages": [...] }

Les niveaux acceptés dépendent du modèle et sont donnés par reasoning_efforts dans /v1/pricing : none et high sur mistral-small et mistral-medium ; les quatre niveaux sur qwen-small, qwen-large et gemma ; low, medium et high sur gpt-oss. Les autres modèles n’ont pas de réglage, et leur envoyer le paramètre vaut une erreur explicite plutôt qu’un silence.

L’écart n’est pas anecdotique : sur mistral-medium, la même question produit 601 tokens de sortie en none contre 3 000 en high. Sur une automatisation répétée, c’est la différence entre payer une réflexion utile et la payer pour rien.

Plutôt que de connaître les niveaux de chaque modèle, vous pouvez poser un seul réglage, miraca_niveau, que la plateforme traduit pour le modèle qui répond :

NiveauCléTours d’outilsRaisonnement visé
1direct1none
2rapide3low
3standard8medium
4approfondi20high
5maximal99high
{ "model": "gpt-oss", "miraca_niveau": "approfondi", "tools_enabled": ["web_search"], "messages": [...] }

Le raisonnement posé est le niveau visé si le modèle le propose, sinon le niveau qu’il propose juste en dessous (jamais plus que ce que vous avez demandé), sinon son plus bas. Sur mistral-small et mistral-medium (none, high), les niveaux 1 à 3 donnent none et 4 et 5 high ; sur gpt-oss (low, medium, high), 1 et 2 donnent low, 3 medium, 4 et 5 high. Un modèle sans réglage de raisonnement reçoit seulement le nombre de tours, sans erreur. Les tours ne comptent que si la requête active des outils (tools_enabled, base de connaissance en mode agentique) ; au niveau 1, un seul tour d’outils est permis.

Ce que vous posez explicitement prime : reasoning_effort remplace le raisonnement du niveau, tools_max_steps (ou knowledge_base_max_steps) remplace son nombre de tours, y compris avec une base en knowledge_base_mode: "agentic". Une intégration existante qui n’envoie pas miraca_niveau garde exactement son comportement.

Les sous-agents (tools_enabled: ["agents"]) ne sont offerts qu’aux niveaux 4 et 5, chacun avec un budget de tours propre (5 et 10) : aux niveaux 1 à 3, le jeton agents est ignoré. Sans miraca_niveau, il reste honoré comme avant.

miraca_niveau accepte un entier de 1 à 5, la même valeur en chaîne de chiffres ("3") ou la clé ("standard") ; toute autre valeur (y compris des chiffres non latins comme "3") est refusée en 400, avec la liste des valeurs acceptées.

Les tokens de raisonnement sont comptabilisés dans completion_tokens. Avec max_tokens trop bas, le quota peut être épuisé avant la réponse finale → content vide ou tronqué.

Règle pratique :

  • Sortie structurée (json_schema / json_object) : max_tokens ≥ 200 suffit (pas de raisonnement)
  • Chat court (classification, extraction) : max_tokens ≥ 300
  • Chat long (rédaction, analyse) : max_tokens 1000–2000

Avec stream: true, la réponse arrive en Server-Sent Events (même format qu’OpenAI). Les chunks de raisonnement arrivent dans delta.reasoning_content, les chunks de réponse finale dans delta.content.

stream = client.chat.completions.create(
model="mistral-small",
messages=[{"role": "user", "content": "Résume ce compte-rendu en 3 points."}],
max_tokens=600,
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta
if delta.content:
print(delta.content, end="", flush=True)

Une requête qui active des outils (bases de connaissance en mode agent, recherche web, connecteurs, exécution de code) enchaîne plusieurs tours côté serveur. La réponse porte alors, en plus du usage standard, un champ additionnel miraca_usage : le cumul des tokens de tous les tours, et le forfait des outils web.

{
"miraca_usage": {
"prompt_tokens": 18420,
"completion_tokens": 912,
"total_tokens": 19332,
"cached_prompt_tokens": 12288,
"cache_creation_prompt_tokens": 0,
"web_searches": 0,
"tools_cost_eur": 0
}
}

Comme les autres champs miraca_*, il est ignoré par les SDK OpenAI standards et aussi servi sous son ancien nom astrolabe_usage, avec la même valeur.

cached_prompt_tokens compte les tokens d’entrée que le fournisseur a servis depuis son cache de prompt, facturés à tarif réduit quand le modèle en prévoit un. Ce cache n’est jamais partagé entre organisations ni entre personnes : chaque requête commence par une courte ligne propre à l’appelant, ajoutée par Miraca, qui compte dans prompt_tokens (environ 26 tokens).

cache_creation_prompt_tokens compte les tokens d’entrée que le fournisseur a écrits dans son cache. Seuls les modèles Claude le facturent à part, 1,25 fois le prix d’entrée ; pour les autres modèles il vaut 0. Comme cached_prompt_tokens, ces tokens sont déjà comptés dans prompt_tokens.

Si le fournisseur du modèle échoue en cours de route, la réponse reste un 200 : le message est rendu dans content, sans erreur HTTP. Quatre cas :

miraca_usage.incidentMessage rendu dans contentÀ faire
saturation« Le service d’inférence est momentanément saturé… »Réessayer dans quelques instants
delai« Le service d’inférence n’a pas répondu à temps… », ou « Le modèle « X » n’a rien renvoyé en 10 minutes… »Réessayer, ou alléger la demande, ou choisir un autre modèle
indisponible« Le fournisseur du modèle « X » est momentanément indisponible… » (ou « n’est pas accessible pour le moment »)Réessayer plus tard, ou choisir un autre modèle
refus« Le fournisseur du modèle « X » a refusé la requête (erreur 400 : raison)… »Ne pas relancer à l’identique : le même refus reviendrait. Choisir un autre modèle, ou alléger la demande

Les messages d’indisponibilité et de refus nomment le modèle public que vous avez demandé, et la raison d’un refus n’est dite que lorsqu’elle est reconnue (par exemple « la conversation dépasse la fenêtre de contexte de ce modèle »). Le texte brut du fournisseur n’est jamais recopié.

Quand le modèle avait déjà écrit un texte avant le refus (typiquement « Je cherche… »), ce texte est conservé et le refus est ajouté dessous, précédé de « Réponse interrompue ». Ce marqueur n’est pas ajouté à une sortie JSON demandée par response_format (il la rendrait illisible).

Chaque fournisseur ferme lui-même une demande à laquelle il n’a encore rien répondu, au bout d’une durée qu’il fixe : 5 minutes de silence chez Scaleway, 10 minutes sans réponse chez OVHcloud, 15 minutes chez Mistral (mesuré le 16 octobre 2026). Passé ce délai, aucune réponse ne peut plus arriver.

  • En cours de route (un appel de la boucle d’outils) : l’appel est abandonné à ce délai, sans être relancé (la même demande attendrait autant). La réponse reste un 200, avec l’incident delai et un message qui nomme le modèle : « Le modèle « X » n’a rien renvoyé en 10 minutes : son fournisseur ne répond pas à cette demande. Réessayez, ou choisissez un autre modèle. »
  • Dès le premier appel : la réponse est une erreur HTTP 504. Le même message est dans error.message, et la nature de l’incident dans error.provider_specific_fields.miraca_incident ("delai", aussi servi sous astrolabe_incident).
{
"error": {
"message": "Le modèle « qwen-27b » n'a rien renvoyé en 10 minutes : son fournisseur ne répond pas à cette demande. Réessayez, ou choisissez un autre modèle.",
"type": "internal_server_error",
"code": "504",
"provider_specific_fields": { "miraca_incident": "delai", "astrolabe_incident": "delai" }
}
}

POST /v1/audio/transcriptions, compatible avec l’API OpenAI (champ file, en multipart/form-data), avec le modèle voxtral-transcribe. La transcription est servie par Mistral dans l’Union européenne.

Fenêtre de terminal
curl https://api.miraca.fr/v1/audio/transcriptions \
-H "Authorization: Bearer sk-..." \
-F model=voxtral-transcribe \
-F file=@reunion.flac
  • Permission : une clé restreinte doit porter le scope audio. Sans lui, la requête est refusée en 401.
  • Formats acceptés : FLAC, WAV et OGG (ainsi que les autres formats non compressés : AIFF, CAF). La transcription est facturée à la durée mesurée du fichier (voir Modèles et tarifs).
  • Formats refusés : MP3, M4A/AAC et WebM répondent 400 (« Format audio non pris en charge »). Leur durée ne peut pas être mesurée de façon fiable, et une durée inconnue ne se facture pas. Convertissez-les avant l’envoi :
Fenêtre de terminal
ffmpeg -i reunion.m4a -ac 1 -ar 16000 reunion.flac

Code HTTPCauseÀ faire
429 Too Many RequestsDébit maximal de la clé atteint (tokens par minute, réglé dans le portail), ou fournisseur du modèle momentanément saturéAttendre et réessayer : les SDK OpenAI gèrent le retry avec backoff automatiquement
503 Service UnavailableBackend temporairement indisponibleRéessayer après 30 s
401 UnauthorizedClé absente, invalide, supprimée ou bloquéeVérifier la clé dans le portail
422 Unprocessable EntityCrédits épuisés (« Budget has been exceeded! »). Chaque requête réserve son coût maximal estimé le temps de s’exécuter : quand le solde est bas, des requêtes simultanées peuvent être refusées alors qu’il n’est pas nulRecharger les crédits ; quand le solde est bas, fixer max_tokens et éviter de lancer en parallèle des requêtes coûteuses
404 Not FoundPoint d’accès non servi (/v1/responses, /v1/completions…)Utiliser l’un des points d’accès servis
400 Bad RequestParamètre invalide, contexte dépassé, ou règle de conformité violéeVérifier max_tokens + taille du prompt ; lire le message d’erreur (les refus de conformité y sont explicites)
413 Payload Too LargeCorps de requête trop volumineux sur une route de gestion (/v1/kb, /v1/workspaces, /v1/anonymize, /v1/tasks…) : 24 Mo par requête JSON, 15 Mo par fichier envoyé en multipart/form-dataEnvoyer le fichier en multipart/form-data plutôt qu’en base64, ou découper le contenu en plusieurs documents

Requêtes simultanées : Miraca n’impose pas de plafond global de requêtes simultanées. Un 429 vient soit du débit maximal posé sur votre clé, soit du fournisseur du modèle quand il est saturé ; votre client SDK retente automatiquement. Au-delà de quelques dizaines de requêtes simultanées soutenues, les réponses ralentissent : pour un tel volume, contactez-nous.

La page Usage du portail liste les requêtes en échec des 30 derniers jours, avec leur cause : limite de débit du fournisseur ou de la clé, crédits épuisés, clé absente ou bloquée, modèle inconnu ou non autorisé pour l’organisation, refus des règles de conformité, requête trop longue, délai dépassé, fournisseur indisponible. Quand elle est sûre, une précision s’y ajoute (le modèle refusé, le type de donnée personnelle détectée).

Le message d’erreur lui-même n’y figure pas : il peut recopier une partie de la requête, et une requête d’un membre n’est pas lisible par l’administrateur de l’organisation. Le message complet reste dans la réponse reçue par l’application qui a fait l’appel.