Skip to content

Payment API

토스 프론트에서 결제 및 환불을 처리하기 위한 API입니다. 카드, 애플페이, 삼성페이, 현금 영수증, 간편결제 등 다양한 결제 수단을 지원합니다.

주의 사항

프론트에서 카드 결제 테스트 시 실제 승인이 발생하여 주의가 필요합니다.

주의 사항

[카드 결제 테스트 시]

  • 테스트 후 반드시 즉시 취소 처리 필요
  • 결제 응답의 paymentKey, approvalNumber, timestamp 등 승인 취소를 위한 값을 저장하여 취소에 활용

[권장 테스트 방법]

  • 동작 확인 목적이라면 현금 결제 > 현금영수증 미발급으로 테스트 권장
  • 실제 금전적 부담 없이 결제 플로우 확인 가능

Methods

requestPayment

통합 결제를 요청합니다.

Parameters

파라미터타입필수기본값설명
paymentKeystring-중복되지 않는 고유한 결제 식별자
taxnumber-세금 (일반적으로 Math.floor(price / 11), 면세인 경우 0)
supplyValuenumber-공급가액 (결제 금액 - 세금)
tipnumber-봉사료
installmentnumber0할부 개월
timeoutMsnumber60000타임아웃 (ms 단위)
localeCode'ko' | 'en''ko'언어 설정
excludePaymentTypes['CASH']-제외할 결제 수단 (현재 현금만 지원)

Example

js
/**
 * 통합 결제 요청
 * @param {Object} params 통합 결제 요청 파라미터
 * @returns {Object} 결제 결과
 */
const price = 10000;
const tax = Math.floor(price / 11);
const supplyValue = price - tax;

const result = await sdk.payment.requestPayment({
  paymentKey: "paymentKey",
  tax,
  supplyValue,
  tip: 0,
  timeoutMs: 60000,
  localeCode: "ko", // "ko" or "en" default "ko"
  excludePaymentTypes: ["CASH"], // 현금 결제 제외
});

if (result.type === "CANCELED" || result.type === "TIMEOUT") {
  return;
}

switch (result.response.paymentMethod) {
  case "CARD":
    console.log(result.response.card);
    break;
  case "CASH":
    console.log(result.response.cash);
    break;
  case "BARCODE":
    console.log(result.response.barcode);
    break;
}

Response

카드/삼성페이/애플페이 결제
js
{
    type: 'SUCCESS',
    response: {
        paymentMethod: 'CARD',
        card: {
            van: string,                // VAN사 코드
            timestamp: number,          // 승인 시간
            approvalNumber: string,     // 승인번호
            acquirerName: string,       // 매입사 명
            acquirerCode: string,       // 매입사 코드
            issuerName: string,         // 발급사 명
            issuerCode: string,         // 발급사 코드
            cardType: string,           // 카드 종류
            balance: number,            // 선불카드 잔액
            installment: number,        // 할부 개월
            maskedCardNumber: string,   // 마스킹된 카드 번호 (bin 8자리만 표시)
        },
    },
}
현금 영수증
js
// 현금영수증 발급 시
{
    type: 'SUCCESS',
    response: {
        paymentMethod: 'CASH',
        cash: {
            isCashReceipt: true,
            cashReceipt: {
                van: string,                                            // VAN사 코드
                timestamp: number,                                      // 승인 시간
                issuerType: 'CONSUMER' | 'BUSINESS',                    // 발급 대상 유형
                issuanceType: 'PHONE' | 'BUSINESS_NUMBER' | 'CARD',     // 발급 방식
                identityNumber: string,                                 // 현금영수증 번호 값
                maskedIdentityNumber: string,                           // 현금영수증 번호 값 (일부 별표 처리)
                approvalNumber: string,                                 // 승인번호
                isSelfIssuance: boolean,                                // 자진 발급 여부
            },
        },
    },
}

// 현금영수증 미발급 시
{
    type: 'SUCCESS',
    response: {
        paymentMethod: 'CASH',
        cash: {
            isCashReceipt: false,
        },
    },
}
간편결제
js
{
    type: 'SUCCESS',
    response: {
        paymentMethod: 'BARCODE',
        barcode: {
            van: string,              // VAN사 코드
            timestamp: number,        // 승인 시간
            approvalNumber: string,   // 승인번호
            acquirerName: string,     // 매입사 명
            acquirerCode: string,     // 매입사 코드
            issuerName: string,       // 발급사 명
            issuerCode: string,       // 발급사 코드
            cardType: string,         // 카드 종류
            balance: number,          // 선불카드 잔액
            installment: number,      // 할부 개월
            shopCode: string,         // 가맹점 번호 (숫자 9자리)
        },
        extraData: {
            vanTransactionManagementId: string, // 알리페이/위챗페이 취소 시 필요
        },
    },
}

