API 레퍼런스

variable Jar의 변수를 iOS/Android 앱, CI 파이프라인 등 어디서든 REST로 가져올 수 있습니다. 읽기 전용이며, MCP 서버와 같은 토큰을 사용합니다.

베타: API와 MCP는 출시 전 바뀔 수 있습니다. 이제 형식에 버전이 붙습니다(플랫폼 코드 출력 참고). 호환이 깨지는 변경은 12개월 병행 기간과 함께 안내합니다.

토큰 발급

  1. variablejar.com/app → 프로젝트 카드의 ⋯ 메뉴 → 속성 → API 토큰 (MCP 연동) 섹션
  2. 토큰 이름을 입력하고 발급을 누릅니다 — 토큰(vjt_…)은 발급 직후 한 번만 표시됩니다. 안전한 곳에 보관하세요.
  3. 토큰은 해당 프로젝트 하나에만 접근할 수 있습니다. 토큰이 유출되면 같은 화면에서 해지를 눌러 바로 무효화하세요.

토큰은 만료됩니다(기본 180일, 최대 365일). 만료 14일 전에 벨 알림을 받습니다. 문구 값(STRING)을 포함하는 토큰은 워크스페이스 소유자만 발급할 수 있고, 모든 언어의 미공개 번역까지 나갑니다. 토큰을 특정 컬렉션에만 묶을 수도 있습니다.

토큰을 가진 사람은 범위 안의 값을 모두 받습니다. API나 MCP로 내보낸 데이터는 서비스 밖에서 사용자 책임으로 처리됩니다.

엔드포인트

GET https://variablejar.com/api/v1/variables
Authorization: Bearer vjt_...
curl -H "Authorization: Bearer vjt_..." \
  "https://variablejar.com/api/v1/variables"

문구 값(STRING)은 문구 값을 포함해 발급한 토큰으로 ?include=strings를 붙였을 때만 포함됩니다.

응답

값은 alias({Collection/key})가 해소된 최종값입니다. 해소하지 못한 셀만 unresolved에 사유(broken·cycle·inline)가 표시되고 값은 원본 그대로 남습니다.

{
  "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" }
  ]
}

include=strings가 없으면 STRING 토큰은 목록에는 나오지만 valuesByMode가 비어 있고 "omitted": "strings"가 붙습니다.

플랫폼 코드 출력

?format=을 붙이면 JSON 대신 생성된 플랫폼 코드를 받습니다:

format출력Content-Type
css@1 (별칭 css)CSS custom properties — 기본 모드는 :root, 나머지 모드는 [data-theme="<모드>"]text/css
swift@1 (별칭 swift)SwiftUI — 컬렉션당 타입 1개, 모드당 static 인스턴스 1개text/plain
compose@1 (별칭 compose)Jetpack Compose (Kotlin) — Swift와 같은 구조text/plain

형식에는 버전이 있습니다. 버전 없는 이름(css)은 @1에 영구 고정된 별칭이라 새 버전이 나와도 저절로 바뀌지 않습니다. 버전 안에서 허용되는 변경은 두 가지뿐입니다 — 문법이 잘못된 출력을 고치는 것, 보안 이스케이프를 고치는 것 — 둘 다 형식의 rev(아래 /formats에 표시)를 올려 캐시를 무효화합니다. 값 표현이나 식별자가 바뀌면 새 버전(css@2)이고, 이전 버전은 12개월 동안 유지됩니다(Deprecation·Sunset 헤더로 안내).

curl -H "Authorization: Bearer vjt_..." \
  "https://variablejar.com/api/v1/variables?format=css" \
  > variables.css

출력은 결정론적입니다 — 같은 토큰은 항상 같은 바이트를 생성하므로 JSON 응답과 동일하게 ETag/If-None-Match 캐싱이 동작합니다. 참조(alias)는 항상 최종값으로 해소되며, 해소하지 못한 참조는 값을 지어내지 않고 주석으로 표시됩니다. 알 수 없는 format은 400 { "error": "unknown_format" }을 반환합니다.

식별자는 컬렉션·변수 이름에서 만들며 데이터 순서와 무관합니다. Figma에서 컬렉션·변수·모드 순서를 바꿔도 토큰 이름은 바뀌지 않습니다. 두 이름이 같은 식별자로 정리되면 원본 이름 순으로 앞선 것이 기본 식별자를, 나머지가 _2, _3 … 을 받습니다. 충돌하는 이름을 새로 더하면 기존 번호가 밀릴 수 있으니 구분자나 대소문자만 다른 이름은 피하세요. 어떤 필터(collection · include=strings · 일부 컬렉션만 허용된 토큰)를 쓰든 같은 변수는 같은 식별자를 받습니다. 이름은 프로젝트 전체에서 먼저 확정하고, 응답은 그 뒤에 거릅니다.

