Tradovate API

Error 400 “Invalid JSON” del token de acceso de Tradovate

Envía credenciales correctas al endpoint del token de acceso y aun así recibe un 400 “invalid JSON”. Aquí están todos los errores de formato que lo causan, y la solicitud corregida para curl, Python y JavaScript.

Revisado por el equipo de Sistemas de Trading de PickMyTrade Última actualización
· Lectura de 7 minutos
Cliente REST mostrando una respuesta 400 con un mensaje de error de JSON inválido en la solicitud del token de acceso

Envía su nombre de usuario y contraseña al endpoint del token de acceso, y en lugar de un token recibe un tajante 400 con un mensaje como [Invalid JSON: expected '}' or ',', offset: 0x00000028]. Las credenciales están bien. La cuenta funciona en la plataforma web. ¿Entonces qué pasa?

Aquí la respuesta corta: el servidor nunca llegó a leer su inicio de sesión. Un 400 “invalid JSON” ocurre en la etapa de análisis, antes de cualquier verificación de credenciales. Algo en la forma de su cuerpo de solicitud, las comillas, la cabecera, la forma en que su lenguaje lo serializó, no es JSON válido. Corrija el formato y esas mismas credenciales pasarán sin problema.

Esta guía recorre cada versión de ese error de formato, en el orden en que es más probable que se encuentre con él, con la solicitud corregida para curl, Python y JavaScript.

Cómo se ve realmente el error

La solicitud va al endpoint de autenticación. En el entorno demo es:

POST https://demo.tradovateapi.com/v1/auth/accesstokenrequest

En real es https://live.tradovateapi.com/v1/auth/accesstokenrequest. Mismo cuerpo, distinto host, confundirlos es un problema aparte, pero no producirá un mensaje “invalid JSON”, así que déjelo de lado por ahora.

Una llamada exitosa devuelve un objeto JSON con un accessToken y una expirationTime. Una malformada devuelve HTTP 400 y un cuerpo que nombra la queja del analizador y un desplazamiento de bytes. Ese desplazamiento es su mejor pista, y volveremos a él.

La causa real: su cuerpo no es JSON válido

JSON tiene reglas estrictas que mucho código rompe silenciosamente. Las formas más comunes en que un cuerpo de inicio de sesión termina siendo inválido:

  • Comillas simples. JSON exige comillas dobles alrededor de las claves y los valores de cadena. Si imprime un dict de Python, un objeto de JavaScript o un hash de Ruby directamente en la solicitud, obtiene comillas simples y deja de ser JSON.
  • Una coma final. Una coma después del último campo es legal en la mayoría de los lenguajes e ilegal en JSON.
  • Codificación de formulario. Muchas bibliotecas HTTP usan por defecto application/x-www-form-urlencoded. El servidor, que espera JSON, se atraganta desde el primer byte.
  • Doble codificación. Convierte el objeto en cadena una vez, y luego entrega esa cadena a un cliente que la convierte en cadena otra vez. Ahora el cuerpo es una cadena entre comillas, no un objeto.
  • Caracteres ocultos. Una marca de orden de bytes o una “comilla tipográfica” pegada de un documento o un chat se ve idéntica en pantalla pero rompe el analizador.

Cada uno de estos produce la misma familia de errores 400. Vamos a eliminarlos uno por uno.

Solución 1: envíe JSON real con comillas dobles

Empecemos por el objetivo. Así es como se ve un cuerpo válido, comillas dobles por todas partes, sin coma final, cid como número desnudo:

{ "name": "your_username", "password": "your_password", "appId": "My App", "appVersion": "1.0", "cid": 8, "sec": "your-api-secret", "deviceId": "123e4567-e89b-12d3-a456-426614174000" }

Solo name y password son estrictamente obligatorios; el resto identifica su aplicación y se necesita para el acceso completo a la API. Compare eso con la versión rota que la gente suele enviar, que es un objeto de lenguaje impreso como texto:

{'name': 'your_username', 'password': 'your_password', 'appId': 'My App', 'cid': '8'}

Dos problemas ahí: comillas simples por todas partes, y cid envuelto en comillas por lo que se lee como una cadena. Cambie las comillas simples por dobles y quite las comillas del valor cid, y el cuerpo se valida.

Comparación lado a lado de un cuerpo de solicitud roto con comillas simples y un cuerpo JSON corregido con comillas dobles

Solución 2: configure la cabecera Content-Type

JSON válido en el cuerpo no basta. También debe indicarle al servidor que el cuerpo es JSON. Añada estas cabeceras a la solicitud:

