본문으로 건너뛰기

결제 연동 정책

1. 목적

Apple App Store와 Google Play Store를 통한 인앱 결제(IAP) 연동, 결제 검증, 환불 처리에 대한 기술 정책을 정의합니다.


2. Apple App Store 연동

2-1. AppStoreTransaction 구조

Apple 거래 정보를 캐싱하여 멱등성 있는 검증을 제공합니다.

필드설명
transaction_id거래 고유 ID (unique)
original_transaction_id원본 거래 ID (갱신 추적용)
product_id상품 ID
subscription_type구독 유형
purchase_date구매 일시
expires_date만료 일시
price_amount결제 금액
price_currency통화 코드
auto_renew_status자동 갱신 상태
is_trial_period무료 체험 여부
is_in_intro_offer_period인트로 오퍼 기간 여부
ownership_type소유 유형: PURCHASED 또는 FAMILY_SHARED
environment환경: Sandbox / Production
app_account_token앱 계정 토큰 (사용자 매핑용)
signed_transaction_jws서명된 거래 JWS
raw_transaction원본 거래 JSON
raw_renewal원본 갱신 JSON

2-2. Apple Server Notification Webhook

  • Endpoint: POST /api/payments/apple/notifications/
  • Apple Server Notifications V2를 수신합니다.
  • 구독 갱신, 해지, 환불 등의 이벤트를 실시간으로 처리합니다.

2-3. iOS 클라이언트 결제 흐름

  1. InAppPurchase 플러그인을 통해 상품 정보 조회
  2. StoreKit 2 기반 결제 처리 (iOS 15 미만은 StoreKit 1으로 폴백)
  3. appAccountToken을 UUID v5로 생성하여 사용자 식별에 활용
  4. 결제 완료 후 서버에 검증 요청 (transaction_id, product_id, server_verification_data)

3. Google Play Store 연동

3-1. GooglePlayReceipt 구조

Google Play v2 API 기반 구독 영수증을 관리합니다.

필드설명
latest_order_id결제 단위 식별자 (unique, 정산 매칭)
purchase_token현재 구매 토큰
linked_purchase_token토큰 교체(업그레이드/다운그레이드) 추적
subscription_state구독 상태
acknowledgement_state확인(ack) 상태
start_time구독 시작 기준일
expiry_time만료/다음 갱신 시점
price_amount_micros가격 (micros 단위, 1,000,000 = 1.00)
currency_code통화 코드
region_code지역 코드
product_id상품 ID
base_plan_id기본 플랜 ID
offer_id오퍼 ID
offer_tags프로모/인트로 오퍼 태그 (JSON)
auto_renew_enabled자동 갱신 활성화 여부
raw_json원문 전체 JSON 스냅샷 (감사, 분쟁 대응)

3-2. Google Play 구독 상태

상태설명
SUBSCRIPTION_STATE_ACTIVE활성
SUBSCRIPTION_STATE_PENDING대기
SUBSCRIPTION_STATE_PAUSED일시정지
SUBSCRIPTION_STATE_IN_GRACE_PERIOD유예 기간
SUBSCRIPTION_STATE_ON_HOLD보류
SUBSCRIPTION_STATE_CANCELED해지
SUBSCRIPTION_STATE_EXPIRED만료

3-3. Google Play Webhook (RTDN)

  • Endpoint: POST /api/payments/rtdn/pubsub/
  • Google Pub/Sub를 통한 Real-Time Developer Notification을 수신합니다.
  • 구독 상태 변경, 결제 갱신, 환불 등의 이벤트를 실시간 처리합니다.

3-4. Google Play 관리

  • Endpoint: POST /api/payments/google-play/manage/
  • 구독 확인(Acknowledge), 환불, 권한 취소 등의 관리 작업을 수행합니다.
  • 미확인 구독(ACKNOWLEDGEMENT_STATE_PENDING)은 즉시 ack 처리가 필요합니다.

