이 글은 누구를 위한 것인가
- 한 스토어에서 EU·미국·일본 등 복수 관할권으로 파는 팀
- "화면에 보인 금액과 결제 금액이 다르다"는 CS를 줄이고 싶은 PM·운영
- 카탈로그에 세전/세포함 표기를 섞지 않고 싶은 개발·데이터팀
들어가며
글로벌 커머스에서 세금 문제는 단순히 "세율 곱하기"가 아니다. 어디에 세금 귀속이 있는지, 표시 의무가 있는지, 면세·역할감(Seller of Record) 여부에 따라 같은 SKU라도 체크아웃 흐름이 달라진다. 여기에 환율, 반품, 부분 취소까지 얹히면, 시스템이 **한 가지 진실(source of truth)**을 잃는 순간 재무·CS 비용이 기하급수로 늘어난다.
이 글에서는 법적 세부를 대체하지 않는다. 대신 제품·엔지니어링이 합의해야 할 정합성 규칙과, 그걸 지키기 위한 데이터 모델·경계를 정리한다.
1. 먼저 질문 세 가지
구현에 들어가기 전에 조직적으로 답이 있어야 한다.
-
가격은 세전인가, 세포함인가?
B2C 사이트 표시, 마켓플레이스 내 판매자 정책, 광고 채널(예: 구글 쇼핑)의 요구가 한데 모이면 규칙이 갈린다. "기본은 세포함, B2B 견적은 세전"처럼 페르소나·채널별 원칙을 문서로 고정한다. -
Seller of Record(SoR)는 누구인가?
SoR이 플랫폼이면 세금 계산·신고 책임이 팔 형태로 바뀐다. 마켓플레이스 정산 글(marketplace-settlement-seller-payouts)과 연결해, 누가 세금을 거두는 주체인지가 불명확하면 안 된다. -
세금은 "주문 시점"에 확정되는가?
일부 관할권에서는 배송지·결제 수단에 따라 세율이 바뀐다. 확정 시점(장바구니 표시 vs 결제 확정 vs 출고)을 정하지 않으면 부분 취소·반품 시 금액이 깨진다.
2. 계층을 나누라: 카탈로그·오퍼·주문
실무에서 흔한 실패는 "상품 테이블에 최종 판매가 하나"인 구조다.
권장하는 최소 분리는 다음과 같다.
| 계층 | 역할 | 예시 |
|---|---|---|
| 카탈로그 SKU | 속성·분류·기본 통화 가격(정책에 따라 세전/세포함 명시) | list_price, currency |
| 오퍼(채널·세그먼트) | 프로모션, 회원 등급, 지역별 노출 가격 | 멤버십 가격, 쿠폰 스택 규칙 |
| 장바구니 스냅샷 | 세율 후보, 예상 세금, 배송비 시뮬레이션 | 체크아웃 전 UI |
| 주문 라인 스냅샷 | 확정 세율·통화·단가·세금·할인 분해 | 환불·세무 대응의 근거 |
핵심은 주문 확정 시점에 "고객이 동의한 숫자"가 고정되어야 한다는 것이다. 이후 PG 웹훅·WMS는 이 스냅샷을 참조해 변형하면 안 된다. (결제 수명주기·멱등은 order-payment-lifecycle-idempotency-key-design 참고.)
3. 세금 엔진을 어디에 둘 것인가
선택지는 대략 세 가지다.
-
외부 Tax API(Stripe Tax, Avalara 등)
규칙 업데이트·신고 연동 부담을 줄인다. 단, 호출 시점·캐시·실패 시 폴백을 설계해야 한다. -
자체 엔진 + 테이블
SKU 수·국가 수가 작고 규칙이 단순할 때. 규칙 버전을 반드시 둔다. "2026-Q2 세율"처럼 과거 주문 재현이 가능해야 한다. -
하이브리드
표시는 자체, 확정은 외부 등. 이 경우 두 결과가 불일치할 때 어떤 쪽이 승자인지를 미리 정한다.
공통 체크리스트:
- 주소 정규화 실패 시 세율을 어떻게 취급할지(차단 vs 보수적 고율 vs CS 큐)
- B2B 면세 증빙 업로드 전후로 세액이 바뀌는 플로
- 디지털 상품과 실물의 과세 지점 차이
4. 통화·환율과의 관계
멀티 통화를 쓰면 "세전 EUR, 결제 USD" 같은 조합이 생긴다.
- 표시 통화와 정산 통화를 분리할지 한데 갈지 합의한다.
- 환율은 어느 시점의 어떤 소스(PG, ECB, 매일 고정)인지 기록한다.
- 부분 환불 시 라인 단위로 원 통화 기준을 추적하면 분쟁이 줄어든다.
5. 반품·부분 취소와 세금
반품 시 문제는 "금액"이 아니라 세금 신고·환급 가능 여부다.
- 환불 금액은 주문 라인 스냅샷의 비율/수량에 맞춰 계산한다.
- 세금만 따로 취소되는지, 역산되는지는 관할 규칙 + PG 정책에 의존한다.
- CS 도구에 "당시 스냅샷 링크"가 있어야 한다.
6. 구현 체크리스트 (요약)
- 채널별 세전/세포함 원칙 문서화
- 카탈로그 vs 주문 스냅샷 분리,
tax_rule_version저장 - 세금 API 타임아웃·재시도·수동 보정 경로
- 부분 취소·반품 시 동일 스냅샷 기준 환불 로직
- 감사 로그: 요청 파라미터(주소 요약)·응답 세액·버전
7. 지역별로 자주 터지는 함정
7.1 유럽: IOSS·OSS와 판매자 소재지
EU 소비자에게 원거리 판매를 할 때 한 국가에 신고하며 여러 회원국 세금을 정산하는 메커니즘(일반적으로 이커머스에서 OSS·IOSS 등으로 이해되는 흐름)이 존재한다. 엔지니어링 관점에서 중요한 건, 세금이 “고객 국가율”로 계산된다는 사실이 카탈로그 기본가와 자동으로 같아 보이지 않는다는 점이다. 같은 EUR 표시라도 세율이 국가마다 다르면, 최종 금액은 배송지·VAT ID 유효성·B2B 역전세 과세 여부에 따라 달라진다.
실무에서는 다음을 명시한다.
- 표시: 장바구니에 배송지가 없을 때 “예상 세액” 문구를 쓸지, 아예 세액을 비워 둘지
- 확정: 배송지 입력이 끝난 시점에만 세금 API를 한 번 더 호출할지
- 역전세: B2B 유효 VAT 번호가 있을 때 **0%**가 되는 플로에서 결제 수단·발행 국가 검증 타이밍
7.2 미국: 판매세와 마켓플레이스 법
미국은 연방 VAT가 아니라 주·카운티·시 구역 단위로 합성 세율이 달라진다. 마켓플레이스가 facilitator로 세금을 거두는지, 판매자가 직접 신고하는지에 따라 시스템 분기가 갈린다. 엔지니어링 팀은 법을 대신 판단할 수 없고, 제품이 어떤 역할(SoR, 결제 주체)을 한다는 가정 하에 세금 결과를 스냅샷에 고정하는 데 집중한다.
주소가 아파트 단위까지 정규화되지 않으면 세율 엔진은 잘못된 구역에 매핑할 수 있다. “상세 주소 없이 우편번호만으로는 부족하다”는 것을 데이터 모델에 반영한다.
7.3 일본·호주 등: 소비세·GST 표시 관습
일본 소비세·호주 GST 등은 포함표시가 일반적인 채널이 많다. 글로벌 사이트가 **미국식 “+tax at checkout”**과 **일본식 “세포함”**을 한 페이지에서 섞으면, 같은 언어 UI라도 국가별로 심리적 기대가 어긋난다. 최소한 국가별 가격 표시 정책을 위키에 적고, 프런트에선 로케일 단위로 단위·통화 기호 순서까지 맞춘다.
8. 반올림·소수점: 금액이 1원씩 어긋나는 이유
세율을 곱한 뒤 라인 단위로 반올림할지, 장바구니 합계에만 반올림할지는 PG·세무 엔진·회계 팀 규칙과 맞춰야 한다.
- 라인 단위 반올림: 부분 환불·수량 변경 시 추적은 쉬우나, 라인 합이 총액과 1단위 차이 날 수 있다 → 허용 오차와 “어느 쪽이 마스터인지” 합의
- 세전 단가 × 수량 후 합산: 회계적으로 선호되는 경우가 있으나, UI에 보이는 퍼센트 할인과 어긋날 수 있음
주문 스냅샷에는 정수로 저장한 최소 화폐 단위(예: cent, 원)와 표시용 포맷을 분리한다. 부동소수점 float로 금액을 저장하면 반드시 어딘가에서 깨진다.
9. 스냅샷 필드 예시 (개념 스키마)
팀마다 이름은 다르지만, 주문 라인에 아래에 가깝게 들어가 있으면 감사·환불·세무 대응이 수월하다.
| 필드 그룹 | 예시 | 설명 |
|---|---|---|
| 상품 참조 | sku_id, offer_id | 당시 적용된 오퍼·캠페인 추적 |
| 가격 | unit_price_minor, line_subtotal_minor | 부가세 별도/포함 중 무엇을 썼는지 플래그와 함께 |
| 세금 | tax_rate_id, tax_amount_minor, tax_inclusive | 세율 자체가 아니라 당시 유효했던 규칙 ID를 남김 |
| 할인 | discount_allocations[] | 쿠폰·포인트가 라인에 안분된 금액 |
| 환율 | fx_rate, fx_source, quoted_at | 멀티 통화 주문 시 필수 |
규칙 ID(세율 테이블 버전)만 있으면, 나중에 “지금 세율은 바뀌었는데 당시엔 얼마였나”를 재현할 수 있다.
10. 장애·분쟁 대응 플레이북
현업에서 비용이 큰 순서대로 정리하면 다음과 같다.
- 고객 화면 ≠ 결제 금액: 대부분은 스냅샷 누락, 만료된 장바구니 세션, 또는 PG가 재시도한 멱등 키 불일치. 주문 ID로 스냅샷 vs PG 로그를 나란히 놓고 본다.
- 부분 취소 후 세금이 안 맞음: 취소 요청이 “금액 기준”인지 “수량 기준”인지, PG가 역산 세액을 어떻게 쪼개는지 확인한다. 내부 원장이 취소 라인을 별도 이벤트로 쌓는지 여부가 핵심이다.
- 해외 CS가 영수증을 요구: B2B는 세금계산서·인보이스 요구가 섞인다. 같은 주문에 스토어 영수증과 회계 인보이스가 둘 다 존재할 수 있음을 문서화한다.
맺음말
글로벌 VAT·판매세는 법·회계 전문가와의 협업이 전제다. 다만 엔지니어링이 할 수 있는 일은 명확하다. 가격을 한 군데에서 흔들리지 않게 만들고, 주문 시점의 스냅샷을 불변 근거로 삼고, 규칙 버전으로 과거를 재현 가능하게 만드는 것이다. 그 세 가지가 갖춰지면, 세율이 바뀌어도 배포가 아니라 데이터 패치로 버틸 여지가 생긴다.