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 -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.
# 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
| Canal | Réponse | Cause |
|---|---|---|
| REST | 403 — X-Deny-Reason: key | En-tête absent, clé inconnue ou révoquée. Le corps dit « Cle API absente, invalide ou revoquee ». |
| REST | 403 — X-Deny-Reason: family | La clé est bonne, mais la famille de cet endpoint n’est pas dans votre offre. |
| MCP | 401 — header X-API-KEY requis | En-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é. |
| WebSocket | 403 au handshake | Clé absente ou invalide dans l’URL (key), ou offre sans flux (websocket). La connexion ne s’ouvre pas. |
| WebSocket | fermeture 4003 | Plafond 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.