requestBarcodePayment

QR, 바코드를 인식하는 간편결제를 요청합니다.

Parameters

파라미터타입필수기본값설명
paymentKeystring-중복되지 않는 고유한 결제 식별자
taxnumber-세금
supplyValuenumber-공급가액
tipnumber-봉사료
installmentnumber0할부 개월
timeoutMsnumber60000타임아웃 (ms 단위)
localeCode'ko' | 'en''ko'언어 설정

Example

js
/**
 * 간편결제 요청
 * @param {Object} params 간편결제 요청 파라미터
 * @returns {Object} 결제 결과
 */
const price = 10000;
const tax = Math.floor(price / 11);
const supplyValue = price - tax;

const result = await sdk.payment.requestBarcodePayment({
  paymentKey: "barcodePaymentKey",
  tax,
  supplyValue,
  tip: 0,
  timeoutMs: 60000,
  localeCode: "ko", // "ko" or "en" default "ko"
});

if (result.type === "CANCELED" || result.type === "TIMEOUT") {
  return;
}

console.log(result.response.barcode);

requestCashPayment

현금 결제 후 현금영수증 발급을 요청합니다.

Parameters

파라미터타입필수기본값설명
paymentKeystring-중복되지 않는 고유한 결제 식별자
taxnumber-세금
supplyValuenumber-공급가액
tipnumber-봉사료
installmentnumber0할부 개월
timeoutMsnumber60000타임아웃 (ms 단위)
localeCode'ko' | 'en''ko'언어 설정
identityNumberstring-현금영수증 번호 (휴대폰번호 또는 사업자번호)
issuerType'CONSUMER' | 'BUSINESS'-소득 구분

Example

js
/**
 * 현금 결제 요청
 * @param {Object} params 현금 결제 요청 파라미터
 * @returns {Object} 결제 결과
 */
const price = 10000;
const tax = Math.floor(price / 11);
const supplyValue = price - tax;

const result = await sdk.payment.requestCashPayment({
  paymentKey: "cashPaymentKey",
  tax,
  supplyValue,
  tip: 0,
  timeoutMs: 60000,
  localeCode: "ko", // "ko" or "en" default "ko"
  identityNumber: "01000000000",
});

if (result.type === "CANCELED" || result.type === "TIMEOUT") {
  return;
}

console.log(result.response.cash);

requestPaymentCancel

승인된 결제에 대한 환불을 요청합니다.

Parameters

파라미터타입필수기본값설명
paymentKeystring-원본 결제의 식별자
paymentMethod'CARD' | 'CASH' | 'BARCODE'-원본 결제 수단
taxnumber-취소할 세금
supplyValuenumber-취소할 공급가액
tipnumber-취소할 봉사료
timestampnumber-원본 결제의 승인 시간
approvalNumberstring-원본 결제의 승인번호
installmentnumber0원본 결제의 할부 개월
timeoutMsnumber60000타임아웃 (ms 단위)
localeCode'ko' | 'en''ko'언어 설정
extraData.vanTransactionManagementIdstring-알리페이/위챗페이 취소 시 필요한 값
isSelfIssuanceboolean-현금영수증 자진발급 여부
excludePaymentTypes['CASH']-제외할 결제 수단

Example

js
/**
 * 결제 취소 요청
 * @param {Object} params 결제 취소 요청 파라미터
 * @returns {Object} 취소 결과
 */
const price = 10000;
const tax = Math.floor(price / 11);
const supplyValue = price - tax;

const result = await sdk.payment.requestPaymentCancel({
  paymentKey: "결제했던 paymentKey",
  paymentMethod: "CARD", // "CASH" 또는 "BARCODE"
  tax,
  supplyValue,
  tip: 0,
  timestamp: 1723628943812, // 승인 시 timestamp
  approvalNumber: "000000000", // 승인 시 approvalNumber
  installment: 0, // 승인 시 installment
  timeoutMs: 60000,
  extraData: {
    vanTransactionManagementId: string, // 알리/위챗 승인 시 값
  },
  isSelfIssuance: false, // 현금영수증 자진발급여부
  localeCode: "ko",
});

