B2B SaaS 결제수단 업데이트·만료 카드 복구 체크리스트 2026, updater 결과와 다음 갱신 검증 기준
B2B SaaS 결제수단 업데이트·만료 카드 복구 체크리스트 2026, updater 결과와 다음 갱신 검증 기준
B2B SaaS에서 카드 만료는 payment_failed 하나로 끝나는 사건이 아닙니다. 만료된 결제수단을 발견한 시점, account updater가 돌려준 결과, 고객이 직접 결제수단을 바꿔야 하는지, 다음 갱신이 실제로 어떤 결제수단을 사용했는지를 분리해야 합니다.
이 글의 흐름은 네 단계입니다.
card expiry signal
→ account updater result
→ customer action required
→ next renewal verification
재시도·dunning 자동화, token vault migration, payout·settlement, PCI·법률 조언은 이 글의 범위가 아닙니다. 복구가 항상 성공한다고 가정하지도 않습니다. 운영팀이 해야 할 일은 각 단계의 결과와 다음 담당 행동을 같은 account_id·subscription_id에 연결하는 것입니다.
먼저 만료 카드의 기준일과 식별자를 고정합니다
카드의 exp_month와 exp_year만 보고 고객 상태를 바꾸면 월말과 timezone 경계에서 오판할 수 있습니다. 공급사 원문이 표시하는 상태와 내부 관찰 시각을 함께 남기십시오.
| 필드 | 기록할 값 | 확인 질문 |
|---|---|---|
account_id |
회사 또는 workspace 내부 ID | 개인 사용자와 법인 계정을 혼동하지 않는가 |
subscription_id |
공급사·내부 구독 ID | 같은 고객의 다른 구독과 섞이지 않는가 |
payment_method_ref |
provider 결제수단 ID | 카드번호 대신 재조회 가능한 참조값인가 |
expiry_month / expiry_year |
공급사 원문 또는 마스킹된 만료 정보 | 표시 기준 timezone을 기록했는가 |
expiry_observed_at |
만료를 관찰한 UTC 시각 | 데이터 수집 시각과 이벤트 시각을 구분하는가 |
billing_contact_ref |
현재 billing owner 참조 | 퇴사자나 제품 관리자와 혼동하지 않는가 |
next_renewal_at |
다음 갱신 예정 시각 | 계정·구독·가격 버전과 연결되는가 |
expiry_state |
expiring, expired, unknown 등 |
provider 원문과 내부 상태 매핑이 남는가 |
Stripe는 구독의 default_payment_method, customer 설정, invoice 설정이 결제수단 선택에 관여할 수 있다고 설명합니다. 따라서 “고객에게 카드가 하나 있다”는 사실보다 그 구독의 다음 invoice가 어떤 결제수단 참조를 우선하는가를 저장해야 합니다.
원문: Stripe Docs – Update payment method
원문: Stripe API Reference – Update a PaymentMethod
1단계: 만료 신호를 고객 조치로 바로 바꾸지 않습니다
만료를 관찰하면 먼저 expiry_detected 사건을 만듭니다. 이 사건은 고객이 새 카드를 입력했다는 뜻도 아니고, updater가 새 정보를 제공했다는 뜻도 아닙니다.
다음 네 가지를 분리해 기록하면 상태가 덜 흔들립니다.
| 상태 | 의미 | 다음 확인 |
|---|---|---|
expiring |
현재 결제수단의 만료가 임박했거나 provider가 예정 상태로 표시 | updater 대상과 예정 갱신일 연결 |
expired |
관찰 시각 기준 결제수단이 만료됨 | updater 조회 결과 수신 여부 |
not_current |
내부 표와 provider 원문이 다름 | 최신 payment-method 객체 재조회 |
unknown |
만료일 또는 결제수단 연결을 확인하지 못함 | 자동 완료하지 않고 owner 지정 |
expired를 기록한 행에는 source_event_id, 조회 시각, 원문 객체의 버전 또는 updated_at을 붙입니다. Chargebee의 Payment Sources API는 결제수단에 valid, expiring, expired, invalid 같은 상태를 제공하고, resource_version과 updated_at으로 변경 시점을 추적할 수 있게 합니다. 이 값은 내부의 “복구 완료” 플래그와 별개입니다.
원문: Chargebee API – Payment sources
2단계: account updater 결과를 다섯 가지로 정규화합니다
Account updater는 “업데이트됨” 또는 “실패” 두 값으로만 저장하기 어렵습니다. 만료일만 바뀐 경우, 카드번호가 바뀐 경우, 변경 없음, 계정 폐쇄, 고객 조치 필요가 각각 다음 단계가 다르기 때문입니다.
내부 공통 코드는 아래처럼 제한하는 편이 좋습니다.
| 내부 코드 | 의미 | 고객 조치 기본값 |
|---|---|---|
updater_updated_expiry |
만료일이 새 값으로 반영됨 | 즉시 입력 요청 없음. 다음 갱신 검증 예약 |
updater_updated_number |
새 카드 참조 또는 번호 변경 결과가 반영됨 | brand·인증 상태를 확인하고 필요 시 고객 재인증 요청 |
updater_no_change |
updater가 새 값을 주지 않음 | 안전한 결제수단 업데이트 경로 안내 검토 |
updater_closed_or_invalid |
카드 계정 폐쇄 또는 사용 불가 결과 | billing owner의 새 결제수단 입력 필요 |
updater_unknown |
요청은 만들었지만 결과 증거를 확인하지 못함 | 자동 완료 금지, 담당자와 재조회 시각 지정 |
Recurly는 Account Updater가 Visa, Mastercard, American Express, Discover의 카드 업데이트 프로그램과 연결되며, Updated expiration date, Updated card number, Credit card account closed 같은 결과를 구분한다고 설명합니다. 또한 결과마다 Update Billing Info webhook이 발생하고, 일부 구독은 갱신 전에 결제수단 정보를 확인합니다. 이때 중요한 것은 Recurly의 서비스가 돌았다는 로그와 내부 시스템이 그 결과를 올바른 account_id·subscription_id에 반영했다는 사실을 따로 남기는 것입니다.
원문: Recurly Docs – Account updater
Stripe를 사용하는 팀은 provider의 결제수단을 바꾼 뒤 구독에 실제로 연결됐는지 확인해야 합니다. Stripe는 Dashboard에서 자동 청구 구독에 일회성 결제수단 업데이트 링크를 만들 수 있고, API에서는 customer 또는 subscription의 결제수단 참조를 갱신할 수 있다고 안내합니다. 링크를 만들었다는 이벤트를 customer_action_completed로 집계하지 말고, 고객 입력이 저장된 결과와 분리하십시오.
원문: Stripe API Reference – Update a subscription
3단계: 고객 조치 필요 여부를 명시합니다
운영자가 고객에게 연락할지 여부는 updater 결과만으로 결정하지 말고, 새 결제수단이 어느 구독에 연결됐는지까지 확인한 뒤 정합니다.
| 판정 | 고객에게 필요한 조치 | 내부 완료 조건 |
|---|---|---|
not_required |
자동 업데이트 사실을 별도 입력 없이 기록 | 새 만료일과 payment-method 참조가 구독에 매핑됨 |
required_update |
billing portal 또는 provider가 발급한 결제수단 업데이트 경로에서 새 카드 입력 | 고객 입력 완료 이벤트와 저장된 참조 확인 |
required_reauthenticate |
카드번호·brand 변경처럼 재인증이 필요한 경우 다시 인증 | 인증 결과와 새 결제수단 상태 확인 |
owner_followup |
billing owner 또는 고객 관리자에게 담당자 확인 요청 | 연락 시각, 결과, next action 기록 |
unknown |
고객에게 확정된 실패 문구를 보내기 전 상태 재조회 | source object와 updater 결과의 연결 확보 |
고객 안내에는 카드번호를 적지 않습니다. “결제수단 확인 필요”와 확인할 구독, 만료 또는 업데이트 관찰 시각, 안전한 업데이트 경로, 담당 부서 연락 방법 정도를 명확히 적습니다. 개인 사용자가 제품 관리자이고 법인카드 소유자는 재무 담당자인 B2B 환경에서는 두 역할을 구분해야 합니다.
Chargebee 고객 문서는 고객 화면에서 결제수단을 추가·변경할 수 있고 API 또는 hosted page를 사용할 수 있다고 설명합니다. 또 고객의 billing information과 카드의 billing 정보가 서로 자동으로 같은 값이 되지 않을 수 있다고 안내합니다. 따라서 고객이 주소나 청구 연락처만 수정한 사건을 카드 업데이트 완료로 집계하지 마십시오.
원문: Chargebee Docs – Managing customers
customer_opened만 있고 payment_method_saved가 없으면 고객 조치 완료가 아닙니다. 저장 이벤트가 있어도 다른 구독이나 다른 account에 연결됐다면 해당 갱신의 복구 증거로 사용할 수 없습니다.
4단계: 다음 갱신에서 실제 사용 결과를 검증합니다
updater 결과나 고객 입력이 확인된 시점에 사건을 닫지 마십시오. 최종 검증 기준은 다음 갱신 시점에 billing 시스템이 어떤 payment-method reference를 선택했고, invoice 또는 renewal 결과가 그 구독에 연결됐는지입니다.
| 검증 시점 | 확인할 값 | 통과 기준 |
|---|---|---|
| 갱신 전 | next_renewal_at, subscription의 default 결제수단 |
예정 구독과 새 결제수단 참조가 일치 |
| 갱신 생성 | invoice·renewal 객체 ID | 다른 account나 이전 구독으로 빠지지 않음 |
| 결제 처리 후 | 결제수단 참조, provider 상태, 결과 이벤트 | 사용된 참조가 검증 대상과 일치 |
| 고객 조치 후 | action event, 저장 시각, 담당자 | 고객 입력·provider 저장·내부 매핑이 연결됨 |
| 검증 종료 | next_renewal_verified_at, 판정 코드 |
원문 객체와 내부 레코드의 차이가 없음 |
Stripe는 subscription, customer, invoice 설정에 따라 결제수단 우선순위가 달라질 수 있다고 설명합니다. Recurly는 webhook을 실시간 알림으로 제공하지만, webhook만을 유일한 원장으로 사용하지 말고 API 응답과 함께 확인하라고 안내합니다. 따라서 다음 갱신 검증은 “webhook이 왔다”가 아니라 renewal_id와 provider 객체를 재조회한 결과를 기준으로 합니다.
원문: Stripe Docs – Subscription webhooks
다음 필드를 한 행으로 남기면 담당자가 updater와 갱신 결과를 혼동하기 어렵습니다: account_id, subscription_id, expired_observed_at, updater_result, customer_action, payment_method_ref_after, next_renewal_at, renewal_payment_method_ref, renewal_result, evidence_ref.
renewal_result=unknown이면 성공으로 닫지 않습니다. provider 이벤트가 지연됐거나 내부 매핑이 누락됐거나, updater 결과가 다른 결제수단에 적용됐을 수 있습니다. 원인을 모르는 행은 담당자와 다음 조회 시각을 유지해야 합니다.
기존 글과의 경계
이번 글은 만료 카드의 updater 결과와 다음 갱신 검증에만 초점을 둡니다. 결제 실패 뒤 흐름은 B2B SaaS 결제 실패·dunning 자동화 체크리스트, 토큰 이전은 결제 토큰 이전 체크리스트 2026, 정산금 예외는 B2B SaaS payout 예외 triage 체크리스트 2026에서 각각 별도 확인합니다. 이 글은 이미 존재하는 provider 결제수단 참조가 같은 구독에 연결됐는지만 확인합니다.
최종 체크리스트
- [ ] 만료 관찰 시각, account·subscription·payment-method 참조를 함께 저장했는가
- [ ]
expired와updater_unknown을 같은 상태로 처리하지 않았는가 - [ ] updater 결과를 만료일 변경, 결제수단 변경, 변경 없음, 폐쇄·무효, unknown으로 구분했는가
- [ ] update link 발급과 고객 입력 완료를 다른 이벤트로 저장했는가
- [ ] 고객 입력이 올바른 account·subscription에 매핑됐는가
- [ ] 자동 업데이트 결과에도 next renewal verification을 예약했는가
- [ ] 다음 갱신에서 실제 사용된 payment-method reference와 예정 참조를 비교했는가
- [ ] webhook 수신과 API 원문 재조회 결과를 구분했는가
- [ ]
renewal_result=unknown을 성공으로 닫지 않았는가 - [ ] 고객 카드번호 자체가 아니라 provider ID, 시간, 상태, evidence reference를 연결했는가
카드 만료 복구의 완료 기준은 “updater가 실행됐다”가 아닙니다. 어떤 결제수단이 어떤 구독에 연결됐고, 고객 조치가 필요했는지, 다음 갱신에서 같은 연결이 실제로 검증됐는지를 재현할 수 있어야 합니다. 이 네 단계가 분리되어 있으면 provider별 기능 차이가 있어도 운영팀은 동일한 체크리스트로 미해결 행을 찾을 수 있습니다.