Primeros pasos

Respuestas y errores para código y agentes de IA

Todas las respuestas correctas comparten un mismo sobre, y todos los errores una misma forma. Esta página describe el sobre, la forma de data ruta por ruta, la manera de reducir la respuesta, cómo leer un campo vacío y qué significa cada código de error.

Un agente de IA lee lo mismo: el servidor MCP conserva estos nombres de campo, unidades y convenciones, y una llamada de herramienta fallida lleva el mismo error.code estable.

#El sobre estándar

Respuesta
{
  "status": "ok",
  "server_time": "2026-10-10T08:51:22.927Z",
  "data_type": "basis",
  "symbol": "BTCUSDT",
  "data": {
    "time": "2026-10-10T08:51:14.104Z",
    "basis_value": -42.0048049747,
    "basis_pct": -0.0507185886791,
    "futures_price": 82776.0067294,
    "spot_price": 82818.0115344
  }
}
CampoTipoDescripción
statusstringok o error.
server_timestringEl instante en que se produjo la respuesta, en ISO 8601 UTC con milisegundos: el formato de todas las fechas de data. Nunca la hora del dato, que cada fila lleva en time.
data_typestringEl nombre del tipo devuelto. Permite enrutar una respuesta sin depender de la ruta llamada, útil cuando un cliente pasa por una cola o una caché.
symbolstringEl símbolo de la petición, repetido fuera de data. Presente cuando la ruta admite un símbolo.
timeframestringEl timeframe que enviaste (o el valor por defecto de la ruta), y solo ese. ?fields= no toca estas claves.
stepstringEn una lista (toda ruta /history y las series de eventos): el intervalo entre sus filas — el timeframe pedido, o la cadencia de la serie cuando la ruta no lo acepta (1d para una serie diaria, 8h para el funding, 1m para las lecturas de comisiones de Bitcoin). Una fila de bucket se fecha al inicio de su bucket; una lectura periódica en su propio instante. Ausente cuando las filas no tienen intervalo fijo (presentaciones de ETF, instantáneas del max pain de opciones, lecturas del mercado global).
marketstringEl mercado del dato: tomado de la ruta en las rutas que sirven varios (all sin sufijo = spot + futuros perpetuos, spot, futures), fijo en las rutas que sirven uno (futures en funding, interés abierto, liquidaciones y trades/large; futures, o spot para una stablecoin, en el spread entre mercados).
dataobject | array | nullLa carga útil: un objeto en una ruta «latest», una lista (la más reciente primero) en una ruta /history, null cuando no hay nada que servir — entonces unavailable dice por qué.
nextstring | nullEn las rutas paginadas: la URL relativa de la página siguiente, lista para llamar (null una vez leído el rango). Ver Paginar un historial.

Las sondas, la ruta POST y la forma de los datos

Las sondas usan el mismo sobre: /v1/health (data_type: health, todo bajo data) y /v1/status (data_type: status; su status vale ok como cualquier respuesta correcta, el estado de los flujos es data.state, ok o degraded). POST /v1/indicators usa el sobre como cualquier otra ruta; su data lleva un objeto indicators indexado por tus identificadores. Una ruta «latest» sirve siempre un objeto (o null) — /v1/klines es la última vela cerrada —, una ruta /history siempre una lista. Las únicas otras listas son colecciones, una fila por elemento: /v1/symbols, /v1/macro/series, /v1/macro/intraday/series, /v1/etf/fundamentals (una fila por emisor), /v1/options/max-pain, /v1/options/expiry, /v1/options/oi/distribution y las series de eventos (/v1/trades/spot, /v1/trades/futures, /v1/trades/large, /v1/trades-kline/futures/seconds, /v1/liquidations/events). La referencia interactiva da el esquema exacto de cada ruta.

#Reducir la respuesta

El parámetro ?fields= restringe data a los campos pedidos: una lista separada por comas, con notación de puntos para los campos anidados. En una serie de mil filas de la que solo usas dos columnas, la respuesta se reduce en la misma proporción.

curl
# The full response
curl -H "X-API-KEY: $BYTNODE_API_KEY" \
  "https://api.bytnode.com/v1/basis?symbol=BTCUSDT"

# Two fields only
curl -H "X-API-KEY: $BYTNODE_API_KEY" \
  "https://api.bytnode.com/v1/basis?symbol=BTCUSDT&fields=time,basis_pct"

# Dotted notation for a nested field
curl -H "X-API-KEY: $BYTNODE_API_KEY" \
  "https://api.bytnode.com/v1/btc/network?fields=difficulty,next_adjustment.estimated_retarget_at"

