토스페이먼츠 결제 연동하기

토스페이먼츠·2024년 1월 24일
6
post-thumbnail

온라인 결제 연동은 어렵고 복잡하다는 인식이 있어요. 하지만 토스페이먼츠와 함께라면 PG 심사부터 연동까지 간편하게 완료할 수 있어요. 오늘은 토스페이먼츠 PG 계약을 신청하는 방법과 결제를 연동하는 방법을 간략히 알아볼게요.

PG 심사 준비하기

일단 PG를 가입하기 전에 기본적으로 아래 4가지 사항을 충족해야 돼요. 사이트가 아래 조건을 모두 충족하는지 확인하세요. 더 자세한 내용은 전자결제 심사, 한 번에 통과하는 방법에서 확인하세요.

PG 심사 준비하기

  1. 토스페이먼츠 입점 허용 업종에서 온라인 판매가 가능한 업종인지 확인하세요.
  2. 1개 이상의 상품이 필요해요. 상품 이미지와 배송 안내, 비회원 구매 가능 여부를 명시하세요.
  3. 사이트 하단에 상호명, 대표자명, 사업자등록번호, 사업장 주소, 유선번호, 통신판매업 신고번호를 기재하세요.
  4. 주문서에서 결제창이 노출되고 열려야 해요. 클라이언트의 결제 요청 작업만 해도 심사가 가능한 것이죠.

1~3번은 직접 확인하고 구현하고, 4번은 토스페이먼츠와 함께 해요.

토스페이먼츠 회원가입하기

먼저 결제 연동 및 심사를 위해 토스페이먼츠 홈페이지에서 회원가입하세요. 이메일 주소, 이름, 휴대폰 번호만 있으면 바로 가입할 수 있어요.

회원가입하고 메일 인증을 완료하면 아래 그림의 왼쪽 화면이 보이는데요. 개발 테스트 배너를 눌러서 개발자용 테스트 상점의 개발 정보를 확인하세요. API 키 메뉴에서 보이는 결제위젯 연동 키로 시작할게요.

토스페이먼츠 회원가입하기

토스페이먼츠 결제 연동하기: 클라이언트

클라이언트 연동만 완료해도 PG 계약 및 카드사 심사는 통과할 수 있어요. 사이트에서 결제창(카드사 인증창)이 열리는 것만 심사하기 때문이에요.

토스페이먼츠 결제 연동하기: 클라이언트

✅ 클라이언트 연동 과정

클라이언트 연동 과정을 간략히 알아볼게요. 결제위젯 SDK를 초기화하면 결제위젯 인스턴스가 생성돼요. 이 인스턴스로 SDK의 결제 UI 렌더링 메서드, 이용약관 UI 렌더링 메서드 등 다양한 메서드를 호출할 수 있어요.

결제창을 띄우고 결제를 요청하는 메서드는 requestPayment()이고, 이 메서드의 파라미터로 다양한 설정을 바꿀 수 있어요. 예를 들어 successUrl, failUrl는 필수 파라미터인데요. 결제창에서 카드사 인증에 성공 또는 실패했을 때 구매자가 이동하는 페이지에요. 또 선택 파라미터로 면세 금액, 문화비 지출 여부 등 다양한 요소를 제어할 수 있으니 SDK 문서를 읽어보고 필요한 파라미터를 넘기세요.

클라이언트 연동 과정에 대한 더 자세한 설명은 토스페이먼츠 공식 결제 연동 가이드에서 확인하세요.

✅ 결제 요청 샘플 코드

