이 글을 쓰게 된 이유는 외부 API를 사용하여 결제하는 시스템을 제작하는 걸 처음해봐서 정리하는 겸 Version2 윗젯 연동 블로그 문서들이 별로 없었기 때문에 독자들의 고통을 줄이고자 작성하였습니다. 참고 문헌은 TossPayments 공식 개발 문서와 블로그를 참고했습니다.
먼저 PG사 란?
➡️ PG사는 가맹점과 수 많은 결제 기관(카드사, 은행 등) 사이에서 중간역할을 하여서 가맹점들이 별도로 각각의 결제수단을 관리할 필요가 없어 편리하게 결제 서비스를 이용할 수 있도록 돕는 시스템을 제공하는 곳이라고 생각하면 됩니다.
토스 페이먼츠와 연동하기 전 결제 흐름을 먼저 보고 가는게 더욱 빠른 이해가 되므로 토스 페이먼츠는 어떤 식으로 결제 흐름이 흘러가는지 보고 가시죠.

1️⃣ 구매자가 상점에서 물품을 담고 주문을 시작
2️⃣ 클라이언트가 TossPayments에게 결제 위젯을 렌더링 하도록 요청
3️⃣ 결제 윗젯이 구매자에게 렌더링이되면 결제 수단을 선택
4️⃣ 클라이언트가 TossPayments에 결제 요청을 한다.
5️⃣ 구매자가 결제 버튼을 클릭하면 결제 수단 및 정보를 클라이언트에 전달 ➡️ 클라이언트는 TossPayments API를 호출하여 결제 프로세스를 시작
6️⃣ 결제창이 뜨고 구매자는 결제 정보를 입력 ➡️ 결제 진행이 완료되면 브라우저는 successUrl 이나 failUrl로 이동
참고로 이때 TossPayments의 최종 결제 승인을 받을 때 필요한 PaymentKey를 넘겨줌!
7️⃣ 결제가 완료되면 브라우저는 서버의 특정 URL로 이동
8️⃣ 서버는 TossPayments의 결제 승인 API(POST /payments/confirm)를 호출하여 최종 결제 승인 요청
9️⃣ TossPayments는 결제 승인 결과를 서버에 반환
연동 프로젝트를 진행하면서 저희는 successUrl과 failUrl을 프론트엔드로 리다이렉트 받지 않고 바로 백엔드로 설정할 것 입니다.


일단 먼저 토스 페이먼츠 윗젯을 사용하려면 API키가 필요합니다. 하지만 이 부분은 사업자 등록을 해야하기 때문에 저희는 토스 페이먼츠에서 직접 윗젯 테스트 키를 제공하는데 그걸 사용할겁니다!
연동하기
1️⃣ 토스 페이먼츠가 제공하는 윗젯 HTML(JS 포함), CSS를 복사해오자!



이걸 복사 붙여넣기 해줘야 예쁜 TossPayments의 윗젯이 뜰겁니다!
여기까지만 작성하고 서버를 켜준 상태에서 http://localhost:8080/checkout.html 로 접속해주면 아래 사진처럼 윗젯이 뜹니다.

2️⃣ 이제 주문과 결제에 필요한 아주아주 간단한 Member 엔티티와 Order 엔티티를 작성하고 멤버 생성과 주문까지 해보기


✅ 참고) 토스 공식 문서에서는 고유한 랜덤값 orderId, orderName, amount를 필수적으로 TossPayments에 넘겨줘야해서 필드에 꼭 추가해줘야합니다!!
Member와 Order의 Controller, Service, Repository는 기본 CRUD이기 때문에 올리지 않겠습니다!
그럼 Postman으로 한번 사용자 등록부터 주문까지 해보겠습니다.


3️⃣ 주문 데이터를 DB에 넣었으니 윗젯에서 결제 요청 해보기


이 상태가 되었으면 결제하기 누르기!

결제하기를 누르면 이렇게 결제 창이 띄어질 것 입니다!
결제 창에 저희의 결제 정보를 입력하시면 됩니다!
4️⃣ TossPayments에서 보내준 successUrl과 요청 파라미터 정보로 다시 TossPayments에게 최종 결제 승인 받기

