API Tradovate : 'Access is denied' lors du passage d'ordre
Vos identifiants fonctionnent, votre jeton est valide, et /order/placeOrder rejette pourtant chaque ordre avec Access is denied. Ce n'est presque jamais une clé défectueuse, mais l'une de quatre erreurs banales et faciles à corriger.
Vous connectez un bot à l'API REST de Tradovate, le premier ordre en direct part, et la réponse est Access is denied. Cela ressemble à un mur. Vos identifiants ont fonctionné. L'authentification vous a remis un jeton. Vous pouvez même voir vos positions. Pourtant, /order/placeOrder rejette chaque exécution avec ce même message laconique, parfois sous forme de 401, parfois sous forme de HTTP 200 contenant {"failureReason":"UnknownReason","failureText":"Access is denied"}. Bonne nouvelle : ce n'est presque jamais un problème de « clé cassée ». C'est l'une de quatre erreurs banales et faciles à corriger : le mauvais id de compte, une permission Orders trop restreinte, le mauvais host demo/live, ou un flag isAutomated mal géré. Vous trouverez ci-dessous la checklist complète, ce que signifie réellement l'erreur, chaque cause racine avec une correction étape par étape, et comment PickMyTrade évite entièrement cette catégorie de problème afin que vos alertes TradingView soient routées vers Tradovate sans que vous ayez à déboguer du JSON à l'ouverture.
Checklist rapide pour "Access is denied"
- Mauvais id de compte, lisez l'
idnumérique depuis/account/list, jamais le nom affiché (comme « DEMO1235 »). - Permission Orders trop faible, la permission Orders de la clé API doit être réglée sur Full Access, pas en lecture seule.
- Host incompatible, générez le jeton et envoyez l'ordre sur le même host :
demo.tradovateapi.compour le sim,live.tradovateapi.compour le live. -
isAutomatedincorrect, incluez le flag et réglez-le surtruepour tout ordre de bot ou algorithmique, et surveillez le type de donnée lors d'un form-encode. - Symbole obsolète ou incorrect, utilisez le contrat du mois frontal actif (ou son id de contrat), pas un symbole expiré ou continu.
- Appareil non approuvé en live, le live impose strictement un
deviceIdconnu et stable ; le demo est plus permissif à ce sujet.
Ce que signifie "Access is denied"
Access is denied est la réponse générique de Tradovate signifiant « cette requête n'est pas autorisée à faire cela ». Le piège, c'est que ce n'est pas une erreur d'authentification au sens habituel : vous pouvez détenir un access token parfaitement valide et non expiré et l'obtenir quand même. Elle se déclenche au moment où Tradovate vérifie si ce jeton est autorisé à passer cet ordre sur ce compte. Toute rupture dans cette chaîne, un id de compte que le jeton ne possède pas, une clé API à qui les droits de passage d'ordre n'ont jamais été accordés, ou un jeton généré sur le host demo puis rejoué sur le live, se traduit par les mêmes trois mots.
Deux formes de réponse comptent ici. Un 401 Access Denied brut pointe généralement vers le jeton ou le host : le jeton a expiré, il a été demandé depuis la mauvaise base URL, ou (en live) l'appareil n'est pas approuvé. Un 200 OK dont le corps contient {"failureReason":"UnknownReason","failureText":"Access is denied"} signifie que la requête s'est authentifiée correctement, mais que l'ordre lui-même a été refusé au niveau des permissions, classiquement à cause d'un accountId erroné ou d'une permission Orders manquante.
Comme les deux variantes affichent le même message, il est facile de perdre une heure à revérifier des mots de passe alors que le véritable problème se trouve dans un seul champ du corps de la requête. Vérifiez d'abord le statut HTTP, puis parcourez les causes ci-dessous dans l'ordre.
Principales causes de "Access is denied" lors du passage d'ordre
1. Vous envoyez le nom affiché au lieu de l'id de compte numérique
C'est de loin la cause la plus fréquente. Votre compte affiche un nom comme DEMO1235 ou TRAD123456, et il est tentant de transmettre le nombre final comme accountId. Mais accountId est l'id d'entité interne de Tradovate, une valeur numérique distincte qui n'a aucun rapport avec les chiffres du nom affiché. Si vous transmettez le mauvais id, le jeton ne « possède » pas ce compte, et l'ordre est refusé.
La correction consiste à lire les deux identifiants depuis /account/list. Chaque objet de compte renvoie un id (l'id d'entité numérique à placer dans accountId) et un name (le libellé lisible à placer dans accountSpec). En résumé : l'id de compte n'est pas le nombre dont votre compte porte le nom. Ne le codez jamais en dur, récupérez-le toujours.

