npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@divetocode/tosspayments

v1.0.3

Published

A TypeScript wrapper around @tosspayments/tosspayments-sdk for React, Next.js, and Node.js server integrations.

Readme

@divetocode/tosspayments

npm version license TypeScript

React, Next.js, Node.js를 위한 토스페이먼츠 TypeScript 래퍼

토스페이먼츠 SDK를 더 쉽고 안전하게 사용할 수 있도록 설계된 TypeScript 우선 라이브러리입니다.

✨ 특징

  • 🔒 완전한 타입 안전성: TypeScript로 작성된 end-to-end 타입 지원
  • 🌐 클라이언트/서버 분리: 브라우저용 클라이언트와 Node.js 서버 API 별도 제공
  • ⚛️ React/Next.js 최적화: React 18+ 및 Next.js 환경에서 완벽 호환
  • 🔄 스마트 재시도: 네트워크 오류 시 지수 백오프를 통한 자동 재시도
  • 🛡️ Idempotency 지원: 중요한 API 호출에 대한 자동 중복 방지
  • 📦 ESM/CJS 듀얼 지원: 모던 프로젝트와 레거시 프로젝트 모두 지원
  • 트리 셰이킹: 필요한 부분만 번들에 포함

📋 시스템 요구사항

  • Node.js: 18.0.0 이상
  • React: 18.0.0 이상 (클라이언트 사용 시)
  • TypeScript: 5.0.0 이상 권장

📦 설치

# npm
npm install @divetocode/tosspayments

# yarn
yarn add @divetocode/tosspayments

# pnpm
pnpm add @divetocode/tosspayments

🚀 빠른 시작

모듈 가져오기

// 전체 패키지
import { TossPaymentsAPI, TossServer } from '@divetocode/tosspayments';

// 클라이언트만 (번들 사이즈 최적화)
import { TossPaymentsAPI } from '@divetocode/tosspayments/client';

// 서버만
import { TossServer } from '@divetocode/tosspayments/server';

// 타입만
import type { RequestPaymentParams } from '@divetocode/tosspayments/types';

🖥️ 클라이언트 사용법 (브라우저)

기본 설정

import { TossPaymentsAPI } from '@divetocode/tosspayments/client';

// 익명 사용자
const toss = await TossPaymentsAPI.init({
  clientKey: 'test_ck_D5GePWvyJnrK0W0k6q8gLzN97Eoqo9O',
  customerKey: 'ANONYMOUS'
});

// 회원 사용자
const toss = await TossPaymentsAPI.init({
  clientKey: 'test_ck_D5GePWvyJnrK0W0k6q8gLzN97Eoqo9O',
  customerKey: 'customer_123'
});

React 컴포넌트 예제

import React from 'react';
import { TossPaymentsAPI, generateRandomString } from '@divetocode/tosspayments/client';

export default function PaymentButton() {
  const handlePayment = async () => {
    try {
      const toss = await TossPaymentsAPI.init({
        clientKey: process.env.NEXT_PUBLIC_TOSS_CLIENT_KEY!,
        customerKey: 'ANONYMOUS'
      });

      await toss.requestPayment({
        method: 'CARD',
        amount: {
          value: 15000,
          currency: 'KRW'
        },
        orderId: generateRandomString(),
        orderName: '토스 티셔츠',
        successUrl: `${window.location.origin}/payment/success`,
        failUrl: `${window.location.origin}/payment/fail`,
        customerEmail: '[email protected]',
        customerName: '김토스'
      });
    } catch (error) {
      console.error('결제 실패:', error);
    }
  };

  return (
    <button onClick={handlePayment}>
      결제하기
    </button>
  );
}

카드 결제

await toss.requestPayment({
  method: 'CARD',
  amount: {
    value: 15000,
    currency: 'KRW'
  },
  orderId: 'order_123',
  orderName: '토스 티셔츠',
  successUrl: 'https://mysite.com/success',
  failUrl: 'https://mysite.com/fail',
  customerEmail: '[email protected]',
  customerName: '김토스',
  card: {
    useEscrow: false,
    flowMode: 'DEFAULT',
    useCardPoint: true,
    useAppCardOnly: false
  }
});

계좌이체

await toss.requestPayment({
  method: 'TRANSFER',
  amount: {
    value: 50000,
    currency: 'KRW'
  },
  orderId: 'order_456',
  orderName: '온라인 강의',
  successUrl: 'https://mysite.com/success',
  failUrl: 'https://mysite.com/fail',
  transfer: {
    cashReceipt: { type: '소득공제' },
    useEscrow: true
  }
});

