Prise en main

Authentification

Une seule clé ouvre les trois canaux. Elle se transmet différemment sur chacun — un en-tête en REST et en MCP, un paramètre d’URL au handshake en WebSocket — mais sa valeur est la même partout, et ce sont les droits de votre offre qui s’appliquent sur chacun.

#API REST

La clé se pose dans l’en-tête X-API-KEY. Ni paramètre d’URL, ni Authorization: Bearer : une clé en query string finirait dans les journaux d’accès de tous les intermédiaires du chemin.

curl
curl -H "X-API-KEY: $BYTNODE_KEY" \
  "https://api.bytnode.com/v1/basis?symbol=ETHUSDT"

La comparaison se fait en temps constant, donc une clé fausse met exactement le même temps à être rejetée qu’une clé presque juste.

#La route sans clé

Une seule route répond sans authentification : /v1/health, qui dit si le service est debout. Les deux routes qu’on interroge juste après — la fraîcheur de la donnée et le catalogue des actifs — demandent la clé, comme tout le reste. /v1/status est une sonde : jamais décomptée du quota mensuel, mais soumise au débit de l’offre. /v1/symbols relève de la famille prix et volume, ouverte sur toutes les offres, et compte comme n’importe quel appel.

GET/v1/healthsans clé
GET/v1/status
GET/v1/symbols
curl
# La seule route qui repond sans cle.
curl https://api.bytnode.com/v1/health

# Les deux suivantes demandent la cle. /v1/status est une sonde : jamais
# decomptee du quota mensuel, mais soumise au debit de l'offre.
curl -H "X-API-KEY: $BYTNODE_KEY" https://api.bytnode.com/v1/status
curl -H "X-API-KEY: $BYTNODE_KEY" https://api.bytnode.com/v1/symbols

#Flux WebSocket

La clé se présente dans l’URL, en paramètre ?api_key=, et elle est vérifiée au handshake — avant que la connexion ne s’ouvre. Un navigateur ne peut pas poser d’en-tête sur une WebSocket : c’est la seule forme qui marche partout, et c’est celle que les exemples utilisent.

import asyncio
import json
import os

import websockets


async def main() -> None:
    # La cle voyage dans l'URL, au handshake : la connexion s'ouvre deja
    # authentifiee. Une cle absente ou invalide recoit 403 avant l'ouverture.
    url = f"wss://api.bytnode.com/ws?api_key={os.environ['BYTNODE_KEY']}"
    async with websockets.connect(url) as ws:
        await ws.send(json.dumps({
            "op": "subscribe",
            "channels": ["trades.futures.BTCUSDT"],
        }))
        print(await ws.recv())   # {"op": "subscribed", "channels": [...]}


asyncio.run(main())

La session s’ouvre déjà authentifiée : le premier message peut être l’abonnement. Une clé absente, invalide ou révoquée, ou une offre qui n’inclut pas le flux, reçoit un 403 à la poignée de main et rien ne s’établit. Le plafond de connexions simultanées de l’offre s’applique au compte entier : la connexion de trop est fermée avec le code 4003. L’ancienne trame {"op": "auth", "api_key": "…"} reste acceptée et répond ok, mais elle est facultative.

#Serveur MCP

Le serveur MCP attend la même clé, dans le même en-tête X-API-KEY, posé sur la connexion HTTP. Sans elle, aucun outil n’est exposé : le serveur refuse par défaut plutôt que d’ouvrir par défaut.

from fastmcp import Client

headers = {"X-API-KEY": "votre_cle"}

async with Client("https://api.bytnode.com/mcp", headers=headers) as client:
    info = await client.call_tool("get_system_info", {})

La forme exacte du fichier de configuration dépend de l’agent ; le principe ne change pas — une URL et un en-tête. Voir Serveur MCP.

#Ce que dit un refus

CanalRéponseCause
REST403X-Deny-Reason: keyEn-tête absent, clé inconnue ou révoquée. Le corps dit « Cle API absente, invalide ou revoquee ».
REST403X-Deny-Reason: familyLa clé est bonne, mais la famille de cet endpoint n’est pas dans votre offre.
MCP401header X-API-KEY requisEn-tête absent sur la connexion, ou clé refusée. Le contrôle a lieu avant que le moindre outil ne soit annoncé ; ensuite, chaque appel d’outil est jugé aux droits de la clé.
WebSocket403 au handshakeClé absente ou invalide dans l’URL (key), ou offre sans flux (websocket). La connexion ne s’ouvre pas.
WebSocketfermeture 4003Plafond de connexions simultanées de l’offre atteint, pour le compte entier. Le motif donne le plafond.

#Protéger et faire tourner la clé

Où la garder

  • Dans une variable d’environnement ou un gestionnaire de secrets, jamais dans le dépôt de code.
  • Côté serveur uniquement. Une clé posée dans du JavaScript de page est publique, quelle que soit l’obfuscation.
  • Une clé par environnement — développement, recette, production. Une fuite se révoque alors sans arrêter le reste.

La faire tourner

  • Créez la nouvelle clé dans la console. Les deux restent valides pendant le recouvrement.
  • Déployez-la partout, puis vérifiez que le trafic de l’ancienne est retombé à zéro.
  • Révoquez l’ancienne. La révocation est immédiate.