Règle n°1 : N'appelez jamais l'API Anthropic directement depuis le navigateur ou une application mobile. La clé API doit rester sur votre serveur, en variable d'environnement.

1. Prérequis — Compte Anthropic et modèles 2026

Obtenir une clé API

  1. Créez un compte sur console.anthropic.com
  2. Dans API Keys, cliquez sur Create API Key
  3. Copiez la clé — elle n'est affichée qu'une seule fois
  4. Stockez-la dans une variable d'environnement : ANTHROPIC_API_KEY
⚠️ Ne jamais committer la clé API dans Git. Ajoutez .env à votre .gitignore dès le départ.

Choisir le bon modèle en 2026

La famille Claude 4 est la plus récente. Voici comment choisir :

Modèle ID API Cas d'usage Vitesse
Claude Haiku 4.5 claude-haiku-4-5-20251001 Classification, résumés courts, réponses rapides ⚡⚡⚡
Claude Sonnet 4.6 ★ claude-sonnet-4-6 Chat, génération, analyse — recommandé pour débuter ⚡⚡
Claude Opus 4.8 claude-opus-4-8 Raisonnement complexe, code avancé, recherche
Recommandation : commencez avec claude-sonnet-4-6. Passez à claude-opus-4-8 uniquement si vos tâches l'exigent vraiment.

2. Backend Python avec Flask

Installation

pip install anthropic flask flask-cors python-dotenv

Fichier .env

ANTHROPIC_API_KEY=sk-ant-votre_cle_api_ici

Application Flask — app.py

from flask import Flask, request, jsonify
from flask_cors import CORS
from anthropic import Anthropic, RateLimitError, APIConnectionError
import os
from dotenv import load_dotenv

load_dotenv()
app = Flask(__name__)
CORS(app)  # Autorise les requêtes depuis votre frontend

client = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))

@app.route("/api/ask-claude", methods=["POST"])
def ask_claude():
    data = request.get_json()
    prompt = data.get("prompt", "").strip()

    if not prompt:
        return jsonify({"error": "Le champ 'prompt' est requis."}), 400
    if len(prompt) > 10_000:
        return jsonify({"error": "Prompt trop long (max 10 000 car.)."}), 400

    try:
        response = client.messages.create(
            model="claude-sonnet-4-6",
            max_tokens=1024,
            system="Tu es un assistant intelligent. Réponds en français.",
            messages=[{"role": "user", "content": prompt}]
        )
        return jsonify({
            "response": response.content[0].text,
            "tokens_used": response.usage.input_tokens + response.usage.output_tokens
        })
    except RateLimitError:
        return jsonify({"error": "Limite d'appels atteinte. Réessayez."}), 429
    except APIConnectionError:
        return jsonify({"error": "Impossible de contacter l'API."}), 503
    except Exception as e:
        return jsonify({"error": str(e)}), 500

if __name__ == "__main__":
    app.run(debug=True, port=5000)

Test avec cURL

python app.py

# Dans un autre terminal :
curl -X POST http://localhost:5000/api/ask-claude \
     -H "Content-Type: application/json" \
     -d '{"prompt": "Explique l'\''IA en 3 points."}'

3. Backend Node.js avec Express

Installation

npm install express @anthropic-ai/sdk dotenv cors

Serveur Express — server.js

require('dotenv').config();
const express = require('express');
const cors = require('cors');
const Anthropic = require('@anthropic-ai/sdk');

const app = express();
app.use(express.json());
app.use(cors());

const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });

app.post('/api/ask-claude', async (req, res) => {
  const { prompt } = req.body;

  if (!prompt?.trim()) {
    return res.status(400).json({ error: "Le champ 'prompt' est requis." });
  }

  try {
    const message = await anthropic.messages.create({
      model: 'claude-sonnet-4-6',
      max_tokens: 1024,
      system: 'Tu es un assistant intelligent. Réponds en français.',
      messages: [{ role: 'user', content: prompt }],
    });

    res.json({
      response: message.content[0].text,
      tokens_used: message.usage.input_tokens + message.usage.output_tokens,
    });
  } catch (err) {
    const status = err.status || 500;
    res.status(status).json({ error: err.message });
  }
});

app.listen(3000, () => console.log('API démarrée sur http://localhost:3000'));

