Endpoints

Chat

Envoyer un message à un modèle ou à un assistant et obtenir la réponse, en un seul bloc ou en streaming.

Afficher en Markdown

Un seul endpoint couvre le chat : vous envoyez un message utilisateur, AYETO exécute le modèle ou l'assistant (y compris les outils d'IA qu'il utilise, comme la recherche web ou la génération d'images), enregistre les deux messages dans une conversation et renvoie la réponse. La réponse est renvoyée sous la forme d'un seul objet message, ou sous la forme d'un stream si vous le demandez.

Envoyer un message

Endpoint POST /api/v3/chat
Portée ayeto.chat
Limite de débit par défaut
Réponse Message, ou un stream lorsque stream vaut true

Conversations

Chaque message appartient à une conversation, identifiée par conversation_id. C'est vous qui créez l'id : générez un UUID (version 4) de votre côté et envoyez-le avec le premier message. Si aucune conversation avec cet id n'existe encore, AYETO la crée ; si elle existe et appartient à l'utilisateur de la clé, le message y est ajouté et le modèle voit les messages précédents.

La réponse ne contient pas l'id de la conversation. Si vous omettez conversation_id, une nouvelle conversation est créée pour ce seul message et vous n'avez aucun moyen de la poursuivre : envoyez donc toujours un id que vous conservez.

Une conversation reste liée à ce avec quoi elle a été créée :

  • Assistant. Une conversation créée avec assistant_id reçoit les réponses de cet assistant (ses instructions, ses outils, ses connaissances et son modèle) pendant toute sa durée de vie. Envoyer plus tard un autre assistant_id ou un model ne la fait pas passer à un autre assistant. Une conversation créée avec un model reste une simple conversation avec un modèle.
  • Organisation. Une conversation créée dans une organisation y reste. Un message de suivi qui ne précise aucune organisation s'exécute dans l'organisation de la conversation ; préciser une autre organisation est refusé (voir Organisations et crédits).

Pour lister, lire ou supprimer des conversations, utilisez l'API Conversations.

En-têtes de requête

En-tête Obligatoire Description
uni-api-key oui Votre clé API.
Content-Type oui application/json
language non Le code de langue de l'utilisateur, par exemple EN, CZ ou FR. La langue est communiquée au modèle avec chaque message, afin qu'il puisse répondre dans cette langue. Par défaut : EN.

Requête

Champ Type Obligatoire Description
message chaîne oui Le message de l'utilisateur, en Markdown ou en texte brut. Un message peut activer une compétence de l'assistant avec /skill-slug (voir ci-dessous).
conversation_id UUID non Conversation à laquelle ajouter le message ; elle est créée si elle n'existe pas. Générez-le vous-même, voir Conversations. Par défaut : un nouvel id aléatoire.
assistant_id UUID l'un de assistant_id, model Assistant avec lequel discuter. Il doit s'agir de votre propre assistant ou d'un assistant partagé avec l'utilisateur de la clé. Lorsqu'il est défini, model est ignoré et c'est le modèle de l'assistant qui répond.
model chaîne l'un de assistant_id, model Id du modèle avec lequel discuter directement, sans assistant, par exemple gpt-5-mini. Les ids sont listés par Modèles et outils. Obligatoire lorsque assistant_id n'est pas défini.
organization_id UUID non Exécute le message dans cette organisation : les crédits de l'organisation le paient et ses fichiers sont décomptés du stockage de l'organisation. L'utilisateur de la clé doit être administrateur ou membre (pas invité) de l'organisation. Par défaut : l'organisation de l'assistant lorsque l'assistant appartient à une organisation, sinon l'organisation de la conversation lorsque le message poursuit une conversation créée dans une organisation, sinon aucune (compte personnel).
stream booléen non true renvoie la réponse sous forme de stream pendant sa génération. Par défaut : false.
runner_version chaîne non Format du stream : "1" transmet du texte brut, "2" transmet des événements structurés (texte, raisonnement, activité des outils, statut). Utilisé uniquement lorsque stream vaut true. Par défaut : "1". Voir Streaming.
attachments tableau de Pièce jointe non Fichiers envoyés avec le message (documents, images).
max_tokens entier non Nombre maximal de tokens que le modèle peut générer par appel au modèle. Doit être compris entre 1 et le maximum propre au modèle. Par défaut : la valeur par défaut du modèle.
dynamic_tools booléen non Conversations avec un modèle uniquement : donne au modèle l'ensemble standard d'outils d'IA (recherche web, génération d'images, rédaction de documents, etc.). Ignoré pour les assistants, dont les outils sont configurés sur l'assistant. Par défaut : false.
use_vision booléen non Permet au modèle de regarder les images jointes (modèles dotés de la vision). Avec false, le modèle est informé des images jointes mais ne peut pas les regarder. Par défaut : true.
relevant_history booléen non N'envoie au modèle que la partie de l'historique de la conversation pertinente pour le nouveau message, sélectionnée par un appel supplémentaire à un modèle. S'applique uniquement aux modèles qui le prennent en charge et aux conversations d'au moins 3 messages ; ignoré pour les modèles de raisonnement qui utilisent des outils. Par défaut : false.
remove_tool_calls booléen non Retire les blocs d'appels d'outils du content de la réponse, pour ne garder que le texte propre au modèle. Ne s'applique pas aux streams. Par défaut : false.
follow_options booléen non Demande au modèle de terminer sa réponse, lorsque c'est pertinent, par un bloc de code délimité étiqueté ayeto-follow-options : un objet JSON avec une question facultative, un multi_select facultatif et une liste d'options (label, prompt, description facultative) parmi lesquelles l'utilisateur peut choisir son message suivant. Utile uniquement si votre client l'affiche. Par défaut : false.

