블로그로 돌아가기

세무 신고를 위한 환율: IRS·HMRC·EU 부가가치세 환산에 대한 개발자 가이드

V
Vlado Grigirov
August 20, 2026
Currency API Exchange Rates Historical Rates Tax Reporting VAT Accounting Finexly

모든 다중 통화 시스템은 언젠가 회계사를 만나게 됩니다. 그리고 사소해 보이지만 결코 사소하지 않은 질문을 받습니다. "이 인보이스에는 어떤 환율을 쓰셨나요?" 정직한 답이 "그날 오후에 API가 돌려준 값이고, 따로 보관하지는 않았습니다"라면, 아무리 코드를 깔끔하게 짜도 신고 시점에는 해결되지 않는 문제를 안고 있는 것입니다.

세무 신고를 위한 환율을 제대로 다루는 일의 핵심은 올바른 환율을 고르는 데 있지 않습니다. 대부분의 당국은 그 점에 대해 의외로 관대합니다. 진짜 핵심은 몇 년이 지난 뒤에도 어떤 환율을 사용했고, 그것이 어디서 왔으며, 같은 기간의 다른 모든 거래에도 동일한 규칙을 적용했음을 증명할 수 있느냐입니다. 이것은 데이터 모델링 문제이고, 아무도 다루지 않는 부분이기도 합니다.

이 가이드에서는 IRS, HMRC, EU 부가가치세 지침이 실제로 요구하는 것, 재작성으로 이어지는 다섯 가지 환산 버그, 그리고 이번 주에 바로 구현할 수 있는 환율 스냅샷 스키마를 다룹니다.

"그" 환율에 대해 아무도 합의하지 않았다 — 그리고 그게 핵심이다

이 영역 전체에서 가장 쓸모 있는 한 문장은 IRS 자신에게서 나옵니다.

"미국 국세청에는 공식 환율이 없습니다. 일반적으로, 일관되게 사용되는 공표 환율이라면 어떤 것이든 인정합니다."

두 번 읽어 보십시오. 거의 모든 관할권에서 같은 형태가 반복되기 때문입니다. 의무는 좀처럼 이 특정 숫자를 쓰라가 아닙니다. 방어 가능한 출처를 쓰고, 그것을 일관되게 쓰라는 것입니다. 일관성은 환율 공급자의 속성이 아니라 여러분 시스템의 속성입니다. 주말이면 코드가 조용히 다른 출처로 폴백한다면, 잘못된 숫자를 한 번도 가져오지 않았더라도 이미 요건을 위반한 것입니다.

미국: 기본은 현물환율, 양보로서의 연평균 환율

IRS의 기준선은 현물환율입니다. "일반적으로, 해당 항목을 수취·지급 또는 발생시킨 시점에 통용되는 환율(즉, 현물환율)을 사용하십시오." 급여, 임대료, 지속적인 사업 수익처럼 소득이 고르게 발생하는 경우, IRS는 연평균 통화 환율표를 공표하고 신고자에게 "외화 금액을 해당 연평균 환율로 나누라"고 안내합니다. 해당 페이지가 마지막으로 갱신된 2026년 2월 24일 기준으로, 이 표는 2021년부터 2025년까지의 과세연도를 다룹니다.

이 연산의 방향에 주의하십시오. IRS 표는 미화 1달러당 외화 단위 수로 표시되므로 나눗셈을 해야 합니다. 실수로 뒤집으면 조금 틀리는 정도가 아니라 환율의 제곱만큼 틀립니다. 엔화 금액이라면 대략 네 자릿수 차이입니다. 환율 방향에 대해서는 아래에서 더 다룹니다. 이 분야에서 가장 흔한 단일 통합 버그이기 때문입니다.

미국 연방기관 보고에는 두 번째 공식 시계열이 있습니다. Treasury Reporting Rates of Exchange로, FiscalData.Treasury.gov에서 분기별로 CSV, JSON, XML 형식으로 공표됩니다. 재무부는 이를 "공표 보고서 일자 직전 월의 마지막 영업일에 각 공관의 지출관이 보고한, 미국 정부가 공적 지출을 위해 외화를 취득할 수 있는 환율을 반영한 것"이라고 설명합니다. 실시간 환율이 공표 환율에서 10% 이상 벌어지면 재무부는 분기 중간에 수정본을 발행합니다. Fiscal Data API는 공개되어 있으며 계정이나 토큰이 필요 없습니다. 대조에 쓸 정부 출처의 참조 시계열이 필요하다면 알아 둘 만합니다.