주문서가 있는 페이지에 아래 코드를 넣어보세요. widgetClientKey를 토스페이먼츠 회원가입해서 받은 결제위젯 연동 키 > 클라이언트 키로 바꾸세요. 그럼 페이지에 결제 및 이용약관 UI가 보일 거예요. React, Next.js, Vue 샘플이 필요하다면 토스페이먼츠 GitHub을 확인하세요.

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="utf-8" />
    <script src="https://js.tosspayments.com/v1/payment-widget"></script>
  </head>
  <body>
    <!-- 결제 UI, 이용약관 UI 영역 -->
    <div id="payment-method"></div>
    <div id="agreement"></div>
    <!-- 결제하기 버튼 -->
    <button id="payment-button">결제하기</button>
    
    <script>
      const coupon = document.getElementById("coupon-box");
      const button = document.getElementById("payment-button");
      
			// 1. SDK 초기화
      const widgetClientKey = "{WIDGET_CLIENT_KEY}";
      const customerKey = "_oXp1imMWLpbSNQ2g3bqB";
      const paymentWidget = PaymentWidget(widgetClientKey, customerKey); // 회원 결제
			
			// 2. 결제 UI 렌더링
      const paymentMethodWidget = paymentWidget.renderPaymentMethods(
        "#payment-method",
        { value: 50000 },
        { variantKey: "DEFAULT" }
      );

			// 3. 이용약관 UI 렌더링
      paymentWidget.renderAgreement(
        "#agreement", 
        { variantKey: "AGREEMENT" }
      )

			// 4. 버튼에 결제 요청 이벤트 걸기
      button.addEventListener("click", function () {
        paymentWidget.requestPayment({
          orderId: "1W_pCfO4rzG9szJEcThKe",
          orderName: "토스 티셔츠 외 2건",
          successUrl: window.location.origin + "/success",
          failUrl: window.location.origin + "/fail",
          customerEmail: "customer123@gmail.com",
          customerName: "김토스",
          customerMobilePhone: "01012341234",
        });
      });
    </script>
  </body>
</html>

✅ successUrl 샘플 코드

결제 요청(카드 인증)에 성공해도 아직 결제는 완료되지 않았어요. 인증에 성공하면 구매자는 successUrl로 이동해요. successUrl에는 결제 승인에 필요한 값들이 쿼리 파라미터가 붙어요. 결제 승인 API는 보안상 서버에서 호출해야 돼요.

아래 코드는 successUrl 페이지에서 쿼리 파라미터로 넘어온 결제 데이터로 결제 승인 엔드포인트 /confirm 을 호출해요. 서버 쪽의 코드는 밑에서 알아볼게요.

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="utf-8" />
  </head>
  <body>
    <h2>결제 성공</h2>

    <script>
      // 쿼리 파라미터 값이 결제 요청할 때 보낸 데이터와 동일한지 반드시 확인하세요.
      // 클라이언트에서 결제 금액을 조작하는 행위를 방지할 수 있습니다.
      const urlParams = new URLSearchParams(window.location.search);
      const paymentKey = urlParams.get("paymentKey");
      const orderId = urlParams.get("orderId");
      const amount = urlParams.get("amount");

      async function confirm() {
        const requestData = {
          paymentKey: paymentKey,
          orderId: orderId,
          amount: amount,
        };

        const response = await fetch("/confirm", {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify(requestData),
        });

        const json = await response.json();

        if (!response.ok) {
          // 결제 실패 비즈니스 로직을 구현하세요.
          console.log(json);
          window.location.href = `/fail?message=${json.message}&code=${json.code}`;
        }

        // 결제 성공 비즈니스 로직을 구현하세요.
        console.log(json);
      }
    </script>
  </body>
</html>

토스페이먼츠 결제 연동하기: 서버

PG 계약 및 카드사 심사에는 서버 연동이 필요 없지만 실제로 구매자에게 결제를 받을 때 꼭 필요하죠. 서버는 API를 호출하고 결제 데이터를 저장하는 역할을 해줘요.

✅ 결제 데이터 저장하기

토스페이먼츠 결제 승인 API는 Payment 객체를 응답으로 반환해요. 서버에서 Payment 객체를 처리할 수 있는 데이터 객체를 만드세요. 그리고 paymentKey, amount, orderId 필드는 필수로 데이터베이스에 저장하세요. 결제 조회, 취소 등 결제 운영에 사용되는 값이에요. 다른 필드의 값은 필요에 따라 저장하세요.

Payment 객체와 각종 결제 API를 더 자세히 알아보고 싶다면 토스페이먼츠 코어 API 문서를 확인하세요.

✅  결제 승인 샘플 코드