Compétences de l'assistant. Un mot de la forme /slug (lettres minuscules, chiffres et traits d'union, séparé par des espaces) dans message active la compétence de l'assistant ayant ce slug, lorsque l'utilisateur de la clé en est propriétaire ou qu'elle est partagée avec lui et qu'elle appartient au même contexte d'organisation que la requête. L'instruction et les outils de la compétence s'appliquent à ce message. Les slugs inconnus sont laissés tels quels en texte brut.

Pièces jointes

Chaque pièce jointe est un fichier encodé dans le corps de la requête.

Champ Type Obligatoire Description
filename chaîne oui Nom du fichier avec son extension, par exemple report.pdf.
data chaîne oui Contenu encodé en base64 sous forme de data URI, par exemple data:application/pdf;base64,JVBERi0xLjcK.... Le base64 brut sans le préfixe data:...;base64, est également accepté. Les espaces blancs, comme les sauts de ligne, dans le texte base64 sont ignorés ; tout autre caractère hors de l'alphabet base64, ou un padding incorrect, fait refuser la requête avec 422.
mime_type chaîne oui Type MIME, par exemple application/pdf ou image/png. Pour les images, le type est détecté à partir du contenu (JPEG, PNG, WebP) et corrigé s'il diffère.

La taille enregistrée est calculée à partir du contenu décodé. Un champ size envoyé par d'anciens clients est ignoré.

Les pièces jointes sont enregistrées comme fichiers de l'utilisateur de la clé (ou de l'organisation, voir organization_id) et conservées avec la conversation ; supprimer la conversation les supprime.

  • Limite de taille. Chaque fichier est limité par la limite d'upload du déploiement, 50 Mo par défaut. Un fichier plus volumineux est refusé avec 422 file is too large.
  • Quota de stockage. Les pièces jointes sont décomptées du quota de stockage de l'utilisateur ou de l'organisation. Lorsqu'il est plein, la requête échoue avec 422 storage quota exceeded ou 422 organization storage quota exceeded.
  • Vérifiées en premier, tout ou rien. Les pièces jointes sont décodées et enregistrées avant tout autre élément de la requête. Lorsque l'une d'elles est refusée (base64 invalide, trop volumineuse, au-delà du quota de stockage), la requête échoue avec 422, les pièces jointes de la même requête qui avaient déjà été enregistrées sont de nouveau supprimées et la conversation reste en l'état : le message utilisateur n'est pas ajouté et aucune nouvelle conversation n'est créée. Corrigez la pièce jointe et renvoyez le message avec le même conversation_id.
  • Comment le modèle les lit. Le modèle est informé des fichiers joints et les lit avec des outils intégrés : les documents sous forme de texte extrait, les images par la vision (lorsque le modèle la prend en charge et que use_vision vaut true ; les grandes images sont réduites pour le modèle). Les pièces jointes ne sont donc utiles qu'avec des modèles qui prennent en charge les outils d'IA. L'extraction de texte couvre les formats bureautiques, PDF et texte courants, voir Fichiers et médias.

Réponse

Sans stream, la réponse est la réponse de l'assistant au message.