2. La permission Orders de la clé API n'est pas Full Access
Tradovate permet de restreindre une clé API par capacité. Une clé peut lire les positions, lire les informations de compte et lire la bibliothèque de contrats tout en ayant Orders réglé en dessous de Full Access, ce qui suffit exactement à s'authentifier, lister les comptes, et paraître fonctionnelle, mais elle est bloquée dès qu'elle tente de passer un ordre. La correction est directe : accordez à la clé Orders → Full Access dans les paramètres d'application/API Tradovate, puis régénérez le jeton pour que la nouvelle permission soit prise en compte.

3. Vous avez généré le jeton sur un host et passez l'ordre sur un autre
Tradovate exploite deux environnements entièrement séparés avec deux base URLs :
- Demo / simulation :
https://demo.tradovateapi.com/v1 - Live :
https://live.tradovateapi.com/v1
Un jeton demandé sur le host demo n'est valide que contre le host demo. Pointez ce jeton vers le /order/placeOrder du live (ou l'inverse) et vous obtenez Access is denied. L'erreur classique consiste à appeler auth/accessTokenRequest avec une base URL malformée ou incohérente, puis à se demander pourquoi chaque ordre suivant échoue. Vérifiez que votre appel d'authentification et votre appel d'ordre utilisent la même chaîne de host, caractère pour caractère, et que le host correspond au compte sur lequel vous voulez réellement trader.
4. isAutomated est manquant ou du mauvais type
Si un bot, un algorithme ou tout processus impersonnel déclenche l'ordre, les règles du CME exigent isAutomated: true ; un humain cliquant sur un bouton de l'interface donne false. Au-delà du simple fait d'inclure le flag, surveillez le type de donnée. Lorsque vous envoyez du JSON en POST, isAutomated est un booléen (true). Mais si vous encodez le corps en formulaire (data= au lieu de json= dans requests en Python), tout est sérialisé en chaînes, il doit donc être envoyé comme la chaîne "true". Un booléen qui retombe silencieusement à False, ou un type que le serveur ne peut pas analyser, vous ramène directement à Access is denied.
5. Format du symbole et (en live) un appareil non approuvé
Deux causes moins fréquentes complètent la liste. Premièrement, le format du symbole : transmettre un contrat expiré ou mal formé, un ancien code d'expiration, ou un symbole continu/de rollover que l'API ne peut pas router, peut se lire comme un refus plutôt que comme une erreur claire de « symbole invalide ». Passer au contrat du mois frontal actif (ou à son id de contrat) résout le problème. Deuxièmement, l'id d'appareil en live : le live impose strictement que les ordres proviennent d'un deviceId connu et approuvé, fourni lors de auth/accessTokenRequest, alors que le demo l'ignore en grande partie. Si votre code passe des ordres en demo mais est refusé uniquement en live, c'est le signe.
Comment résoudre "Access is denied" : étape par étape
Corriger l'id de compte
Authentifiez-vous et récupérez votre access token depuis le bon host. Appelez GET /account/list sur ce même host. Dans la réponse, repérez votre objet de compte. Copiez la valeur id, cet id d'entité numérique est votre accountId. Copiez la valeur name (généralement votre nom d'utilisateur Tradovate ou le libellé du compte), c'est votre accountSpec. Placez les deux dans le corps de l'ordre. Ne réutilisez pas les chiffres du nom affiché.
Accorder Orders Full Access, puis régénérer le jeton
Ouvrez les paramètres d'application/clé API Tradovate où figurent les permissions par capacité. Réglez la permission Orders sur Full Access (laissez les portées de lecture selon vos besoins). Enregistrez, puis demandez un access token nouveau, les changements de permission ne s'appliquent qu'aux jetons émis ensuite. Vérifiez avec un appel de lecture comme GET /position/list avant de réessayer l'ordre.
Faire correspondre le host demo/live
Déterminez dans quel environnement se trouve le compte (sim ou live). Utilisez demo.tradovateapi.com/v1 pour le sim et live.tradovateapi.com/v1 pour le live, pour à la fois l'appel d'authentification et l'appel d'ordre. Si vous changez d'environnement, ré-authentifiez-vous ; ne transportez jamais un jeton demo vers le live. Rappelez-vous que les jetons ont une durée de vie courte (environ 90 minutes). Si un script qui fonctionnait auparavant commence à échouer en cours de session, renouvelez le jeton plutôt que de rediagnostiquer les permissions.
Transmettre isAutomated correctement
Incluez toujours isAutomated dans le corps de l'ordre. Réglez-le sur true pour les ordres de bot/algorithmiques, sur false uniquement pour des actions d'interface réellement déclenchées par un humain. Si vous envoyez du JSON, gardez-le en booléen. Si vous encodez en formulaire, envoyez la chaîne "true". Renvoyez l'ordre et vérifiez que la réponse contient un véritable id d'ordre, pas un failureText.

