Payment API
토스 프론트에서 결제 및 환불을 처리하기 위한 API예요. 카드, 애플페이, 삼성페이, 현금 영수증, 간편결제 등 다양한 결제 수단을 지원해요.
주의 사항
프론트에서 카드 결제 테스트 시 실제 승인이 발생하여 주의가 필요해요.
주의 사항
[카드 결제 테스트 시]
- 테스트 후 반드시 즉시 취소 처리 필요
- 결제 응답의
paymentKey,approvalNumber,timestamp,vanTransactionKey등 승인 취소를 위한 값을 저장하여 취소에 활용
[권장 테스트 방법]
- 동작 확인 목적이라면 현금 결제 > 현금영수증 미발급으로 테스트 권장
- 실제 금전적 부담 없이 결제 플로우 확인 가능
Methods
requestPayment
통합 결제를 요청해요.
Parameters
| 파라미터 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
paymentKey | string | ✓ | - | 중복되지 않는 고유한 결제 식별자 |
tax | number | ✓ | - | 세금 (일반적으로 Math.floor(price / 11), 면세인 경우 0) |
supplyValue | number | ✓ | - | 공급가액 (결제 금액 - 세금) |
taxExemptValue | number | - | 면세 금액 | |
tip | number | ✓ | - | 봉사료 |
installment | number | 0 | 할부 개월 | |
tid | string | - | 결제 TID (CAT ID) | |
timeoutMs | number | 60000 | 타임아웃 (ms 단위) | |
localeCode | 'ko' | 'en' | 'ko' | 언어 설정 | |
excludePaymentTypes | ['CASH'] | - | 제외할 결제 수단 (현재 현금만 지원) |
면세 금액 설정
- 과세·면세가 함께 포함된 결제에서는
supplyValue에 면세 금액을 포함하고,taxExemptValue에 면세 금액을 입력해요. taxExemptValue를 생략하면tax가 0인 경우supplyValue전체를 면세로 처리하고,tax가 0보다 크면 면세 금액을 0으로 처리해요.- 결제를 취소할 때는 원거래와 동일한
tax,supplyValue,taxExemptValue를 전달해요.
paymentKey는 파트너가 직접 만들어요
paymentKey는 토스에서 발급하는 값이 아니라 파트너가 만들어 전달하는 중복되지 않는 결제 식별자예요. 64자 이하로 만들어주세요.
결제를 취소하거나 영수증을 출력할 때 같은 값을 다시 사용하니, 결제를 요청할 때 쓴 값을 저장해 두세요.
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,
taxExemptValue: 0, // 면세 금액
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',
tid?: string, // 결제 TID (CAT ID)
vanTransactionKey?: string, // VAN 거래 일련번호 (무카드 취소 시 사용)
card: {
van: 'NICE' | 'KIS' | 'KOVAN' | 'KFTC' | 'SMARTRO' | 'KSNET' | 'DAOU' | 'NICEPAY',
timestamp: number, // 승인 시간
approvalNumber: string, // 승인번호
acquirerName: string, // 매입사 명
acquirerCode: string, // 매입사 코드
issuerName: string, // 발급사 명
issuerCode: string, // 발급사 코드
cardType: 'CREDIT_CARD' | 'CHECK_CARD' | 'PREPAID_CARD',
balance: number, // 선불카드 잔액
installment: number, // 할부 개월
shopCode?: string, // 가맹점 번호 (숫자 9자리)
maskedCardNumber?: string, // 마스킹된 카드 번호 (bin 8자리만 표시)
},
},
}현금 영수증
js
// 현금영수증 발급 시
{
type: 'SUCCESS',
response: {
paymentMethod: 'CASH',
tid?: string, // 결제 TID (CAT ID)
vanTransactionKey?: string, // VAN 거래 일련번호
cash: {
isCashReceipt: true,
cashReceipt: {
van: 'NICE' | 'KIS' | 'KOVAN' | 'KFTC' | 'SMARTRO' | 'KSNET' | 'DAOU' | 'NICEPAY',
timestamp: number, // 승인 시간
issuerType: 'CONSUMER' | 'BUSINESS', // 발급 대상 유형
issuanceType: 'PHONE' | 'BUSINESS_NUMBER' | 'CARD', // 발급 방식
identityNumber: string, // 현금영수증 번호 값
maskedIdentityNumber: string, // 현금영수증 번호 값 (일부 별표 처리)
approvalNumber: string, // 승인번호
isSelfIssuance: boolean, // 자진 발급 여부
shopCode: null, // 현금영수증에는 없는 값이라 항상 null이에요
},
},
},
}
// 현금영수증 미발급 시
{
type: 'SUCCESS',
response: {
paymentMethod: 'CASH',
tid?: string, // 결제 TID (CAT ID)
vanTransactionKey?: string, // VAN 거래 일련번호
cash: {
isCashReceipt: false,
},
},
}간편결제
js
{
type: 'SUCCESS',
response: {
paymentMethod: 'BARCODE',
tid?: string, // 결제 TID (CAT ID)
vanTransactionKey?: string, // VAN 거래 일련번호
barcode: {
van: 'NICE' | 'KIS' | 'KOVAN' | 'KFTC' | 'SMARTRO' | 'KSNET' | 'DAOU' | 'NICEPAY',
timestamp: number, // 승인 시간
approvalNumber: string, // 승인번호
acquirerName: string, // 매입사 명
acquirerCode: string, // 매입사 코드
issuerName: string, // 발급사 명
issuerCode: string, // 발급사 코드
cardType: 'CREDIT_CARD' | 'CHECK_CARD' | 'PREPAID_CARD',
balance: number, // 선불카드 잔액
shopCode: string, // 가맹점 번호 (숫자 9자리)
},
extraData?: {
vanTransactionManagementId: string, // 알리페이/위챗페이 취소 시 필요
},
},
}vanTransactionKey 안내
vanTransactionKey는 무카드 취소에 필요한 VAN 거래 일련번호예요. 선택 값이라 VAN사·결제 환경에 따라 내려오지 않을 수 있으니, 값이 있으면 저장해두었다가 취소에 활용해주세요.
requestBarcodePayment
QR, 바코드를 인식하는 간편결제를 요청해요.
Parameters
| 파라미터 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
paymentKey | string | ✓ | - | 중복되지 않는 고유한 결제 식별자 |
tax | number | ✓ | - | 세금 |
supplyValue | number | ✓ | - | 공급가액 |
taxExemptValue | number | - | 면세 금액 | |
tip | number | ✓ | - | 봉사료 |
installment | number | 0 | 할부 개월 | |
tid | string | - | 결제 TID (CAT ID) | |
timeoutMs | number | 60000 | 타임아웃 (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,
taxExemptValue: 0, // 면세 금액
tip: 0,
timeoutMs: 60000,
localeCode: "ko", // "ko" or "en" default "ko"
});
if (result.type === "CANCELED" || result.type === "TIMEOUT") {
return;
}
console.log(result.response.barcode);Response
requestPayment Response의 간편결제와 같아요. paymentMethod는 항상 'BARCODE'예요.
requestCashPayment
현금 결제 후 현금영수증 발급을 요청해요.
Parameters
| 파라미터 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
paymentKey | string | ✓ | - | 중복되지 않는 고유한 결제 식별자 |
tax | number | ✓ | - | 세금 |
supplyValue | number | ✓ | - | 공급가액 |
taxExemptValue | number | - | 면세 금액 | |
tip | number | ✓ | - | 봉사료 |
installment | number | 0 | 할부 개월 | |
tid | string | - | 결제 TID (CAT ID) | |
timeoutMs | number | 60000 | 타임아웃 (ms 단위) | |
localeCode | 'ko' | 'en' | 'ko' | 언어 설정 | |
identityNumber | string | - | 현금영수증 번호 (휴대폰번호 또는 사업자번호) | |
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,
taxExemptValue: 0, // 면세 금액
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);Response
requestPayment Response의 현금 영수증과 같아요. paymentMethod는 항상 'CASH'이고, 현금영수증 발급 여부에 따라 cash 안의 필드가 달라져요.
requestPaymentCancel
승인된 결제에 대한 환불을 요청해요.
현금 결제 취소는 현금영수증 승인을 취소해요
현금 결제 취소는 현금영수증 승인을 취소하는 방식으로 동작해요. 그래서 현금영수증을 발행하지 않은 현금 결제는 취소할 대상이 없어요.
Parameters
| 파라미터 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
paymentKey | string | ✓ | - | 원본 결제에 전달했던 paymentKey |
paymentMethod | 'CARD' | 'CASH' | 'BARCODE' | ✓ | - | 원본 결제 수단 |
tax | number | ✓ | - | 취소할 세금 |
supplyValue | number | ✓ | - | 취소할 공급가액 |
taxExemptValue | number | - | 취소할 면세 금액 | |
tip | number | ✓ | - | 취소할 봉사료 |
timestamp | number | ✓ | - | 원본 결제의 승인 시간 |
approvalNumber | string | ✓ | - | 원본 결제의 승인번호 |
installment | number | 0 | 원본 결제의 할부 개월 | |
tid | string | - | 결제 TID (CAT ID) | |
timeoutMs | number | 60000 | 타임아웃 (ms 단위) | |
localeCode | 'ko' | 'en' | 'ko' | 언어 설정 | |
extraData.vanTransactionManagementId | string | - | 알리페이/위챗페이 취소 시 필요한 값 | |
isSelfIssuance | boolean | - | 현금영수증 자진발급 여부 | |
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,
taxExemptValue: 0, // 원거래의 면세 금액
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;
}Response
requestPayment의 Response와 동일해요. 원본 결제 수단에 따라 paymentMethod가 'CARD', 'CASH', 'BARCODE' 중 하나로 와요.
requestCardlessPaymentCancel
승인된 카드 결제를 카드 인식 없이 취소해요(무카드 취소). VAN 거래 일련번호(vanTransactionKey)로 취소를 진행하며, 프론트 단말기에 취소 화면이 표시되지 않고 백그라운드로 처리돼요.
참고
- 지원 VAN: NICE
- 지원 결제수단: 카드(
CARD)
Parameters
requestPaymentCancel의 파라미터에 vanTransactionKey가 추가된 형태예요.
| 파라미터 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
paymentKey | string | ✓ | - | 원본 결제에 전달했던 paymentKey |
paymentMethod | 'CARD' | ✓ | - | 원본 결제 수단 (현재 카드만 지원) |
tax | number | ✓ | - | 취소할 세금 |
supplyValue | number | ✓ | - | 취소할 공급가액 |
taxExemptValue | number | - | 취소할 면세 금액 | |
tip | number | ✓ | - | 취소할 봉사료 |
timestamp | number | ✓ | - | 원본 결제의 승인 시간 |
approvalNumber | string | ✓ | - | 원본 결제의 승인번호 |
vanTransactionKey | string | ✓ | - | 원본 결제 응답의 vanTransactionKey 값 |
installment | number | 0 | 원본 결제의 할부 개월 | |
tid | string | - | 결제 TID (CAT ID) | |
timeoutMs | number | 60000 | 타임아웃 (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.requestCardlessPaymentCancel({
paymentKey: "결제했던 paymentKey",
paymentMethod: "CARD",
tax,
supplyValue,
taxExemptValue: 0, // 원거래의 면세 금액
tip: 0,
timestamp: 1723628943812, // 승인 시 timestamp
approvalNumber: "000000000", // 승인 시 approvalNumber
vanTransactionKey: "000000000000", // 승인 시 전달받은 VAN 거래 일련번호
installment: 0, // 승인 시 installment
timeoutMs: 60000,
localeCode: "ko",
});
if (result.type === "CANCELED" || result.type === "TIMEOUT") {
return;
}
console.log(result.response.card);Response
js
{
type: 'SUCCESS',
response: {
paymentMethod: 'CARD',
tid?: string, // 결제 TID (CAT ID)
vanTransactionKey: string, // VAN 거래 일련번호
card: {
van: 'NICE' | 'KIS' | 'KOVAN' | 'KFTC' | 'SMARTRO' | 'KSNET' | 'DAOU' | 'NICEPAY',
timestamp: number, // 승인 시간
approvalNumber: string, // 승인번호
acquirerName: string, // 매입사 명
acquirerCode: string, // 매입사 코드
issuerName: string, // 발급사 명
issuerCode: string, // 발급사 코드
cardType: 'CREDIT_CARD' | 'CHECK_CARD' | 'PREPAID_CARD',
balance: number, // 선불카드 잔액
installment: number, // 할부 개월
shopCode?: string, // 가맹점 번호 (숫자 9자리)
maskedCardNumber?: string, // 마스킹된 카드 번호 (bin 8자리만 표시)
},
},
}getPayment
최근 승인 결과를 조회해요. requestPayment의 데이터를 유실했을 때, 같은 paymentKey로 단말 로컬 캐시에 저장된 승인 결과를 다시 읽어와요.
참고
- 용도:
requestPayment의 결과 복구용 API예요. WebView reload, 페이지 이동, JS 런타임 재초기화 등으로 데이터를 유실했을 경우 사용해요. - 단말기 기반 동작: 결제를 요청한 단말기에서만 조회할 수 있어요. 다른 단말기나 서버에서는 조회할 수 없어요.
- 캐시 정책: TTL 14일, 최대 1,000건이 저장돼요.
SUCCESS결과만 캐시되며,CANCELED,TIMEOUT, 승인 실패 결과는 캐시되지 않아요.
Parameters
| 파라미터 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
paymentKey | string | ✓ | - | 승인 결과를 조회할 결제 식별자 |
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_PARAMS | paymentKey가 누락되었거나 빈 문자열인 경우 |
PAYMENT_NOT_FOUND | 캐시된 승인 결과가 없는 경우. 아직 캐시가 생성되지 않았거나, 결과가 TIMEOUT, 승인 실패였거나, 캐시 TTL(14일)이 만료된 경우에 발생해요. |
getPaymentCancel
최근 취소 결과를 조회해요. requestPaymentCancel의 데이터를 유실했을 때, 같은 paymentKey로 단말 로컬 캐시에 저장된 취소 결과를 다시 읽어와요.
참고
- 용도:
requestPaymentCancel의 결과 복구용 API예요. WebView reload, 페이지 이동, JS 런타임 재초기화 등으로 데이터를 유실했을 경우 사용해요. - 단말기 기반 동작: 취소를 요청한 단말기에서만 조회할 수 있어요. 다른 단말기나 서버에서는 조회할 수 없어요.
- 캐시 정책: TTL 14일, 최대 1,000건이 저장돼요.
SUCCESS결과만 캐시되며,CANCELED,TIMEOUT, 승인 취소 실패 결과는 캐시되지 않아요. - 승인 캐시와 독립: 같은
paymentKey에 대해 승인 결과와 취소 결과는 별도로 저장돼요. 취소 성공 이후에도getPayment는 기존 승인 결과를 반환할 수 있어요.
Parameters
| 파라미터 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
paymentKey | string | ✓ | - | 취소 결과를 조회할 결제 식별자 |
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_PARAMS | paymentKey가 누락되었거나 빈 문자열인 경우 |
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,
});
}