영국: VAT Notice 700 §7.6은 법적 효력을 가진다

영국은 더 규범적이며, 해당 조문은 1994년 부가가치세법 부칙 6 제11항에 따라 법적 효력을 갖습니다. VAT Notice 700은 외화 공급을 파운드로 환산하는 세 가지 경로를 사업자에게 제시합니다.

  1. 공급 시점의 영국 시장 매도 환율. 이것이 기본값입니다. 해당 고시는 "전국 일간지에 게재된 환율은 해당 시점의 환율에 대한 증거로 인정됩니다"라고 명시합니다.
  2. HMRC 기간 환율로, 관세 목적으로 공표됩니다. "귀사의 모든 공급에 대해, 또는 특정 종류나 명세의 모든 공급에 대해" 채택할 수 있습니다. 사전 통지는 필요 없지만, "일단 그러한 선택을 한 후에는 VAT Written Enquiries Team에 서면으로 신청하여 동의를 받지 않고서는 이를 변경할 수 없습니다."
  3. 자체적인 상업 환율 또는 방법으로, 서면 신청이 필요합니다. HMRC는 그 환율이 "영국 통화 시장을 참조하여 결정"되는지, "객관적으로 검증 가능"한지, 그리고 얼마나 자주 갱신되는지를 따집니다. 결정적으로 "선물환율 또는 선물환율에서 파생된 방법은 인정되지 않습니다." 이는 현물환율과 선물환율의 차이와 함께 이해해 둘 만한 명확한 경계선입니다.

그리고 캐싱 계층을 규율하는 문장이 있습니다. "어떤 환율이나 방법을 채택하든, 특정 공급에 적용되는 환율은 그 공급 시점에 통용되는 환율입니다." 공급 시점이지, 인보이스 발행 시점도, 지급 시점도, 하물며 여러분의 야간 배치 작업 시점도 아닙니다.

경로 2를 택한다면 그 메커니즘은 기분 좋을 만큼 기계 친화적입니다. HMRC는 월별 환율을 매월 끝에서 두 번째 목요일에 공표합니다. 이 환율은 다음 달력 월에 적용되며, 공표 전날 정오 기준 환율을 나타냅니다. 파일은 예측 가능한 URL에 놓여 있습니다. 월에 0이 채워지지 않는다는 점에 유의하십시오.

https://www.trade-tariff.service.gov.uk/exchange_rates/view/files/monthly_csv_2026-9.csv
https://www.trade-tariff.service.gov.uk/exchange_rates/view/files/monthly_xml_2026-9.xml

한 달에 한 번 가져와 그달 동안 캐싱하면, 해당 기간의 모든 영국 부가가치세 환산은 조사관에게 그대로 건넬 수 있는 파일로부터 재현 가능합니다.

유럽연합: 부가가치세 지침 제91조

EU 역내 공급에 대해, 이사회 지침 2006/112/EC 제91조 제2항은 그 규칙을 "부가가치세 납세의무가 성립하는 시점에 해당 회원국의 가장 대표적인 하나 또는 복수의 외환시장에서 기록된 최근 매도 환율, 또는 그 시장을 참조하여 결정된 환율"로 정합니다.

이를 27개 회원국 전체에 걸쳐 구현하기는 어려우므로, 지침은 실용적인 탈출구를 덧붙입니다. 회원국은 "그 대신 세금의 납세의무가 성립하는 시점에 유럽중앙은행이 공표한 최근 환율의 사용을 인정하여야 한다"는 것입니다. 유로가 아닌 두 통화 간 환산은 "각 통화의 유로 환율을 사용하여" 수행합니다. 다시 말해, 통화쌍을 직접 호가하는 대신 EUR을 경유해 크로스합니다. 회원국은 이 선택권을 행사하고 있다는 통지를 요구할 수 있습니다.