Un campo desconocido se rechaza, con la sugerencia del más cercano en lugar de un silencio:

422
{
  "status": "error",
  "server_time": "2026-09-30T16:07:27.808Z",
  "error": {
    "code": "unknown_field",
    "message": "Unknown field 'basis_percent'. Did you mean 'basis_pct'? Accepted fields: basis_pct, basis_value, futures_price, spot_price, time.",
    "param": "fields",
    "details": {
      "suggestion": "basis_pct",
      "accepted": [
        "basis_pct",
        "basis_value",
        "futures_price",
        "spot_price",
        "time"
      ]
    }
  }
}

#Leer un campo vacío

Un null o una lista vacía no prueba la ausencia del fenómeno: también puede significar que el fenómeno no existe para este activo. Confundir ambos lleva a afirmaciones falsas, como «ninguna liquidación» cuando el activo es una stablecoin, que no tiene mercado de futuros.

Todas las rutas eliminan la ambigüedad con la clave unavailable: cuando data está vacío (null o una lista vacía), la respuesta dice por qué — tanto en una ruta REST como en cada campo del snapshot. Comprueba unavailable, no si data está vacío:

MotivoTipoDescripción
not_applicablestructuralLa métrica no tiene sentido aquí: un campo derivado del mercado de futuros en una stablecoin spot. Ninguna recopilación lo cambiaría.
no_api_keyconfigurationLa fuente de origen no está conectada en esta instalación: el dato nunca se recopiló. Es una carencia de infraestructura, no un hecho de mercado.
no_datamarketUna ausencia real de datos en la ventana pedida. El único caso del que se puede sacar una conclusión.

El detalle de estas claves en el snapshot está en la página Snapshot. Para saber de antemano qué puede servir un activo, consulta su informe de capacidades.

#Los errores

Todo error tiene la misma forma: status: "error", server_time y un objeto error (code, estable y legible por máquina; message, en inglés; param cuando un parámetro es el culpable). Los rechazos ligados al plan llevan también la cabecera X-Deny-Reason, cuyo valor es el error.code (missing_api_key, invalid_api_key, plan_family, plan_websocket, rate_limited, quota_exceeded, history_depth); los rechazos temporales añaden error.details.retry_after_s en el cuerpo y Retry-After como cabecera, con el mismo valor: la espera hasta la próxima petición permitida en el límite de ritmo, los segundos hasta el reinicio en la cuota mensual. Toda respuesta, errores incluidos, lleva una cabecera X-Request-Id: cítala cuando informes de un problema. error.details, presente cuando el error lleva datos estructurados, da lo mismo para el código: suggestion (el valor aceptado más cercano), accepted (los valores aceptados), la ventana de tu plan en un history_depth.

{
  "status": "error",
  "server_time": "2026-09-30T16:07:27.808Z",
  "error": {
    "code": "rate_limited",
    "message": "Rate limit exceeded: your plan allows a limited number of requests per minute. Retry after the Retry-After delay.",
    "details": {
      "retry_after_s": 2
    }
  }
}
CódigoCausa más frecuenteQué hacer
401
Clave de API rechazada
La clave de API está ausente, es inválida o está revocada (error.code: invalid_api_key). La respuesta lleva WWW-Authenticate: ApiKey header="X-API-KEY".Comprueba que la cabecera X-API-KEY se envía de verdad: algunos clientes HTTP la pierden tras una redirección. Crea o copia una clave desde la consola.
403
Rechazada por el plan
La clave es válida pero el plan no cubre la petición; la cabecera X-Deny-Reason lleva el mismo código que error.code: plan_family (familia de datos de mercado fuera del plan), plan_websocket (flujo WebSocket fuera del plan) o history_depth (una profundidad de historial más allá de la ventana del plan).En plan_family y plan_websocket, el dato existe pero no está en tu plan. En history_depth, error.message indica el límite máximo que puedes usar.
404
Ruta desconocida
La ruta no existe (error.code: not_found). El mensaje propone la ruta más cercana cuando la hay.Revisa la ruta: el mensaje da la ruta más cercana cuando la hay; todas las rutas están en el contrato.
405
Método no permitido
La ruta existe, pero no con este método (error.code: method_not_allowed); la cabecera Allow lista los que acepta.Usa GET (POST solo para /v1/indicators); HEAD se acepta en toda ruta GET, y OPTIONS (el preflight CORS) en toda ruta.
422
Parámetro ausente, desconocido o no válido
Un símbolo, un activo o una serie desconocidos o desactivados, una profundidad por encima del límite del campo, un parámetro de indicador fuera de rango, symbol ausente, temporalidad fuera de la lista, campo multitemporalidad solicitado sin el sufijo @tf, campo desconocido en ?fields=, parámetro que la ruta no declara o parámetro repetido, since_ms o until_ms expresado en segundos o fuera de rango, cuerpo JSON no válido.Ante un campo o un parámetro desconocido, la respuesta sugiere el nombre más parecido. En una temporalidad, enumera los valores aceptados.
429
Velocidad o cuota superada
O más peticiones por minuto de las que permite tu plan, o una ráfaga demasiado densa (X-Deny-Reason: rate_limited, Retry-After: la espera hasta la próxima ficha); o la cuota mensual de la cuenta está agotada (X-Deny-Reason: quota_exceeded, Retry-After: los segundos hasta que se reinicie).En rate_limited, espera los segundos que indica Retry-After. En quota_exceeded, el contador se reinicia el primer día del mes (UTC); también puedes cambiar de plan desde la consola.
503
Indisponibilidad momentánea
Una dependencia de lectura se está recuperando. En el handshake WebSocket, el servicio de flujo ha alcanzado su capacidad, sumando todas las cuentas: no es el límite de conexiones de tu plan, que cierra con 4003.Reinténtalo tras el plazo que indica Retry-After o, si no está, con un plazo creciente. El error es transitorio por naturaleza.
500
Error inesperado
Un fallo del servicio, nunca causado por la petición.Reinténtalo; si la respuesta persiste, notifícala con la cabecera X-Request-Id de la respuesta.
504
Petición demasiado larga
La consulta tardó demasiado para la ventana o la profundidad pedida (error.code: upstream_timeout).Reduce limit o el intervalo de tiempo (since_ms / until_ms) y vuelve a intentarlo: repetir la misma petición tardaría lo mismo.