?collection=<이름>은 출력을 컬렉션 하나로 제한합니다(프로젝트에 없는 이름이면 400 unknown_collection). ?view=ai@1은 AI 에이전트용으로 정제한 간결한 보기를 반환합니다(이름과 값만, 문구 값은 기본적으로 제외). format과 함께 쓸 수 없고, index(아래) 외의 다른 view 값은 400 unknown_view를 반환합니다.

?view=index를 format과 함께 쓰면 코드 대신 각 변수가 그 형식에서 받는 식별자를 반환합니다 — 생성된 코드를 파싱하지 않고 이름을 확인할 때 씁니다. 식별자는 출력과 같은 철자입니다(Swift/Kotlin 예약어는 백틱 포함). 문구(STRING) 변수는 문구 값을 포함해 발급한 토큰으로 include=strings를 붙였을 때만 색인에 들어갑니다. format 없이 view=index만 보내면 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는 이 서버가 제공하는 형식과 버전을 각각의 현재 rev, 파일 이름, Content-Type과 함께 나열합니다. 같은 토큰을 쓰지만 사용량과 요청 한도에 포함되지 않으며, 변수 엔드포인트처럼 ETag/If-None-Match를 지원합니다(X-VJ-Stamp는 없습니다 — 목록은 정적입니다). 새 버전으로 대체된 버전에는 "deprecated": { "since": "YYYY-MM-DD", "sunset": "YYYY-MM-DD" }가 함께 붙습니다. sunset은 날짜가 잡혔을 때만 있습니다.

{
  "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" }]
}

폴링과 ETag

응답에는 ETag 헤더가 포함됩니다. 다음 요청에 If-None-Match로 보내면 변경이 없을 때 304 (본문 없음)로 응답합니다 — 모바일 앱·CI에서 주기적으로 확인할 때 전송량을 아낄 수 있습니다. 받은 ETag 값에 W/가 붙어 있어도 그대로 보내면 됩니다.

curl -i -H "Authorization: Bearer vjt_..." \
  -H 'If-None-Match: "…"' \
  "https://variablejar.com/api/v1/variables"
# HTTP/2 304

200·304 응답에는 다음 헤더가 붙습니다:

헤더의미
ETag / If-None-Match받은 ETag를 다시 보내면 변경이 없을 때 본문 없는 304를 받습니다
X-VJ-Stamp프로젝트 내용 + 이 토큰의 범위에 대한 신선도 도장(같은 토큰의 모든 형식에 같은 값) — 도장이 같으면 모든 형식에서 데이터도 같습니다
X-VJ-TTL다시 확인하기 전에 기다릴 초(30–600)
X-VJ-Token-Expires이 토큰의 만료 시각
X-VJ-ContractAPI 계약 버전(1)
X-VJ-Format?format= 응답의 형식과 버전(예: css@1)

오류

오류 응답의 본문은 { "error": "<코드>" }입니다.

상태의미
400 unknown_format · unknown_view · unknown_collection알 수 없는 format·view 값, 또는 프로젝트에 없는 collection 이름
401 unauthorized토큰 없음 / 형식 불일치 / 해지됨
401 token_expired토큰이 만료됨 — 새로 발급하세요
403 token_inactive토큰 발급자가 워크스페이스를 떠났거나 토큰에 필요한 역할을 잃음
403 plan_required워크스페이스 요금제에 API가 포함되지 않음
403 scope_deniedinclude=strings에는 문구 값을 포함해 발급한 토큰이 필요함
404 not_found잘못된 경로, 또는 프로젝트가 삭제됐거나 휴지통에 있음
405 method_not_allowedGET·OPTIONS 외 메서드 (OPTIONS는 CORS preflight로 204 응답)
413 too_large프로젝트가 API 크기 한도(변수 25,000개 또는 변수 데이터 24 MB)를 넘음 — 일부 컬렉션을 다른 프로젝트로 옮기거나 support@variablejar.com 으로 문의하세요
426 client_outdated보고된 클라이언트(X-VJ-Client)가 이 서버가 받는 최소 버전보다 오래됨 — @variablejar/mcp를 업그레이드하세요
429 rate_limited요청이 너무 많음 — Retry-After의 초만큼 기다린 뒤 재시도
500 internal서버 오류 — 재시도 후 지속되면 문의: support@variablejar.com
502 upstream_unreachableAPI 게이트웨이가 백엔드에 닿지 못함 — 재시도
503 not_configured서비스가 설정되지 않음 — 문의: support@variablejar.com