수입의 경우, 제91조 제1항은 대신 관세 목적의 과세가격 산정에 관한 관세 규정을 따릅니다. 같은 원장 안에, 실제로 다른 날짜의 실제로 다른 환율이 존재하는 것입니다. 여러분의 시스템이 "EU 부가가치세"를 하나의 환산 규칙으로 취급하고 있다면, 그것은 이미 틀렸습니다.

그 모든 것의 밑바탕: IAS 21

세무 규정은 회계정책 위에 얹혀 있고, IFRS 보고 기업에게 그 정책은 IAS 21입니다. 네 가지 규정이 대부분의 일을 합니다.

  • 외화 거래는 최초 인식 시 거래일의 현물환율로 인식됩니다(IAS 21.21).
  • 간편법으로 평균환율이 허용되지만, 이는 "환율이 유의적으로 변동하지 않는 한"에서만 그렇습니다(IAS 21.22). 이는 기본값이 아니라 조건이며, 변동성이 큰 분기에 조용히 무너지는 것이 바로 이 조항입니다.
  • 화폐성 항목은 보고일에 마감환율로 재환산됩니다(IAS 21.23).
  • 역사적 원가로 측정되는 비화폐성 항목은 거래일 환율에 그대로 남으며 재환산되지 않습니다.

미국 회계기준도 ASC 830 아래에서 대체로 유사한 결론에 이릅니다. 개발자에게 실질적인 귀결은, 하나의 거래가 그 생애 동안 두세 개의 서로 다른 환율을 정당하게 요구할 수 있다는 것입니다. 인식 시점에 하나, 기말 마감에 하나, 결제 시점에 하나. 스키마에는 그 모두를 담을 공간이 필요합니다. 그로부터 발생하는 손익이 사업적으로 무엇을 뜻하는지는 기업을 위한 환위험 관리 가이드에서 다룹니다.

재작성으로 이어지는 다섯 가지 환산 버그

1. 환율 방향

base=USD&symbols=EUR는 달러당 유로를 반환합니다. base=EUR&symbols=USD는 유로당 달러를 반환합니다. IRS 연간 표는 미화 1달러당 외화이므로 나누고, base=EUR인 Finexly 응답은 유로당 미화이므로 곱합니다. 둘 다 옳으며, 섞는 것만이 틀립니다.

해결책은 지루하지만 효과적입니다. 열 이름을 절대 rate로 짓지 마십시오. quote_per_base라고 이름 붙여, 방향을 주석이 아니라 스키마에서 명확하게 만드십시오.

2. 재생이 아닌 재조회

2029년의 감사가 2026년의 거래를 묻습니다. 보고서 코드가 보고서 생성 시점에 라이브 endpoint를 호출한다면, 같은 보고서를 두 번 실행할 때 두 개의 서로 다른 숫자가 나옵니다. 어떤 거래에 적용된 환율은 조회가 아니라 그 거래에 관한 사실입니다. 환산하는 그 순간에 영속화하십시오. 히스토리컬 endpoint는 백필대사를 위해 존재하는 것이지 저장을 대체하기 위한 것이 아닙니다. 백필 패턴은 히스토리컬 환율 API 가이드를 참고하십시오.

3. 현물환율이 필요한 곳에 평균환율

월평균은 편리하고 종종 허용되지만, IAS 21.22는 조건을 붙이고 있으며 일회성 거래는 IRS 지침상 일반적으로 거래일 환율을 요구합니다. 방법을 환율과 함께 저장해 두면 "왜 이 숫자인가?"에 고고학 발굴 없이 답할 수 있습니다.

4. 누락된 날짜

주말, 공휴일, TARGET 비영업일에는 공표 환율이 없습니다. 모든 시스템에는 명시적 규칙(보통 "해당 날짜 이전의 최근 공표 환율")이 필요하며, 어떤 규칙이 발동했는지도 기록해야 합니다. 반년이 지나면 조용한 폴백은 버그와 구별되지 않습니다. 이는 캐싱 및 오류 처리 실무와 직접 겹칩니다.

5. 정밀도와 반올림

