Créer un message
POST/messages
Reçoit une conversation au format Messages d'Anthropic et répond dans le même format, avec un modèle d'Evanesca : Claude Code et les SDK d'Anthropic fonctionnent dès qu'ils ont l'URL de base et une clé Evanesca. En dessous, chaque appel est une chat completion — les mêmes modèles, les mêmes opérateurs européens, la même facturation au token.
BientôtOuverture prochaine : ce qui suit décrit le service tel qu'il fonctionnera.
https://evanesca.app/api/v1/messagesOuvre au lancementBearer $EVANESCA_API_KEYx-api-keystringrequisVotre clé, qui commence par sk-eva-. Authorization: Bearer suivi de la clé marche aussi : c'est là que Claude Code l'envoie quand ANTHROPIC_AUTH_TOKEN est posé.
anthropic-versionstringEnvoyé par les SDK d'Anthropic ; accepté, sans effet ici.
Content-Typestringrequisapplication/json : le corps est du JSON.
Corps de la requête
application/jsonmodelstringrequisUn identifiant de modèle de chat d'Evanesca, pris dans le tableau des modèles, par exemple gemma-4-26b — jamais un identifiant Claude, qui répond 404.
messagesarrayrequisLes tours, avec les rôles user et assistant. Le contenu est une chaîne ou une liste de blocs : text, image (base64 ou URL), tool_use, tool_result et document.
systemchaîne | tableauLe prompt système ; les blocs de texte sont mis bout à bout.
max_tokensintegerPlafond de tokens de la réponse, réflexion comprise. Anthropic l'exige ; ici, on peut l'omettre.
streambooleantrue envoie les server-sent events d'Anthropic (Streaming).
tools, tool_choicetableau · objetLe format d'Anthropic : name, description, input_schema ; tool_choice auto, any, none ou tool (quels modèles appellent des outils).
temperature, top_p, top_k, stop_sequencesdiversTransmis à l'opérateur ; stop_sequences devient la liste stop d'OpenAI.
Où l'appel tourne, ce qu'il coûte
Evanesca · au dossier
- Exécuté
- Mistral AI · Région UE de Mistral AI
mistral-large-4,mistral-small-4-119b - AKI.IO · Allemagne
deepseek-v4.1-flash,glm-5.3,gemma-4-26b - Scaleway · Paris, France
qwen3.8-27b,deepseek-v4-flash,glm-5.2,qwen3.6-35b,qwen3.5-397b,gpt-oss-120b,qwen3-coder-30b,qwen3-235b,mistral-small-3.2,llama-3.3-70b,pixtral-12b - Infomaniak · Suisse
apertus-v1.5-70b
- Mistral AI · Région UE de Mistral AI
- L'opérateur garde
Mistral AI conserve les entrées et sorties de l'API pendant trente jours glissants pour surveiller les abus (politique de confidentialité de Mistral).
AKI.IO annonce que prompts, entrées et réponses générées sont traités en mémoire volatile, sans être journalisés, stockés ni analysés (AKI.IO) ; sa politique de confidentialité garde 90 jours les données d'usage — identifiant de requête, modèle, statut, horodatages, tokens — pour la facturation et la maintenance (politique de confidentialité d'AKI.IO).
Scaleway peut conserver et lire les requêtes qui provoquent des erreurs ou paraissent abusives, jusqu'à 14 jours (page confidentialité de Scaleway).
OVHcloud annonce ne garder que les données nécessaires à la facturation, « zero data retention » (OVHcloud AI Endpoints).
Infomaniak annonce que les requêtes ne sont ni enregistrées ni utilisées pour entraîner des modèles (Infomaniak AI Tools).
- Coût
- Ce que coûte le même appel en chat completion : au token, TVA comprise, 0,168 € à 3,024 € par million de tokens d'entrée et 0,336 € à 9,24 € par million de tokens de sortie, raisonnement compté en sortie. Une question rapide (300 tokens en entrée, 400 en sortie) sur gemma-4-26b : environ 0,0004 € (tous les prix).
- En-têtes de réponse
x-evanesca-operator: mistral | aki | scaleway | infomaniakx-evanesca-location: mistral-eu-region | germany | paris | switzerland
Comment la requête est traduite
Evanesca transforme la requête Messages en chat completion, l'exécute comme le ferait POST /chat/completions, puis retraduit la réponse. Le prompt système devient un message system, les blocs tool_use deviennent des appels d'outils, et chaque tool_result part en message tool placé avant le reste du tour de l'utilisateur. Les images vont au modèle telles quelles ; un document texte passe en texte, tandis qu'un document binaire comme un PDF est remplacé par une courte note qui en demande le texte — aucun fichier n'est transmis.
Certains champs n'ont pas d'équivalent et sont ignorés sans erreur : thinking, cache_control, metadata, l'en-tête anthropic-beta, les blocs thinking de l'historique, et les outils serveur d'Anthropic (des outils sans input_schema). disable_parallel_tool_use est ignoré lui aussi, parce que certains opérateurs refusent sa traduction : un modèle peut alors appeler plusieurs outils dans le même tour.
La réponse est un objet message standard. Son champ model reprend l'identifiant envoyé ; stop_reason vaut end_turn, max_tokens, tool_use ou refusal. Dans usage, input_tokens exclut les tokens que l'opérateur a lus dans son cache, comptés dans cache_read_input_tokens ; cache_creation_input_tokens vaut toujours 0. La réflexion d'un modèle ne revient pas en blocs thinking : il leur faudrait une signature que seul Anthropic peut donner.
Streaming
Avec "stream": true, la réponse arrive en événements d'Anthropic : message_start, puis pour chaque bloc content_block_start, ses fragments (text_delta pour le texte, input_json_delta pour les arguments d'un appel d'outil) et content_block_stop, puis message_delta avec la raison d'arrêt et l'usage, et message_stop. Tant qu'un modèle réfléchit, des événements ping gardent la connexion ouverte. L'usage de message_delta est ce sur quoi l'appel est facturé.
Claude Code
Claude Code lit son URL de base, sa clé et ses modèles dans l'environnement. Faites pointer les quatre variables de modèle sur des identifiants d'Evanesca : tant qu'elles ne sont pas posées, Claude Code demande des modèles Claude, et un identifiant Claude répond 404 model_not_found — Evanesca ne remplace jamais le modèle demandé par un autre. Claude Code travaille avec des outils : choisissez un modèle qui renvoie des appels d'outils.
export ANTHROPIC_BASE_URL="https://evanesca.app/api"
export ANTHROPIC_AUTH_TOKEN="$EVANESCA_API_KEY"
export ANTHROPIC_MODEL="gemma-4-26b"
export ANTHROPIC_DEFAULT_OPUS_MODEL="gemma-4-26b"
export ANTHROPIC_DEFAULT_SONNET_MODEL="gemma-4-26b"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="gemma-4-26b"
claudeFormat des erreurs
Les erreurs gardent l'enveloppe d'Anthropic — {"type": "error", "error": {"type", "message"}} — pour que les SDK d'Anthropic les lèvent comme d'habitude, mais error.type porte les valeurs de l'API d'Evanesca listées ci-dessous, les mêmes que sur POST /chat/completions.
Erreurs
| Statut | type | Signification |
|---|---|---|
| 400 | invalid_ | Le corps n'est pas du JSON valide, ou model ou messages manque. |
| 401 | invalid_ | Pas de clé, une clé malformée, ou une clé révoquée. |
| 402 | insufficient_ | Votre crédit est à zéro ou en dessous. Rechargez pour continuer. |
| 404 | model_ | Un identifiant Claude, un identifiant inconnu, un modèle qu'Evanesca ne sert pas, ou un modèle d'embedding. GET /models?kind=chat liste les identifiants valides. |
| 502 | upstream_ | L'opérateur est injoignable, a renvoyé une réponse illisible, ou a refusé le compte d'Evanesca elle-même. Votre clé n'est pas en cause : réessayez. |
| 503 | model_ | Le modèle est en pause, ou son opérateur est injoignable pour Evanesca pour l'instant. Réessayez plus tard ou choisissez un autre modèle. |
Les autres erreurs d'opérateur vous parviennent avec son statut et son corps, et Retry-After quand il en envoie un (erreurs).
curl https://evanesca.app/api/v1/messages \
-H "x-api-key: $EVANESCA_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "gemma-4-26b",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "Bonjour"}]
}'import os
import anthropic
client = anthropic.Anthropic(
base_url="https://evanesca.app/api",
api_key=os.environ["EVANESCA_API_KEY"],
)
message = client.messages.create(
model="gemma-4-26b",
max_tokens=1024,
messages=[{"role": "user", "content": "Bonjour"}],
)
print(message.content[0].text)import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
baseURL: "https://evanesca.app/api",
apiKey: process.env.EVANESCA_API_KEY,
});
const message = await client.messages.create({
model: "gemma-4-26b",
max_tokens: 1024,
messages: [{ role: "user", content: "Bonjour" }],
});
console.log(message.content[0].type === "text" ? message.content[0].text : message.content);package main
import (
"fmt"
"io"
"net/http"
"os"
"strings"
)
func main() {
body := strings.NewReader(`{"model":"gemma-4-26b","max_tokens":1024,"messages":[{"role":"user","content":"Bonjour"}]}`)
req, err := http.NewRequest("POST", "https://evanesca.app/api/v1/messages", body)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("EVANESCA_API_KEY"))
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(res.Status, string(out))
}{
"id": "msg_…",
"type": "message",
"role": "assistant",
"model": "gemma-4-26b",
"content": [{ "type": "text", "text": "…" }],
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": {
"input_tokens": 9,
"output_tokens": 12,
"cache_read_input_tokens": 0,
"cache_creation_input_tokens": 0
}
}{
"type": "error",
"error": {
"type": "model_not_found",
"message": "Evanesca does not serve \"claude-sonnet-4-5\": every model it serves runs in Europe. Set ANTHROPIC_MODEL … to Evanesca model IDs. …"
}
}