API REST para desarrolladores y agentes de IA
Una petición, una respuesta ya agregada. Todas las rutas comparten la misma forma, el mismo sobre y los mismos parámetros transversales: lo que vale para una familia vale para las demás.
Los agentes de IA llegan a las mismas rutas sin construir una URL: las herramientas del servidor MCP las llaman con tu clave y devuelven los mismos campos.
#La forma de una petición
GET https://api.bytnode.com/v1/<family>/<metric>
?symbol=BTCUSDT # required on per-asset routes
&timeframe=1h # on bucketed routes
&limit=100 # on /history routes
&fields=time,rate_pct
X-API-KEY: your_keyLa ruta indica la familia y la métrica. Los parámetros indican el activo, la temporalidad y la profundidad. La cabecera lleva la clave. No hace falta saber nada más para llamar a cualquier ruta.
Un solo endpoint escapa a esta forma: POST /v1/indicators, que recibe un cuerpo JSON porque describe un cálculo, no una lectura.
#Último valor o historial
La mayoría de las métricas existen en dos versiones. La ruta sin sufijo devuelve el último valor: un objeto o null. El sufijo /history devuelve una lista de ventanas cerradas únicamente, de la más reciente a la más antigua.
# The latest value
GET /v1/basis?symbol=BTCUSDT
# The last 24, from newest to oldest
GET /v1/basis/history?symbol=BTCUSDT&timeframe=1h&limit=24
# A dated window, in epoch milliseconds (here the last 12 hours, computed by the shell)
NOW=$(( $(date +%s) * 1000 ))
curl -H "X-API-KEY: $BYTNODE_API_KEY" \
"https://api.bytnode.com/v1/basis/history?symbol=BTCUSDT&timeframe=1h&since_ms=$(( NOW - 43200000 ))&until_ms=$NOW"#Parámetros comunes
| Parámetro | Tipo | Por defecto | Descripción |
|---|---|---|---|
symbol | string | obligatorio | El activo, en el formato del catálogo (BTCUSDT), en mayúsculas o minúsculas. Ausente: 422. Desconocido: 422 con la lista. Las rutas de todo el mercado no lo aceptan. |
timeframe | string | obligatorio | En las rutas por intervalos, obligatorio: 1m, 5m, 15m, 30m, 1h, 4h, 1d (y 1w en las velas). Ausente o fuera de la lista: 422. Una fila por minuto es timeframe=1m. |
limit | integer | — | Número de filas, de la más reciente a la más antigua, en las rutas /history y las series: 100 por defecto y 1000 como máximo en todas las rutas; 10 000 como máximo en los eventos individuales (ticks spot y futuros, operaciones grandes, liquidaciones). Más allá de una página, sigue next. |
since_ms / until_ms | integer | — | Ventana de tiempo en milisegundos Unix, donde la ruta lo acepta. El filtro se aplica antes que limit. |
live | boolean | false | En las rutas de último valor por intervalos: expone el periodo en curso, marcado is_closed: false. |
fields | string | — | Proyección CSV de data, notación con puntos para los campos anidados. Campo desconocido: 422 con una sugerencia. |
Lo que no existe
El parámetro exchange no existe en ninguna ruta: las respuestas están agregadas y no nombran su mercado, con la única excepción de los diferenciales entre mercados. Pasarlo devuelve 422, igual que cualquier parámetro que una ruta no declara o un parámetro repetido; el error sugiere el nombre más parecido.
#Paginar un historial
Cada ruta /history se pagina con next: cada respuesta lleva la URL de la página siguiente, o null una vez leído el rango. Las filas llegan de la más reciente a la más antigua por defecto; con order=asc (y since_ms), de la más antigua. Cada fila lleva time e is_closed.
- Pide una primera página:
limitfilas, sin límite para las más recientes, osince_msyorder=ascpara avanzar desde una fecha. - Llama a
nexttal cual: es la URL relativa de la página siguiente (/v1/klines/history?symbol=BTCUSDT&timeframe=1h&limit=500&before_ms=…), con tus parámetros incluidos — antepón el host de la API. Hacia atrás, usabefore_ms, un límite EXCLUSIVO: ninguna fila vuelve dos veces, nada que restar. - Detente cuando
nextseanull: el rango está leído, o la página siguiente saldría de la ventana de historial de tu plan (la última página solo pide entonces las filas que aún caben). Un403history_depthsolo aparece si tú mismo escribes un límite más allá de esa ventana;GET /v1/limitsda las ventanas de tu plan. En los trades individuales (/v1/trades/*), una página cubre como máximo 15 minutos y puede estar vacía o incompleta aunquenextno seanull: solonext: nulltermina el rango. Lo mismo vale en toda ruta paginada: una lectura de histórico que llega a un periodo denso devuelve, dentro de su presupuesto de tiempo, las filas ya leídas — una página corta con unnext, nunca un tiempo de espera agotado. Los SDK oficiales siguennextpor usted.
import os
import requests # pip install requests
def history(path: str, params: dict, max_pages: int = 20) -> list[dict]:
"""Every row of a /history route, following `next` until the range is read."""
rows: list[dict] = []
url, query = f"https://api.bytnode.com{path}", params
for _ in range(max_pages):
body = requests.get(
url,
params=query,
headers={"X-API-KEY": os.environ["BYTNODE_API_KEY"]},
timeout=30,
).json()
if body["status"] == "error":
# history_depth: the range asked goes further back than your plan's window;
# error.message gives the largest limit that fits. Never swallow it.
raise RuntimeError(f'{body["error"]["code"]}: {body["error"]["message"]}')
page = body["data"] or []
rows += page
if body.get("next") is None:
break # the range is read
# `next` is the relative URL of the following page, your parameters
# included: call it as is. It never repeats a row.
url, query = f"https://api.bytnode.com{body['next']}", None
return rows
# Without `limit`, each page stops at your plan's history window: no 403.
candles = history("/v1/klines/history", {"symbol": "BTCUSDT", "timeframe": "1h"})#Las familias
Todas las rutas caben en una página en el catálogo de endpoints; cada campo de cada ruta, con su unidad y una respuesta real, está en la referencia interactiva.