지금 이 순간 서로 다른 다섯 개 서비스에 EUR/USD 환율을 물어보면 미세하게 다른 다섯 개의 숫자가 돌아옵니다. 크게 다르지는 않습니다. 다만 소수점 넷째 자리, 때로는 셋째 자리가 다릅니다. 결제 페이지는 1.0847을 보여줬는데 은행 명세서에는 1.0821이 찍혀서 재무팀이 티켓을 올린 적이 있다면, 이것이 학문적인 질문이 아니라는 걸 이미 아실 겁니다.
그렇다면 환율 API는 데이터를 어디서 가져올까요? 정직한 답은 이렇습니다. 어떤 API도 환율을 "알지" 못합니다. 알아야 할 단일한 환율이라는 것이 존재하지 않기 때문입니다. 외환은 중앙 거래소도 폐장 종도 없는 장외 시장이며, 전 세계 수천 개 기관이 서로에게 가격을 호가할 뿐입니다. 여러분이 호출할 수 있는 모든 API는 그 시장을 샘플링하고, 정제하고, 하나의 숫자로 건네주는 파이프라인입니다. 이 글은 그 파이프라인을 층별로 짚고, 두 제공업체가 왜 정확히 달라지는지 설명하며, 결제 로직을 얹기 전에 데이터 소스를 검증하는 방법을 보여줍니다.
짧은 답: 시장과 여러분의 JSON 사이에는 세 개의 층이 있다
모든 환율 API는 무료든 유료든, 저희 것을 포함해 동일한 세 층으로 구성됩니다.
- 수집. 원시 가격이 상위 소스에서 당겨집니다. 기관용 FX 피드, 중앙은행 공표치, 브로커 또는 소매 호가입니다.
- 정규화. 이 원시 가격들이 검증되고, 이상치가 걸러지고, 여러 소스가 혼합되어 통화쌍마다 하나의 기준 환율이 도출됩니다.
- 전달. 도출된 환율이 일정 주기로 스냅샷되고, 캐시되며, 타임스탬프와 함께 HTTP로 제공됩니다.
이 세 층 중 어느 하나에서 차이가 생기면 응답 바디의 숫자가 달라집니다. 대부분의 개발자는 불일치가 1층에서 온다고 생각합니다. 실제로는 2층과 3층도 그만큼 원인이 됩니다.
1층 — 원시 가격은 실제로 어디서 오는가
인터뱅크 및 기관용 피드
"진짜" 환율에 가장 가까운 것은 인터뱅크 시장, 즉 대형 은행과 유동성 공급자가 서로 거래하는 가격입니다. 이 가격들은 거래 플랫폼, 프라임 브로커, 시장 데이터 벤더로부터 bid와 ask 호가의 연속 스트림으로 들어옵니다.
이런 피드는 가용한 것 중 가장 정확도가 높은 소스이며, 동시에 가장 비쌉니다. 무료 API가 이를 주 소스로 거의 쓰지 않는 핵심 이유가 여기 있습니다. 어떤 제공업체가 "실시간" 또는 "1분 미만" 환율을 내세운다면, 거의 언제나 파이프라인 최상단에 기관용 피드가 있기 때문입니다.
인터뱅크 피드는 하나가 아니라 두 개의 가격, 즉 bid와 ask를 준다는 점에 유의하세요. API 응답에서 보는 단일 환율은 보통 그 둘의 중간값입니다. 이 구분이 낯설다면 외환 거래의 bid-ask 스프레드 가이드에서 자세히 다룹니다.
중앙은행 기준환율
두 번째 큰 소스는 중앙은행의 공식 공표치입니다. 가장 잘 알려진 사례는 유럽중앙은행으로, 유럽 각국 중앙은행 간 협의 절차에 근거해 모든 TARGET 영업일 16:00 CET 무렵 유로 기준환율을 공표합니다. 수십 개의 다른 중앙은행도 자국 통화에 대해 동등한 일별 환율을 공표합니다.
중앙은행 환율에는 두 가지 큰 장점이 있습니다. 무료이고, 권위가 있다는 점입니다. 많은 과세 당국과 회계 기준이 보고 목적의 사용을 명시적으로 인정합니다. 무료 API 생태계의 상당 부분이 이 위에 세워진 이유입니다. 이 분야에서 널리 쓰이는 오픈소스 프로젝트 Frankfurter는 84개 중앙은행에서 201개 통화의 일별 환율을 추적하며, 이력은 1948년까지 거슬러 올라갑니다. 모두 공개 데이터를 재배포한 것입니다.
한편 심각한 한계도 두 가지 있습니다.
- 일별 스냅샷이지 실시간 가격이 아닙니다. 16:00 CET 기준환율은 09:00이나 22:00에 무슨 일이 있었는지 전혀 알려주지 않습니다.
- 주말과 공휴일에는 멈춥니다. API가 토요일 데이터를 반환하지 않거나 금요일 숫자를 반복한다면, ECB 기반 소스라는 것이 통상적인 설명입니다.
소매 및 브로커 호가
세 번째 소스는 최종 고객 대상 가격입니다. 은행, 카드 네트워크, 결제 대행사, 송금 서비스가 실제로 고객에게 주는 값입니다. 이 환율에는 이미 마크업, 즉 시장 환율 위에 얹힌 마진이 포함되어 있습니다.
소비자 비교 사이트에서 본 환율이 은행 명세서와 맞지 않는 이유가 이것입니다. 어느 쪽도 오류가 아니며, 서로 다른 것을 측정할 뿐입니다. 소비자 대상 사이트는 보통 중간시장 환율을 보여주고, 은행은 중간시장 환율에 자체 스프레드를 더해 호가합니다. 대부분의 소프트웨어 사용 사례에서는 중간시장 숫자를 받아, 자신의 마크업을 눈에 보이고 감사 가능한 형태로 명시적으로 적용하는 편이 맞습니다.
2층 — 제공업체는 피드를 어떻게 하나의 환율로 만드는가
원시 가격이 들어오면 제공업체는 어떤 숫자를 공표할지 정해야 합니다. 여기서 네 가지 결정이 이뤄지고, 그 하나하나가 제공업체들이 갈라지는 지점입니다.
블렌딩. 대부분의 상용 API는 단일 상위 소스에 의존하지 않습니다. 예컨대 Open Exchange Rates는 자사 데이터를 여러 제공업체에서 수집해 알고리즘으로 혼합한 것으로 설명합니다. 블렌딩은 단발성 이상 틱을 완만하게 만들지만, 혼합 가중치는 비공개입니다. 두 개의 블렌딩 피드가 결코 정확히 일치하지 않는 이유가 바로 이것입니다.
이상치 제거. 한 거래 플랫폼에서 온 잘못된 호가는 자릿수 단위로 어긋날 수 있습니다. 제공업체는 합의값 주변 허용 밴드를 벗어난 가격을 버리는 필터를 적용합니다. 공격적인 필터링은 환율을 안정시키지만 진짜 움직임에 대한 반응이 느려집니다. 느슨한 필터링은 반응이 빠르지만 가끔 노이즈가 섞입니다.
중간값 도출. 상위 피드가 bid/ask라면 제공업체는 중간값을 공표합니다. 단순 중점 (bid + ask) / 2가 표준이지만, 거래량 가중 방식은 약간 다른 결과를 냅니다.
크로스 환율 삼각계산. 3만 개가 넘는 가능한 통화쌍 전부를 직접 조달하는 제공업체는 없습니다. 대부분의 쌍은 기축 통화, 보통 USD나 EUR를 거쳐 계산됩니다.
GBP/JPY = (USD/JPY) / (USD/GBP)즉 이그조틱 쌍의 환율은 다른 두 쌍의 반올림과 타이밍을 물려받습니다. USD를 축으로 하는 제공업체와 EUR를 축으로 하는 제공업체는 같은 크로스에 대해 다른 숫자에 도달합니다. 원리는 크로스 환율 설명에서 다룹니다.
3층 — 환율이 여러분의 코드에 도달하는 과정
마지막 층은 개발자가 가장 많이 통제하면서 가장 적게 생각하는 층입니다.
갱신 주기는 제공업체 간, 그리고 요금제 간 가장 큰 단일 차별점입니다. 무료 플랜은 보통 하루 한두 번 갱신합니다. 유료 등급은 매시간, 10분마다, 또는 60초마다 갱신합니다. 동일한 데이터를 쓰는 두 API도 하나가 14:00에, 다른 하나가 14:47에 스냅샷을 찍었다는 이유만으로 어긋납니다.
캐싱은 이를 증폭합니다. 대부분의 API는 CDN 뒤에 있고, 잘 만든 클라이언트는 그 위에 로컬 캐시를 더합니다. 10분 갱신에 15분 엣지 캐시를 더하면 애플리케이션은 25분 지난 환율로 동작할 수 있습니다. 가격 표시에는 괜찮지만 거래 정산에는 용납되지 않습니다. 실무의 질문은 언제나 이 특정 작업에 대해 얼마나 오래되면 너무 오래된 것인가입니다. 통화 API의 캐싱과 오류 처리 가이드에서 그 윈도를 어떻게 잡을지 설명합니다.
타임스탬프가 여러분의 방어선입니다. 제대로 된 API는 환율이 포착된 시점을 반환합니다. 그 값을 읽으세요. 응답을 받은 순간이 곧 그 환율이 유효했던 순간이라고 가정하지 마세요.
const MAX_AGE_SECONDS = 900; // 15 minutes
async function getRate(base, symbol) {
const res = await fetch(
`https://api.finexly.com/v1/latest?base=${base}&symbols=${symbol}`,
{ headers: { Authorization: `Bearer ${process.env.FINEXLY_API_KEY}` } }
);
const data = await res.json();
const ageSeconds = Math.floor(Date.now() / 1000) - data.timestamp;
if (ageSeconds > MAX_AGE_SECONDS) {
throw new Error(`Rate is ${ageSeconds}s old — refusing to price on stale data`);
}
return { rate: data.rates[symbol], ageSeconds };
}기반이 되는 요청과 대표적인 응답 형태는 다음과 같습니다.
curl "https://api.finexly.com/v1/latest?base=USD&symbols=EUR,GBP,JPY" \
-H "Authorization: Bearer YOUR_API_KEY"{
"success": true,
"base": "USD",
"timestamp": 1755244800,
"rates": {
"EUR": 0.9241,
"GBP": 0.7863,
"JPY": 147.2150
}
}파라미터와 엔드포인트 상세는 Finexly API 문서에 있습니다.
두 API가 같은 통화쌍에 다른 숫자를 반환하는 이유
세 층을 합치면 불일치의 원인은 여섯 가지이며, 대략 피해가 큰 순서대로 정리하면 다음과 같습니다.
- 스냅샷 시각의 차이. 압도적으로 가장 흔한 원인입니다. 두 피드 모두 잘못되지 않았고, 그저 본 순간이 다릅니다.
- 소스 구성의 차이. 중앙은행 기반 환율과 인터뱅크 기반 환율은 정의상 서로 다른 것을 측정합니다.
- 중간시장 대 마크업 포함. 한쪽은 시장 중간값을, 다른 쪽은 스프레드가 이미 들어간 고객 가격을 줍니다.
- 크로스의 기축 통화 차이. USD 축과 EUR 축 삼각계산은 같은 비USD 쌍에 대해 다른 결과를 냅니다.
- 정밀도와 반올림. 소수 여섯 자리를 네 자리로 자르거나, 역방향 쌍으로 공표된 값을 다시 역수화하면 모두 드리프트가 생깁니다.
- 잊고 있던 캐싱 층. CDN, 프레임워크의 HTTP 캐시, 자체 Redis 층이 각각 데이터 나이를 더합니다.
유용한 경험칙 하나. 주요 통화쌍이라면 신뢰할 만한 두 중간시장 소스 간 몇 베이시스포인트(0.01% = 1bp) 차이는 정상이고 예상 범위입니다. 50bp 이상 벌어진다면 둘 중 하나가 오래됐거나, 마크업이 붙었거나, 고장 난 것입니다. 배포 전에 어느 쪽인지 밝혀야 합니다.
신뢰하기 전에 환율 API를 검증하는 방법
제공업체의 정확도 주장을 그대로 믿지 마세요. 재무팀이 권위 있다고 보는 소스를 기준으로 일주일간 이 점검을 돌려보세요.
import os
import requests
from datetime import datetime, timezone
FINEXLY_URL = "https://api.finexly.com/v1/latest"
HEADERS = {"Authorization": f"Bearer {os.environ['FINEXLY_API_KEY']}"}
def get_rate(base: str, symbol: str) -> dict:
r = requests.get(
FINEXLY_URL,
headers=HEADERS,
params={"base": base, "symbols": symbol},
timeout=5,
)
r.raise_for_status()
data = r.json()
return {
"rate": data["rates"][symbol],
"captured_at": datetime.fromtimestamp(data["timestamp"], tz=timezone.utc),
}
def basis_points(a: float, b: float) -> float:
"""Difference between two rates, in basis points."""
return abs(a - b) / ((a + b) / 2) * 10_000
primary = get_rate("EUR", "USD")
reference = 1.0839 # whatever your accounting source published
diff = basis_points(primary["rate"], reference)
print(f"Finexly: {primary['rate']} captured {primary['captured_at']:%H:%M UTC}")
print(f"Reference: {reference}")
print(f"Delta: {diff:.1f} bp -> {'OK' if diff < 25 else 'INVESTIGATE'}")결과에서 살펴볼 세 가지입니다.
- 차이가 안정적인가, 드리프트하는가? 일정한 오프셋은 체계적 마크업을, 무작위한 차이는 타이밍 문제를 시사합니다.
- 특정 시간대에 차이가 튀는가? 그렇다면 스냅샷 시각, 보통 중앙은행 공표 구간 주변을 가리킵니다.
- 주말에는 어떻게 되는가? 소스가 금요일 오후에 멈췄다가 월요일에 재개된다면 중앙은행 기반입니다. 월요일 대사 작업을 그에 맞춰 계획하세요.
삼각계산도 점검할 수 있습니다. 크로스를 직접 조회한 뒤 USD를 거쳐 계산해 보면, 둘은 1~2베이시스포인트 이내로 일치해야 합니다.
사용 사례에 맞는 데이터 소스 선택
보편적으로 "가장 좋은" 소스는 없습니다. 지금 만드는 것에 맞는 소스가 있을 뿐입니다.
| 사용 사례 | 필요한 것 | 허용 가능한 지연 |
|---|---|---|
| 구매자에게 가격 표시 | 중간시장 환율에 자체 마크업 적용 | 시간 단위 |
| SaaS 구독 결제 | 중간시장, 청구 실행마다 스냅샷 1건, 인보이스와 함께 저장 | 시간 단위, 단 기록 필수 |
| 회계 및 세무 보고 | 해당 일자의 중앙은행 기준환율 | 정의상 일별 |
| 분석 및 대시보드 | 단일 소스에서 온 일관된 과거 시계열 | 일별 |
| 지급 및 송금 | 명시적 허용 밴드를 갖춘 최신 중간시장 환율 | 분 단위 |
| 트레이딩 및 헤징 | 기관용 피드의 실제 bid/ask | 초 단위 |
아직 옵션을 검토 중이라면, 무료 대 유료 통화 API 비교에서 등급을 올릴 때 무엇이 달라지는지 정리했고, 요금제 페이지에서 갱신 주기와 요청 한도의 위치를 확인할 수 있습니다. 특정 통화쌍을 빠르게 수동 점검하려면 통화 변환기가 API와 동일한 기반 피드를 사용합니다.
자주 묻는 질문
무료 통화 API는 데이터를 어디서 가져오나요?
거의 언제나 중앙은행 공표치, 가장 흔하게는 유럽중앙은행의 일별 유로 기준환율이며, 때때로 소수의 다른 공개 소스와 혼합됩니다. 무료 등급이 보통 하루 한 번 갱신하고, 주말을 건너뛰며, 유료보다 이그조틱 통화를 적게 다루는 이유입니다.
제 API의 환율이 Google과 다른 이유는 무엇인가요?
Google은 중간시장 기준환율을 표시하는데, 이는 연속적인 실시간 가격이 아니라 스냅샷이며 여러분의 API 호출과 같은 순간에 샘플링된다는 보장이 없습니다. 작은 차이는 정상입니다. 큰 차이는 대개 둘 중 하나가 중간시장 환율이 아니라 마크업이 붙은 소매 환율이라는 뜻입니다.
회계와 세무 보고에는 어떤 환율을 써야 하나요?
거래일에 대해 해당 중앙은행이 공표한 공식 기준환율을 쓰세요. 대부분의 과세 당국이 기대하는 값입니다. 실시간 환율을 재활용하지 말고 날짜를 명시한 과거 데이터 엔드포인트에서 가져와 거래 기록과 함께 저장하세요.
실시간 환율 API는 정말 실시간인가요?
문자 그대로의 의미로는 드뭅니다. "실시간"은 보통 제공업체가 짧은 주기로 갱신한다는 뜻이며, 최상위 등급에서 60초가 흔합니다. 틱 단위로 스트리밍한다는 뜻이 아닙니다. 마케팅 문구가 아니라 응답의 타임스탬프와 문서화된 갱신 주기를 확인하세요.
API 대신 환율을 스크래핑해도 되나요?
가능하지만, 스크래핑하는 페이지의 모든 실패 양상을 떠안게 됩니다. 레이아웃 변경, 레이트 리밋, 타임스탬프 부재, 과거 데이터 백필 불가, 그리고 흔히 이용약관 위반입니다. 전체 절충점은 통화 API 대 웹 스크래핑에서 다뤘습니다.
검증할 수 있는 피드 위에 구축하세요
환율 데이터의 출처를 아는 것은 한 문장으로 설명 가능한 통화 버그와, 엔지니어링 일주일을 삼키는 버그를 가르는 차이입니다. 통합 전에 어떤 제공업체에든 세 가지를 물으세요. 소스는 무엇인지, 얼마나 자주 갱신하는지, 모든 응답에 포착 타임스탬프가 담기는지.
정말로 검증 가능한 환율을 연동할 준비가 되셨나요? 무료 Finexly API 키 받기 — 신용카드가 필요 없습니다. 170개 이상 통화에 대해 월 1,000회 무료 요청으로 시작하고, 첫날부터 타임스탬프가 찍힌 응답과 과거 데이터를 사용하세요.
Explore More
Vlado Grigirov
Senior Currency Markets Analyst & Financial Strategist
Vlado Grigirov is a senior currency markets analyst and financial strategist with over 14 years of experience in foreign exchange markets, cross-border finance, and currency risk management. He has wo...
View full profile →