if (result.type === "CANCELED" || result.type === "TIMEOUT") {
  return;
}

switch (result.response.paymentMethod) {
  case "CARD":
    console.log(result.response.card);
    break;
  case "CASH":
    console.log(result.response.cash);
    break;
  case "BARCODE":
    console.log(result.response.barcode);
    break;
}

getPayment

최근 승인 결과를 조회합니다. requestPayment의 데이터를 유실했을 때, 같은 paymentKey로 단말 로컬 캐시에 저장된 승인 결과를 다시 읽어옵니다.

참고

  • 용도: requestPayment의 결과 복구용 API입니다. WebView reload, 페이지 이동, JS 런타임 재초기화 등으로 데이터를 유실했을 경우 사용합니다.
  • 단말기 기반 동작: 결제를 요청한 단말기에서만 조회할 수 있습니다. 다른 단말기나 서버에서는 조회할 수 없습니다.
  • 캐시 정책: TTL 14일, 최대 1,000건이 저장됩니다. SUCCESS 결과만 캐시되며, CANCELED, TIMEOUT, 승인 실패 결과는 캐시되지 않습니다.

Parameters

파라미터타입필수기본값설명
paymentKeystring-승인 결과를 조회할 결제 식별자

Example

js
const result = await sdk.payment.getPayment({
  paymentKey: "paymentKey",
});

if (result.type === "CANCELED" || result.type === "TIMEOUT") {
  return;
}

switch (result.response.paymentMethod) {
  case "CARD":
    console.log(result.response.card);
    break;
  case "CASH":
    console.log(result.response.cash);
    break;
  case "BARCODE":
    console.log(result.response.barcode);
    break;
}

Response

requestPayment의 Response와 동일합니다.

Error

에러 메시지설명
INVALID_PARAMSpaymentKey가 누락되었거나 빈 문자열인 경우
PAYMENT_NOT_FOUND캐시된 승인 결과가 없는 경우. 아직 캐시가 생성되지 않았거나, 결과가 TIMEOUT, 승인 실패였거나, 캐시 TTL(14일)이 만료된 경우에 발생합니다.

getPaymentCancel

최근 취소 결과를 조회합니다. requestPaymentCancel의 데이터를 유실했을 때, 같은 paymentKey로 단말 로컬 캐시에 저장된 취소 결과를 다시 읽어옵니다.

참고

  • 용도: requestPaymentCancel의 결과 복구용 API입니다. WebView reload, 페이지 이동, JS 런타임 재초기화 등으로 데이터를 유실했을 경우 사용합니다.
  • 단말기 기반 동작: 취소를 요청한 단말기에서만 조회할 수 있습니다. 다른 단말기나 서버에서는 조회할 수 없습니다.
  • 캐시 정책: TTL 14일, 최대 1,000건이 저장됩니다. SUCCESS 결과만 캐시되며, CANCELED, TIMEOUT, 승인 취소 실패 결과는 캐시되지 않습니다.
  • 승인 캐시와 독립: 같은 paymentKey에 대해 승인 결과와 취소 결과는 별도로 저장됩니다. 취소 성공 이후에도 getPayment는 기존 승인 결과를 반환할 수 있습니다.

Parameters

파라미터타입필수기본값설명
paymentKeystring-취소 결과를 조회할 결제 식별자

Example

js
const result = await sdk.payment.getPaymentCancel({
  paymentKey: "paymentKey",
});

if (result.type === "CANCELED" || result.type === "TIMEOUT") {
  return;
}

switch (result.response.paymentMethod) {
  case "CARD":
    console.log(result.response.card);
    break;
  case "CASH":
    console.log(result.response.cash);
    break;
  case "BARCODE":
    console.log(result.response.barcode);
    break;
}

Response

requestPaymentCancel의 Response와 동일합니다.

Error

에러 메시지설명
INVALID_PARAMSpaymentKey가 누락되었거나 빈 문자열인 경우
PAYMENT_NOT_FOUND캐시된 취소 결과가 없는 경우. 아직 캐시가 생성되지 않았거나, 결과가 TIMEOUT, 승인 취소 실패였거나, 캐시 TTL(14일)이 만료된 경우에 발생합니다.

사용 예시

결제 관리 클래스

