개발 slecs

이커머스 파트너 충전 결제 연동과 잔액 정산 안정화

목차

결제대행사 충전 플로우 붙이기

이커머스 파트너 잔액에 충전 기능 하나 추가하는 일이었음. 단순히 API 한 개 더 까는 줄 알았는데, 결제대행사 쪽 응답 파싱이랑 트랜잭션 경계 잡는 게 생각보다 까다로웠음.

기본 흐름은 이렇게 정리:

  • 클라이언트 충전 요청 → 서버에서 주문 키 발급
  • 결제대행사 팝업 띄워서 결제 진행
  • 콜백 수신 → 검증 → 잔액 반영

처음엔 콜백 받자마자 바로 잔액에 더하는 식으로 짰다가 다시 갈아엎음. 결제대행사 응답이 홀딩 상태로 먼저 들어오는 경우가 있어서, 확정 전에 잔액을 건드리면 환불 한 번에 바로 꼬여버림.

PENDING/CONFIRMED 분리

홀딩 상태로 한 번 들어왔다가 실제 정산 시점에 확정되는 패턴으로 재설계. 가상계좌는 입금 + 2시간, 카드는 +3일 정도 후 확정으로 잡았음.

상태 시점 잔액 반영
PENDING 결제 직후 변동 없음
CONFIRMED 홀딩 종료 후 충전액 가산
CANCELLED 홀딩 중 취소 변동 없음

이렇게 두 단계로 쪼개니까 취소·환불이 어느 시점에 들어오든 잔액이 어긋날 일이 없음. 예전 즉시 반영 코드는 환불 한 번 뜨면 마이너스 잔액 나와서 정산 맞추느라 매번 손으로 보정했었음.

결제 팝업 사이즈 이슈

원래 width/height를 결제대행사 권장값 그대로 박아뒀는데, 모바일에서 인증서 입력칸이 잘린다는 제보가 들어옴. 권장값이 데스크탑 기준이었던 것.

const w = isMobile() ? Math.min(screen.width, 420) : 600;
const h = isMobile() ? screen.height - 80 : 750;
window.open(payUrl, "pay", `width=${w},height=${h}`);

조건부로 분기 태우고 모바일은 거의 풀스크린에 가깝게 띄우도록 변경. 모바일 사파리에서 popup blocker 회피하려면 사용자 클릭 핸들러 안에서 즉시 window.open 호출해야 한다는 것도 다시 확인. async then 안에서 띄우면 차단됨.

배운 것

  • 외부 결제 연동은 항상 PENDING → CONFIRMED 두 단계 분리. 즉시 반영은 거의 항상 버그로 돌아옴.
  • UI 권장값은 디바이스 분기 한 번 더 검증. 데스크탑/모바일 권장값이 다른 경우가 흔함.
  • 콜백 검증은 서명·금액·주문번호 3종 세트 다 맞춰보고, 하나라도 어긋나면 무조건 거부.

다음은 정산 리포트에 PENDING 건만 별도 라벨링해서 회계팀이 한눈에 거를 수 있게 만들 예정. 끝.

댓글 0

첫 댓글 달아줘.