TossPayments 연동 가이드

2025. 11. 14. 20:51·여러가지 모음집

1. PG사란 

온라인에서 카드 결제를 붙일 때, 서비스 입장에서는 카드사 A, 카드사 B, 은행 C… 같은 수많은 결제사와 직접 통신할 수 없다. 각 회사마다 망도 다르고, 계약 절차도 다르고, API 규격·보안 요구사항도 전부 제각각이기 때문이다. 그래서 그 사이에 Payment Gateway, 줄여서 PG가 서 있다. PG는 여러 카드사·은행과 이미 망을 연결해 둔 “결제 허브” 역할을 한다. 우리는 오른쪽 카드사/은행들과 직접 대화하지 않고, 가운데 PG 한 곳과만 연동하면 된다.

그림에서 보듯

  • 왼쪽 – Client / Server : 내가 구현해야 할 서비스 (웹/앱 + 백엔드 서버)
  • 가운데 – Payment Gateway(TossPayments) : 결제 요청을 받아서 카드사·은행과 실제 승인/취소를 처리해 주는 PG
  • 오른쪽 – 카드사 A, 카드사 B, 은행 C : 진짜 돈이 움직이는 결제 기관들
    → 여기는 PG사가 대신 통신해 주기 때문에, 우리는 신경 쓸 필요가 없다.

2. 왜 PG를 써야 할까?

서비스가 PG 없이 카드사·은행과 “직접” 붙으려고 하면 다음을 전부 감당해야 한다.

  1. 여러 결제사와 각각 연동
    • 카드사·은행마다 다른 API, 프로토콜, 계약 절차
    • 신규 결제수단 추가/변경 때마다 연동 작업 반복
  2. 보안·인증·심사 이슈
    • 카드 정보 취급에 따른 PCI-DSS 같은 보안 규격
    • 각 결제사별 보안 심사, 로그 보관, 암호화 정책 등
    • 3D Secure, 비밀번호/본인인증 등 인증 로직 직접 구현
  3. 정산·취소·부분취소·환불 처리
    • 승인만 있는 게 아니라, 매일매일 정산, 취소·부분취소, 환불까지 모두 회계적으로 맞춰야 함
    • 각 결제사에서 내려오는 정산 데이터를 직접 파싱해서 돈 흐름을 맞춰야 함
  4. 장애·예외 상황 처리
    • 카드사 장애, 네트워크 오류, 중복 결제, 취소 실패 등 온갖 예외 처리
    • 차지백(고객 이의제기)이나 부정 결제에 대한 대응

PG는 이 복잡한 것들을 한 덩어리로 감싸서 서비스에게는 단순한 인터페이스만 제공한다.

그래서 우리는:

  • Client / Server에서는
    • 주문 생성
    • 결제 요청
    • 결제 성공/실패 콜백 처리
    • 우리 서비스 DB에 “결제 상태” 반영

이 정도만 구현하면 되고, 카드사/은행과의 실제 통신, 승인·취소·정산·보안 같은 무거운 일은 TossPayments 같은 PG사가 모두 대신 처리한다.

3. PG사 선택 – 왜 토스페이먼츠 단독 연동을 택했는가

