✅ 가상계좌를 연동한 뒤 웹훅으로 입금 알림을 받을 수 있는 방법을 알 수 있어요.
✅ 가상계좌 입금 상태가 어떻게 변하는지 이해할 수 있어요.
토스페이먼츠에서 제공하는 전체 웹훅 이벤트가 궁금하다면 웹훅 가이드를 참고하세요.
결제 진행 과정이 다른 결제수단과 다르기 때문에 필수입니다. 결제 요청과 동시에 결제가 시도되는 다른 결제수단과 달리, 가상계좌 결제는 구매자에게 먼저 가상계좌를 발급합니다. 구매자가 가상계좌 결제를 요청하면, 구매자 이름으로 계좌가 발급되고 직접 해당 계좌에 주문 금액을 정확히 입금하면 결제가 완료됩니다.
즉, 가상계좌는 구매자가 결제를 완료하는 시점을 직접 결정하는 결제수단입니다. 따라서 가맹점에서는 이 시점을 알기 위해 웹훅 연동을 해야합니다. 아래 흐름도로 살펴보면 가맹점이 7번 '입금 통보', 즉 토스페이먼츠 서버에 구매자가 입금을 했다는 통보를 받기 위함이죠. 입금 통보를 받고 나면 이어서 구매자에게 서비스와 제품을 제공할 수 있습니다. 더 자세한 내용은 가상계좌 용어사전에서 확인해보세요.
가상계좌 웹훅을 연동하고 ‘입금 완료’ 웹훅 이벤트를 받는 방법을 알아봅니다.
결제위젯 샘플 프로젝트 중 node-ejs
예제를 사용해서 가상계좌를 연동할게요. 샘플 프로젝트를 클론하고 해당 폴더로 이동합니다.
$ git clone https://github.com/tosspayments/payment-widget-sample.git
$ cd node-ejs
/views/index.ejs
파일을 열어보면, 결제위젯 SDK를 사용하는 간단한 주문서 페이지가 구현되어 있어요. 결제위젯을 초기화하는 코드에 내 클라이언트 키를 넣어주세요.
const paymentWidget = PaymentWidget(
"{MY_CLIENT_KEY}", // 내 클라이언트 키
PaymentWidget.ANONYMOUS
);
다음으로 /routes/index.js
파일에 있는 secretKey
를 내 시크릿 키로 교체해주세요.
var secretKey = "{MY_SECRET_KEY}"; // 내 시크릿 키
내 클라이언트 키, 시크릿 키는 개발자센터에서 확인할 수 있습니다. 이제 웹훅을 본격적으로 연동할 준비가 됐습니다.
routes/index.js
파일에 이벤트 페이로드를 받을 /hook
엔드포인트를 아래와 같이 이어서 만들어주세요.
//...
// 웹훅 받을 엔드포인트 추가하기
router.post("/hook", function (req,res){
console.log(req.body)
/* 돌아온 웹훅 페이로드를 처리하는 코드를 추가해주세요. */
res.status(200).end() // 성공 응답 보내기
})
성공 응답 코드는 반드시 보내줘야 합니다. 토스페이먼츠 서버는 가맹점에서 보내준 상태 코드가 HTTP 2xx
인지 확인하고 웹훅이 정상적으로 전송된 것을 판단하기 때문입니다. HTTP 2xx
상태 코드가 없다면 계속해서 웹훅이 재전송되고, 7회까지 재전송에 실패하면 웹훅 상태가 '실패'로 변경됩니다.
이제 샘플 프로젝트를 실행하기 위해 터미널에서 아래 명령어를 실행해주세요.
$ npm install
$ npm start
http://localhost:8080
에 접속했을 때 주문서 화면이 보이고, 터미널에 http://localhost:8080 으로 샘플 앱이 실행되었습니다.
라는 메시지가 나오면 로컬 개발 환경에서 프로젝트가 실행된 것입니다.
이제 내 로컬 프로젝트 주소를 웹훅으로 등록해서 테스트 해 볼 차례입니다. 웹훅은 로컬 개발 환경은 외부에서 접근할 수 없기 때문에 로컬 서버를 노출해주는 ngrok 같은 도구를 사용해야 합니다.
현재 환경에 맞게 ngrok을 설치합니다.
설치가 잘 되었다면 터미널에서 현재 로컬 개발 환경에 열린 포트번호를 포함해 ngrok http 8080
명령어를 실행하세요. 그러면 아래와 같은 화면이 나옵니다.
ngrok (Ctrl+C to quit)
🤯 Try the ngrok Kubernetes Ingress Controller: https://ngrok.com/s/k8s-ingress
Session Status online
Session Expires 1 hour, 59 minutes
Update update available (version 3.3.1, Ctrl-U to update)
Terms of Service https://ngrok.com/tos
Version 3.1.1
Region Japan (jp)
Latency -
Web Interface http://127.0.0.1:4040
Forwarding https://acd8-2001-2d8-ef3d-27b9-8886-a828-e1a9-99ea.ngrok.io -> http://localhost:8080
Connections ttl opn rt1 rt5 p50 p90
0 0 0.00 0.00 0.00 0.00
Forwarding 항목을 보겠습니다. https://{NGROK_TEST_DOMAIN}.ngrok.io
와 같은 링크가 생성된 것을 알 수 있습니다. 이 링크가 외부에서 http://localhost:8080
에 접근하는데 사용할 수 있도록 제공된 링크라는 것이 화살표로 표기되어 있습니다. 즉, 생성된 링크로 들어가면 내 로컬 환경과 똑같이 주문서 화면이 뜹니다.
이 링크 뒤에 /hook
을 추가하면 아까 서버에 등록한 웹훅의 엔드포인트와 연결됩니다. https://acd8-2001-2d8-ef3d-27b9-8886-a828-e1a9-99ea.ngrok.io/hook
과 같은 형태입니다.
이렇게 만든 웹훅 엔드포인트를 개발자센터에 등록합니다. 웹훅 엔드포인트를 가리키는 이름, 엔드포인트를 입력하고 가상계좌 입금 이벤트를 받을 수 있는 DEPOSIT_CALLBACK
이벤트를 등록하면 됩니다.
이제 테스트로 가상계좌 입금을 한 뒤 웹훅 이벤트를 받을 차례입니다. 샘플 프로젝트를 띄운 http://localhost:8080
로 이동하면 주문서 페이지가 나옵니다. 결제수단으로 가상계좌를 선택하고 임의 환불 계좌 정보를 넣어주세요. 결제하기 버튼을 누르고 결제창에서 가상계좌를 발급받을 은행을 선택하고 가상계좌를 발급 받으세요.
테스트 가상계좌 결제는 입금처리와 취소를 개발자센터에서 직접 테스트 해 볼 수 있습니다. 개발자센터 테스트 결제내역에서 입금처리를 할게요.
테스트 입금처리가 완료되면 아래와 같이 콘솔에 이벤트 페이로드가 찍히고 내 서버에서 성공 응답을 잘 보낸 것을 확인할 수 있습니다.
{
createdAt: '2023-05-23T14:42:26.000000',
secret: 'ps_Z1aOwX7K8mYpalqAGRwj8yQxzvNP',
orderId: '3f9c765d-60ed-4735-8af5-ab9d1142a3e8',
status: 'DONE',
transactionKey: '83B3CD71DF004878066FEDCB7C21E775'
}
POST /hook 200 0.752 ms - -
웹훅 이벤트가 토스페이먼츠에서 보낸 정상적인 이벤트인지 확인하기 위해 필요한 값이에요. 결제를 완료하면 돌아오는 응답에 secret
값이 있어요. 해당 시크릿 값과 웹훅 이벤트 페이로드의 secret
값을 비교해보세요. 두 값이 같다면 토스페이먼츠에서 보낸 이벤트가 맞고 믿을 수 있는 정보예요. 하지만 만약 두 값이 다르다면, 불분명한 제3자가 보낸 데이터이며 정확하지 않은 정보예요.
개발자센터에서도 웹훅 전송 기록에 성공 내역이 찍힌 것을 확인할 수 있습니다. 이벤트 발생 시간을 선택하면 이벤트 페이로드 기록도 볼 수 있습니다.
웹훅 전송에 실패했다면 "다시 시도" 버튼으로 웹훅을 다시 전송할 수 있습니다. 최대 7회까지 다시 시도할 수 있고, 7회 이후에도 실패한다면 웹훅 상태가 '실패'로 변경됩니다.
라이브 환경이라면 웹훅으로 가상계좌 입금 알림을 받은 뒤 구매자에게 상품을 발송하는 등 다음 단계를 진행하세요.
테스트를 끝냈다면 라이브 환경에서 웹훅을 연동해보세요. 라이브 환경에서는 아래 세 가지를 꼭 확인하세요.
✔️ 토스페이먼츠의 IP 주소를 방화벽에서 허용해주세요.
✔️ 웹훅 이벤트 전송에 실패하면 최대 7회까지 다시 전송을 시도해요.
✔️ 가상계좌 결제 상태가 DONE
에서 WAITING_FOR_DEPOSIT
으로 바뀌면 구매자에게 재입금 안내가 필요해요.
WAITING_FOR_DEPOSIT
상태에서는 구매자가 가상계좌에 입금을 완료하거나 입금할 때 오류가 발생한 경우, 입금 기한 만료이 만료된 경우 세 가지 케이스로 이어질 수 있습니다. 각각의 상태 변화에 대해 자세히 알아봅니다.
WAITING_FOR_DEPOSIT
상태는 발급한 가상계좌에 구매자가 입금하기를 기다리고 있는 상태입니다. 이 상태에서 가능한 네 가지 케이스는 입금 완료, 입금 오류, 입금 기한 만료, 입금 전 취소입니다.
- 입금 완료: 첫 번째는 입금이 성공적으로 완료되어 상태가
DONE
으로 변경되는 경우입니다. 웹훅이 전송됩니다. - 입금 오류: 두 번째는
WAITING_FOR_DEPOSIT
으로 상태가 되돌아가는 경우로, 구매자가 입금할 때 오류가 발생했을 때의 상태 변화입니다. 웹훅이 전송됩니다. - 입금 기한 만료: 구매자가 가상계좌에 입금을 완료하지 않아 입금 기한이 만료되어
WAITING_FOR_DEPOSIT
상태가 유지되는 경우입니다. 웹훅이 전송되지 않습니다. - 입금 전 취소: 구매자가 가상계좌에 입금하기 전에 결제를 취소해서 상태가
CANCELED
가 되는 경우입니다. 웹훅이 전송됩니다.
입금 기한이 만료됐을 때는 상태 변경이 일어나지 않았기 때문에 웹훅이 전송되지 않습니다. 가상계좌를 발급할 때 설정한 기한을 저장해두고 기한이 만료되기 전에 구매자에게 재입금 안내를 해주세요.
구매자가 가상계좌에 입금을 아직 안 했다면, 결제를 취소해도 환불해야 되는 금액이 없고 발급된 가상계좌는 더 이상 사용할 수 없습니다. 또 입금 전에는 부분 취소를 할 수 없습니다. 발급된 가상계좌의 입금 금액을 바꿀 수 없기 때문입니다.
구매자가 가상계좌에 입금한 후에 결제를 취소하면 금액을 환불해줘야 합니다. 환불을 하려면 가상계좌에 입금한 구매자의 계좌 정보가 필요하기 때문에 구매자로부터 직접 환불계좌 정보를 입력 받아야 합니다. 환불계좌의 은행명, 계좌번호, 예금주 정보가 필요합니다.
refundReceiveAccount
에 환불받을 구매자의 계좌 정보를 포함해서 결제 취소를 요청하세요. 환불 계좌의 번호와 예금주의 유효성이 확인되면 해당 계좌로 취소 금액이 환불됩니다.
curl --request POST \
--url https://api.tosspayments.com/v1/payments/yqIxKa7_xObFWjiuXjNru/cancel \
--header 'Authorization: Basic dGVzdF9za196WExrS0V5cE5BcldtbzUwblgzbG1lYXhZRzVSOg==' \
--header 'Content-Type: application/json' \
--data '{"cancelReason":"구매자가 취소를 원함","cancelAmount":10000,"refundReceiveAccount":{"bank":"20","accountNumber":"1000123456789","holderName":"김토페"}}'
응답은 다른 취소 요청과 동일하게 Payment 객체의 cancels
로 돌아옵니다.
토스페이먼츠는 가상계좌 결제를 환불할 때 계좌의 유효성을 검사합니다. 은행명, 계좌번호, 예금주 정보가 일치해야만 환불이 정상적으로 됩니다. 정보가 일치하지 않으면 INVALID_REFUND_ACCOUNT_INFO
, INVALID_REFUND_ACCOUNT_NUMBER
와 같은 에러가 발생합니다. 환불이 실패했을 때는 구매자에게 환불 계좌 정보를 다시 입력 받아야 합니다.