표시하는 것보다 더 많은 소수 자릿수를 저장하고, 반올림은 최종 표시 또는 전기 단계에서 정확히 한 번만 하십시오. 수천 건의 인보이스에 걸쳐 중간 단계마다 반올림하면, 설명하기는 번거롭고 되돌리기는 불가능한 대사 차이가 생깁니다. 그 산술은 통화 반올림과 소수 자릿수에서 자세히 다뤘습니다.

환율 조회가 아니라 환율 스냅샷을 설계하라

환산을 함수 호출로 생각하기를 멈추고 불변 레코드로 생각하기 시작하면 문제 전체가 무너집니다. 다음은 위에서 논의한 모든 요건을 충족하는 최소 스키마입니다.

CREATE TABLE fx_rate_snapshot (
    id                BIGSERIAL PRIMARY KEY,
    transaction_id    BIGINT      NOT NULL,
    -- direction is in the name, not in a comment
    base_currency     CHAR(3)     NOT NULL,   -- e.g. 'EUR'
    quote_currency    CHAR(3)     NOT NULL,   -- e.g. 'USD'
    quote_per_base    NUMERIC(20,10) NOT NULL,

    rate_date         DATE        NOT NULL,   -- the date the rate APPLIES to
    method            TEXT        NOT NULL,   -- 'spot' | 'monthly_period' | 'yearly_average'
    fallback_applied  TEXT,                   -- 'previous_business_day' | NULL

    source            TEXT        NOT NULL,   -- 'finexly' | 'hmrc_monthly' | 'irs_yearly'
    source_reference  TEXT,                   -- file name, request id, or table year
    retrieved_at      TIMESTAMPTZ NOT NULL,   -- when WE obtained it

    amount_base       NUMERIC(20,4) NOT NULL,
    amount_quote      NUMERIC(20,4) NOT NULL,

    created_at        TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- one authoritative conversion per transaction per purpose
CREATE UNIQUE INDEX ux_fx_snapshot_txn_method
    ON fx_rate_snapshot (transaction_id, method, rate_date);

감사 무게의 대부분은 세 개의 열이 감당합니다. rate_date는 그 환율이 적용되는 날짜이며, 여러분이 그것을 취득한 순간인 retrieved_at과 의도적으로 분리되어 있습니다. 9월 백필 중에 가져온 3월 13일 환율은 전혀 문제가 없으며, 이 두 timestamp의 쌍이 그 사실을 정직하게 말해 줍니다. fallback_applied는 주말 규칙을 보이지 않는 동작에서 기록된 증거로 바꿔 놓습니다.

행은 결코 갱신되지 않는다는 점에 유의하십시오. 환율이 정정되면 새 행을 삽입해 기존 행을 대체하십시오. 수정할 수 있는 감사 추적은 감사 추적이 아닙니다.

방어 가능한 히스토리컬 환율 가져오기

거래일 환율이 필요하다면 현재 날짜가 아니라 특정 날짜를 요청하십시오.

curl "https://api.finexly.com/v1/historical?date=2026-03-13&base=EUR&symbols=USD" \
  -H "Authorization: Bearer YOUR_API_KEY"
{
  "base": "EUR",
  "date": "2026-03-13",
  "rates": {
    "USD": 1.0842
  }
}

base=EUR인 경우 그 값은 유로당 달러입니다. 따라서 €10,000짜리 인보이스는 곱셈을 통해 $10,842.00로 환산됩니다. 다음은 Python으로 구현한 쓰기 시점 스냅샷 패턴으로, 누락일 폴백과 위 스키마가 요구하는 필드를 포함합니다.

import requests
from datetime import date, timedelta
from decimal import Decimal, ROUND_HALF_UP

API = "https://api.finexly.com/v1/historical"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY"}


def fetch_rate(base: str, quote: str, on: date, max_lookback: int = 5):
    """Return (quote_per_base, rate_date, fallback) for a given date.

    Walks back to the most recent published rate if `on` is a weekend
    or a market holiday, and reports which day it actually landed on.
    """
    for offset in range(max_lookback + 1):
        d = on - timedelta(days=offset)
        r = requests.get(
            API,
            params={"date": d.isoformat(), "base": base, "symbols": quote},
            headers=HEADERS,
            timeout=10,
        )
        r.raise_for_status()
        rates = r.json().get("rates", {})
        if quote in rates:
            fallback = "previous_business_day" if offset else None
            return Decimal(str(rates[quote])), d, fallback

    raise LookupError(f"No {base}/{quote} rate within {max_lookback} days of {on}")


def convert_for_filing(amount_base, base, quote, transaction_date):
    """Convert once, and return everything an auditor will ask for."""
    rate, rate_date, fallback = fetch_rate(base, quote, transaction_date)
    amount = Decimal(str(amount_base))
    converted = (amount * rate).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)

    return {
        "base_currency": base,
        "quote_currency": quote,
        "quote_per_base": rate,
        "rate_date": rate_date.isoformat(),
        "method": "spot",
        "fallback_applied": fallback,
        "source": "finexly",
        "amount_base": amount,
        "amount_quote": converted,
    }