아래는 Java 코드는 /confirm 엔드포인트에서 토스페이먼츠 결제 승인 API를 호출하는 코드에요. 코드의 widgetSecretKey결제위젯 연동 키 > 시크릿 키를 넣으세요. 더 자세한 설명과 다양한 언어의 코드 샘플은 토스페이먼츠 공식 결제 연동 가이드에서 확인하세요.

package com.example.demo.controller;
  
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

@Controller
public class WidgetController {
  
  private final Logger logger = LoggerFactory.getLogger(this.getClass());

  @RequestMapping(value = "/confirm")
  public ResponseEntity<JSONObject> confirmPayment(@RequestBody String jsonBody) throws Exception {
    
    JSONParser parser = new JSONParser();
    String orderId;
    String amount;
    String paymentKey;
    try {
      // 클라이언트에서 받은 JSON 요청 바디입니다.
      JSONObject requestData = (JSONObject) parser.parse(jsonBody);
      paymentKey = (String) requestData.get("paymentKey");
      orderId = (String) requestData.get("orderId");
      amount = (String) requestData.get("amount");
    } catch (ParseException e) {
      throw new RuntimeException(e);
    };
    JSONObject obj = new JSONObject();
    obj.put("orderId", orderId);
    obj.put("amount", amount);
    obj.put("paymentKey", paymentKey);
    
    // 토스페이먼츠 API는 시크릿 키를 Basic 인증의 사용자 ID로 사용하고, 비밀번호는 사용하지 않습니다.
    // 비밀번호가 없다는 것을 알리기 위해 시크릿 키 뒤에 콜론을 추가합니다.
    String widgetSecretKey = "{WIDGET_SECRET_KEY}";
    Base64.Encoder encoder = Base64.getEncoder();
    byte[] encodedBytes = encoder.encode((widgetSecretKey + ":").getBytes("UTF-8"));
    String authorizations = "Basic " + new String(encodedBytes, 0, encodedBytes.length);
    
    // 결제를 승인하면 결제수단에서 금액이 차감돼요.
    URL url = new URL("https://api.tosspayments.com/v1/payments/confirm");
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    connection.setRequestProperty("Authorization", authorizations);
    connection.setRequestProperty("Content-Type", "application/json");
    connection.setRequestMethod("POST");
    connection.setDoOutput(true);
    
    OutputStream outputStream = connection.getOutputStream();
    outputStream.write(obj.toString().getBytes("UTF-8"));
    
    int code = connection.getResponseCode();
    boolean isSuccess = code == 200 ? true : false;
    
    InputStream responseStream = isSuccess ? connection.getInputStream() : connection.getErrorStream();
    
    // 결제 성공 및 실패 비즈니스 로직을 구현하세요.
    Reader reader = new InputStreamReader(responseStream, StandardCharsets.UTF_8);
    JSONObject jsonObject = (JSONObject) parser.parse(reader);
    responseStream.close();
    
    return ResponseEntity.status(code).body(jsonObject);
  }
  
}

토스페이먼츠 계약 신청하기

PG 계약 심사를 위한 준비가 끝났다면 토스페이먼츠 계약을 신청하세요.

토스페이먼츠 홈페이지에서 로그인해서 ‘결제 서비스 신청하기’ 배너를 누르세요. 사업자등록번호, 홈페이지 주소 등 내 회사 정보를 입력하는 페이지가 차례대로 나와요. 필요한 회사 정보를 모두 입력하면 신청서 접수 완료입니다. 1~3일 내에 연락처로 심사 결과를 알려드려요.

토스페이먼츠 계약 신청하기

도움이 필요하신가요?

계약 과정에서 어려움이나 문의가 있다면 토스페이먼츠 고객센터(1544-7772, support@tosspayments.com)로 연락해주세요.

결제 연동에 도움이 필요하다면 토스페이먼츠 개발자센터의 다양한 가이드와 콘텐츠를 확인하세요.

Write 박수연 Graphic 이은호, 이나눔

토스페이먼츠 Twitter를 팔로우하시면 더욱 빠르게 블로그 업데이트 소식을 만나보실 수 있어요.


profile
개발자들이 만든, 개발자들을 위한 PG사 토스페이먼츠입니다.

0개의 댓글