4. Frontend React

Création et installation

npx create-react-app claude-chat && cd claude-chat
npm install axios

Composant de chat — src/components/ClaudeChat.jsx

import { useState, useRef, useEffect } from 'react';
import axios from 'axios';

const API = process.env.REACT_APP_API_URL || 'http://localhost:5000';

export default function ClaudeChat() {
  const [messages, setMessages] = useState([]);
  const [input, setInput]       = useState('');
  const [loading, setLoading]   = useState(false);
  const endRef = useRef(null);

  useEffect(() => endRef.current?.scrollIntoView({ behavior: 'smooth' }), [messages]);

  const send = async (e) => {
    e.preventDefault();
    const prompt = input.trim();
    if (!prompt || loading) return;

    setMessages(m => [...m, { role: 'user', text: prompt }]);
    setInput('');
    setLoading(true);

    try {
      const { data } = await axios.post(`${API}/api/ask-claude`, { prompt });
      setMessages(m => [...m, { role: 'claude', text: data.response }]);
    } catch (err) {
      setMessages(m => [...m, { role: 'error', text: err.message }]);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div className="chat">
      <div className="messages">
        {messages.map((m, i) => (
          <p key={i} className={m.role}>{m.text}</p>
        ))}
        {loading && <p className="claude typing">Claude réfléchit…</p>}
        <div ref={endRef} />
      </div>
      <form onSubmit={send}>
        <input value={input} onChange={e => setInput(e.target.value)}
               placeholder="Votre question…" disabled={loading} />
        <button type="submit" disabled={loading || !input.trim()}>Envoyer</button>
      </form>
    </div>
  );
}
Bonne pratique : créez un fichier .env à la racine React avec REACT_APP_API_URL=http://localhost:5000 en dev et votre URL de production pour le déploiement.

5. Frontend Vue.js

npm create vue@latest claude-vue && cd claude-vue && npm install axios && npm install

Composant — src/components/ClaudeChat.vue

<script setup>
import { ref, nextTick } from 'vue';
import axios from 'axios';

const messages = ref([]);
const input    = ref('');
const loading  = ref(false);
const endRef   = ref(null);

const scrollDown = async () => { await nextTick(); endRef.value?.scrollIntoView({ behavior:'smooth' }); };

const send = async () => {
  const prompt = input.value.trim();
  if (!prompt || loading.value) return;
  messages.value.push({ role: 'user', text: prompt });
  input.value = '';
  loading.value = true;
  await scrollDown();

  try {
    const { data } = await axios.post(
      import.meta.env.VITE_API_URL + '/api/ask-claude', { prompt }
    );
    messages.value.push({ role: 'claude', text: data.response });
  } catch (err) {
    messages.value.push({ role: 'error', text: err.message });
  } finally {
    loading.value = false;
    await scrollDown();
  }
};
</script>

<template>
  <div class="chat">
    <div class="messages">
      <p v-for="(m,i) in messages" :key="i" :class="m.role">{{ m.text }}</p>
      <p v-if="loading" class="claude typing">Claude réfléchit…</p>
      <div ref="endRef" />
    </div>
    <form @submit.prevent="send">
      <input v-model="input" placeholder="Votre question…" :disabled="loading" />
      <button type="submit" :disabled="loading || !input.trim()">Envoyer</button>
    </form>
  </div>
</template>

6. Streaming — réponses en temps réel

Le streaming affiche la réponse mot par mot, comme sur claude.ai, au lieu d'attendre la réponse complète. Indispensable pour une bonne UX sur les réponses longues.

Endpoint Flask (SSE)

from flask import Response, stream_with_context
import json

@app.route("/api/stream-claude", methods=["POST"])
def stream_claude():
    data = request.get_json()
    prompt = data.get("prompt", "").strip()
    if not prompt:
        return {"error": "Prompt requis"}, 400

    def generate():
        with client.messages.stream(
            model="claude-sonnet-4-6",
            max_tokens=1024,
            messages=[{"role": "user", "content": prompt}]
        ) as stream:
            for text in stream.text_stream:
                yield f"data: {json.dumps({'text': text})}\n\n"
        yield "data: [DONE]\n\n"

    return Response(
        stream_with_context(generate()),
        mimetype="text/event-stream",
        headers={"Cache-Control": "no-cache", "X-Accel-Buffering": "no"}
    )

Consommation côté client (JavaScript)

const streamChat = async (prompt) => {
  let buffer = '';
  setLoading(true);

  const response = await fetch('/api/stream-claude', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ prompt })
  });

  const reader = response.body.getReader();
  const decoder = new TextDecoder();

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    const chunk = decoder.decode(value);
    const lines = chunk.split('\n').filter(l => l.startsWith('data: '));

    for (const line of lines) {
      const payload = line.slice(6);
      if (payload === '[DONE]') { setLoading(false); return; }
      const { text } = JSON.parse(payload);
      buffer += text;
      setResponse(buffer);  // Mise à jour progressive de l'UI
    }
  }
};

