LabHub

자본시장과 결제 · 청산·결제와 카드 승인 · 이론

승인과 매입 사이에서 돈이 새는 자리

LabHub 에서 이어서 보기

한 줄 요약

카드 결제는 승인과 매입이라는 두 사건으로 나뉘어 있고 그 사이에 몇 시간에서 며칠이 벌어지는데, 그 간격에서 매입 누락·부분 매입 잔액·멱등키 실패로 인한 이중 청구가 생긴다.

왜 이게 필요했나

PG(결제 대행)사에 들어가면 처음 받는 질문이 대개 이것입니다. "승인 건수랑 매입 건수가 왜 다르죠?"

다른 것이 정상입니다. 카드 결제는 한 번에 끝나지 않습니다.

승인 authorization  이 카드로 이만큼 쓸 수 있는지 확인하고                    그만큼을 한도에서 떼어 둔다. 돈은 아직 안 움직인다.매입 capture        실제로 청구한다. 여기서 돈이 움직인다.

배송이 끝난 뒤 매입하는 가맹점이 많아서 둘 사이는 몇 시간에서 며칠까지 벌어집니다. 그래서 승인 건수와 매입 건수는 원래 다릅니다. 문제는 다르다는 사실이 아니라 어떤 사유로 다른지를 못 대는 것입니다. 사유를 못 대면 그 차이 안에 진짜 사고가 섞여 있어도 알 수 없습니다.

어떻게 동작하나

승인 하나는 결국 셋 중 하나가 됩니다.

전량 매입   승인 금액만큼 청구됐다. 정상 종료.부분 매입   승인 금액보다 적게 청구됐다. 주문 일부 취소·품절이 원인.            차액은 승인 취소를 따로 내지 않으면 고객 한도에 계속 묶인다.매입 없음   승인만 나고 끝났다. 여기가 위험하다.

매입 없는 승인이 위험한 이유는 승인에 유효기간이 있기 때문입니다. 보통 며칠에서 한 달 사이에 자동으로 풀리고, 풀린 뒤에 매입을 시도하면 거절됩니다. 그 시점에는 되돌릴 방법이 없습니다 — 가맹점은 물건을 보냈는데 돈을 못 받은 상태로 끝납니다. 그래서 승인만 있고 매입이 없는 건은 유효기간이 지나기 전에 찾아야 하고, 이것은 배치로 매일 돌려야 하는 종류의 점검입니다.

부분 매입의 잔액도 성질이 같습니다. 5만원 승인에 3만원만 매입했으면 2만원은 승인 취소(void)를 따로 내지 않는 한 고객 한도에 계속 묶여 있습니다. 고객은 쓰지도 않은 2만원 때문에 다음 결제가 거절되고, 그 문의가 콜센터로 옵니다.

멱등키와 이중 청구. 결제 요청은 타임아웃이 나도 실제로는 성공해 있을 수 있습니다. 응답을 못 받은 클라이언트는 재시도하고, 서버가 같은 요청을 같은 결과로 돌려주지 않으면 승인이 두 번 납니다. 두 승인이 각각 매입되면 고객은 두 번 청구받습니다.

여기서 가장 중요한 사실은 이것입니다. 두 승인은 auth_id 가 다릅니다. 승인 번호로 중복을 찾으면 아무것도 나오지 않습니다. 같은 것을 두 번 했다는 사실은 멱등키에만 남아 있습니다. 그래서 이중 청구 조사는 언제나 멱등키 기준 집계에서 시작합니다. 멱등키를 아예 저장하지 않는 시스템이라면 그 사실 자체가 첫 번째 보고 항목입니다.

현장에서 만나는 모습

한 PG 에서 특정 가맹점의 이중 청구 민원이 몰린 적이 있습니다. 그 가맹점의 결제 모듈은 응답 타임아웃을 3초로 잡고 있었는데, 카드사 승인 응답이 평소 2.8초쯤 걸렸습니다. 평소에는 아슬아슬하게 넘어가다가 카드사 쪽이 조금만 느려지면 무더기로 타임아웃이 나고, 그때마다 재시도가 나갔습니다. 멱등키는 요청 본문에 있었지만 PG 서버가 그것을 저장하지 않고 그냥 통과시키고 있었습니다.

고친 것은 두 가지였습니다. 타임아웃을 늘린 것이 아니라 멱등키를 저장하고 같은 키에는 같은 응답을 돌려주게 한 것입니다. 재시도는 없어지지 않으므로 받는 쪽에서 막아야 합니다. 그리고 이미 발생한 이중 청구를 찾아 환불했는데, 그 목록을 만드는 데 쓴 것이 멱등키 기준 집계였습니다. 승인 번호로 아무리 뒤져도 나오지 않던 45건이 멱등키로 묶는 순간 한 번에 나왔습니다.

승인·매입의 시차는 증권의 T+2 와 같은 구조입니다. 사건이 둘로 나뉘어 있고 그 사이에 상태가 살아 있으며, 그 상태를 감시하지 않으면 돈이 샙니다. 도메인은 다르지만 다뤄야 할 문제의 모양은 같습니다.

다음 실습에서 할 것

승인 3,045건과 매입 2,745건 로그를 만들고, 그 차이를 승인 취소·거절·부분 매입·매입 없음으로 남김없이 설명합니다. 매입이 없는 승인의 금액과 부분 매입의 잔액을 각각 내고, 마지막으로 멱등키 기준으로 묶어 이중 청구된 금액을 찾습니다.