B2B SaaS 결제 공급사 장애 대응 체크리스트 2026: webhook 지연·중복·상태 대사 복구
B2B SaaS 결제 공급사 장애 대응 체크리스트 2026: webhook 지연·중복·상태 대사 복구
B2B SaaS 결제 공급사 장애가 발생하면 가장 위험한 대응은 실패한 요청을 무제한으로 다시 보내는 것입니다. 결제 API가 느리다고 checkout·invoice·refund·webhook worker가 동시에 retry를 늘리면 공급사가 복구되는 순간 같은 업무가 여러 번 실행될 수 있습니다. 고객에게는 결제가 실패한 것처럼 보였지만 실제로는 승인됐을 수도 있고, 운영팀이 수동 환불한 뒤 자동화가 다시 환불을 시도할 수도 있습니다.
따라서 장애 대응의 목표는 단순히 queue를 비우는 것이 아닙니다. 신규 action을 안전하게 제한하고, 공급사 원문 상태를 다시 확인하고, 중복 없이 한 번만 후속 처리한 뒤 invoice부터 payout까지 대사하는 것입니다.
이 글은 Stripe, Paddle, Chargebee, Recurly의 공식 status와 webhook 문서를 기준으로 다음 네 가지를 다룹니다.
- 공급사 장애와 내부 연동 장애를 구분하는 방법
- webhook 지연·중복·순서 역전을 견디는 상태 모델
- 자동 retry 폭주와 중복 청구·환불을 막는 incident runbook
- 복구 뒤 transaction·invoice·subscription·payout 정합성을 검증하는 방법
이 문서는 운영 통제와 서비스 복구를 위한 일반 체크리스트입니다. 특정 공급사의 가용성이나 복구 시간을 보장하지 않으며, 법률·회계·세무 판단을 제공하지 않습니다. 계정별 기능, webhook 동작, 지원 범위는 계약과 현재 설정에 따라 달라질 수 있으므로 2026년 7월 17일 확인한 공식 문서와 실제 계정 화면을 함께 봐야 합니다.
결제 전 위험 판단은 B2B SaaS 결제 부정사용 방지 비교로 분리합니다. 장애 중 분쟁과 차지백이 접수됐다면 B2B SaaS 결제 분쟁·차지백 운영 체크리스트를 연결하고, 복구 뒤 금액 검증은 B2B SaaS 구독 청구 월말 대사 체크리스트에서 이어갑니다. 공급사 변경이나 이전이 필요하다면 B2B SaaS 구독 청구 플랫폼 이전 체크리스트의 mapping·dual run·rollback 기준을 적용합니다. 정상적인 결제 실패와 재시도는 B2B SaaS 결제 실패·dunning 자동화 체크리스트로 분리해야 합니다.
먼저 결론: 장애 중에는 더 많이 실행하지 말고 더 정확히 확인합니다
공급사 장애 runbook은 다음 순서를 지켜야 합니다.
[탐지·영향 범위 확인]
↓
[고위험 쓰기·자동 retry 제한]
↓
[webhook 원문과 action 요청 보존]
↓
[공급사 status/API로 최종 상태 재조회]
↓
[멱등한 replay와 정합성 복구]
↓
[invoice·refund·payout 대사]
↓
[고객 영향 확인·사후 회고]
HTTP timeout = 결제 실패로 확정하면 안 됩니다. 응답을 받지 못했어도 공급사에서는 transaction이 생성됐을 수 있습니다. 반대로 webhook을 받았다는 사실만으로 내부 invoice·subscription·entitlement가 모두 갱신됐다고 단정할 수도 없습니다.
장애 중 action의 기본 원칙은 세 가지입니다.
- 결제·환불·취소 같은 쓰기는 안정적인 idempotency key와 내부 action ID가 없으면 자동 재시도하지 않습니다.
- 고객 권한이나 CRM 상태를 바꾸기 전에 공급사의 현재 객체 상태를 다시 조회합니다.
- webhook 수신 성공, 내부 업무 완료, 금액 대사 완료를 서로 다른 상태로 기록합니다.
1단계: 공급사 장애와 내부 장애를 분리합니다
checkout 오류가 늘었다고 곧바로 공급사 전체 장애라고 단정하지 않습니다. 배포 직후의 API credential 오류, DNS·network 문제, webhook endpoint의 5xx, worker backlog, database lock, 특정 결제수단 문제도 비슷하게 보일 수 있습니다.
| 확인 계층 | 확인할 증거 | 장애 범위 질문 |
|---|---|---|
| 고객 화면 | checkout 오류율, 응답 시간, 영향을 받은 지역·결제수단 | 모든 고객인가, 특정 경로인가 |
| 내부 API client | endpoint, status code, timeout, request ID, 배포 버전 | 읽기와 쓰기 모두 실패하는가 |
| webhook ingress | 수신 시각, event ID, 서명 검증 결과, 응답 코드 | 공급사가 보내지 못한 것인가, 우리가 처리하지 못한 것인가 |
| worker·queue | backlog, oldest age, retry count, dead letter | 단순 지연인가, 반복 실패인가 |
| 공급사 원문 | dashboard transaction, invoice, refund, subscription 상태 | 요청이 실제로 생성됐는가 |
| 공식 status | incident component, 시작·업데이트 시각 | 공개된 공급사 incident와 범위가 일치하는가 |
Stripe Status, Paddle Status, Chargebee Status, Recurly Status를 확인하되 status page 하나만으로 내부 영향 범위를 확정하지 않습니다. 공개 incident가 없어도 특정 계정·지역·결제수단만 영향을 받을 수 있고, 공개 incident가 있어도 내부 오류의 원인이 별도일 수 있습니다.
incident record에는 최소 incident_id, detected_at, provider, affected_endpoints, payment_methods, regions, first_bad_event, last_known_good, internal_deploy_version, provider_status_url, incident_owner를 남깁니다. 추측을 사실처럼 쓰지 않고 confirmed, suspected, unknown을 구분합니다.
2단계: 초기 대응에서 자동화의 폭주 지점을 제한합니다
초기 대응에서 모든 시스템을 끄는 것은 과도할 수 있지만, 아무 제한 없이 retry를 계속하는 것도 위험합니다. 업무별로 계속할 읽기와 제한할 쓰기를 나눕니다.
| 업무 | 초기 기본값 | 재개 전 조건 |
|---|---|---|
| provider status·객체 조회 | 낮은 빈도로 계속 | rate limit과 응답 안정성 확인 |
| 신규 checkout | 영향 범위에 따라 안내·제한 | 실제 승인 결과를 추적할 키가 있음 |
| invoice 생성·확정 | queue 보관 또는 제한 | 중복 invoice 방지 키와 원문 상태 확인 |
| 자동 결제 retry | dunning scheduler와 별도로 일시 제한 | 공급사 incident 종료와 고객별 최종 상태 확인 |
| refund·void·cancel | 고위험 쓰기로 수동 승인 전환 | 원거래와 기존 action 상태 재조회 |
| entitlement 변경 | webhook 하나만 보고 실행하지 않음 | payment·subscription 최종 상태 확인 |
| 고객 이메일·CRM task | 중복 생성 제한 | 동일 사건의 notification key 확인 |
retry 제한은 단순 on/off가 아닙니다. endpoint별 concurrency, exponential backoff, jitter, 최대 시도 횟수, circuit breaker, queue 소비율을 조정할 수 있어야 합니다. 결제·환불 같은 쓰기를 재시도할 때는 Stripe의 idempotent requests 공식 문서처럼 해당 공급사가 제공하는 멱등 처리 방식과 현재 API 동작을 먼저 확인합니다. 다만 장애 중에 처음 보는 정책을 즉석에서 production에 넣지 않도록 정상 시점에 설정과 rollback 절차를 미리 검증합니다.
자동 dunning은 정상적인 결제 실패를 회복하는 운영입니다. 공급사 장애 중 대량 실패를 평상시 dunning 정책으로 그대로 밀어 넣으면 고객 이메일과 결제 시도가 폭증할 수 있습니다. 장애 영향 건에는 별도 provider_incident_id를 붙이고 결제 실패·dunning 자동화 체크리스트의 일반 실패 queue와 구분합니다.
3단계: webhook은 알림이고 최종 원장은 아닙니다
Stripe webhooks 공식 문서는 webhook endpoint 구성, 이벤트 처리, 재전송과 관련된 기본 사항을 확인하는 출발점입니다. Paddle webhooks 공식 문서도 notification 수신과 검증 흐름을 설명합니다. Chargebee webhook 설정 문서와 Chargebee Webhooks API는 webhook 구성과 원문 기록을 확인할 공식 자료입니다. Recurly webhooks 문서에서는 Recurly notification 처리의 현재 범위를 확인할 수 있습니다.
공통 원칙은 webhook payload를 받은 순서대로 현재 상태를 덮어쓰지 않는 것입니다. 네트워크와 retry 때문에 이벤트가 늦게 오거나 중복될 수 있고, 내부 worker 처리 순서는 공급사 생성 순서와 다를 수 있습니다.
webhook inbox에는 최소 다음 필드를 보존합니다.
provider
provider_event_id
event_type
provider_object_id
provider_created_at
received_at
signature_verified
payload_checksum
processing_status
processing_attempts
last_error_code
related_internal_action_id
incident_id
원문 payload는 접근을 제한하고 보존 정책을 적용합니다. 카드 정보나 인증정보를 별도 로그·Slack·티켓에 복사하지 않습니다. 처리 worker는 provider + provider_event_id에 고유 제약을 두고, 중복 수신 시 새 업무를 생성하지 않아야 합니다.
webhook endpoint는 빨리 응답하고 업무는 분리합니다
Paddle의 webhook 응답 가이드는 endpoint가 notification에 응답하는 방식과 비동기 처리 설계의 공식 출발점입니다. 공급사마다 구체 동작은 다르지만 운영 구조는 다음처럼 나눌 수 있습니다.
[서명 검증 + 원문 저장 + 빠른 성공 응답]
↓
[durable internal queue]
↓
[현재 객체 재조회 + business action]
↓
[처리 결과 + 대사 evidence 저장]
webhook 요청 안에서 CRM, 이메일, entitlement, ERP 쓰기를 모두 끝내려 하면 한 downstream 장애가 공급사 재전송과 내부 중복 처리를 동시에 늘릴 수 있습니다. 응답과 업무 완료를 분리하되, queue 저장이 실패했는데 성공 응답을 보내는 구조도 피해야 합니다.
4단계: 지연·중복·순서 역전을 상태 모델로 흡수합니다
내부 레코드에 webhook_received=true 하나만 두면 복구할 수 없습니다. 공급사 원문 상태와 내부 workflow 상태를 분리합니다.
| 필드 | 예시 | 목적 |
|---|---|---|
provider_status |
succeeded, failed, refunded 등 원문 값 | 공급사 현재 상태 보존 |
provider_status_at |
공급사 객체의 갱신 시각 | 오래된 event 판단 보조 |
workflow_status |
pending_verify, action_blocked, reconciled | 내부 업무 진행 상태 |
last_event_id |
공급사 event ID | 처리 근거 연결 |
last_retrieved_at |
API 재조회 시각 | webhook과 조회 상태 구분 |
internal_action_id |
pay, refund, cancel 업무 ID | 같은 업무의 중복 실행 방지 |
reconciliation_status |
open, matched, exception | 금액 대사 상태 분리 |
이벤트 시각만 비교해서 새 event를 무조건 정답으로 만들지 않습니다. event type마다 상태 전이가 다르고, 서로 다른 객체의 이벤트가 독립적으로 올 수 있습니다. 중요한 action 직전에는 payment·transaction·invoice·subscription·refund 중 필요한 공급사 객체를 다시 조회하고 허용된 상태 전이인지 검사합니다.
예를 들어 payment succeeded와 subscription updated가 모두 필요하다면 먼저 도착한 webhook 하나로 entitlement를 두 번 변경하지 않습니다. account별 state machine이 두 조건과 현재 entitlement를 확인한 뒤 같은 internal_action_id에는 한 번만 쓰도록 합니다.
5단계: Stripe 미전달 이벤트는 목록을 기준으로 복구합니다
Stripe의 미전달 webhook 처리 문서는 미전달 이벤트를 조회하고 처리할 때 확인할 공식 절차를 제공합니다. 장애 복구 때 단순히 endpoint를 다시 열고 기다리거나 모든 과거 event를 무차별 replay하지 않습니다.
Stripe 복구 작업에는 다음 항목을 포함합니다.
- 장애 시작 전 마지막 정상 event와 복구 시각을 고정합니다.
- 해당 기간과 endpoint의 미전달 event 범위를 확인합니다.
- event ID가 이미 내부 inbox에 있는지 검사합니다.
- 관련 Stripe 객체의 현재 상태를 다시 조회합니다.
- 아직 필요한 내부 action만 idempotent handler로 실행합니다.
- 처리 결과와 event ID, object ID, 조회 시각을 기록합니다.
- 자동 재전송과 수동 처리 경로가 겹쳐도 업무가 한 번만 실행되는지 확인합니다.
수동 resend를 했다는 이유로 처리 완료로 표시하지 않습니다. Stripe가 event를 보냈는지, endpoint가 받았는지, 내부 queue가 처리했는지, 최종 객체가 맞는지는 서로 다른 검증입니다.
6단계: Paddle·Chargebee·Recurly도 공급사별 원문을 유지합니다
제품을 하나의 공통 billing_event 형식으로 정상화하더라도 공급사 원문 ID와 상태를 지우지 않습니다.
Paddle
Paddle은 Merchant of Record 구조를 사용하는 경우가 있으므로 transaction·subscription·adjustment와 내부 order·account를 연결하는 키를 먼저 확인합니다. Paddle notification을 받지 못했거나 늦게 받았을 때 내부 상태만으로 환불·취소를 재실행하지 않습니다. Paddle webhooks 문서와 현재 계정의 transaction 상태, Paddle Status를 함께 확인합니다.
Chargebee
Chargebee는 billing 상태와 실제 payment gateway 상태가 다를 수 있습니다. Chargebee invoice·transaction·subscription ID와 gateway payment ID를 함께 보존합니다. Chargebee webhook 설정, Webhooks API, Chargebee Status를 기준으로 수신·설정·현재 객체 상태를 각각 확인합니다. gateway 장애라면 Chargebee 상태만 보고 결제 성공·실패를 확정하지 않습니다.
Recurly
Recurly webhooks 문서와 Recurly Status를 현재 계정 구성과 함께 봅니다. 이 글에서는 확인되지 않은 재시도 횟수나 주기를 고정값으로 제시하지 않습니다. Recurly account·invoice·transaction·subscription 원문 상태와 내부 처리 이력을 연결하고, 현재 지원 동작은 계정 문서와 지원 경로로 다시 확인합니다.
7단계: 중복 청구·환불·취소를 action ledger로 막습니다
webhook event의 중복 제거만으로는 충분하지 않습니다. 서로 다른 event가 같은 환불 업무를 촉발할 수 있고, 사람과 자동화가 동시에 같은 action을 실행할 수도 있습니다. 별도의 action ledger가 필요합니다.
internal_action_id
action_type
provider
provider_object_id
business_reason
requested_amount
currency
idempotency_key
requested_by
approved_by
request_status
provider_action_id
provider_status_before
provider_status_after
verified_at
incident_id
중복 방지 키는 업무 의미를 반영해야 합니다. 단순 timestamp나 worker 실행 번호를 키로 쓰면 재시도마다 새 action이 됩니다. 예를 들어 하나의 dispute case에 대한 승인된 환불이라면 내부 case ID, 원거래 ID, action type, 승인 버전을 조합해 같은 결정이 다시 실행되지 않게 합니다.
환불·void·cancel 전에는 다음을 확인합니다.
- 원거래가 실제로 생성·승인됐는가.
- 이미 전액 또는 일부 환불됐는가.
- dispute나 chargeback이 진행 중인가.
- 다른 운영자가 같은 action을 승인·실행했는가.
- 고객에게 약속한 금액·통화와 일치하는가.
- action 뒤 invoice·subscription·entitlement에 필요한 후속 처리는 무엇인가.
분쟁과 환불이 겹친 거래는 결제 분쟁·차지백 운영 체크리스트의 case ID와 evidence를 연결합니다. 장애를 이유로 환불과 차지백 상태를 하나로 합치지 않습니다.
8단계: 복구는 canary → 제한 replay → 전체 대사 순서로 진행합니다
공급사 status가 resolved로 바뀌었다고 즉시 전체 queue를 최대 속도로 소비하지 않습니다. status update는 복구의 신호이지 내부 정합성 완료 증거가 아닙니다.
1. canary 확인
영향이 낮고 추적 가능한 소수의 조회·처리로 API 응답, webhook ingress, queue, database, downstream action이 정상인지 확인합니다. 실제 고객 결제나 환불을 테스트 수단처럼 반복하지 않습니다.
2. 제한된 replay
시간 구간·event type·공급사 객체별로 작은 batch를 처리합니다. batch마다 중복 skip, 상태 충돌, API error, 처리 latency, downstream action 건수를 확인합니다.
3. final-state reconciliation
처리한 event 수가 아니라 공급사 객체와 내부 객체의 최종 상태가 맞는지 비교합니다. event가 여러 번 왔어도 transaction 하나는 한 번만 집계합니다.
4. 금액 대사
결제·환불·credit·dispute·fee·payout을 원거래 ID에서 은행 reference까지 연결합니다. 자세한 ledger와 cutoff 기준은 구독 청구 월말 대사 체크리스트를 적용합니다.
5. 고객 영향 복구
결제는 성공했지만 권한이 열리지 않은 고객, 실패했는데 성공 안내를 받은 고객, 이메일이 중복 발송된 고객, invoice가 중복 생성된 고객을 별도 queue로 만듭니다. 자동 보상이나 무조건 환불을 실행하지 않고 회사 정책과 승인 절차에 따라 처리합니다.
9단계: 정합성 대사 표를 공급사 객체별로 만듭니다
복구 완료 판단은 다음 control total과 예외 queue로 합니다.
| 대사 대상 | 비교할 값 | 대표 예외 |
|---|---|---|
| checkout/request | 내부 action ID ↔ provider transaction ID | timeout 뒤 실제 승인 |
| payment | amount, currency, final status | 내부 failed, provider succeeded |
| invoice | invoice ID, total, paid status | 중복 invoice, payment 미연결 |
| subscription | plan, status, period end | payment 복구 후 상태 미반영 |
| refund·void | 원거래, action ID, amount, final status | 수동·자동 중복 실행 |
| entitlement | account, access state, source payment | 성공 결제 후 권한 미부여 |
| notification | template, recipient, notification key | 동일 장애 안내 중복 발송 |
| payout | balance transaction, fee, net, payout ID | 복구 거래가 다른 기간에 반영 |
예외 queue에는 exception_id, provider_object_id, internal_object_id, expected_state, observed_state, amount, currency, owner, due_at, evidence_url, resolution, verified_at을 둡니다. 미해결 건을 평균 성공률 안에 숨기지 않습니다.
10단계: 고객 안내와 내부 커뮤니케이션을 분리합니다
내부 incident channel에는 확인된 영향 범위, 일시 제한한 자동화, queue 크기, 다음 업데이트 시각, owner를 공유합니다. 고객 안내에는 내부 상세 설정이나 추측을 넣지 않고 고객이 해야 할 행동과 중복 결제 여부 확인 경로를 명확히 씁니다.
고객에게 반복 결제를 권하기 전에는 다음을 확인합니다.
- 첫 요청이 공급사에서 생성됐는지 조회할 수 있는가.
- 같은 cart·invoice·account에 두 번째 transaction이 생길 수 있는가.
- pending 상태가 언제까지 유지될 수 있는지 공식 근거가 있는가.
- 지원팀이 고객의 원거래 ID를 안전하게 찾을 수 있는가.
- 중복이 확인되면 누가 어떤 승인 절차로 처리하는가.
결제 공급사 문제로 모두 실패했습니다처럼 범위를 과장하지 않습니다. 일부 카드 결제의 완료 확인이 지연되고 있으며, 반복 결제 전에 주문 상태를 확인해 달라처럼 현재 확인된 사실과 고객 행동을 분리합니다. 정상화 뒤에도 원인 분석이 끝나지 않았다면 복구 사실과 원인 조사 상태를 구분합니다.
11단계: 장애 훈련은 실패 코드보다 운영 경계를 검증합니다
production에서 실제 장애를 만들어 시험하지 않습니다. 공급사가 제공하는 sandbox·test mode와 내부 staging에서 다음 시나리오를 검증합니다.
- API timeout 뒤 공급사에는 transaction이 생성된 경우
- 같은 webhook event가 여러 번 도착한 경우
- 오래된 event가 최신 event 뒤에 처리된 경우
- webhook endpoint는 성공했지만 downstream worker가 실패한 경우
- 수동 환불과 자동 환불 workflow가 동시에 시작된 경우
- invoice는 paid지만 entitlement가 pending인 경우
- provider status는 resolved지만 queue backlog가 남은 경우
- replay 중 rate limit 또는 부분 실패가 다시 발생한 경우
- payment와 refund가 서로 다른 월의 payout에 반영된 경우
- primary 담당자 부재 시 backup이 승인·중단·복구할 수 있는 경우
훈련 결과에는 scenario, expected_state, observed_state, configuration_version, event_id, action_id, evidence, gap, owner, due_date를 남깁니다. 실제 공격 방법이나 회피 가능한 보안 규칙은 문서화하지 않습니다.
장애 지표는 처리량보다 안전한 복구를 측정합니다
| 지표 | 목적 | 주의점 |
|---|---|---|
| time to detect | 고객 문의 전 탐지 능력 확인 | 공급사 status 게시 시각과 혼동하지 않음 |
| time to contain | 고위험 retry·write 제한 시간 | 전체 시스템 중단 시간과 구분 |
| oldest webhook age | backlog의 가장 오래된 event 확인 | 평균 age만 보면 장기 누락이 숨음 |
| duplicate event rate | 공급사 재전송·내부 중복 관찰 | 중복 action 건수와 별도 집계 |
| state mismatch count | provider와 내부 상태 충돌 확인 | 처리 event 수로 대체하지 않음 |
| duplicate action count | 결제·환불·알림의 실제 중복 검증 | 0을 목표로 하되 탐지 누락도 점검 |
| customer impact count | 권한·invoice·안내 오류 확인 | 문의 건수만으로 전체 영향 단정 금지 |
| unreconciled amount | 금액 예외의 규모와 통화 확인 | 서로 다른 통화를 바로 합산하지 않음 |
| time to reconcile | 최종 대사 완료 시간 | provider resolved 시각과 구분 |
팀별 RACI와 승인 경계를 미리 정합니다
| 업무 | 실행 책임 | 최종 책임 | 협의 | 통보 |
|---|---|---|---|---|
| incident 선언·범위 설정 | on-call·payments ops | incident commander | vendor support, engineering | support, finance |
| retry·circuit breaker 조정 | engineering | system owner | payments, SRE | support |
| refund·void·cancel 승인 | payments 지정 담당자 | 회사 정책상 승인자 | finance, support | account owner |
| webhook replay | engineering | integration owner | payments | incident commander |
| 상태 대사 | billing operations | payments owner | engineering | finance, support |
| payout·bank 대사 | finance operations | finance owner | payments | RevOps |
| 고객 안내 | support·communications | incident commander | legal·privacy 필요 시 | account team |
| 사후 회고·개선 | incident owner | system owner | 관련 전 팀 | 경영진 필요 시 |
팀 이름만 쓰지 말고 primary와 backup을 지정합니다. 야간·휴일 승인권자, 공급사 지원 escalation 경로, 자동화 중단 권한, 환불 금액별 승인 정책은 장애 전에 정해야 합니다.
최종 체크리스트
장애 종료를 선언하기 전에 다음 항목을 확인합니다.
- 공급사 장애와 내부 배포·network·worker 문제를 분리했습니다.
- 공식 status URL과 incident 업데이트 시각을 evidence에 남겼습니다.
- 영향받은 endpoint·지역·결제수단·고객 범위를 확인했습니다.
- timeout을 결제 실패로 자동 확정하지 않습니다.
- 결제·invoice·refund·cancel의 자동 retry 폭주를 제한했습니다.
- 정상 dunning과 공급사 장애 실패 건을 분리했습니다.
- webhook endpoint의 서명 검증과 원문 저장을 확인했습니다.
- provider event ID에 고유 제약이 있습니다.
- webhook 응답과 downstream 업무 완료를 분리했습니다.
- 공급사 원문 상태와 내부 workflow 상태를 별도로 저장합니다.
- 중요한 action 직전 공급사 객체의 현재 상태를 재조회합니다.
- 오래된 event가 최신 상태를 덮어쓰지 않게 상태 전이를 검증합니다.
- 결제·환불·취소에 내부 action ID와 idempotency key가 있습니다.
- 사람과 자동화가 같은 환불을 실행하지 않도록 action ledger를 확인합니다.
- 이미 refund·void·dispute된 거래에서 충돌 action을 멈춥니다.
- replay 범위를 시간·event type·object로 제한했습니다.
- canary batch를 검증한 뒤 queue 소비율을 늘렸습니다.
- 자동 재전송과 수동 replay가 겹쳐도 업무는 한 번만 실행됩니다.
- provider status
resolved와 내부 복구 완료를 구분했습니다. - payment·invoice·subscription·entitlement 상태를 대사했습니다.
- refund·credit·dispute·fee·payout 금액을 대사했습니다.
- 중복 invoice·알림·CRM task가 없는지 확인했습니다.
- 고객 영향 예외에 owner와 due date가 있습니다.
- 미해결 state mismatch와 미대사 금액을 별도 보고했습니다.
- 원문 payload와 민감정보의 접근·보존 정책을 지켰습니다.
- primary·backup 담당자와 승인 경계가 작동했습니다.
- incident timeline, 설정 변경, 승인, rollback을 기록했습니다.
- 사후 회고의 개선 항목에 owner와 완료 기한이 있습니다.
공식 출처
아래 공식 자료를 2026년 7월 17일 기준으로 확인했습니다. 공급사의 webhook 재전송, API, status component와 계정별 지원 범위는 바뀔 수 있으므로 실제 장애 대응 전 현재 문서를 다시 확인합니다.
- Stripe Docs – Webhooks
- Stripe Docs – Process undelivered webhook events
- Stripe Docs – Idempotent requests
- Stripe Status
- Paddle Developer – Webhooks
- Paddle Developer – Respond to webhooks
- Paddle Status
- Chargebee Docs – Configuring webhooks
- Chargebee API – Webhooks
- Chargebee Status
- Recurly Docs – Webhooks
- Recurly Status
결론적으로 결제 공급사 장애 대응의 핵심은 실패 요청을 빨리 많이 재시도하는 데 있지 않습니다. 고위험 쓰기를 제한하고, webhook을 멱등하게 저장하고, 공급사 현재 상태를 재조회하고, 필요한 action만 한 번 실행한 뒤 금액과 고객 상태를 끝까지 대사하는 것이 안전한 복구의 기준입니다.