7. Bonnes pratiques et optimisation des coûts

Sécurité — checklist

  • ✅ Clé API uniquement dans les variables d'environnement serveur
  • .env dans .gitignore
  • ✅ Validation et limite de longueur des prompts entrants
  • ✅ Rate limiting par IP (ex: flask-limiter ou express-rate-limit)
  • ✅ HTTPS obligatoire en production
  • ✅ CORS restreint à votre domaine frontend uniquement

Prompt Caching — jusqu'à 90 % d'économie

Si votre system prompt est long et identique d'un appel à l'autre (contexte métier, instructions fixes), activez le cache Anthropic :

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    system=[{
        "type": "text",
        "text": "Vous êtes expert en droit fiscal français. [Contexte de 2000 tokens ici]",
        "cache_control": {"type": "ephemeral"}  # Ce bloc sera mis en cache
    }],
    messages=[{"role": "user", "content": prompt}]
)
# Les appels suivants avec le même system prompt économisent ~90% sur ces tokens
Autres optimisations : ajustez max_tokens au besoin réel (256 pour un résumé court, 2048 pour un article). Utilisez Claude Haiku pour les tâches de classification simples et Sonnet pour le reste.

8. Déploiement

🖥️ Backend (Flask / Node.js)
  • Render — gratuit, simple, recommandé
  • Railway — très rapide à déployer
  • Heroku — solution historique
🎨 Frontend (React / Vue)
  • Vercel — optimal pour React/Next.js
  • Netlify — excellent pour Vue/statique
  • GitHub Pages — pour les sites statiques
Variables d'environnement en prod : configurez ANTHROPIC_API_KEY dans le dashboard de votre plateforme (Render → Environment, Railway → Variables). Ne déployez jamais de fichier .env.

Checklist avant mise en ligne

  • ANTHROPIC_API_KEY configurée en variable d'environnement
  • .env dans .gitignore
  • ☐ CORS restreint au domaine de production
  • ☐ HTTPS activé (automatique sur Vercel, Netlify, Render)
  • ☐ Rate limiting activé
  • ☐ Logs d'erreurs configurés (Sentry, Logtail…)

9. FAQ

Peut-on appeler l'API Claude depuis le navigateur ?

Non. Appeler l'API directement depuis le frontend exposerait votre clé dans le code source (visible via "Inspecter l'élément"). Utilisez toujours un backend pour faire le relais.

Quel modèle Claude choisir pour une PME en 2026 ?

Commencez par claude-sonnet-4-6 pour le meilleur équilibre. Pour les tâches simples (classification, réponses courtes), passez à claude-haiku-4-5-20251001 pour réduire les coûts. Réservez claude-opus-4-8 aux analyses complexes.

Comment réduire les coûts API ?

Activez le Prompt Caching sur les system prompts fixes (économie jusqu'à 90 %). Limitez max_tokens au besoin réel. Mettez en cache (Redis) les réponses aux questions fréquentes. Utilisez Haiku pour les tâches simples.

Comment afficher la réponse en temps réel ?

Utilisez le streaming : côté serveur avec client.messages.stream() et côté client avec la Fetch API (ReadableStream) ou EventSource. Voir section 6 ci-dessus.

Peut-on envoyer des images à Claude ?

Oui, tous les modèles Claude 4 supportent la vision. Encodez l'image en base64 et passez-la dans le tableau content du message avec type: "image". Voir la documentation vision.

Sources et documentation officielle

Voir aussi