3-5. Android 클라이언트 결제 흐름

  1. InAppPurchase 플러그인을 통해 상품 정보 및 오퍼 조회
  2. basePlanId, offerId, 가격 정보를 서버에 전달
  3. 결제 완료 후 purchase_token, product_id를 포함하여 서버 검증 요청

4. 결제 검증

4-1. 검증 API

  • Endpoint: POST /api/payments/verify/
  • Rate Limit: 30회/분
  • iOS와 Android 모두 이 단일 엔드포인트로 검증합니다.

4-2. 검증 파라미터

파라미터iOSAndroid설명
platformiosandroid플랫폼 식별
transaction_idOO거래 ID
product_idOO상품 ID
purchase_token-OGoogle Play 구매 토큰
base_plan_id-O (선택)기본 플랜 ID
offer_id-O (선택)오퍼 ID
server_verification_dataO (선택)-JWS 서명 데이터
receipt_dataO (선택)-iOS 영수증 데이터
app_account_tokenO (선택)O (선택)앱 계정 토큰

4-3. PaymentTransaction 구조

결제 거래 기록을 관리합니다.

필드설명
type거래 유형: subscription / renewal / refund / cancellation
status거래 상태: pending / completed / failed / refunded
amount결제 금액
currency통화 코드
payment_method결제 수단 (google_play 등)
gateway_transaction_id외부 거래 ID
purchase_token구매 토큰
metadata추가 메타데이터 (JSON)

5. 환불 정책

5-1. 환불 기준

본 앱의 구독 결제는 Apple App Store 또는 Google Play Store를 통해 이루어지며, 각 플랫폼의 환불 정책을 따릅니다.

5-2. iOS 사용자 (Apple App Store)

  • 환불은 Apple에서만 진행 가능합니다.
  • 앱 운영자는 Apple의 환불 요청을 승인하거나 개입할 수 없습니다.
  • 환불 신청: Apple 환불 신청 페이지를 통해 직접 진행
  • 구독 취소: 설정 > Apple ID > 구독 관리 > 앱 이름 선택 > 구독 취소
  • 취소 시 다음 갱신일부터 결제되지 않으며, 현재 결제 기간까지 서비스는 유지됩니다.

5-3. Android 사용자 (Google Play Store)

구분정책
결제 후 48시간 이내Google Play에서 직접 환불 가능
48시간 이후 ~ 7일 이내신규 구독자에 한해 고객센터 통해 전액 환불 신청 가능
7일 이후기술적 문제 발생 시 예외적으로 부분 환불 검토 가능

5-4. 장기 구독 환불

  • 6개월/12개월 구독의 경우 잔여 기간에 대한 부분 환불 가능
  • 환불금액 = 총 결제금액 - (월정액 x 이용 개월수)
  • 할인 혜택은 소급 적용하여 재계산

5-5. 환불 처리 기간

  • 승인: 영업일 기준 3~5일
  • 실제 환불: 영업일 기준 30~60일 (플랫폼 정산 주기에 따름)

5-6. 환불 제한 사항

  • 동일 계정 2회 이상 환불 제한
  • 환불 후 30일간 재가입 제한
  • 프로모션 코드는 환불 시 재사용 불가
  • 래퍼럴 코드 혜택은 환불 시 회수

6. 환불 요청 (RefundRequest)

6-1. 데이터 구조

필드설명
status상태: pending / approved / rejected / completed / failed
refund_type환불 유형: full (전액) / partial (부분) / subscription_cancel (해지 환불)
reason사유: user_request / technical_issue / billing_error / duplicate_purchase / fraud_prevention / other
reason_description상세 사유 (텍스트)
google_refund_idGoogle Play 환불 ID
google_order_idGoogle Play 주문 ID
purchase_token구매 토큰
revoke_entitlement접근 권한 즉시 회수 여부 (기본 true)
initiated_by환불을 처리한 관리자

6-2. 환불 API

Endpoint설명
POST /api/payments/refund-request/환불 요청 생성
POST /api/payments/refund-process/환불 처리 (관리자)

7. 결제 이력

  • Endpoint: GET /api/payments/history/
  • 사용자의 전체 결제 거래 이력을 조회합니다.