국내에는 토스페이먼츠 같은 PG사(결제대행사)와, 아임포트처럼 여러 PG를 한꺼번에 붙일 수 있게 해주는 연동 플랫폼이 함께 존재한다.

  • 아임포트(I'mport)
    • 스스로 결제를 처리하는 PG라기보다, 여러 PG사의 API를 한 번에 다룰 수 있게 도와주는 “연동 허브”에 가깝다.
  • 토스페이먼츠
    • 실제로 카드사·은행과 망을 연결하고, 승인/취소/정산을 처리하는 진짜 PG사다.

문제는 “아임포트에서 토스페이먼츠 간편결제를 쓰고 싶다”고 했을 때다. 이 경우 아임포트만 가입한다고 끝나는 게 아니라, 결국 토스페이먼츠 상점ID(MID)를 따로 발급받아서 가맹 계약을 해야 한다.

 

즉, 구조상

“아임포트 + (개별 PG, 여기서는 토스페이먼츠)”

이렇게 두 레이어가 생긴다.

비용 관점에서 보면 2025년 기준으로:

  • 토스페이먼츠
    • 가입비: 22만 원
    • 연관리비: 11만 원
  • 아임포트
    • 가입비: 22만 원
    • 실제 결제를 위해서는 어차피 각 PG(예: 토스페이먼츠)와 별도 계약 + 비용이 필요하다.

그래서 “아임포트를 통해 토스 간편결제를 쓴다”는 것은, 현실적으로는 토스페이먼츠 비용 + (아임포트에서 요구하는 조건/비용) 이 겹쳐질 수 있는 구조다. 완전히 같은 항목이 두 번 빠져나가는 건 아니라 해도, 운영과 비용 면에서 중복 레이어가 생기는 건 사실이다.

이번 프로젝트는

  • 국내 이용자 대상
  • 토스페이, 네이버페이, 카카오페이 등 국내 주요 간편결제와 기본 카드 결제 정도면 충분
  • 여러 PG를 동시에 운용하거나 해외 결제를 붙일 계획은 없음

이라는 전제가 있었기 때문에, 굳이 아임포트를 통해 여러 PG를 묶을 필요가 없었다.

결국:

“아임포트로 돌아가서 토스 간편결제를 쓰느니,애초에 토스페이먼츠만 깔끔하게 직연동하는 게 구조도 단순하고, 비용도 더 예측 가능하다.”

라는 결론에 도달했고, 그래서 이번에는
아임포트가 아닌 토스페이먼츠 단독 연동을 선택하게 되었다.

 

4. 토스페이먼츠 결제 흐름

토스페이먼츠 결제는 크게 “인증(결제창 단계)”와 “승인(Confirm 단계)” 두 단계로 나눌 수 있다. 클라이언트는 결제창을 띄우고 인증을 완료하는 역할만 담당하고, 실제 돈이 움직이는 승인/정산은 서버와 PG, 카드사·은행 사이에서 처리된다. 아래는 Client–Server–PG–카드사/은행 사이의 흐름을 단계별로 정리한 것이다.


4-1. 결제창 호출 및 인증 단계

  1. 클라이언트 → PG : 결제창 호출
    사용자가 “결제하기” 버튼을 누르면, 클라이언트는 토스페이먼츠 SDK를 이용해 결제 금액, 주문번호(orderId), 주문명, 고객 정보 등을 포함한 결제창 호출 요청을 보낸다.
  2. PG → 클라이언트 : 결제창 제공
    토스페이먼츠는 전달받은 정보를 기반으로 카드/간편결제 UI가 포함된 결제창을 렌더링해 준다. 사용자는 이 화면에서 카드 정보 입력 또는 토스페이·네이버페이·카카오페이 같은 간편결제를 선택한다.
  3. 클라이언트 ↔ PG : 카드 인증 / 간편결제 진행
    사용자가 비밀번호 입력, ARS 인증, 휴대폰 본인인증 등 필요한 절차를 진행하면 클라이언트와 PG 사이에서 인증 관련 트래픽이 오간다. 이때 클라이언트는 단순히 PG가 제공한 UI를 통해 입력만 받을 뿐, 카드 정보나 민감한 데이터는 직접 다루지 않는다.
  4. PG ↔ 카드사/은행 : 한도·본인 인증 처리
    PG는 백엔드에서 카드사·은행과 통신하며 카드 사용 가능 여부, 한도/잔액 체크, 본인 인증 결과 등을 확인한다. 이 과정은 모두 PG와 카드사/은행 사이에서 처리된다.
  5. PG → 클라이언트 : 인증 결과 및 리다이렉트
    인증이 정상적으로 끝나면 PG는 사전에 지정해 둔 successUrl 로 리다이렉트하면서 paymentKey, orderId, amount 같은 중요 파라미터를 함께 전달한다. 이 시점까지는 거래 “예약” 상태에 가깝고, 실제로 돈이 확정 결제된 것은 아니다.

4-2. 승인(Confirm) 단계 – 실제 결제 확정

  1. 클라이언트 → 서버 : 승인 요청 전달 (Confirm 트리거)
    successUrl 로 돌아온 클라이언트는 URL에 포함된 paymentKey, orderId, amount 값을 꺼내 이를 서버로 보내 “이 결제를 최종 승인해 달라”고 요청한다. (여기서 서버는 DB의 주문 정보와 금액이 일치하는지도 함께 검증할 수 있다.)
  2. 서버 → PG : 승인 API 호출 (Confirm)
    서버는 토스페이먼츠의 Confirm API 를 호출하여 paymentKey, orderId, amount 를 전달한다. 이 단계가 실제로 “이 결제를 진짜로 처리해도 된다”라고 PG에 최종 허락을 주는 과정이다.
  3. PG ↔ 카드사/은행 : 실제 거래 발생
    PG는 카드사/은행에 최종 승인 요청을 보내고, 카드사/은행에서는 해당 금액에 대한 실제 결제 승인/거절을 처리한다.여기서 승인되면 카드사 기준으로도 거래가 잡히게 된다.
  4. PG → 서버 : 결제 결과 응답
    승인 성공/실패 여부, 결제 수단 정보, 영수증 URL 등 최종 결제 결과가 서버로 전달된다. 서버는 이 응답을 기반으로 주문 상태를PAID, FAILED 등으로 갱신하고, 결제 로그/영수증 정보를 DB에 저장한다.
  5. 서버 → 클라이언트 : 승인 결과 전달
    마지막으로 서버는 프론트엔드에 결제 성공/실패 여부, 주문 상세 정보, 영수증 링크 등을 내려주고, 클라이언트는 이에 맞게 성공/실패 화면을 보여준다.

5. 우리 팀에 적용하면서 커스터마이징한 부분

위 시퀀스 다이어그램은 토스페이먼츠 문서의 기본 흐름을 그대로 가져온 것이 아니라, 우리 팀의 도메인에 맞게 커스터마이징한 버전이다.

예를 들어, 결제 연동 자체는 orderId, amount, paymentKey 만 맞춰주면 충분히 동작하지만, 우리 서비스는 결제가 항상 사업계획서(businessPlan) 와 연결되어 있기 때문에

  • 사전 저장 요청(POST /api/toss/request)에 businessPlanId, buyerId 등을 함께 보내고
  • 승인 완료 응답에도 businessPlanId, 우리 쪽 order_no 등을 포함해서 결제 내역과 도메인 데이터를 한 번에 추적할 수 있도록 구성했다.

토스페이먼츠의 JS 위젯과 Confirm API 자체는 어렵지 않다. 공식 문서만 따라가면 금방 결제창을 띄우고, 결제를 성공시키는 것까지는 금방 할 수 있다. 하지만 절차를 쭉 늘어놓고 보면 생각보다 단계가 많다.

  1. 사전 주문 생성 및 DB 저장
  2. 클라이언트에서 widgets.requestPayment() 호출
  3. successUrl 로 리다이렉트되며 paymentKey, orderId, amount 수신
  4. 서버로 승인 요청 전달
  5. 서버에서 토스페이먼츠 Confirm API 호출
  6. 최종 결제 결과를 다시 우리 도메인(사업계획, 사용자, 로그 등)에 반영

이걸 머릿속으로만 기억하고 있으면 팀원마다 이해하는 포인트가 미묘하게 달라지고, 어디까지가 “PG 책임”이고 어디부터가 “우리 서비스 책임”인지 헷갈리기 쉽다. 그래서 나는 공식 문서의 코드 조각과 우리 서비스용 시퀀스 다이어그램을 한 화면에 붙여서 어떤 단계에서 어떤 API를 호출하는지, 요청/응답에 우리 도메인 필드가 어떻게 섞여 들어가는지 한 눈에 볼 수 있도록 정리해서 팀에 공유했다.

핵심은,

“토스페이먼츠 연동 자체는 단순하지만, 실제 서비스에 녹여 넣으려면 각 팀의 도메인에 맞는 추가 필드와 절차를 설계해야 한다”

는 것이다.

커스터마이징하는 것에 맞춰 우리팀만의 시퀀스 다이어그램을 작성하면 새로 합류하는 팀원도 “결제가 어디서 시작해서, 어디에서 확정되는지” 금방 이해할 수 있지 않을까?

저작자표시 비영리 동일조건 (새창열림)

'여러가지 모음집' 카테고리의 다른 글

시크릿키를 잘못올렸을 때  (0) 2025.03.05
github branch 관련 명령어 모음  (0) 2025.02.24
github Issue 및 PR 템플릿  (0) 2025.02.24
EC2에 접속 및 파일 옮기기  (0) 2025.02.24
'여러가지 모음집' 카테고리의 다른 글
  • 시크릿키를 잘못올렸을 때
  • github branch 관련 명령어 모음
  • github Issue 및 PR 템플릿
  • EC2에 접속 및 파일 옮기기
SungHoJung
SungHoJung
  • SungHoJung
    HOLOUD
    SungHoJung
  • 전체
    오늘
    어제
    • 분류 전체보기 (43)
      • AlgoMate (13)
      • TroubleShooting (0)
      • 여러가지 모음집 (5)
      • Infra (18)
  • 링크

    • github
  • 인기 글

  • 태그

    컨테이너 간 통신
    결제 다이어그램
    docker-compose
    ci-cd
    celery+redis
    스왑 메모리 설정
    bypass recaptcha
    크롤링
    redis
    TossPayments
    ECS
    IAM
    EC2
    Celery
    k8s
    Kubernetes
    AWS
    host.docker.internal
    토스페이먼츠 연동
    로컬 서버와 통신
  • hELLO· Designed By정상우.v4.10.3
SungHoJung
TossPayments 연동 가이드
상단으로

티스토리툴바