핵심 요약
AI에게 결제 기능을 맡길 때 가장 위험한 프롬프트는 단순히 ‘결제 붙여줘’라고 요청하는 것입니다. 결제는 돈을 받는 코드가 아니라 돈의 흐름을 책임지는 운영·회계·고객지원 시스템입니다.
기술적으로는 결제창 연동, 승인 API 호출, 웹훅 수신, 주문 저장을 AI가 빠르게 구현할 수 있습니다. 그러나 다음 정책이 정해져 있지 않으면 실제 서비스에서는 유령 주문, 이중 결제, 환불 지연, 고객센터 폭주, 법적 고지 누락 문제가 발생할 수 있습니다.
| 결정 영역 | 미리 정해야 할 질문 | 실패 시 위험 |
|---|---|---|
| 주문 상태 | 주문은 어떤 상태를 순서대로 거치는가? | 결제는 됐지만 주문이 없는 유령 주문 발생 |
| 환불 기한 | 청약철회와 환불 처리 기한을 어떻게 반영할 것인가? | 법정 기한 위반, 지연 이자, 분쟁 위험 |
| 부분 환불 | 일부 상품 반품, 쿠폰, 배송비를 어떻게 계산할 것인가? | 운영자가 매번 수동 계산, 고객 불신 |
| 이중 결제 | 같은 주문에 결제가 두 번 잡히지 않게 어떻게 막을 것인가? | 카드 명세서 기준 고객 불만, 신뢰 하락 |
| 실패 안내 | 한도 초과, 잔액 부족, 인증 실패를 어떻게 안내할 것인가? | 재시도 전환율 하락, 불필요한 문의 증가 |
| 결제 내역 | 고객이 결제와 환불 상태를 어디서 확인하는가? | 고객센터 문의 증가, 상태 불투명 |
| 환불 고지 | 환불 규정과 취소 버튼을 어디에 배치하는가? | 다크패턴 논란, 규제 리스크 |
1. 주문 상태 설계: 상태가 곧 운영 언어다
결제 기능을 만들 때 주문 상태를 ‘주문 완료’ 하나로만 두면 안 됩니다. 실제 주문은 결제 시도, 승인, 취소, 환불, 실패, 만료 같은 여러 단계를 거칩니다.
권장 상태 예시
| 상태 코드 예시 | 고객에게 보이는 상태 | 의미 |
|---|---|---|
payment_pending |
결제 대기 | 주문은 생성됐지만 결제가 끝나지 않음 |
paid |
결제 완료 | 결제 승인이 완료되어 주문이 유효함 |
payment_failed |
결제 실패 | 결제 시도가 실패했고 재시도 가능 여부를 판단해야 함 |
cancel_requested |
취소 요청 | 고객이 취소를 신청했고 처리 대기 중임 |
cancelled |
취소 완료 | 결제 전 주문 취소 또는 승인 취소가 완료됨 |
refund_requested |
환불 요청 | 결제 후 환불 신청이 접수됨 |
refund_processing |
환불 진행 중 | 환불 승인 또는 결제수단 환급 처리 중임 |
partially_refunded |
부분 환불 완료 | 주문 금액 중 일부만 환불됨 |
refunded |
환불 완료 | 환불 처리가 완료됨 |
expired |
주문 만료 | 결제 대기 시간이 지나 주문이 무효화됨 |
상태 설계 원칙
- 주문 상태와 결제 상태를 완전히 같은 것으로 보지 않습니다. 주문은 존재하지만 결제가 실패할 수 있고, 결제는 승인됐지만 주문 저장이 실패할 수도 있습니다.
- 모든 상태 변경에는 발생 시각, 처리자, 사유, 결제 거래 식별자, 환불 거래 식별자를 남깁니다.
- 고객 화면, 관리자 화면, 고객센터 응대 문구가 같은 상태 정의를 사용해야 합니다.
- 상태 전이는 일방향으로 설계하고, 예외 복구는 별도 관리자 권한으로 기록을 남겨 처리합니다.
2. 청약철회와 법정 환불 기한: 정책이 아니라 법적 요구사항이다
한국에서 소비자 대상 전자상거래를 운영한다면 전자상거래 등에서의 소비자보호에 관한 법률을 고려해야 합니다. 일반적으로 소비자는 일정 기간 안에 청약철회를 할 수 있고, 사업자는 환불 요청 또는 반환 절차 이후 정해진 기한 안에 대금을 환급해야 합니다.
실무에서 특히 중요한 기준은 다음과 같습니다.
- 소비자는 원칙적으로 재화 등을 공급받은 날 등 법이 정한 기준일부터 7일 이내에 청약철회를 할 수 있습니다.
- 사업자는 환급 사유가 발생한 뒤 법정 기한 안에 대금을 환급해야 하며, 지연되는 경우 지연 배상금 또는 지연 이자 문제가 생길 수 있습니다.
- 디지털 콘텐츠, 맞춤 제작 상품, 사용으로 가치가 현저히 감소하는 상품 등은 예외가 될 수 있지만, 예외를 적용하려면 사전 고지와 동의 등 요건을 신중히 확인해야 합니다.
- 실제 적용은 상품 유형, 계약 방식, 소비자에게 제공한 고지, 사용 개시 여부에 따라 달라질 수 있으므로 법무 검토가 필요합니다.
개발 요구사항으로 바꾸는 방법
법적 기준은 약관 문구에만 적어두면 부족합니다. 시스템 요구사항으로도 바꿔야 합니다.
| 법·정책 요구 | 시스템 요구사항 |
|---|---|
| 7일 내 청약철회 가능 여부 판단 | 주문 수령일 또는 서비스 제공일 기준으로 환불 가능 기간 자동 계산 |
| 3영업일 내 환급 처리 필요 | 관리자 화면에 환불 신청일과 처리 마감일 표시 |
| 환급 지연 위험 | 마감 임박, 마감 초과 알림 표시 |
| 예외 상품 고지 필요 | 결제 전 환불 제한 상품임을 명확히 표시하고 동의 로그 저장 |
| 분쟁 대응 필요 | 약관 버전, 고지 시각, 동의 시각, 고객 IP 또는 계정 로그 보관 |
3. 부분 환불 규칙: 쿠폰, 배송비, 세금을 미리 정의한다
부분 환불은 전체 취소보다 훨씬 복잡합니다. 여러 상품을 한 번에 주문한 뒤 일부만 반품하면, 원래 적용된 할인과 배송비를 어떻게 나눌지 결정해야 합니다.
반드시 정해야 할 항목
- 상품별 결제 금액을 어떻게 배분할 것인가
- 주문 전체 쿠폰을 상품별로 비례 배분할 것인가
- 특정 상품 쿠폰은 해당 상품에만 적용할 것인가
- 무료배송 조건이 깨졌을 때 배송비를 차감할 것인가
- 단순 변심 반품 배송비와 상품 하자 반품 배송비를 어떻게 구분할 것인가
- 포인트, 적립금, 기프트카드 결제분을 어떤 순서로 환급할 것인가
- 부분 환불 후 세금계산서, 현금영수증, 영수증 표기를 어떻게 바꿀 것인가
부분 환불 계산 예시
| 항목 | 금액 |
|---|---|
| A 상품 | 30,000원 |
| B 상품 | 70,000원 |
| 주문 전체 쿠폰 | -10,000원 |
| 실제 결제 금액 | 90,000원 |
쿠폰을 상품 금액 비율로 배분하면 A 상품에는 3,000원, B 상품에는 7,000원의 할인이 배분됩니다. 이때 A 상품만 환불하면 환불 기준 금액은 30,000원이 아니라 27,000원입니다. 무료배송 조건, 반품 배송비, 결제수단별 환급 제한이 있다면 최종 환불액은 더 달라질 수 있습니다.
정답은 하나가 아닙니다. 중요한 것은 일관된 규칙을 사전에 정하고, 고객이 결제 전 또는 환불 신청 전에 이해할 수 있게 고지하는 것입니다.
4. 이중 결제 방지: 버튼 비활성화만으로는 부족하다
이중 결제는 고객이 가장 빠르게 발견하는 결제 사고입니다. 고객은 서비스 내부 주문 상태보다 카드 승인 문자와 카드 명세서를 먼저 봅니다. 같은 주문이 두 번 결제되면 신뢰가 크게 떨어집니다.
발생 원인
- 고객이 결제 버튼을 연속 클릭함
- 결제 직후 새로고침하거나 뒤로 가기를 누름
- 모바일 네트워크 지연으로 같은 요청이 재전송됨
- 결제 승인 응답은 성공했지만 서비스 서버 저장이 실패함
- 웹훅과 클라이언트 리다이렉트가 동시에 주문 상태를 변경함
방어 설계
| 방어 장치 | 설명 |
|---|---|
| 클라이언트 버튼 잠금 | 결제 버튼 클릭 후 재클릭을 막지만 보조 수단으로만 사용 |
| 서버 단 주문 잠금 | 같은 주문 ID에 대해 동시에 결제 승인 요청이 실행되지 않게 처리 |
| 멱등성 키 | 같은 결제 요청을 여러 번 보내도 결과가 한 번만 생성되게 하는 식별자 사용 |
| 고유 거래번호 | 주문 번호와 결제 거래번호의 중복 저장을 데이터베이스 제약조건으로 방지 |
| 상태 기반 검증 | 이미 paid인 주문에는 추가 승인 요청을 막음 |
| 웹훅 중복 처리 | 같은 웹훅 이벤트가 여러 번 와도 상태 변경이 한 번만 일어나게 처리 |
AI에게 결제 코드를 요청할 때는 ‘중복 클릭 방지’가 아니라 ‘동일 주문에 대해 결제 승인과 결제 완료 처리는 멱등하게 동작해야 한다’고 명시하는 것이 좋습니다.
5. 결제 실패 안내 문구: 실패는 사고가 아니라 정상 흐름이다
결제 실패는 매일 발생하는 정상 상황입니다. 한도 초과, 잔액 부족, 카드 인증 실패, 비밀번호 오류, 3D Secure 인증 실패, 간편결제 앱 미응답, 네트워크 오류는 모두 흔한 케이스입니다.
나쁜 안내는 ‘오류가 발생했습니다’로 끝나는 문구입니다. 고객은 결제가 된 것인지, 다시 눌러도 되는지, 주문이 사라지는지 알 수 없습니다.
안내 문구 예시
| 상황 | 권장 안내 |
|---|---|
| 잔액 부족 | 결제수단의 잔액이 부족해 결제가 완료되지 않았습니다. 다른 결제수단을 선택하거나 잔액을 확인한 뒤 다시 시도해 주세요. |
| 한도 초과 | 카드 한도 또는 1회 결제 한도를 초과해 결제가 실패했습니다. 카드사 앱에서 한도를 확인하거나 다른 카드로 결제해 주세요. |
| 인증 실패 | 결제 인증이 완료되지 않아 주문이 결제 대기 상태로 유지됩니다. 30분 안에 다시 결제할 수 있습니다. |
| 네트워크 오류 | 결제 결과 확인이 지연되고 있습니다. 중복 결제를 막기 위해 잠시 후 결제 내역을 확인해 주세요. |
| 주문 만료 | 결제 대기 시간이 지나 주문이 만료되었습니다. 상품을 다시 선택해 주문해 주세요. |
실패 안내의 핵심 요소
- 결제가 실제로 완료되지 않았는지 명확히 말합니다.
- 주문이 유지되는 시간을 알려줍니다.
- 다시 시도해도 되는지, 다른 결제수단을 써야 하는지 안내합니다.
- 고객센터에 문의할 때 필요한 주문번호를 보여줍니다.
- 결제 결과가 불확실한 경우 무조건 재결제를 유도하지 말고 확인 중 상태를 제공합니다.
6. 결제 내역 페이지: 고객센터를 줄이는 핵심 화면이다
결제 내역 페이지가 없으면 고객은 결제, 취소, 환불 상태를 확인하기 위해 고객센터에 문의합니다. 결제 내역은 단순한 영수증 화면이 아니라 고객이 자기 돈의 현재 상태를 확인하는 신뢰 장치입니다.
결제 내역 페이지에 포함할 정보
- 주문번호
- 주문일시와 결제일시
- 상품명, 수량, 옵션
- 결제수단과 승인번호 또는 거래 식별자
- 상품 금액, 할인, 배송비, 포인트 사용액, 최종 결제액
- 현재 주문 상태와 환불 상태
- 환불 신청일, 환불 승인일, 환불 완료 예정일
- 취소 또는 환불 가능 여부
- 영수증, 거래명세서, 현금영수증 확인 링크
- 고객센터 문의 시 필요한 정보
운영자 화면과의 연결
고객 화면과 관리자 화면은 같은 데이터를 봐야 합니다. 고객에게는 ‘환불 진행 중’이라고 보이는데 관리자 화면에는 ‘처리 완료’로 보이면 고객센터 응대가 꼬입니다. 상태명은 다르게 표현할 수 있지만, 내부 상태 코드와 전이 규칙은 하나여야 합니다.
7. 환불 규정 고지 위치: 숨기면 정책이 아니라 위험이 된다
환불 규정은 약관 페이지 구석에만 두면 부족합니다. 고객이 결제 결정을 내리는 화면에서 환불 가능 기간, 환불 제한 조건, 취소 방법을 쉽게 확인할 수 있어야 합니다.
좋은 고지 위치
- 상품 상세 페이지의 가격 또는 구매 버튼 근처
- 장바구니 또는 주문서 화면
- 결제 버튼 바로 위의 약관 및 환불 규정 동의 영역
- 결제 완료 페이지
- 마이페이지의 주문 상세 화면
- 환불 신청 화면
피해야 할 설계
- 가입과 결제는 한 번에 되지만 해지나 환불은 고객센터 전화로만 가능하게 만드는 설계
- 취소 버튼을 여러 단계 안쪽에 숨기는 설계
- 환불 제한 조건을 결제 후에야 보여주는 설계
- 고객이 오해하도록 버튼 색상, 문구, 순서를 배치하는 설계
- 무료 체험 종료 후 자동 결제 사실을 명확히 알리지 않는 설계
이런 설계는 고객 경험을 해칠 뿐 아니라 다크패턴으로 평가될 수 있습니다. 특히 취소와 해지의 난이도는 가입과 결제의 난이도와 크게 다르지 않게 설계하는 것이 안전합니다.
AI에게 줄 프롬프트에 포함할 체크리스트
AI 개발 도구에 결제 기능 구현을 요청할 때는 아래처럼 정책을 먼저 전달해야 합니다.
결제 기능 프롬프트 예시
한국 소비자 대상 전자상거래 서비스의 결제 기능을 구현해 줘.
다음 정책을 반드시 반영해.
1. 주문 상태는 payment_pending, paid, payment_failed, cancel_requested, cancelled, refund_requested, refund_processing, partially_refunded, refunded, expired를 사용한다.
2. 결제 대기 주문은 30분 후 expired로 변경한다.
3. 동일 주문에는 결제 승인 1건만 허용하고, 서버 단 주문 잠금과 멱등성 키를 사용한다.
4. 결제 웹훅은 중복 수신될 수 있으므로 같은 이벤트 ID는 한 번만 처리한다.
5. 환불 신청일, 환불 처리 마감일, 처리자, 사유, 환불 거래번호를 저장한다.
6. 부분 환불은 상품별 실결제금액 기준으로 계산하고, 주문 전체 쿠폰은 상품 금액 비율로 배분한다.
7. 결제 실패 시 실패 사유별 고객 안내 문구를 반환한다.
8. 고객이 마이페이지에서 결제 내역과 환불 상태를 확인할 수 있게 한다.
9. 결제 전 환불 규정 링크와 동의 체크박스를 표시하고, 동의 시각과 약관 버전을 저장한다.
10. 정하지 않은 정책이 있으면 코드를 작성하기 전에 먼저 질문해 줘.
마지막 문장인 ‘정하지 않은 정책이 있으면 먼저 질문해 줘’는 중요합니다. 환불 자동 승인 여부, 관리자 승인 권한, 배송비 차감 방식처럼 사람이 놓치기 쉬운 정책을 AI가 되묻게 만들 수 있습니다.
운영자 화면에 필요한 기능
결제 기능은 고객 화면만으로 완성되지 않습니다. 환불과 취소는 매일 처리되는 운영 업무이므로 관리자 화면이 반드시 필요합니다.
| 관리자 기능 | 필요한 이유 |
|---|---|
| 환불 대기 목록 | 처리해야 할 환불 건을 놓치지 않기 위해 필요 |
| 법정 처리 기한 표시 | 환불 지연 위험을 줄이기 위해 필요 |
| 기한 임박·초과 경고 | 3영업일 같은 내부 기준을 운영자가 즉시 인지하도록 필요 |
| 환불 사유 선택 | 단순 변심, 상품 하자, 오배송 등 통계와 비용 배분에 필요 |
| 부분 환불 계산 미리보기 | 운영자의 수동 계산 오류를 줄이기 위해 필요 |
| 처리 로그 | 분쟁과 감사 대응을 위해 필요 |
| 권한 관리 | 환불 승인과 강제 상태 변경을 제한하기 위해 필요 |
결제 데이터 모델의 최소 구성
서비스마다 데이터 구조는 다르지만, 최소한 아래 수준의 데이터는 분리해 두는 것이 좋습니다.
| 테이블 또는 객체 | 핵심 필드 |
|---|---|
| 주문 | 주문 ID, 고객 ID, 주문 상태, 주문 금액, 할인액, 배송비, 생성일시, 만료일시 |
| 주문 상품 | 상품 ID, 상품명, 옵션, 수량, 상품별 금액, 상품별 할인 배분액 |
| 결제 | 결제 ID, 주문 ID, 결제수단, 승인번호, 승인금액, 결제 상태, 승인일시 |
| 환불 | 환불 ID, 주문 ID, 환불 금액, 환불 사유, 환불 상태, 신청일시, 완료일시 |
| 상태 이력 | 대상 ID, 이전 상태, 변경 상태, 변경자, 변경 사유, 변경일시 |
| 약관 동의 | 약관 종류, 약관 버전, 동의 여부, 동의일시, 고객 ID |
중요한 점은 결제 승인 금액, 환불 금액, 주문 총액을 덮어쓰지 않는 것입니다. 돈과 관련된 값은 가능하면 이력과 거래 단위로 보존해야 나중에 장부와 고객 응대가 맞습니다.
출시 전 점검 목록
- 같은 주문에 대해 결제 버튼을 10번 눌러도 결제는 1번만 승인되는가?
- 결제 승인 후 서버 저장이 실패하면 복구할 수 있는가?
- 결제 웹훅이 같은 이벤트를 여러 번 보내도 중복 처리되지 않는가?
- 고객이 결제 실패 사유와 재시도 방법을 이해할 수 있는가?
- 결제 대기 주문이 일정 시간 후 자동 만료되는가?
- 부분 환불 금액이 쿠폰, 포인트, 배송비 정책과 일치하는가?
- 환불 신청일부터 처리 마감일까지 관리자 화면에 표시되는가?
- 환불 규정이 결제 전 화면에서 쉽게 확인되는가?
- 디지털 콘텐츠 또는 환불 제한 상품은 사전 고지와 동의 로그가 있는가?
- 고객이 마이페이지에서 결제 내역과 환불 상태를 직접 확인할 수 있는가?
결론
AI는 결제 기능의 코드를 빠르게 만들 수 있습니다. 하지만 안전하고 합법적으로 운영되는 결제 시스템은 코드 이전의 정책 결정에서 시작됩니다.
주문 상태, 법정 환불 기한, 부분 환불 계산식, 이중 결제 방지, 결제 실패 안내, 결제 내역 페이지, 환불 규정 고지 위치를 먼저 정리한 뒤 AI에게 구현을 맡기면 훨씬 안정적인 결과를 얻을 수 있습니다. 결제는 ‘돈을 받는 기능’이 아니라 ‘돈을 책임지는 기능’이라는 관점으로 설계해야 합니다.