B2B SaaS 구독 취소·churn reason 추적 감사 체크리스트 2026, cancel_at_period_end와 cancellation_reason을 매출 보고서와 분리하기 전 확인할 기준
B2B SaaS 구독 취소·churn reason 추적 감사 체크리스트 2026, cancel_at_period_end와 cancellation_reason을 매출 보고서와 분리하기 전 확인할 기준
B2B SaaS에서 구독 취소는 버튼 하나로 끝나는 사건이 아닙니다. 고객이 다음 결제일부터 갱신하지 않겠다고 예약했는지, 즉시 접근을 중단했는지, 결제 실패 뒤 자동 취소됐는지, 영업 계약 전환 때문에 self-serve 구독을 닫았는지에 따라 보고서의 의미가 완전히 달라집니다.
이 흐름을 제대로 나누지 않으면 cancel_at_period_end가 실제 churn처럼 잡히고, 결제 실패 후 취소가 자발적 해지로 섞이며, 제품 사용량 하락과 해지 사유가 CRM에 연결되지 않습니다. 운영팀은 이탈 이유를 본다고 생각하지만 실제로는 billing 상태, CS 처리 상태, 제품 사용 신호, 마케팅 재참여 이벤트가 한 칸에 뒤섞인 숫자를 보게 됩니다.
이 글은 회계, 세무, 법률, 계약 해석 자문이 아닙니다. B2B SaaS 운영팀이 구독 취소와 churn reason 데이터를 제품, billing, CRM, 고객 성공, GA4 보고서와 연결하기 전 확인할 데이터 품질 체크리스트입니다. 실제 환불, 매출 인식, 약관, 계약 조건은 회사 기준과 전문가 검토를 따라야 합니다.
결제 실패와 dunning 자동화는 B2B SaaS 결제 실패·dunning 자동화 체크리스트에서 먼저 정리했습니다. 무료체험에서 유료 전환으로 넘어가는 기준은 B2B SaaS trial-to-paid 전환 추적 감사 체크리스트와 같이 보면 됩니다. 무료체험 품질 필터는 B2B SaaS 무료체험 남용·trial 품질 필터 체크리스트를 참고하고, 결제 관리자와 카드 owner가 흩어져 있다면 SaaS 결제수단·관리자 인수인계 체크리스트부터 확인하는 편이 안전합니다.
먼저 취소 상태를 한 단어로 뭉치지 않습니다
구독 취소를 모두 canceled로만 저장하면 이탈 원인을 볼 수 없습니다. 운영 보고서에서는 적어도 예약 취소, 즉시 취소, 결제 실패 후 취소, 관리자 변경, 플랜 전환, 계약 전환을 나눠야 합니다.
| 상태 | 운영상 의미 | 바로 확인할 점 |
|---|---|---|
| cancel_requested | 고객이 취소를 시작함 | 누가, 어느 화면에서, 어떤 이유로 시작했는가 |
| cancel_at_period_end | 현재 기간 종료 후 갱신 중단 | 실제 접근 종료일과 매출 보고서 기준일이 다른가 |
| canceled_immediately | 즉시 취소 또는 접근 종료 | 데이터 보존, 환불, CS 안내가 연결됐는가 |
| canceled_after_failed_payment | 결제 실패 후 취소 | dunning 실패와 자발적 churn을 분리했는가 |
| plan_migrated | self-serve에서 enterprise 또는 다른 플랜으로 이동 | 이탈이 아니라 플랜 전환으로 처리되는가 |
| admin_transfer_failed | billing owner 부재로 취소 | 결제 관리자 인수인계 문제로 분류되는가 |
| duplicate_workspace_closed | 중복 workspace 정리 | 고객 이탈이 아닌 계정 정리로 제외되는가 |
대시보드에는 churned 하나만 두기보다 cancellation_status, effective_cancel_at, access_end_at, churn_reason, churn_source, save_offer_status, crm_owner_action을 나눠 두는 편이 좋습니다.
Stripe subscription 취소 필드를 그대로 보고서 기준으로 쓰지 않습니다
Stripe Billing을 쓰는 팀은 subscription 객체와 취소 관련 필드를 구분해서 봐야 합니다. cancel_at_period_end는 현재 결제 기간이 끝날 때 취소하겠다는 예약 상태이고, 실제 구독 상태나 접근 종료 시점과 같은 뜻이 아닐 수 있습니다.
출처: Stripe Docs – Cancel subscriptions
출처: Stripe API Reference – Subscription object
출처: Stripe Docs – Subscriptions overview
| 확인 항목 | 감사 질문 |
|---|---|
| subscription status | active, past_due, unpaid, canceled를 별도로 저장하는가 |
| cancel_at_period_end | 갱신 중단 예약인지 실제 취소인지 구분하는가 |
| cancel_at | 특정 시점 취소 예약이 있는지 확인하는가 |
| canceled_at | 취소 요청 또는 취소 처리 시점을 보고서 기준일과 분리하는가 |
| ended_at | 제품 접근 종료 또는 구독 종료 기준과 맞는가 |
| current_period_end | 이미 결제된 기간 종료일을 customer communication에 쓰는가 |
| cancellation_details.reason | Stripe의 취소 사유 필드와 내부 churn reason을 분리하는가 |
| cancellation_details.comment | 고객 자유 입력을 외부 분석 도구로 보내지 않는가 |
| invoice 상태 | 미납, 회수, 환불, void를 churn 사유와 섞지 않는가 |
| subscription_id | 취소, 재개, 재구독을 같은 계정 흐름으로 묶는가 |
구독 취소 보고서에서 중요한 것은 "고객이 언제 떠났는가"와 "매출이 언제 줄었는가"를 분리하는 것입니다. 취소 예약일, 실제 종료일, 제품 접근 종료일, MRR 반영일이 서로 다를 수 있기 때문입니다.
webhook은 취소 이벤트와 업데이트 이벤트를 함께 봅니다
구독 취소 자동화는 webhook에 크게 의존합니다. 하지만 취소 흐름은 customer.subscription.deleted 하나로만 끝나지 않습니다. 업데이트 이벤트에서 cancel_at_period_end가 켜질 수 있고, 결제 실패나 수동 변경 뒤 상태가 바뀔 수도 있습니다.
출처: Stripe Docs – Subscription webhooks
| 이벤트 또는 신호 | 처리 기준 |
|---|---|
customer.subscription.updated |
취소 예약, 플랜 변경, 상태 변화를 감지 |
customer.subscription.deleted |
실제 구독 종료 또는 삭제 흐름 기록 |
invoice.payment_failed |
결제 실패 후 취소와 자발적 취소 분리 |
invoice.payment_succeeded |
취소 전 복구 또는 재개 흐름 반영 |
| event_id | 중복 webhook 처리 방지 |
| previous_attributes | 어떤 필드가 바뀌었는지 추적 |
| subscription_id | 취소와 재개를 같은 구독 흐름에 연결 |
| event created time | 취소 요청일과 처리일을 구분 |
운영 자동화는 webhook 도착 순서보다 billing 시스템의 최종 상태를 기준으로 계산해야 합니다. 취소 예약 이벤트 뒤 결제 성공 또는 고객 재개 이벤트가 들어오면 churn으로 확정하면 안 됩니다.
cancellation_reason은 고객 말과 운영 분류를 따로 둡니다
고객이 입력한 해지 사유는 중요하지만 그대로 경영 보고서의 최종 분류가 되면 위험합니다. Stripe API 기준으로는 일반적인 cancellation_reason이라는 단일 공식 필드가 아니라 cancellation_details.reason, cancellation_details.feedback, cancellation_details.comment 같은 취소 상세 필드를 확인해야 합니다. 고객은 "비싸다"라고 적었지만 실제로는 중복 도구 정리일 수 있고, "안 씀"이라고 적었지만 billing owner 퇴사로 결제가 막힌 경우일 수 있습니다.
| 원천 | 저장 예시 | 용도 |
|---|---|---|
| customer_selected_reason | too_expensive, missing_feature, not_using, switched_tool | 고객의 직접 입력 |
| customer_comment | 자유 입력 텍스트 | CS/PM 검토 참고 |
| system_reason | payment_failed, trial_expired, admin_left, duplicate_workspace | 시스템이 본 원인 후보 |
| owner_reason | budget_cut, no_adoption, competitor, security_blocker | 담당자가 검토한 운영 분류 |
| final_churn_reason | pricing, adoption, feature_gap, billing_issue, consolidation | 보고서용 최종 분류 |
| reason_confidence | customer_only, system_match, owner_reviewed | 신뢰도 표시 |
자유 입력 텍스트에는 개인정보나 민감한 회사 내부 사정이 들어갈 수 있습니다. 분석 도구에는 원문 comment를 그대로 보내지 말고, 제한된 사유 코드와 내부 ID만 보내는 편이 안전합니다.
제품 사용량 하락과 취소 사유를 같이 보되 같은 값으로 만들지 않습니다
구독 취소 전에는 보통 사용량 하락, 핵심 기능 미사용, 팀 초대 실패, 연동 미완료 같은 신호가 먼저 나타납니다. 하지만 사용량 하락이 곧 churn reason은 아닙니다. 제품 사용 이벤트는 사유를 추정하는 보조 신호로 둬야 합니다.
| 제품 신호 | 확인할 질문 |
|---|---|
| active_user_14d | 최근 14일 활성 사용자가 급감했는가 |
| core_action_count | 제품의 핵심 행동이 줄었는가 |
| integration_connected | CRM, Slack, Google Workspace 같은 핵심 연동이 실패했는가 |
| admin_login_recent | workspace admin이 최근 로그인했는가 |
| seat_utilization | 구매 좌석 대비 실제 사용 좌석이 낮은가 |
| support_ticket_recent | 해지 전 장애 또는 billing 문의가 있었는가 |
| onboarding_completed | 도입 체크리스트가 끝났는가 |
제품 사용량은 customer success가 먼저 볼 수 있는 조기 신호입니다. 다만 보고서에서는 usage_drop_before_cancel처럼 보조 지표로 남기고, 최종 churn reason은 고객 입력, 시스템 상태, 담당자 검토를 함께 보고 정해야 합니다.
CRM lifecycle은 churn과 billing 상태를 분리해서 저장합니다
CRM에서 고객 상태를 lost로 바꾸는 순간은 billing 취소와 다를 수 있습니다. self-serve 구독은 취소됐지만 enterprise opportunity로 전환 중일 수 있고, 한 workspace는 닫혔지만 회사 계정은 여전히 customer일 수 있습니다.
출처: HubSpot Knowledge Base – Use lifecycle stages
출처: HubSpot Knowledge Base – HubSpot default contact properties
출처: Adobe Marketo Engage Docs – Create a custom field in Marketo
| CRM 필드 | 예시 값 |
|---|---|
| lifecycle_stage | lead, opportunity, customer, former_customer |
| billing_status | active, cancel_scheduled, canceled, past_due |
| churn_status | at_risk, cancel_requested, saved, churned, migrated |
| churn_reason_final | pricing, low_usage, missing_feature, billing_issue |
| effective_churn_at | 보고서에서 이탈로 반영할 기준일 |
| account_owner_action | none, cs_followup, sales_save, finance_review |
| winback_eligible | true, false, manual_review |
| product_access_status | full, read_only, ended |
CRM에는 모든 webhook 이벤트를 넣기보다 담당자가 다음 행동을 정할 수 있는 요약 필드만 보내는 편이 관리하기 쉽습니다. 원본 subscription, invoice, event log는 billing 시스템이나 데이터 웨어하우스에 남겨야 합니다.
GA4에는 해지를 매출 이벤트처럼 보내지 않습니다
GA4에 취소와 재참여 이벤트를 보낼 수는 있지만, paid conversion이나 매출 이벤트와 같은 구조로 보내면 안 됩니다. 광고 최적화 이벤트에 섞이면 실제 유료 전환과 이탈 분석이 뒤엉킬 수 있습니다.
출처: Google Analytics Help – Events and key events
출처: Google for Developers – GA4 event reference
출처: Google Tag Manager Help – Custom event trigger
아래 이벤트명은 내부 분석 이벤트 예시입니다. Stripe webhook 공식 이벤트명과 섞어 쓰면 안 되고, GTM에서는 필요한 경우 dataLayer custom event로 따로 설계해야 합니다.
| GA4 이벤트 | 권장 역할 |
|---|---|
cancel_flow_started |
취소 화면 진입 분석 |
cancel_reason_selected |
제한된 사유 코드 분석 |
cancel_at_period_end_set |
갱신 중단 예약 상태 |
subscription_canceled |
실제 종료 후보 |
save_offer_viewed |
retention offer 노출 분석 |
save_offer_accepted |
취소 방어 후보 |
subscription_reactivated |
재개 또는 win-back 후보 |
churn_confirmed |
내부 기준에 따른 확정 이탈 |
이 이벤트들은 광고 성과를 키우는 이벤트가 아니라 병목을 설명하는 이벤트입니다. 주요 이벤트로 지정할지 여부는 내부 분석 목적과 광고 계정 연결 구조를 확인한 뒤 제한적으로 정해야 합니다.
Measurement Protocol은 서버 기준 취소 이벤트에만 제한적으로 씁니다
취소 예약, 실제 종료, 재개, win-back은 서버에서 발생하거나 billing webhook을 통해 확정되는 경우가 많습니다. GA4 Measurement Protocol을 쓰면 서버 이벤트를 보낼 수 있지만, 중복 제거와 개인정보 제외 기준을 먼저 확인해야 합니다.
출처: Google for Developers – GA4 Measurement Protocol
| 확인 항목 | 감사 질문 |
|---|---|
| event_id | 같은 취소 이벤트가 중복 전송되지 않는가 |
| account_id | 개인 사용자보다 회사 계정 기준으로 묶을 수 있는가 |
| timestamp_micros | 취소 요청 시점과 전송 시점을 구분하는가 |
| subscription_id | 내부 분석용 ID만 보내고 민감 정보는 제외하는가 |
| reason_code | 자유 입력 comment 대신 제한된 코드만 보내는가 |
| reactivation 흐름 | 재개 이벤트가 기존 churn을 닫는가 |
| consent 기준 | 회사의 데이터 처리 기준에 맞는가 |
서버 이벤트는 정확도를 높일 수 있지만, 이메일, 카드 정보, 청구 주소, 고객의 자유 입력 해지 comment를 분석 도구로 보내면 안 됩니다. 필요한 최소 ID와 상태값만 보내는 구조가 좋습니다.
save offer와 win-back을 churn 방어 숫자로만 보지 않습니다
취소 화면에서 할인, 플랜 다운그레이드, pause, 담당자 상담을 제안할 수 있습니다. 다만 이 숫자를 단순히 "이탈 방어 성공"으로만 보면 장기 품질을 놓칩니다. 할인 수락 후 다시 취소하는 고객, 다운그레이드 후 사용이 멈춘 고객, 상담 예약만 하고 이탈한 고객을 나눠야 합니다.
| 흐름 | 확인할 기준 |
|---|---|
| save_offer_viewed | 어떤 제안을 봤는가 |
| save_offer_accepted | 수락했지만 실제 취소가 막혔는가 |
| downgrade_selected | 매출 감소와 유지 고객을 분리했는가 |
| pause_requested | 일시 중단과 churn을 분리했는가 |
| sales_callback_requested | 상담 요청 후 실제 연락이 됐는가 |
| reactivated_within_30d | 취소 뒤 30일 내 재개했는가 |
| churned_after_save | 방어 후 다시 이탈했는가 |
win-back 보고서는 마케팅 성과 보고서와도 연결될 수 있습니다. 하지만 재가입이 신규 고객처럼 잡히면 CAC, LTV, churn 지표가 모두 흔들립니다. 기존 account_id와 subscription 이력을 기준으로 재개인지 신규인지 분리해야 합니다.
churn 지표는 logo, seat, MRR을 분리합니다
B2B SaaS에서는 이탈을 하나의 숫자로만 보면 안 됩니다. 한 회사가 완전히 떠났는지, 일부 workspace만 닫혔는지, 좌석을 줄였는지, 플랜을 낮췄는지에 따라 액션이 달라집니다.
| 지표 | 정의 예시 |
|---|---|
| logo_churn | 회사 또는 account 단위 완전 이탈 |
| workspace_churn | 특정 workspace 또는 product instance 종료 |
| seat_churn | 좌석 수 감소 |
| gross_mrr_churn | 확장·재개를 빼고 본 MRR 감소 |
| net_mrr_churn | 확장·재개를 반영한 순 MRR 변화 |
| voluntary_churn | 고객이 직접 취소한 이탈 |
| involuntary_churn | 결제 실패 등 비자발적 이탈 |
| contraction | 이탈은 아니지만 플랜 또는 좌석 축소 |
이 글은 매출 인식 기준을 정하는 글이 아닙니다. 운영 보고서에서 어떤 상태를 어떤 이름으로 부를지 먼저 고정해야, CS와 마케팅이 같은 숫자를 보고 움직일 수 있다는 뜻입니다.
취소 후 접근 종료와 데이터 보존 안내를 분리합니다
구독이 취소돼도 고객 데이터가 언제까지 보존되는지, export가 가능한지, 관리자 접근이 남는지, 재가입 시 복구되는지에 대한 안내가 필요합니다. 이 부분은 약관과 보안 정책에 연결되므로 운영 데이터와 고객 안내가 어긋나면 안 됩니다.
| 운영 항목 | 확인할 질문 |
|---|---|
| access_end_at | 제품 접근 종료 시점이 billing 종료일과 맞는가 |
| export_deadline | 데이터 내보내기 가능 기간을 안내하는가 |
| admin_access | 취소 후 관리자 접근 범위가 정해졌는가 |
| reactivation_window | 재개 가능한 기간과 조건을 분리했는가 |
| deletion_policy | 삭제 요청, 보존 기간, 백업 정책 안내가 있는가 |
| support_route | 취소 후 문의 경로가 남아 있는가 |
고객 안내 문구에는 "언제부터 무엇이 달라지는지"를 명확히 적어야 합니다. 다만 실제 보존 기간이나 계약상 의무는 회사 정책과 법무 검토 영역이므로, 자동화 문구를 임의로 단정하면 안 됩니다.
최종 점검 체크리스트
공개 전 또는 대시보드 연결 전에는 아래 항목을 최소 기준으로 확인합니다.
cancel_requested,cancel_at_period_end,canceled,reactivated를 한 이벤트로 뭉치지 않았는가- Stripe subscription 상태와 제품 접근 상태를 분리했는가
- 결제 실패 후 취소와 자발적 해지를 분리했는가
- cancellation reason은 고객 입력, 시스템 추정, 담당자 검토, 최종 보고용 분류를 따로 저장하는가
- 자유 입력 해지 comment를 GA4, 광고 도구, 외부 자동화에 그대로 보내지 않는가
- CRM에는 원본 이벤트 전부가 아니라 담당자 행동에 필요한 요약 필드만 보내는가
- GA4 이벤트는 paid conversion, churn 분석, win-back 분석을 분리해서 설계했는가
- Measurement Protocol에는 개인정보와 결제 민감 정보를 보내지 않는가
- logo churn, seat churn, MRR churn, contraction, migration을 구분했는가
- 취소 후 데이터 보존, export, 접근 종료 안내가 billing 상태와 맞는가
다음 후보
다음으로는 B2B SaaS 환불·크레딧·부분 취소 추적 감사 체크리스트 2026을 볼 만합니다. 구독 취소 다음에는 refund, credit note, prorated invoice, downgrade credit, manual adjustment가 매출 보고서와 광고 성과에 섞이기 쉽기 때문입니다. 다만 회계·세무 판단은 피하고, 운영 이벤트와 보고서 분리 기준으로만 다루는 편이 안전합니다.