가상계좌

await toss.requestPayment({
  method: 'VIRTUAL_ACCOUNT',
  amount: {
    value: 100000,
    currency: 'KRW'
  },
  orderId: 'order_789',
  orderName: '도서 구매',
  successUrl: 'https://mysite.com/success',
  failUrl: 'https://mysite.com/fail',
  virtualAccount: {
    cashReceipt: { type: '지출증빙' },
    validHours: 24,
    useEscrow: false
  }
});

해외 간편결제 (USD)

await toss.requestPayment({
  method: 'FOREIGN_EASY_PAY',
  amount: {
    value: 50,
    currency: 'USD'  // USD 필수
  },
  orderId: 'order_usd_123',
  orderName: 'Global Product',
  successUrl: 'https://mysite.com/success',
  failUrl: 'https://mysite.com/fail',
  foreignEasyPay: {
    provider: 'PAYPAL',
    country: 'US',  // ISO 3166-1 alpha-2
    pendingUrl: 'https://mysite.com/pending'
  }
});

정기결제 빌링키 발급

await toss.requestBillingAuth({
  successUrl: 'https://mysite.com/billing-success',
  failUrl: 'https://mysite.com/billing-fail',
  customerEmail: '[email protected]',
  customerName: '김토스'
});

🖧 서버 사용법 (Node.js)

기본 설정

import { TossServer } from '@divetocode/tosspayments/server';

const toss = new TossServer(process.env.TOSS_SECRET_KEY!, {
  timeoutMs: 15000,  // 15초 타임아웃 (기본값: 10초)
  retries: 3         // 재시도 횟수 (기본값: 2)
});

Next.js API 라우트 예제

// app/api/payments/confirm/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { TossServer } from '@divetocode/tosspayments/server';

const toss = new TossServer(process.env.TOSS_SECRET_KEY!);

export async function POST(request: NextRequest) {
  try {
    const { paymentKey, orderId, amount } = await request.json();

    const result = await toss.confirmPayment({
      paymentKey,
      orderId,
      amount: TossServer.toNumber(amount)
    });

    return NextResponse.json({ success: true, payment: result });
  } catch (error: any) {
    console.error('결제 승인 실패:', error);
    return NextResponse.json(
      { success: false, error: error.message },
      { status: 400 }
    );
  }
}

결제 승인

try {
  const result = await toss.confirmPayment({
    paymentKey: 'payment_key_from_success_callback',
    orderId: 'order_123',
    amount: 15000
  });
  
  console.log('결제 승인 성공:', result);
} catch (error) {
  console.error('결제 승인 실패:', error);
}

결제 조회

try {
  const payment = await toss.retrievePayment('payment_key_123');
  console.log('결제 정보:', payment.status, payment.method);
} catch (error) {
  console.error('결제 조회 실패:', error);
}

결제 취소

// 전체 취소
const result = await toss.cancelPayment({
  paymentKey: 'payment_key_123',
  cancelReason: '고객 요청'
});

// 부분 취소 (환불 계좌 지정)
const result = await toss.cancelPayment({
  paymentKey: 'payment_key_123',
  cancelReason: '부분 환불',
  cancelAmount: 5000,
  currency: 'KRW',
  refundReceiveAccount: {
    bank: '신한',
    accountNumber: '110-123-456789',
    holderName: '김토스'
  },
  taxFreeAmount: 0
});

정기결제 청구

const result = await toss.chargeWithBillingKey({
  billingKey: 'billing_key_123',
  customerKey: 'customer_123',
  orderId: 'subscription_order_456',
  orderName: '월간 구독료',
  amount: 9900,
  currency: 'KRW',
  customerEmail: '[email protected]',
  customerName: '김토스',
  idempotencyKey: 'custom-idempotency-key' // 선택사항
});

💳 지원하는 결제 방식

| 결제 방식 | 메서드명 | 통화 | 설명 | |-----------|----------|------|------| | 💳 카드 | CARD | KRW | 신용카드, 체크카드 | | 🏦 계좌이체 | TRANSFER | KRW | 실시간 계좌이체 | | 🏧 가상계좌 | VIRTUAL_ACCOUNT | KRW | 가상계좌 입금 | | 📱 휴대폰 | MOBILE_PHONE | KRW | 휴대폰 소액결제 | | 🎫 문화상품권 | CULTURE_GIFT_CERTIFICATE | KRW | 문화상품권 | | 📚 도서문화상품권 | BOOK_GIFT_CERTIFICATE | KRW | 도서문화상품권 | | 🎮 게임문화상품권 | GAME_GIFT_CERTIFICATE | KRW | 게임문화상품권 | | 🌍 해외 간편결제 | FOREIGN_EASY_PAY | USD | PayPal, AliPay 등 |