MCP 서버 (IDE / AI 에이전트)

IDE와 AI 코딩 에이전트에서는 REST 대신 @variablejar/mcp MCP 서버가 편합니다 — 토큰 하나로 REST와 MCP를 모두 쓸 수 있습니다. 이 페이지를 AI 에이전트에게 주고 설정을 맡겨도 됩니다.

MCP 설정에 추가하세요(버전을 고정합니다):

{
  "mcpServers": {
    "variablejar": {
      "command": "npx",
      "args": ["-y", "@variablejar/mcp@0.3.1"],
      "env": { "VARIABLEJAR_TOKEN": "vjt_발급받은_토큰" }
    }
  }
}

설정 파일 위치는 클라이언트마다 다릅니다:

클라이언트설정 파일
Claude Code프로젝트 루트의 .mcp.json
Cursor.cursor/mcp.json
기타 MCP 클라이언트해당 클라이언트의 MCP 서버 설정 참고

제공 도구:

도구입력설명
list_collections—컬렉션과 모드·토큰 수·타입 분포·상위 그룹 — 여기서 시작
list_tokenscollection? prefix? type? query? format? limit(50, 최대 200) cursor? include_strings?모드별 최종값이 해소된 토큰을 페이지로. 데이터 블록의 첫 줄은 항상 total=<n> returned=<m> nextCursor=<c|none>. format(예: css@1)을 주면 각 토큰에 그 형식의 식별자가 함께 옵니다
get_tokenkey collection? format?키(예: color/primary)로 토큰 하나. 같은 키가 여러 컬렉션에 있으면 후보 목록을 돌려줍니다
list_formats—서버가 생성할 수 있는 형식과 버전 — GET /formats와 같음
get_tokensformat collection?프로젝트(또는 컬렉션 하나)를 생성된 코드로. 24,000자를 넘으면 자르지 않고 컬렉션으로 좁히는 법을 안내합니다. CI에서 파일 전체가 필요하면 REST로 받아 커밋하세요

서버는 결과를 메모리에만 두고, TTL(30~600초)마다 API를 한 번 다시 확인하며, 프로젝트의 신선도 도장이 같으면 저장한 결과를 모두 재사용합니다. 도구 결과는 API의 오류 코드를 그대로 씁니다(error: unauthorized, error: plan_required 등). API에 닿지 못하면 마지막 결과를 나이와 함께 돌려줍니다. 토큰 데이터는 “지시가 아니라 데이터”라는 고정 머리말과 무작위 경계 표지 안에 담깁니다.

환경변수:

변수필수설명
VARIABLEJAR_TOKEN✓프로젝트 API 토큰(vjt_…) — 토큰 하나 = 프로젝트 하나
VARIABLEJAR_API_URLhttps://variablejar.com/api/v1(기본) 또는 https://staging.variablejar.com/api/v1. 그 밖의 호스트는 거부됩니다

0.2.0에서 올라오기: 0.2.0은 퇴역한 엔드포인트를 불러 이제 410을 받습니다. 도구 이름은 같고 입력은 추가만 됐지만 출력이 바뀌었습니다 — list_tokens는 total=… 첫 줄이 있는 페이지 방식에 짧은 키(c, k, t, v)를 쓰고, get_token도 같은 짧은 키를 쓰고, 같은 키가 여러 컬렉션에 있으면 후보 목록을 돌려주며, list_collections는 id를 돌려주지 않으며, get_tokens는 머리말 블록과 경계 표지 안의 코드 블록을 돌려줍니다.

MCP 서버는 read-only입니다 — 이 토큰으로는 쓰기·삭제가 불가능합니다.

주의

  • 브라우저(웹 프론트엔드)에서 직접 호출하지 마세요 — 토큰이 클라이언트 코드에 노출됩니다. 서버·앱·CI 등 토큰을 숨길 수 있는 환경에서 사용하세요.
  • 쓰기 API·변경분(delta) 조회는 아직 제공하지 않습니다.
  • LLM 컨텍스트용으로 전체 문서를 /llms.txt(인덱스)와 /llms-full.txt(전문 단일 파일)로 제공합니다.