위의 사진을 보면 successUrl을 프론트로 전달하는데 저희는 이번 연동에서는 바로 백엔드로 리다이렉트를 시켜줄 겁니다!
❓왜 토스 페이먼츠 개발 공식 문서에서는 프론트로 전달하는데 왜 네 맘대로 백엔드로 보내?? 라고 생각할 수 있습니다.


그래서 Checkout.html 파일을 보시면 이제 successUrl이 처음에는 "/success.html" 이라고 적혀있을겁니다. 하지만 저희는 위에서 말했다시피 백엔드의 엔드포인트로 잡을거라 "/pament/success" 로 수정해줬습니다.

위 사진처럼 Controller에서 GET /payment/success로 설정하고 TossPayment에서 보내준 paymentKey와 orderId, amount를 요청 파라미터로 받습니다!
✅ 참고) 아마 저처럼 백엔드 엔드포인트로 바로 설정하시면 최종 승인까지 나야지 아래 사진 처럼 뜰 겁니다. 그래서 처음에는 success.html을 먼저 적용해보시고 어떤 식으로 TossPayment가 URL로 값을 넘겨주는지 확인할 필요가 있다고 생각합니다.



✅ 위 사진이나 코드의 주석부분을 보면 DB에 저장된 금액과 successUrl에서 파라미터로 넘어온 금액을 검증하라는데 TossPayments에서 결제 금액 조작을 확인하기 위해서 반드시 이행하라고 합니다.

위 최종 승인 요청 코드에서 중요하다고 생각되는 부분
1️⃣ secretKey에서 Basic과 " : " 붙이기!
➡️ 왜 중요한가?🤔 필자는 시크릿 키에 " : " 을 붙여주지 않아서 꽤 오랜 시간을 애 먹었습니다..
2️⃣ TossPayments에 최종 승인 요청을 보내기 위해 restTemplate를 활용하여 url, 파라미터로 넘어온 정보 넘겨주기
➡️ 왜 RestTemplate를 사용했나?🤔
RestTemplate는 스프링에서 외부 REST API와의 HTTP 통신을 쉽게 처리하기 위해 제공하는 라이브러리입니다.
1) HttpURLConnection을 사용하면 요청 설정, 응답 파싱 등 많은 반복작업이 필요한데 RestTemplate는 HTTP 메서드를 간단한 메서드 호출로 처리할 수 있기 때문입니다.
2) JSON 데이터 형식을 자바 객체로 변환해주는 메시지 컨버터가 내장 되어 있어 응답 데이터를 쉽게 다룰 수 있습니다.
이 정도만 신경 쓰면 될 것 같다는 생각이 듭니다!

이제 결제를 완료하면 이런 식으로 토스 페이먼츠가 보내준 결제 메타 정보들이 뜹니다.
여기서 프론트 쪽으로 더 예쁘게 보내고 싶다 하시면 DTO로 필요 메타 정보들만 뽑아서 보내주면 된다고 생각합니다.
+ /fail 일 때


사용자가 결제를 진행하는 중 오류 발생, 즉 프론트에서 결제가 실패하면 /faill Url로 리다이렉트 시켰습니다. 메커니즘은 /success와 동일합니다!
여기까지 TossPayment Pg 연동하기였고 마무리하겠습니다!
'Project' 카테고리의 다른 글
| 결제 시나리오 1. 결제 재시도 - Self-Invocation 문제 (0) | 2025.03.17 |
|---|---|
| 결제 시나리오 1. 결제 재시도 구현 (1) | 2025.03.17 |
| JPA를 활용한 일정 앱 프로젝트 트러블 슈팅 및 회고 (0) | 2024.12.12 |
| 일정 관리 앱 프로젝트 트러블 슈팅 및 회고 (2) | 2024.12.09 |
| 키오스크 프로젝트 마무리 및 회고(feat.의존성) (2) | 2024.11.28 |