참고

구독 흐름

계약 생성부터 회차 청구·해지까지 구독 흐름을 한눈에 이어져요.

구독 계약 생성부터 회차 자동 결제·조정·해지까지 전체 시퀀스를 이해해요.

개별 API는 구독 계약 / 가입, 구독 > 운영 / 회차 에서 확인해요. 이 문서는 라이프사이클을 한 장으로 봐요.

개념·정책 배경 (먼저 정해야 할 것)

구독 구현 전에 블로그 가이드를 봐요.

이 문서의 위치

구독 사이드바는 구독 메뉴 안의 계약 정의·가입·운영 그룹로 나뉘어 있어요. 이 구독 메뉴는 이 문서를 라이프사이클 단일 소스로 참조해요.

전체 시퀀스

참여자: 고객 | 가맹점 프론트 | 가맹점 서버 | Bootpay | PG사

단계 흐름 유형 비고
1 고객 -> 가맹점 프론트: 구독 상품 선택 실선
2 가맹점 프론트 -> Bootpay: 빌링키 발급 SDK 호출 실선 카드 수집은 SDK ↔ PG 직접
3 Bootpay -> PG사: 빌링키 발급 요청 실선
4 PG사 -> Bootpay: 빌링키 반환 점선
5 Bootpay -> 가맹점 프론트: billing_key 반환 점선
6 가맹점 프론트 -> 가맹점 서버: billing_key + 구독 상품 정보 전달 실선
7 가맹점 서버 -> Bootpay: 구독 계약 생성 (subscribe) 실선 user × plan × billing_key
8 가맹점 서버 -> Bootpay: 계약 승인 (approve) 실선 첫 회차 예약
9 Bootpay: 회차 스케줄러에 등록 실선 status = 구독 중(1)
10 Bootpay -> PG사: 매 회차 빌링키 결제 실선 자동
11 Bootpay -> 가맹점 서버: 웹훅 (subscription.billed / subscription.failed) 실선
12 가맹점 서버: 서비스 접근 제어 실선 active/inactive 토글

구독 라이프사이클 상태 전이

구독 하나는 대기 → 구독 중 → (일시정지) → 해지/만료 흐름을 따라요. 상태 코드는 API 응답·웹훅에서 동일하게 쓰여요.

상태

ID 라벨 위치 타입
pending 대기 (0) col 0, row 0 initial
active 구독 중 (1) col 1, row 0 active
paused 일시정지 (2) col 2, row 0 warning
terminated 해지 (3) col 2, row 1 end
expired 만료 (4) col 3, row 0 end
blocked 거절 (-11) col 0, row 1 end

전이 pending -> active : 승인 pending -> blocked : 거절 active -> paused : 일시정지 paused -> active : 재개 active -> terminated : 해지 요청 paused -> terminated : 해지 요청 active -> expired : 기간 종료

현재 다음 주체 API
대기 (0) 구독 중 (1) 관리자 신규 승인
대기 (0) 거절 (-11) 관리자 구독 거절
구독 중 (1) 일시정지 (2) 고객·관리자 일시정지
일시정지 (2) 구독 중 (1) 고객 재개
구독 중 (1) 해지 (3) 고객·관리자 해지
일시정지 (2) 해지 (3) 고객 해지
구독 중 (1) 만료 (4) 자동 기간 종료

회차(빌링 사이클) 상태

구독이 승인되면 주기에 맞춰 회차​​가 생성돼요. 회차는 구독과 독립 상태를 가져요.

회차 상태 코드 의미 다음 액션
예정 0 결제 예정 (스케줄러 등록됨) 대기
성공 1 결제 완료 웹훅 subscription.billed
실패 2 결제 실패 재시도 스케줄
취소 3 회차 취소 (환불·관리자 취소) 웹훅 subscription.refunded

회차 조회·수정 API는 회차 조회 · 회차 금액 조정 참고.

자동 과금 재시도 흐름

결제 실패 시 Bootpay는 정책에 따라 재시도해요. 가맹점은 웹훅을 받아 서비스 접근만 제어하면 돼요.

흐름 스케줄 -> 결제 시도 결제 시도 -> 성공 결제 시도 -> 실패 실패 -> 재시도 대기 재시도 대기 -> 결제 시도 실패 -> 최종 실패