snapshot = convert_for_filing(10000, "EUR", "USD", date(2026, 3, 13))
print(snapshot["amount_quote"], snapshot["rate_date"], snapshot["fallback_applied"])
# -> 10842.00 2026-03-13 None

이 함수는 환산과 기록을 한 호흡에 처리합니다. 영속화 계층이 무엇이든, 하류의 어떤 것이 그 숫자를 보기 전에 이 딕셔너리를 기록하십시오. 같은 원칙은 다중 통화 인보이싱, SaaS 과금, 국경 간 급여 지급 전반에서 보상을 돌려줍니다. 이 모두가 결국 같은 세무 신고서로 흘러들기 때문입니다.

공식 공표 환율과의 대사

경로 2에 따른 영국 부가가치세라면, HMRC의 월별 파일을 한 달에 한 번 내려받아 해당 기간의 신뢰 원천으로 저장하십시오.

import csv, io, requests
from datetime import date

def hmrc_monthly_rates(year: int, month: int) -> dict:
    """HMRC monthly rates for VAT/customs. Note: month is NOT zero-padded."""
    url = (
        "https://www.trade-tariff.service.gov.uk/exchange_rates/view/files/"
        f"monthly_csv_{year}-{month}.csv"
    )
    resp = requests.get(url, timeout=15)
    resp.raise_for_status()

    reader = csv.DictReader(io.StringIO(resp.text))
    # Don't hard-code the header text: find the ISO-4217 code column by shape.
    code_col = next(
        c for c in reader.fieldnames if "code" in c.strip().lower()
    )
    return {
        row[code_col].strip(): row
        for row in reader
        if row.get(code_col) and len(row[code_col].strip()) == 3
    }

그런 다음 주기적인 괴리 점검을 돌리십시오. 저장된 각 스냅샷을 해당 기간의 공식 환율과 비교하고, 의도적으로 정한 허용 범위를 벗어나는 것에 플래그를 다는 것입니다. 시장 환율과 공표된 행정 환율 사이의 작은 차이는 예상된 것이고 대체로 용인됩니다. 다만 조사관이 대신 계산해 주기 전에 그 격차의 크기를 여러분이 먼저 아는 편이 좋습니다. 이것을 원장에 연결할 계획이라면, 회계 소프트웨어 연동환율 API는 데이터를 어디서 가져오는가에 대한 정리가 그다음에 따라오는 출처 관련 질문들을 다룹니다.

다중 통화 데이터를 위한 신고 전 체크리스트

  1. 환산된 모든 금액에는 저장된 환율이 있다. 실행 시점에 히스토리컬 환산을 다시 계산하는 보고서는 없다.
  2. 환율 방향이 명확하다 — 문서가 아니라 열 이름에서.
  3. rate_dateretrieved_at은 별개의 필드이며, 둘 다 값이 채워져 있다.
  4. 누락일 규칙이 명시되고 기록된다 — 암묵적 재시도가 아니라.
  5. 거래 유형별로 하나의 방법을, 기간 전체에 걸쳐 일관되게 적용한다 — 이것이 미국과 영국 모두의 실제 법적 요건이다.
  6. 반올림은 한 번만, 마지막 단계에서, 문서화된 모드로 이루어진다.
  7. 스냅샷 행은 추가 전용이다. 정정은 대체이며, 결코 덮어쓰지 않는다.