js
class PaymentManager {
  /**
   * 통합 결제 요청
   * @param {number} amount 통합 결제 금액
   * @param {string} paymentKey 통합 결제 식별자
   */
  async requestPayment(amount, paymentKey) {
    const tax = Math.floor(amount / 11);
    const supplyValue = amount - tax;

    try {
      const result = await sdk.payment.requestPayment({
        paymentKey,
        tax,
        supplyValue,
        tip: 0,
        timeoutMs: 60000,
        localeCode: "ko",
      });

      if (result.type === "SUCCESS") {
        return this.handlePaymentSuccess(result.response);
      } else {
        return this.handlePaymentFailure(result.type);
      }
    } catch (error) {
      console.error("결제 요청 실패:", error);
      throw error;
    }
  }

  /**
   * 결제 취소 요청
   * @param {string} paymentKey 결제 식별자
   * @param {string} paymentMethod 결제 수단
   * @param {number} amount 취소 금액
   * @param {Object} originalPayment 원본 결제 정보
   */
  async requestPaymentCancel(
    paymentKey,
    paymentMethod,
    amount,
    originalPayment,
  ) {
    const tax = Math.floor(amount / 11);
    const supplyValue = amount - tax;

    try {
      const result = await sdk.payment.requestPaymentCancel({
        paymentKey,
        paymentMethod,
        tax,
        supplyValue,
        tip: 0,
        timestamp: originalPayment.timestamp,
        approvalNumber: originalPayment.approvalNumber,
        installment: originalPayment.installment,
        timeoutMs: 60000,
      });

      if (result.type === "SUCCESS") {
        return this.handleCancelSuccess(result.response);
      } else {
        return this.handleCancelFailure(result.type);
      }
    } catch (error) {
      console.error("결제 취소 실패:", error);
      throw error;
    }
  }

  /**
   * 간편결제 요청
   * @param {number} amount 결제 금액
   * @param {string} paymentKey 결제 식별자
   */
  async requestBarcodePayment(amount, paymentKey) {
    const tax = Math.floor(amount / 11);
    const supplyValue = amount - tax;

    try {
      const result = await sdk.payment.requestBarcodePayment({
        paymentKey,
        tax,
        supplyValue,
        tip: 0,
        timeoutMs: 60000,
        localeCode: "ko",
      });

      if (result.type === "SUCCESS") {
        return this.handleBarcodePaymentSuccess(result.response);
      } else {
        return this.handlePaymentFailure(result.type);
      }
    } catch (error) {
      console.error("간편결제 요청 실패:", error);
      throw error;
    }
  }

  /**
   * 현금 결제 요청
   * @param {number} amount 결제 금액
   * @param {string} paymentKey 결제 식별자
   */
  async requestCashPayment(amount, paymentKey) {
    const tax = Math.floor(amount / 11);
    const supplyValue = amount - tax;

    try {
      const result = await sdk.payment.requestCashPayment({
        paymentKey,
        tax,
        supplyValue,
        tip: 0,
        timeoutMs: 60000,
        localeCode: "ko",
        identityNumber: "01000000000",
      });

      if (result.type === "SUCCESS") {
        return this.handleCashPaymentSuccess(result.response);
      } else {
        return this.handlePaymentFailure(result.type);
      }
    } catch (error) {
      console.error("현금 결제 요청 실패:", error);
      throw error;
    }
  }

  handlePaymentSuccess(response) {
    // 결제 성공 처리
    console.log("결제 성공:", response);
  }

  handleBarcodePaymentSuccess(response) {
    // 간편결제 성공 처리
    console.log("간편결제 성공:", response);
  }

  handleCashPaymentSuccess(response) {
    // 현금 결제 성공 처리
    console.log("현금 결제 성공:", response);
  }

  handlePaymentFailure(type) {
    // 결제 실패 처리
    console.log("결제 실패:", type);
  }

  handleCancelSuccess(response) {
    // 취소 성공 처리
    console.log("취소 성공:", response);
  }

  handleCancelFailure(type) {
    // 취소 실패 처리
    console.log("취소 실패:", type);
  }
}

// 사용 예시
async function processPayment() {
  const paymentManager = new PaymentManager();

  // 통합 결제 요청
  await paymentManager.requestPayment(10000, "payment-123");

  // 바코드 간편결제 요청
  await paymentManager.requestBarcodePayment(10000, "barcode-payment-456");

  // 현금 결제 요청
  await paymentManager.requestCashPayment(10000, "cash-payment-789");

  // 결제 취소
  await paymentManager.requestPaymentCancel("payment-123", "CARD", 10000, {
    timestamp: 1723628943812,
    approvalNumber: "000000000",
    installment: 0,
  });
}