단계 주체 설명
결제 시도 Bootpay 회차 도래 시 빌링키로 자동 결제
성공 Bootpay 웹훅 subscription.billed 발송, 다음 회차 예약
실패 Bootpay 웹훅 subscription.failed 발송, 재시도 대기로 전환
재시도 대기 Bootpay 재시도 주기(기본 24h) 경과 후 다시 결제 시도
최종 실패 Bootpay 재시도 횟수 초과 시 구독을 일시정지(2)로 전환, subscription.paused 웹훅
재시도 정책은 서비스가 정해요

재시도 횟수·간격·최종 실패 후 동작(일시정지 vs 해지)은 콘솔에서 설정해요. 블로그의 결제 실패 재시도 정책 을 먼저 정리한 뒤 적용해요.

웹훅 이벤트 매핑

가맹점 서버는 아래 이벤트를 받아 서비스 상태와 DB를 동기화해요.

이벤트 발생 시점 가맹점이 할 일
subscription.approved 계약 승인 완료 service_active = true
subscription.billed 회차 결제 성공 다음 회차까지 서비스 유지
subscription.failed 회차 결제 실패 고객에게 결제수단 변경 안내
subscription.paused 일시정지 (고객·관리자·재시도 초과) 서비스 접근 일시 차단
subscription.resumed 일시정지 해제 service_active = true
subscription.terminated 해지 완료 service_active = false, 잔여 기간 정책 적용
subscription.refunded 회차 환불 정산·회계 반영

웹훅 엔드포인트 구현은 웹훅 처리 가이드 참고.

유예 기간(Grace Period) 설계

결제 실패 ~ 최종 실패 사이 구간을 유예 기간으로 두면 이탈률이 줄어들어요.

구간 서비스 상태 고객 커뮤니케이션
회차 실패 직후 유지 (grace) 카드 업데이트 링크 이메일
재시도 1회 실패 후 유지 (grace) 2차 알림 + 앱 내 배너
재시도 N회 실패 후 일시정지 최종 안내, 수동 재결제 안내

유예 기간 길이는 서비스 특성에 따라 달라요 (SaaS 3~7일, 콘텐츠 1~3일이 일반적).

고객 변경 요청 흐름

고객이 해지·인수·이전 같은 변경을 요청하면 관리자 승인 루프​​를 거쳐요.

흐름 고객 요청 -> 대기 (0) 대기 (0) -> 확인 대기 (1) : 승계/인수만 상대방 확인 확인 대기 (1) -> 승인 (2) 대기 (0) -> 승인 (2) 승인 (2) -> 완료 대기 (0) -> 거절 (-1) 대기 (0) -> 철회 (-2)

요청 상태 코드 다음
대기 0 관리자 승인/거절
확인 대기 1 상대 고객 확인 (승계·인수 한정)
승인 2 실제 상태 변경 실행
거절 -1 요청 종료
철회 -2 고객 철회로 종료

API 흐름: 요청 목록 · 요청 승인/거절.

흔한 실수

1웹훅만으로 서비스 활성화 판단

// ❌ 위험 — 웹훅이 지연되면 고객이 결제했는데 서비스 못 씀javascript

결제 완료는 API 응답과 웹훅 둘 다​​로 확인해요. 동기 응답으로 1차 활성화 후, 웹훅으로 최종 동기화.

2구독 상태와 회차 상태 혼동

구독 상태(대기/구독 중/일시정지/해지)와 회차 상태(예정/성공/실패/취소)는 분리된 축​​이에요. 구독이 '구독 중(1)'이어도 해당 월의 회차가 '실패(2)' 일 수 있어요. DB에도 두 축을 분리해서 저장해요.

3재시도 중인 회차를 '실패'로 즉시 취급

첫 결제 실패 후 바로 서비스를 차단하면 일시적 카드사 오류로 이탈이 발생해요. subscription.paused 가 올 때까지는 유예 기간으로 두는 쪽이 안전해요.

4해지 시점을 '즉시' 로 고정

"기간 종료까지 서비스 유지 vs 즉시 차단" 은 정책 결정이에요. 구독 해지 정책 을 먼저 정하고 코드에 반영해요.

참고 문서