Tableau de dépannage
| Erreur | Signification | Correction |
|---|---|---|
| 401 Access Denied | Jeton invalide, expiré, ou généré sur le mauvais host | Se réauthentifier sur le host demo/live correspondant ; renouveler avant l'expiration d'environ 90 minutes |
| 200 + {"failureText":"Access is denied"} | Authentifié, mais l'ordre a été refusé au niveau des permissions | Utiliser l'accountId numérique depuis /account/list et accorder Orders Full Access |
| Access is denied après avoir accordé la permission Orders | accountId est le nombre du nom affiché, pas l'id d'entité | Lire le champ id depuis /account/list |
| Fonctionne en demo, refusé en live | Id d'appareil non approuvé en live | Envoyer un deviceId stable lors de l'authentification et approuver l'appareil |
| Access is denied avec un compte correct | isAutomated manquant ou de type incorrect | Inclure isAutomated ; true pour les bots ; type correct selon JSON ou form-encoded |
| Refusé sur un symbole apparemment valide | Contrat expiré, continu ou mal formé | Utiliser le contrat du mois frontal actif ou son id de contrat |
Où PickMyTrade intervient
La plupart des tickets « Access is denied » proviennent d'une plomberie d'authentification et de passage d'ordre développée à la main. PickMyTrade élimine entièrement cette surface de risque en prenant en charge la connexion à Tradovate pour vous :
- Authentification gérée et routage du host, le bon host demo/live et un jeton récent et valide sont gérés automatiquement, de sorte qu'une session expirée ne se fait jamais passer pour une erreur de permission.
- Résolution du compte et des permissions, l'id de compte numérique correct et la permission Orders sont résolus à partir de votre compte lié, et non devinés à partir d'un nom affiché.
- Gestion conforme d'isAutomated, les ordres automatisés sont correctement marqués selon les règles de la bourse à chaque fois, sans piège booléen/chaîne.
- Validation du symbole et du contrat, les alertes sont associées à un contrat valide et actif avant qu'un ordre ne soit jamais envoyé, éliminant la catégorie d'échec « refusé pour symbole invalide ».
Tradez sans rejets
Démarrez votre essai gratuit de 5 jours, connectez vos alertes dès aujourd'hui et tradez sans rejets.
Démarrer votre essai gratuit de 5 joursQuestions fréquentes
La permission n'est que la moitié de la vérification. La cause restante la plus fréquente est un accountId incorrect, vous envoyez le nombre du nom affiché au lieu de l'id d'entité numérique provenant de /account/list. Un host incompatible, comme utiliser un jeton demo contre le live, produit le même message.
Appelez GET /account/list sur le même host que celui utilisé pour l'authentification. Utilisez le champ id de l'objet (l'id d'entité numérique) pour accountId, et son champ name pour accountSpec. Ne déduisez jamais l'id à partir du nom affiché du compte.
accountSpec est le nom sous forme de chaîne lisible (généralement votre nom d'utilisateur ou le libellé du compte). accountId est l'id interne numérique. Les deux sont requis dans le corps de l'ordre et proviennent tous deux de /account/list.
Non. C'est un refus générique. Vérifiez d'abord Orders → Full Access, mais si c'est déjà réglé, passez à l'id de compte, au host, puis au type d'isAutomated avant de supposer que la clé elle-même est défectueuse.
Le live impose strictement un deviceId approuvé et son propre host, tandis que le demo est plus permissif. Fournissez un id d'appareil stable lors de l'authentification et approuvez l'appareil pour résoudre le problème.
true pour tout ordre passé par un bot, un script ou un algorithme (une exigence de la bourse) ; false uniquement lorsqu'un humain le déclenche physiquement via une interface.
Oui. Tradovate renvoie parfois un 200 OK avec {"failureReason":"UnknownReason","failureText":"Access is denied"} dans le corps. Inspectez toujours le corps, pas seulement le code de statut.
Cela peut être le cas. Certaines prop firms restreignent ou interdisent l'automatisation directe par API sur les comptes d'évaluation, et l'état des données/permissions varie selon la firme et la taille du compte, vérifiez les règles actuelles de votre firme avant d'automatiser.
Ce guide est fourni à des fins éducatives et informatives uniquement et ne constitue pas un conseil financier, d'investissement ou de trading. Le trading de contrats à terme et d'autres produits à effet de levier comporte un risque de perte substantiel et ne convient pas à tous les investisseurs. PickMyTrade est une plateforme d'automatisation tierce indépendante et n'est ni affiliée à, ni approuvée par, ni sponsorisée par Tradovate, Inc. Tous les noms, logos et marques associés sont la propriété de leurs détenteurs respectifs. Les fonctionnalités et les étapes de la plateforme évoluent avec le temps ; confirmez toujours la procédure actuelle dans la plateforme et la documentation officielles de Tradovate avant d'agir.