La página Códigos de error repasa cada caso con los mensajes exactos y los errores propios de los indicadores y del flujo en tiempo real.

#Cabeceras de respuesta

Toda respuesta hecha con una clave contabilizada (cualquier clave creada en la consola) lleva las cabeceras de límite de velocidad, en el formato estándar del IETF: la política de tu plan y lo que queda de ella, cuota mensual incluida. La consola muestra el mismo estado, y avisa al 80 % y después en la primera petición rechazada. Otras dos cabeceras solo aparecen en un rechazo.

CabeceraTipoDescripción
X-Deny-ReasonstringEl motivo de un rechazo ligado al plan: rate (límite de velocidad), quota (cuota mensual), family (familia fuera del plan), websocket (flujo fuera del plan), key (clave ausente, inválida o revocada) o depth (historial más allá de la ventana del plan).
Retry-AfterintegerPresente en un 429, y en un 503 cuando se conoce un plazo de reintento. El número de segundos que hay que esperar antes de reintentar: 1 si se supera el límite de frecuencia, si se agota la cuota mensual, los segundos hasta que se reinicie (el primer día del mes, UTC). Respételo en lugar de inventar un plazo; si no aparece, espacie los reintentos de forma progresiva.
RateLimit-PolicystringEn toda respuesta hecha con una clave contabilizada. Las políticas de tu plan, cuyos nombres son identificadores fijos: "rate" (el cubo de fichas de la velocidad por minuto: q su capacidad de ráfaga, w los segundos para rellenarlo desde vacío) y "quota" (la cuota mensual: q peticiones por mes, w la duración del mes natural en curso, en segundos). Ejemplo para el plan Traders en un mes de 31 días: "rate";q=20;w=20, "quota";q=200000;w=2678400.
RateLimitstringEn toda respuesta hecha con una clave contabilizada. Lo que queda de cada política: r las peticiones restantes (el r de "quota" es la cuota mensual restante) y t los segundos antes de su restauración completa (para "quota": hasta el día 1 del mes siguiente, 00:00 UTC). Ejemplo: "rate";r=19;t=1, "quota";r=187342;t=1641600. Los mismos valores en JSON: GET /v1/limits.
Cache-ControlstringEn toda respuesta de datos: private, max-age=1 como máximo — una respuesta suele tener hasta un segundo de antigüedad (una copia en caché puede llegar a veces a dos segundos). La frecuencia con la que cambia la FUENTE de una ruta (de 2 s para los trades individuales a 5 min para las series diarias de macro, on-chain y ETF) figura en la referencia interactiva: consultar más a menudo devuelve los mismos valores. La cabecera X-Cache-Status (HIT, MISS, EXPIRED, UPDATING) indica si la respuesta viene de la caché de un segundo de la pasarela: es informativa, nunca algo que comprobar en su código.