Referencia de la API
Obtén las variables de variable Jar desde cualquier lugar (apps de iOS/Android, pipelines de CI) mediante REST. Es de solo lectura y usa el mismo token que el servidor MCP.
Beta: la API y MCP pueden cambiar antes del lanzamiento; los formatos ya llevan versión (consulta Salida de código de plataforma), y los cambios incompatibles se anuncian con 12 meses de convivencia.
Emitir un token
- variablejar.com/app → menú ⋯ → Propiedades de una tarjeta de proyecto → la sección Tokens de API (MCP)
- Escribe un nombre de token y pulsa Emitir: el token (
vjt_…) se muestra solo una vez, justo después de emitirlo. Guárdalo en un lugar seguro. - Un token da acceso solo a ese proyecto. Si se filtra, revócalo de inmediato en la misma pantalla.
Los tokens caducan (180 días por defecto, hasta 365). Recibirás una notificación en la campana 14 días antes. Solo el propietario del espacio de trabajo puede emitir un token que incluya valores de texto (STRING): salen todos los idiomas, incluidas las traducciones no publicadas. También puedes limitar un token a las colecciones que elijas.
Un token es tan seguro como el lugar donde lo guardes: quien lo tenga recibe todos los valores dentro de su alcance. Los datos que exportas mediante la API o MCP salen del servicio y se procesan bajo tu responsabilidad.
Endpoint
GET https://variablejar.com/api/v1/variables
Authorization: Bearer vjt_...
curl -H "Authorization: Bearer vjt_..." \
"https://variablejar.com/api/v1/variables"
Los valores de texto (STRING) solo se incluyen si el token se emitió con valores de texto y añades ?include=strings.
Respuesta
Los valores son finales, con los alias ({Collection/key}) resueltos. Solo las celdas que no se pudieron resolver aparecen en unresolved con un motivo (broken · cycle · inline), conservando su valor original.
{
"apiVersion": "v1",
"project": { "name": "My Variables" },
"collections": [
{ "name": "Color", "modes": ["light", "dark"] },
{ "name": "Text", "modes": ["en", "ko"] }
],
"tokens": [
{
"key": "color/primary",
"collection": "Color",
"type": "COLOR",
"valuesByMode": { "light": "#3B82F6", "dark": "#60A5FA" }
},
{ "key": "hello", "collection": "Text", "type": "STRING", "valuesByMode": {}, "omitted": "strings" }
]
}
Sin include=strings, los tokens STRING siguen apareciendo, pero con valuesByMode vacío y "omitted": "strings".
Salida de código de plataforma
Añade ?format= para recibir código de plataforma generado en lugar de JSON:
| format | Resultado | Content-Type |
|---|---|---|
css@1 (alias css) | Propiedades personalizadas de CSS: el modo predeterminado en :root, los demás en [data-theme="<mode>"] | text/css |
swift@1 (alias swift) | SwiftUI: un tipo por colección, una instancia estática por modo | text/plain |
compose@1 (alias compose) | Jetpack Compose (Kotlin): la misma estructura que Swift | text/plain |
Los formatos tienen versión. El nombre sin versión (css) es un alias permanente de @1: nunca pasa por sí solo a una versión más nueva. Dentro de una versión solo se permiten dos tipos de cambio: corregir una salida que no era sintaxis válida y corregir el escape por seguridad; ambos suben el rev del formato (listado por /formats, más abajo) e invalidan las cachés. Todo lo que cambie la representación de un valor o un identificador es una versión nueva (css@2), y la versión anterior sigue disponible durante 12 meses (se anuncia con las cabeceras Deprecation y Sunset).
curl -H "Authorization: Bearer vjt_..." \
"https://variablejar.com/api/v1/variables?format=css" \
> variables.css
La salida es determinista: los mismos tokens producen siempre los mismos bytes, así que la caché con ETag/If-None-Match funciona igual que con la respuesta JSON. Los alias siempre se resuelven a valores finales; las referencias sin resolver se emiten como comentarios, nunca como valores inventados. Un format desconocido devuelve 400 { "error": "unknown_format" }.
Los identificadores se derivan de los nombres de colección y de variable y no dependen del orden de tus datos: reordenar colecciones, variables o modos en Figma nunca renombra un token. Cuando dos nombres se reducen al mismo identificador, el que va primero al ordenar por su nombre original conserva el identificador simple y los demás reciben _2, _3 …; añadir un nombre nuevo que colisione puede renumerar los sufijos existentes, así que evita nombres que solo se diferencien en separadores o en mayúsculas y minúsculas. La misma variable recibe el mismo identificador sea cual sea el filtro que uses (collection, include=strings o un token limitado a algunas colecciones): los nombres se fijan primero en todo el proyecto y la respuesta se filtra después.
?collection=<name> limita la salida a una colección (400 unknown_collection si el nombre no está en el proyecto). ?view=ai@1 devuelve una vista compacta y saneada para agentes de IA (solo nombres y valores, sin valores de texto por defecto); no se puede combinar con format, y cualquier otro valor de view salvo index (más abajo) devuelve 400 unknown_view.
?view=index junto con format devuelve, en lugar de código, el identificador que recibe cada variable en ese formato, para comprobar nombres sin analizar el código generado. Los identificadores se escriben igual que en la salida (las palabras clave de Swift/Kotlin conservan sus comillas invertidas). Las variables de texto (STRING) quedan fuera del índice salvo que el token se haya emitido con valores de texto y pases include=strings. view=index sin format devuelve 400 unknown_view.
curl -H "Authorization: Bearer vjt_..." \
"https://variablejar.com/api/v1/variables?format=css@1&view=index"
{
"format": "css@1",
"rev": "1-1",
"identifiers": [
{ "collection": "Color", "key": "btn/bg", "identifier": "--color-btn-bg" }
]
}
GET /api/v1/formats enumera los formatos y versiones que ofrece este servidor, con el rev actual, el nombre de archivo y el Content-Type de cada uno. Usa el mismo token, no cuenta para el uso ni para el límite de solicitudes y admite ETag/If-None-Match igual que el endpoint de variables (sin X-VJ-Stamp: la lista es estática). Una versión reemplazada incluye además "deprecated": { "since": "YYYY-MM-DD", "sunset": "YYYY-MM-DD" }; sunset solo aparece cuando hay una fecha programada.
{
"contract": "1",
"formats": [
{ "id": "css", "version": 1, "spec": "css@1", "rev": "1-1", "alias": "css", "filename": "variables.css", "mime": "text/css; charset=utf-8" },
{ "id": "swift", "version": 1, "spec": "swift@1", "rev": "1-1", "alias": "swift", "filename": "Tokens.swift", "mime": "text/plain; charset=utf-8" },
{ "id": "compose", "version": 1, "spec": "compose@1", "rev": "1-1", "alias": "compose", "filename": "Tokens.kt", "mime": "text/plain; charset=utf-8" }
],
"views": [{ "view": "ai@1", "rev": "1" }]
}
Sondeo y ETag
Las respuestas incluyen una cabecera ETag. Devuélvela como If-None-Match y obtendrás 304 (sin cuerpo) si nada ha cambiado, lo que ahorra ancho de banda en las comprobaciones periódicas desde apps móviles y CI. Usa el valor de ETag recibido tal cual (puede incluir W/).
curl -i -H "Authorization: Bearer vjt_..." \
-H 'If-None-Match: "…"' \
"https://variablejar.com/api/v1/variables"
# HTTP/2 304
Toda respuesta 200 o 304 lleva estas cabeceras:
| Cabecera | Significado |
|---|---|
ETag / If-None-Match | Devuelve el último ETag; si los datos no cambiaron, obtienes 304 sin cuerpo |
X-VJ-Stamp | Sello de actualización del contenido del proyecto + el alcance de este token (el mismo valor en todos los formatos del mismo token): mismo sello, mismos datos en todos los formatos |
X-VJ-TTL | Segundos que conviene esperar antes de volver a comprobar (30–600) |
X-VJ-Token-Expires | Cuándo caduca este token |
X-VJ-Contract | Versión del contrato de la API (1) |
X-VJ-Format | Formato y versión de una respuesta con ?format=, p. ej. css@1 |
Errores
Las respuestas de error tienen el cuerpo { "error": "<código>" }.
| Estado | Significado |
|---|---|
400 unknown_format · unknown_view · unknown_collection | Valor de format o view desconocido, o un nombre de collection que no está en el proyecto |
401 unauthorized | Token ausente, mal formado o revocado |
401 token_expired | El token caducó: emite uno nuevo |
403 token_inactive | Quien emitió el token dejó el espacio de trabajo o perdió el rol que el token necesita |
403 plan_required | El plan del espacio de trabajo no incluye acceso a la API |
403 scope_denied | include=strings requiere un token emitido con valores de texto |
404 not_found | Ruta incorrecta, o el proyecto se eliminó o se movió a la papelera |
405 method_not_allowed | Método distinto de GET u OPTIONS (OPTIONS responde a la verificación previa de CORS con 204) |
413 too_large | El proyecto supera el límite de tamaño de la API (25.000 variables o 24 MB de datos de variables): mueve algunas colecciones a otro proyecto o escribe a support@variablejar.com |
426 client_outdated | El cliente declarado (X-VJ-Client) es anterior a la versión mínima que acepta este servidor: actualiza @variablejar/mcp |
429 rate_limited | Demasiadas solicitudes: reintenta tras los segundos indicados en Retry-After |
500 internal | Error del servidor: si persiste tras reintentar, escribe a support@variablejar.com |
502 upstream_unreachable | La pasarela de la API no pudo llegar al backend: reintenta |
503 not_configured | El servicio no está configurado: escribe a support@variablejar.com |
Servidor MCP (IDE / agentes de IA)
Desde IDE y agentes de programación con IA, el servidor MCP @variablejar/mcp es más cómodo que REST, y el mismo token sirve para ambos. Puedes pasarle esta página a un agente de IA y pedirle que configure la integración por ti.
Añádelo a tu configuración de MCP (fija la versión):
{
"mcpServers": {
"variablejar": {
"command": "npx",
"args": ["-y", "@variablejar/mcp@0.3.1"],
"env": { "VARIABLEJAR_TOKEN": "vjt_your_token_here" }
}
}
}
La ubicación del archivo depende del cliente:
| Cliente | Archivo de configuración |
|---|---|
| Claude Code | .mcp.json en la raíz del proyecto |
| Cursor | .cursor/mcp.json |
| Otros clientes MCP | Consulta la configuración de servidores MCP del cliente |
Herramientas disponibles:
| Herramienta | Entrada | Descripción |
|---|---|---|
list_collections | — | Colecciones con sus modos, número de tokens, distribución por tipo y grupos de primer nivel: empieza por aquí |
list_tokens | collection? prefix? type? query? format? limit (50, máx. 200) cursor? include_strings? | Tokens paginados, con los valores resueltos por modo. La primera línea del bloque de datos es siempre total=<n> returned=<m> nextCursor=<c|none>. Con format (p. ej., css@1), cada token incluye además su identificador en ese formato |
get_token | key collection? format? | Un token por clave (p. ej., color/primary); si la clave existe en varias colecciones, recibes los candidatos |
list_formats | — | Formatos y versiones que el servidor puede generar, igual que GET /formats |
get_tokens | format collection? | El proyecto (o una colección) como código generado. Los resultados de más de 24.000 caracteres no se truncan: la herramienta le indica al agente cómo acotar por colección. Para archivos completos en CI, usa REST y haz commit del archivo |
El servidor guarda los resultados solo en memoria, vuelve a consultar la API una vez por TTL (30–600 s) y lo reutiliza todo mientras el sello de actualización del proyecto no cambie. Los resultados de las herramientas llevan los códigos de error de la API (error: unauthorized, error: plan_required, …); cuando no se puede llegar a la API, se sirve el último resultado con una nota sobre su antigüedad. Los datos de tokens van envueltos en marcadores de límite aleatorios, con un preámbulo fijo que indica que son datos, no instrucciones.
Variables de entorno:
| Variable | Obligatoria | Descripción |
|---|---|---|
VARIABLEJAR_TOKEN | ✓ | Token de API del proyecto (vjt_…): un token, un proyecto |
VARIABLEJAR_API_URL | https://variablejar.com/api/v1 (por defecto) o https://staging.variablejar.com/api/v1; cualquier otro host se rechaza |
Actualizar desde 0.2.0: esa versión llama a un endpoint retirado y ahora recibe 410. Los nombres de las herramientas no cambian y las entradas solo se ampliaron, pero las salidas cambiaron: list_tokens está paginado, con una primera línea total=… y claves cortas (c, k, t, v); get_token devuelve las mismas claves cortas y, si la clave existe en varias colecciones, lista los candidatos; list_collections ya no devuelve ids, y get_tokens devuelve un bloque de preámbulo más un bloque de código dentro de marcadores de límite.
El servidor es de solo lectura: el token no puede escribir ni eliminar nada.
Notas
- No lo llames directamente desde un navegador (frontend web): el token quedaría expuesto en el código del cliente. Úsalo desde servidores, apps o CI, donde el token queda oculto.
- Todavía no hay API de escritura ni consultas delta (solo cambios).
- Para contexto de LLM, toda la documentación está disponible como /llms.txt (índice) y /llms-full.txt (todo en un archivo), en inglés.