Content-Type: application/json
Accept: application/json

Sin Content-Type: application/json, la mayoría de los clientes recurren a la codificación de formulario y el servidor intenta analizar los campos del formulario como un documento JSON. El análisis falla en el byte cero y obtiene un 400. Esta única cabecera resuelve por sí sola una sorprendente proporción de informes de “invalid JSON”.

Solución 3: en Python, use json= en lugar de data=

La biblioteca requests hace tropezar a la gente constantemente aquí. Si pasa su diccionario a través del parámetro data, se codifica como formulario y las comillas dobles nunca aparecen. Páselo a través de json en su lugar, eso serializa el diccionario a JSON adecuado y configura la cabecera Content-Type automáticamente.

Incorrecto: requests.post(url, data=credentials)
Correcto: requests.post(url, json=credentials)

Con json=credentials nunca toca las comillas a mano, la biblioteca lo hace correctamente. Solo asegúrese de que credentials sea un diccionario real (con cid como int), no un blob previamente convertido a cadena. Si ya llamó a json.dumps() sobre él, elimine eso y use json=, o mantenga la cadena y páselo a través de data= con la cabecera Content-Type configurada manualmente. No haga ambas cosas.

Pestaña de cabeceras de un cliente HTTP mostrando Content-Type application/json con un cuerpo JSON en bruto listo para enviar

Solución 4: en JavaScript, convierta a cadena exactamente una vez

Con fetch, el error clásico es olvidar JSON.stringify (por lo que el cuerpo se convierte en la cadena inútil [object Object]) o llamarlo dos veces. Hágalo una vez y configure la cabecera:

fetch(url, {
  method: "POST",
  headers: { "Content-Type": "application/json", "Accept": "application/json" },
  body: JSON.stringify(credentials)
})

Si credentials ya es una cadena, no la envuelva de nuevo en JSON.stringify, el segundo paso escapa cada comilla y el servidor recibe una larga cadena entrecomillada, que no es un objeto.

Solución 5: con curl, escape sus comillas

El shell se come los caracteres de comillas, así que un payload JSON en bruto en la línea de comandos requiere cuidado. Escape las comillas dobles internas con barras invertidas:

curl -X POST https://demo.tradovateapi.com/v1/auth/accesstokenrequest \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d "{ \"name\": \"your_username\", \"password\": \"your_password\", \"appId\": \"My App\", \"appVersion\": \"1.0\", \"cid\": 8, \"deviceId\": \"123e4567-e89b-12d3-a456-426614174000\", \"sec\": \"your-api-secret\" }"

Una ruta más sencilla: ponga el JSON en un archivo y pase -d @body.json, lo que evita por completo el problema de las comillas del shell. Tenga en cuenta que el -d simple usa por defecto la codificación de formulario, así que la cabecera Content-Type: application/json sigue teniendo que ser explícita.

Solución 6: verifique los tipos de sus campos

Incluso el JSON limpio es rechazado si un valor tiene el tipo incorrecto. El que suele morder a la gente es cid: es un entero, así que envíe "cid": 8, nunca "cid": "8". Mantenga los campos de cadena (name, password, appId, appVersion, sec, deviceId) entre comillas, y deje cid como un número desnudo. Aquí la referencia rápida:

Campo Tipo ¿Obligatorio? Ejemplo
namestring"trader_jane"
passwordstring"S3cureP@ss!"
appIdstringPara acceso completo"My App"
appVersionstringPara acceso completo"1.0"
cidintegerPara acceso completo8
secstringPara acceso completo"f03741b6-..."
deviceIdstringRecomendado"123e4567-..."

Si su contraseña contiene una comilla doble, una barra invertida o un salto de línea, esos caracteres deben escaparse dentro de la cadena JSON. Dejar que su serializador construya el cuerpo (los enfoques json= y JSON.stringify anteriores) se encarga de eso por usted.

Leer el desplazamiento en el error

Cuando el mensaje le entrega un desplazamiento como 0x00000028, úselo. El valor es hexadecimal, 0x28 es 40 en decimal, y apunta al byte donde el analizador se detuvo. Cuente dentro del cuerpo exacto que envió (regístrelo, no adivine) e inspeccione ese carácter. Una comilla simple, una coma sin nada después, o un carácter de control casi siempre está exactamente ahí. Un desplazamiento de 0x0 es distinto: significa que el analizador no encontró nada que leer, por lo que su cuerpo estaba vacío o nunca salió del cliente.