이 일곱 가지를 끝까지 해내면 회계사의 질문은 더 이상 두렵지 않습니다. 답은 하나의 쿼리가 됩니다.

자주 묻는 질문

IRS는 세무 신고에 어떤 환율을 요구하나요? 특정한 것은 없습니다. IRS는 자신에게 "공식 환율이 없다"고 분명히 밝히며 "일관되게 사용되는 공표 환율이라면 일반적으로 인정한다"고 합니다. 기본값은 해당 항목을 수취·지급 또는 발생시킨 시점에 통용되는 현물환율입니다. 고르게 발생하는 소득에 대해서는 IRS가 연평균 환율표를 공표하고, 신고자에게 외화 금액을 표에 기재된 환율로 나누라고 안내합니다.

부가가치세에서 HMRC의 공표 환율 대신 통화 API를 쓸 수 있나요? 쓸 수 있지만 한계가 있습니다. VAT Notice 700 §7.6은 공급 시점의 영국 시장 매도 환율을 기본값으로 삼으므로, 일관되게 적용하는 한 시장 기반 API 환율은 이 경로에 부합합니다. HMRC 자체의 기간 환율은 사전 통지 없이 채택할 수 있는 명시적 대안이지만, 일단 채택하면 서면 동의 없이는 되돌릴 수 없습니다. 두 경로 모두에 해당하지 않는 환율이나 방법은 서면 신청이 필요하며, 선물환율은 인정되지 않습니다.

환율을 저장해야 하나요, 아니면 나중에 다시 조회해도 되나요? 저장하십시오. 저장된 환율은 환산을 재현 가능하게 만듭니다. 재조회는 그것을 새로운 계산으로 만들어 버리며, 이미 제출한 신고서와 맞지 않을 수 있습니다. 환율과 그 날짜, 출처, 그리고 취득한 순간을 저장하는 것이야말로 숫자를 증거로 바꾸는 일입니다.

주말이나 공휴일이 거래일인 경우 어떤 환율을 써야 하나요? 비거래일에는 공표 환율이 없으므로 명시된 규칙이 필요합니다. 가장 흔한 것은 거래일 이전의 최근 공표 환율입니다. 어떤 규칙을 고르느냐보다 중요한 것은 그것이 문서화되고, 일률적으로 적용되며, 영향을 받는 각 행에 기록되는 것입니다.

세무 목적으로 소수 자릿수는 몇 자리를 저장해야 하나요? 공급자가 반환하는 전체 정밀도를 저장하고(소수 6~10자리가 합리적인 열 너비입니다), 전기하거나 표시할 때만 반올림하십시오. 일찍부터 반복해서 반올림하는 것이 아무도 추적할 수 없는 대사 차이의 흔한 원인입니다.

ECB 환율이 EU 부가가치세 요건을 충족하나요? 부가가치세 지침 제91조 제2항은 세금의 납세의무가 성립하는 시점에 공표된 최근 ECB 환율을 회원국이 인정하도록 요구하며, 통화 간 환산은 각 통화의 유로 환율을 경유합니다. 일부 회원국은 이 선택권을 사용하고 있다는 통지를 요구하며, 수입은 대신 관세 평가 규정을 따릅니다.

환율을 감사 대응 가능하게 만드세요

실시간 환율과 히스토리컬 환율을 프로젝트에 통합할 준비가 되셨나요? 무료 Finexly API 키 받기 — 신용카드가 필요 없습니다. 월 1,000회 무료 요청으로 시작해 성장에 맞춰 업그레이드하세요. 히스토리컬 endpoint의 전체 레퍼런스는 API 문서에서 확인하고, 일회성 확인에는 통화 변환기를 사용해 보고, 공급자를 검토 중이라면 통화 API 비교를, 보고 물량이 늘어나면 요금제를 살펴보세요.

이 글은 다중 통화 시스템을 구축하는 개발자를 위한 기술 가이드입니다. 세무 자문이 아니므로, 신고하는 각 관할권에서 자격을 갖춘 자문가와 환산 정책을 확인하십시오.

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 →

이 기사 공유하기