Champ Type Description
id UUID Id du message de réponse dans la conversation.
timestamp horodatage Date de création du message de réponse (millisecondes depuis l'epoch).
role chaîne assistant.
content chaîne La réponse en Markdown. Contient les blocs d'appels d'outils, sauf si remove_tool_calls vaut true.
reasoning_content chaîne ou null Le raisonnement du modèle ou le résumé de sa réflexion, pour les modèles qui l'exposent ; vide ou null sinon.
model chaîne ou null Id du modèle qui a produit la réponse. Pour un assistant qui utilise un modèle automatique, il s'agit du modèle effectivement choisi pour le message.
attachments tableau de Pièce jointe de la réponse Fichiers produits pour l'utilisateur pendant la réponse, comme les images générées.
tool_runs objet Réponses des sous-assistants appelés comme outils, voir Exécutions des sous-assistants. Objet vide lorsqu'il n'y en a pas.

Pièces jointes de la réponse

Champ Type Description
filename chaîne Nom du fichier.
content_type chaîne Type MIME, par exemple image/png.
file_url chaîne Lien qui télécharge le fichier. Il fonctionne sans clé API : traitez-le donc comme un secret.
name chaîne ou null Nom d'affichage facultatif.
description chaîne ou null Description facultative.

Exécutions des sous-assistants

Un assistant peut appeler d'autres assistants comme outils. Ce qu'un tel sous-assistant a répondu est renvoyé dans tool_runs, avec pour clé la position de l'appel d'outil parmi les blocs d'appels d'outils de content, sous forme de chaîne : "0" est le premier appel d'outil, "1" le deuxième. Seuls les appels d'outils auxquels un sous-assistant a répondu ont une entrée.

Champ Type Description
content chaîne La réponse du sous-assistant, avec ses propres blocs d'appels d'outils.
tool_runs objet Exécutions au sein des propres appels d'outils du sous-assistant, avec la même structure.

Appels d'outils dans la réponse

Lorsque le modèle utilise des outils d'IA pendant sa réponse, chaque appel d'outil est écrit dans content sous la forme d'un bloc entre deux marqueurs fixes, suivi de la suite du texte du modèle :

text
Let me check the current exchange rate.

### calling AI tool ...
### Scraping URL: https://example.com/rates
Looking up today's EUR/CZK rate
Successfully scraped 1 page(s)

***
The current rate is 24.35 CZK per euro.

Le marqueur d'ouverture est exactement la chaîne "\n\n### calling AI tool ...\n" et le marqueur de fermeture est "\n***\n". Entre les deux se trouve le texte de progression signalé par l'outil (Markdown). Définissez remove_tool_calls à true pour obtenir content sans ces blocs, ou utilisez le stream d'événements structuré, qui signale l'activité des outils sous forme d'événements distincts.

Images et fichiers générés

Les outils qui créent des fichiers pour l'utilisateur (génération d'images, rédaction de documents) signalent le fichier de deux manières :

  • le bloc d'appel d'outil dans content contient un lien Markdown, pour une image ![image.png](https://ayeto.ai/api/v1/public/file/read?id=...&secret=...) ;
  • les images générées sont listées dans attachments de la réponse.

La génération d'images est disponible lorsque l'assistant dispose d'un outil de génération d'images, ou dans une conversation avec un modèle lorsque dynamic_tools vaut true. Demandez une image dans message ; il n'existe pas d'option distincte pour les images.

Organisations et crédits

Chaque appel au modèle est facturé en crédits, à l'utilisateur de la clé ou, lorsque la requête s'exécute dans une organisation, sur le crédit de l'utilisateur dans cette organisation. Une requête s'exécute dans une organisation lorsque organization_id est défini, lorsque l'assistant appartient à une organisation, ou lorsqu'elle poursuit une conversation créée dans une organisation.

Une conversation créée dans une organisation y reste. Un message de suivi envoyé sans organization_id (et sans assistant d'une autre organisation) s'exécute dans l'organisation de la conversation : il y est facturé, ses pièces jointes sont décomptées du stockage de l'organisation et l'utilisateur de la clé doit toujours en être administrateur ou membre. Un message de suivi qui précise une autre organisation, directement ou via assistant_id, est refusé avec 422 the conversation belongs to another organization avant que quoi que ce soit ne soit enregistré ou facturé. Une conversation créée sans organisation n'est pas soumise à cette règle.

Avant chaque appel au modèle, AYETO estime son coût et refuse l'appel lorsque le solde ne le couvre pas. Pendant la génération d'une réponse, celle-ci est interrompue lorsque son coût dépasserait le solde. Dans les deux cas, l'erreur est 422 avec le détail not enough user credit ou not enough organization credit. Les appels au modèle déjà exécutés sont facturés, et une réponse interrompue en cours de route est conservée dans la conversation.

Voir Compte pour lire le solde de crédits.

Erreurs

Les erreurs sont renvoyées sous la forme {"detail": "..."} avec le statut HTTP ci-dessous. Lorsque stream vaut true, les erreurs marquées pendant surviennent après le début du stream : le statut HTTP est 200 et l'erreur arrive sous la forme d'un chunk d'erreur avec le même statut et le même détail. Les erreurs marquées avant sont renvoyées comme une réponse d'erreur normale dans les deux modes.

Statut detail Moment Cause
401 API key is invalid avant Voir Authentification.
403 permission denied avant L'utilisateur de la clé n'est pas autorisé à utiliser le chat, ou ne peut pas utiliser l'assistant.
403 not shared with user avant L'assistant n'appartient pas à l'utilisateur et n'est pas partagé avec lui.
403 You are not allowed to chat in this conversation avant conversation_id appartient à un autre utilisateur.
403 User is not a member of the organization avant organization_id (ou l'organisation de l'assistant, ou l'organisation de la conversation) ne fait pas partie des organisations de l'utilisateur.
403 User does not have write permissions in the organization avant L'utilisateur est invité dans l'organisation.
404 Assistant not found avant Aucun assistant avec assistant_id.
404 model not found avant Aucun modèle avec l'id indiqué dans model (ou le modèle de l'assistant).
422 liste d'erreurs de champs avant Corps invalide, par exemple ni assistant_id ni model fourni (Either assistant_id or model is required).
422 max_tokens must be between 1 and the maximum allowed tokens for the model avant max_tokens hors limites.
422 the conversation belongs to another organization avant La conversation a été créée dans une organisation et la requête en précise une autre (organization_id, ou l'organisation de assistant_id).
422 invalid base64 data in attachment '<filename>' avant Le data d'une pièce jointe n'est pas du base64 valide.
422 invalid data URI in attachment '<filename>' avant Le data d'une pièce jointe commence par data: mais ne contient pas de , avant le contenu.
422 file is too large avant Une pièce jointe dépasse la limite d'upload.
422 storage quota exceeded, organization storage quota exceeded avant Une pièce jointe ne tient pas dans le quota de stockage.
422 Assistant skill '/<slug>' requires unavailable tools: ... avant La compétence activée a besoin d'un outil qui n'est pas disponible.
422 model is deprecated avant Le modèle (ou le modèle de l'assistant) est retiré.
422 model is disabled avant Le modèle (ou le modèle de l'assistant) est désactivé par l'administrateur.
422 model is not available avant Le modèle (ou le modèle de l'assistant) est un modèle automatique et aucun des modèles parmi lesquels il choisit n'est disponible.
422 model does not have the required capability pendant Le modèle n'est pas un modèle de chat.
422 not enough user credit, not enough organization credit pendant Voir Organisations et crédits.
422 max iterations reached pendant Le modèle a continué à appeler des outils au-delà du nombre de tours autorisé.
403 llm: refusal from provider pendant Le fournisseur du modèle a refusé de répondre.
404 organization membership not found pendant L'utilisateur a quitté l'organisation dans laquelle la requête s'exécute.
429 message de limite de débit avant Trop de requêtes, voir Limites de débit.
500 llm: error on provider side, llm: error in chat stream, llm: max token reached pendant Le fournisseur du modèle a échoué, ou la réponse a atteint la limite de tokens en sortie.
529 llm: provider overload error pendant Le fournisseur du modèle est surchargé ; réessayez plus tard.
500 An error occurred during chat processing pendant Erreur inattendue (sans stream).

Si une erreur interrompt une réponse, la partie générée jusque-là est conservée dans la conversation.

Exemples

Poser une question à un modèle et poursuivre la même conversation :

bash
curl -X POST "https://ayeto.ai/api/v3/chat" \
  -H "uni-api-key: $AYETO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "conversation_id": "3f6c1a9e-8b2d-4e57-9a1c-2d7e5b8f4a10",
    "model": "gpt-5-mini",
    "message": "Summarize the benefits of unit tests in three bullet points."
  }'
json
{
  "id": "b1e4c7d2-5a3f-4c89-8e6b-0f2a9d1c7e35",
  "timestamp": 1759406412345,
  "role": "assistant",
  "content": "- **Catch regressions early** ...\n- **Document behaviour** ...\n- **Make refactoring safe** ...",
  "reasoning_content": "",
  "model": "gpt-5-mini",
  "attachments": [],
  "tool_runs": {}
}
bash
curl -X POST "https://ayeto.ai/api/v3/chat" \
  -H "uni-api-key: $AYETO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "conversation_id": "3f6c1a9e-8b2d-4e57-9a1c-2d7e5b8f4a10",
    "model": "gpt-5-mini",
    "message": "Now give an example for the second point in Python."
  }'

Discuter avec un assistant dans une organisation et joindre un document :

bash
curl -X POST "https://ayeto.ai/api/v3/chat" \
  -H "uni-api-key: $AYETO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "conversation_id": "8d2f0b6a-1c4e-4f7a-b3d9-6e5a2c1f0b87",
    "assistant_id": "c7a9e2f1-4b6d-4d38-9f0e-1a2b3c4d5e6f",
    "organization_id": "5e8b1d3c-7a2f-4c6e-8d9b-0a1f2e3d4c5b",
    "message": "List the payment terms in this contract.",
    "remove_tool_calls": true,
    "attachments": [
      {
        "filename": "contract.txt",
        "data": "data:text/plain;base64,UGF5bWVudCBkdWUgd2l0aGluIDMwIGRheXMu",
        "mime_type": "text/plain"
      }
    ]
  }'

Générer une image dans une conversation avec un modèle :

bash
curl -X POST "https://ayeto.ai/api/v3/chat" \
  -H "uni-api-key: $AYETO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "conversation_id": "0a7c3e5f-9b1d-4a26-8c4e-7f6d5b3a2c19",
    "model": "gpt-5-mini",
    "dynamic_tools": true,
    "message": "Draw a watercolor lighthouse at sunset."
  }'
json
{
  "id": "e2d4f6a8-0b1c-4d3e-9f5a-7b6c8d9e0f12",
  "timestamp": 1759406530112,
  "role": "assistant",
  "content": "\n\n### calling AI tool ...\n### Generating image\n...\n![image.png](https://ayeto.ai/api/v1/public/file/read?id=9c1e...&secret=4f7a...)\n\n***\nHere is your watercolor lighthouse at sunset.",
  "reasoning_content": "",
  "model": "gpt-5-mini",
  "attachments": [
    {
      "filename": "image.png",
      "content_type": "image/png",
      "file_url": "https://ayeto.ai/api/v1/public/file/read?id=9c1e...&secret=4f7a...",
      "name": null,
      "description": null
    }
  ],
  "tool_runs": {}
}

Python (requests) :

python
import base64
import os
import uuid

import requests

API = "https://ayeto.ai/api/v3"
HEADERS = {"uni-api-key": os.environ["AYETO_API_KEY"]}

conversation_id = str(uuid.uuid4())  # keep it to continue the conversation


def chat(message, attachments=None):
    response = requests.post(
        f"{API}/chat",
        headers=HEADERS,
        json={
            "conversation_id": conversation_id,
            "model": "gpt-5-mini",
            "message": message,
            "remove_tool_calls": True,
            "attachments": attachments,
        },
        timeout=600,  # answers that use tools can take minutes
    )
    if response.status_code != 200:
        raise RuntimeError(f"{response.status_code}: {response.json()['detail']}")
    return response.json()


with open("invoice.pdf", "rb") as f:
    pdf = f.read()

answer = chat(
    "What is the total amount of this invoice?",
    attachments=[{
        "filename": "invoice.pdf",
        "data": "data:application/pdf;base64," + base64.b64encode(pdf).decode(),
        "mime_type": "application/pdf",
    }],
)
print(answer["content"])
print(chat("And the due date?")["content"])

JavaScript (fetch) :

javascript
const API = "https://ayeto.ai/api/v3";
const conversationId = crypto.randomUUID(); // keep it to continue the conversation

async function chat(message) {
  const response = await fetch(`${API}/chat`, {
    method: "POST",
    headers: {
      "uni-api-key": process.env.AYETO_API_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      conversation_id: conversationId,
      assistant_id: "c7a9e2f1-4b6d-4d38-9f0e-1a2b3c4d5e6f",
      message,
    }),
  });
  const body = await response.json();
  if (!response.ok) {
    throw new Error(`${response.status}: ${JSON.stringify(body.detail)}`);
  }
  return body;
}

const answer = await chat("Draft a short reply to a customer asking about delivery times.");
console.log(answer.content);

Pour recevoir la réponse pendant sa génération, définissez "stream": true et lisez la réponse comme décrit dans Streaming.