Verifique la solución

Una vez que el cuerpo esté limpio y la cabecera configurada, vuelva a ejecutar la solicitud. Una llamada que funciona devuelve HTTP 200 con un payload JSON que contiene su accessToken, un userId, y una expirationTime de unos 90 minutos. Copie ese token en una cabecera Authorization: Bearer <token> para cada llamada posterior.

Respuesta 200 exitosa devolviendo un token de acceso y una hora de expiración desde la solicitud del token de acceso

Si sigue obteniendo el mismo 400, registre los bytes en bruto de lo que realmente está enviando, no lo que cree que está enviando, y compárelo con el ejemplo válido anterior. La diferencia es casi siempre una comilla o una coma.

Cuando el JSON está limpio y aun así falla

Si el analizador está contento pero la solicitud sigue dando error, ha superado el problema de formato y se encuentra ante un problema de autenticación o de entorno:

  • Host equivocado. Las credenciales de demo en el host real (o viceversa) fallan incluso con JSON perfecto.
  • Secreto de API o cid incorrectos. Un sec o cid incorrecto devuelve un 400 que no tiene nada que ver con el formato, el cuerpo se analizó bien, los valores simplemente no coinciden.
  • Límite de sesión o límite de tasa. Bombardear el endpoint puede bloquearle el acceso. Si ve fallos repetidos bajo carga, lea nuestra nota sobre el límite de tasa 429 de la API de Tradovate.
  • Token expirado en llamadas posteriores. El token en sí solo dura unos 90 minutos; renuévelo antes de que caduque en lugar de volver a autenticarse cada vez. Vea 401 no autorizado de la API de Tradovate (token expirado).

Simplifique la autenticación con PickMyTrade

¿Prefiere no estar pendiente de las solicitudes de token, las caducidades de 90 minutos y el entrecomillado de JSON? PickMyTrade conecta su cuenta de Tradovate y enruta sus alertas de TradingView a órdenes reales, la autenticación y la gestión de sesiones funcionan detrás de escena, así que no hay código de autenticación que usted deba depurar.

Prescinda por completo del código de autenticación

PickMyTrade conecta su cuenta de Tradovate y gestiona las solicitudes de token, las renovaciones y el formato JSON entre bastidores, para que sus alertas se enruten sin que usted tenga que depurar ni una sola llamada de autenticación.

Comience su prueba gratuita de 5 días

Preguntas frecuentes

El 400 se lanza antes de que el servidor verifique su inicio de sesión. El cuerpo no es JSON válido, o no se envió como JSON. Busque comillas simples, una coma final, codificación de formulario, o una cabecera Content-Type: application/json ausente. Corrija el cuerpo y las mismas credenciales se autentican sin problema.

Es la posición en bytes donde el analizador JSON se detuvo, escrita en hexadecimal. 0x28 es 40 en decimal, así que busque alrededor del carácter 40 del cuerpo exacto que envió, ahí es donde se rompió la sintaxis. Un desplazamiento de 0x0 significa que el cuerpo estaba vacío o nunca llegó.

Un número. Envíe "cid": 8, no "cid": "8". Ponerlo entre comillas convierte un campo entero en una cadena y puede hacer que la solicitud sea rechazada incluso cuando el JSON es válido en todo lo demás.

El explorador construye un cuerpo limpio con comillas dobles y configura la cabecera por usted. Su cliente puede estar imprimiendo un objeto de lenguaje con comillas simples, codificando los datos como formulario, o codificando la cadena dos veces. Copie el cuerpo exacto del explorador y hágalo coincidir byte por byte.

Sí. Escape las comillas dobles internas con barras invertidas, o envuelva todo el payload entre comillas simples para que el shell no toque las comillas dobles internas. Pasar el cuerpo desde un archivo con -d @body.json evita por completo el baile de comillas.

Esta guía tiene fines exclusivamente educativos e informativos y no constituye asesoramiento financiero, de inversión ni de trading. Operar con futuros y otros productos apalancados conlleva un riesgo considerable de pérdida y no es adecuado para todos los inversores. PickMyTrade es una plataforma de automatización independiente de terceros y no está afiliada, respaldada ni patrocinada por Tradovate, Inc. ni por Bookmap. Todos los nombres, logotipos y marcas relacionados son propiedad de sus respectivos titulares. Las funciones y los pasos de la plataforma cambian con el tiempo, por lo que siempre debe confirmar el proceso actual en la documentación oficial de la plataforma antes de actuar.