해외 간편결제 제공업체

FOREIGN_EASY_PAY 방식에서 지원하는 제공업체:

| 제공업체 | 코드 | 지역 | |----------|------|------| | PayPal | PAYPAL | 글로벌 | | 알리페이 | ALIPAY | 중국 | | 알리페이 홍콩 | ALIPAYHK | 홍콩 | | Billease | BILLEASE | 필리핀 | | Boost | BOOST | 말레이시아 | | BPI | BPI | 필리핀 | | Dana | DANA | 인도네시아 | | GCash | GCASH | 필리핀 | | 래빗 라인페이 | RABBIT_LINE_PAY | 태국 | | TouchNGo | TOUCHNGO | 말레이시아 | | TrueMoney | TRUEMONEY | 태국 |

⚠️ 오류 처리

라이브러리는 자동으로 재시도를 수행하지만, 최종적으로 실패한 경우 적절한 오류 처리가 필요합니다:

try {
  const result = await toss.confirmPayment({
    paymentKey: 'payment_key',
    orderId: 'order_123',
    amount: 15000
  });
} catch (error: any) {
  // 타임아웃
  if (error.message.includes('Timeout')) {
    console.error('⏰ 요청 타임아웃');
  }
  // 잘못된 요청
  else if (error.message.includes('400')) {
    console.error('❌ 잘못된 요청 파라미터');
  }
  // 인증 실패
  else if (error.message.includes('401')) {
    console.error('🔐 인증 실패 - Secret Key 확인 필요');
  }
  // 서버 오류 (자동 재시도 후 실패)
  else if (error.message.includes('5')) {
    console.error('🔥 서버 오류 - 잠시 후 다시 시도해주세요');
  }
  else {
    console.error('❓ 알 수 없는 오류:', error);
  }
}

🛠️ 유틸리티 함수

안전한 숫자 변환

import { TossServer } from '@divetocode/tosspayments/server';

// URL 쿼리 파라미터나 폼 데이터를 안전하게 숫자로 변환
const amount = TossServer.toNumber(req.query.amount); // string | string[] → number
const price = TossServer.toNumber("15000"); // 15000

랜덤 문자열 생성

import { generateRandomString } from '@divetocode/tosspayments/client';

const randomOrderId = generateRandomString(); // "aBc1De2Fg3Hi4Jk5"
const customerId = `customer_${generateRandomString()}`;

🔒 보안 가이드라인

🚨 필수 보안 사항

  1. Secret Key 보안: 서버용 Secret Key는 절대 클라이언트에 노출되지 않도록 주의하세요.
  2. 환경 변수 사용: API 키는 반드시 환경 변수로 관리하세요.
  3. HTTPS 필수: 프로덕션 환경에서는 반드시 HTTPS를 사용하세요.
  4. 금액 재검증: 클라이언트에서 전송된 금액을 서버에서 반드시 재검증하세요.

환경 변수 설정 예제

# .env.local (Next.js)
NEXT_PUBLIC_TOSS_CLIENT_KEY=test_ck_D5GePWvyJnrK0W0k6q8gLzN97Eoqo9O
TOSS_SECRET_KEY=test_sk_zXLkKEypNArWmo50nX3lmeaxYG5R

# .env (Node.js)
TOSS_SECRET_KEY=test_sk_zXLkKEypNArWmo50nX3lmeaxYG5R

서버 사이드 검증 예제

// 클라이언트에서 전송된 결제 정보를 서버에서 재검증
export async function verifyPayment(orderId: string, expectedAmount: number) {
  const order = await getOrderFromDatabase(orderId);
  
  if (order.amount !== expectedAmount) {
    throw new Error('결제 금액이 일치하지 않습니다');
  }
  
  return order;
}

🏗️ 프로젝트 구조

@divetocode/tosspayments/
├── client          # 브라우저 전용 (TossPaymentsAPI)
├── server          # Node.js 전용 (TossServer)
├── types           # 공통 타입 정의
└── index           # 통합 내보내기

📈 버전 히스토리

  • v1.0.2: 현재 안정 버전
  • React 18+ 지원
  • Next.js App Router 완전 호환
  • ESM/CJS 듀얼 지원

🤝 기여하기

버그 리포트나 기능 제안은 GitHub Issues를 통해 부탁드립니다.

📧 지원

📄 라이센스

MIT License


Made with ❤️ by Divetocode