정기결제 개발하기
미니앱에서 토스페이 정기결제를 연동하는 방법을 안내해요.
빌링키 생성 → 사용자 인증 → 결제 승인 → 해지 순서로 전체 플로우를 설명해요.

사전 준비 사항
콘솔 설정이 필요해요
API를 호출하기 전에 아래 절차를 먼저 완료해야 해요.
- 청약을 진행해 주세요.
- 콘솔에서 토스페이 키 값을 등록해 주세요.
꼭 확인해 주세요
- 기존에 토스페이를 사용하고 있더라도, 앱인토스에서는 별도의 토스페이 가맹점 키 발급이 필요해요.
- 앱인토스에서 토스페이를 사용 중이더라도, 정기결제(자동결제)는 추가 청약이 필요해요.
청약/수수료/설정 방법은 토스페이 소개 문서를 참고해 주세요.
결제 대상 사용자 식별하기
토스페이는 아래 2가지 방법 중 하나로 결제 대상을 식별해요. 두 값을 동시에 전달하지 말고 하나만 선택해 주세요.
| 구분 | 발급 방법 |
|---|---|
x-toss-user-key | 토스 로그인으로 받은 userKey 값이에요. |
x-anon-key | 사용자 식별키 발급으로 받은 hash 값이에요. |
목적에 따라 선택해 주세요.
- 이미 토스 로그인을 연동했거나, 이름·이메일 같은 회원 정보와 묶어 통합 관리하려면 토스 로그인을 사용해요.
- 로그인 연동 없이 가볍게 사용자만 식별하려면 사용자 식별키 발급 기능을 사용해요.
x-anon-key(hash)가 유효한 값인지 미리 확인하고 싶다면 식별키 검증하기 API를 사용해 주세요.
기본 정보
| 항목 | 값 |
|---|---|
| Base URL | https://pay-apps-in-toss-api.toss.im |
| 서버 인증 | mTLS (클라이언트 인증서) |
| Content-Type | application/json |
서버 간 통신에는 mTLS 인증서가 필요해요
정기결제 API는 파트너 서버에서 앱인토스 서버로 호출하는 서버 간 통신이에요.
보안을 위해 서버에 mTLS 인증서를 설정한 뒤 호출해 주세요.
인증서 발급 방법은 mTLS 인증서 발급 방법을 참고해 주세요.
테스트하기
결제 생성 요청 시 isTestPayment: true로 설정하면 샌드박스 환경에서 결제를 테스트할 수 있어요.
콘솔에 별도로 설정하지 않아도 되고, 청약 전에도 테스트할 수 있어요.
단, 샌드박스 환경에는 아래 제한이 있어요.
- 빌링키 생성(1단계)까지만 가능하고, 결제 승인(3단계)은 지원하지 않아요.
- 샌드박스에서 생성된
wrappedToken은 운영 환경에서 사용할 수 없어요. - 실제 결제 흐름 검증은 운영 키로 전환한 뒤 진행해야 해요.
1. 빌링키 생성하기
사용자의 정기결제 수단을 등록해요. 응답으로 받은 wrappedToken을 클라이언트에 전달해서 사용자 인증을 진행해요.
- Content-Type:
application/json - Method:
POST - URL:
/api-partner/v1/apps-in-toss/pay/create-billing-key
요청 헤더
결제 대상을 식별하는 헤더는 아래 2가지 중 하나를 사용해요. 두 헤더를 동시에 전달하지 마세요.
| 이름 | 타입 | 필수 | 설명 |
|---|---|---|---|
x-toss-user-key | string | 택 1 | 토스 로그인으로 받은 userKey예요. 사용자 정보 받기를 통해 획득할 수 있어요. |
x-anon-key | string | 택 1 | 사용자 식별키 발급으로 받은 hash 값이에요. |
요청 파라미터
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
productDesc | String | Y | 정기결제 상품명 (예: "월간 구독") |
isTestPayment | Boolean | Y | 테스트 결제 여부 |
{
"productDesc": "월간 구독",
"isTestPayment": false
}응답 파라미터
| 필드 | 타입 | 설명 |
|---|---|---|
wrappedToken | String | 정기결제 토큰이에요. 이후 모든 API 호출 시 사용해요. |
{
"resultType": "SUCCESS",
"success": {
"wrappedToken": "550e8400-e29b-41d4-a716-446655440000"
}
}꼭 확인해 주세요
wrappedToken은 결제 승인, 상태 조회, 해지 시 모두 사용되므로 반드시 저장해야 해요.
2. 사용자 인증하기
SDK를 통해 연동해 주세요.
빌링키 생성 응답으로 받은 wrappedToken을 클라이언트에 전달해요.
클라이언트는 앱인토스 SDK를 사용해서 토스페이 인증을 수행해요.
import { TossPay } from '@apps-in-toss/web-framework';
const { success, reason } = await TossPay.requestTossPayPaysBilling({ wrappedToken });
if (success) {
// 인증 성공 → 서버에 결제 승인 요청
} else {
// 인증 실패 (reason에 실패 사유)
}반환 값
| 필드 | 타입 | 설명 |
|---|---|---|
success | boolean | 인증 성공 여부 |
reason | string? | 실패 시 사유 |
SDK 최소 지원 버전
- Android:
5.256.0 - iOS:
5.256.0
3. 정기결제 실행하기
등록된 결제수단으로 결제를 승인해요.
- Content-Type:
application/json - Method:
POST - URL:
/api-partner/v1/apps-in-toss/pay/execute-billing
요청 헤더
결제 대상을 식별하는 헤더는 아래 2가지 중 하나를 사용해요. 두 헤더를 동시에 전달하지 마세요.
| 이름 | 타입 | 필수 | 설명 |
|---|---|---|---|
x-toss-user-key | string | 택 1 | 토스 로그인으로 받은 userKey예요. 사용자 정보 받기를 통해 획득할 수 있어요. |
x-anon-key | string | 택 1 | 사용자 식별키 발급으로 받은 hash 값이에요. |
요청 파라미터
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
wrappedToken | String | Y | 빌링키 생성 시 받은 토큰 |
orderNo | String | Y | 주문번호 |
productDesc | String | Y | 상품 설명 |
spreadOut | Int | Y | 할부 개월 수 (0=일시불) |
amount | Long | Y | 결제 금액 |
amountTaxFree | Long | Y | 비과세 금액 |
amountTaxable | Long | N | 과세 금액 |
amountVat | Long | N | 부가세 |
amountServiceFee | Long | N | 봉사료 |
cashReceipt | Boolean | N | 현금영수증 발급 여부 (기본: true) |
sendFailPush | Boolean | N | 실패 시 푸시 발송 여부 (기본: true) |
cashReceiptTradeOption | String | N | 현금영수증 타입 (기본: GENERAL) |
isTestPayment | Boolean | Y | 테스트 결제 여부 |
{
"wrappedToken": "550e8400-e29b-41d4-a716-446655440000",
"orderNo": "ORDER-20260416-001",
"productDesc": "월간 구독 결제",
"spreadOut": 0,
"amount": 9900,
"amountTaxFree": 0,
"isTestPayment": false
}응답 파라미터
| 필드 | 타입 | 설명 |
|---|---|---|
code | Int | 응답 코드예요. 0이면 성공이에요. |
mode | String | 결제 모드예요. |
payToken | String | 결제 토큰이에요. |
orderNo | String | 주문번호예요. |
payMethod | String | 결제 수단이에요. (CARD, TOSS_MONEY 등) |
amount | Int | 승인 금액이에요. |
transactionId | String | 거래 ID예요. |
approvalTime | String | 승인 시각이에요. |
discountedAmount | Int | 할인 금액이에요. |
paidAmount | Int | 실결제 금액이에요. |
cardCompanyName | String | 승인 카드사명이에요. |
cardCompanyCode | String | 승인 카드사 코드예요. |
cardAuthorizationNo | String | 구매자가 확인할 수 있는 카드사 승인번호예요. 라이브 키 결제에서 확인할 수 있어요. |
salesCheckLinkUrl | String | 신용카드 매출전표 호출 URL이에요. |
noInterest | String | 카드 무이자 적용 여부예요. true: 무이자, false: 일반 |
cardNumber | String | 마스킹된 카드번호예요. 카드번호 16자리 중 중간 자리는 마스킹돼요. |
cardUserType | String | 카드 사용자 구분이에요. PERSONAL: 본인카드, PERSONAL_FAMILY: 가족카드, CORP_PERSONAL: 법인지정 결제계좌 임직원, CORP_PRIVATE: 법인 공용, CORP_COMPANY: 법인지정 결제계좌 회사(하나카드만) |
cardBinNumber | String | 카드 BIN 번호예요. |
cardNum4Print | String | 사용자가 선택한 카드의 끝 4자리예요. |
{
"resultType": "SUCCESS",
"success": {
"code": 0,
"mode": "LIVE",
"payToken": "7W3000019000001",
"orderNo": "ORDER-20260416-001",
"payMethod": "CARD",
"amount": 9900,
"transactionId": "20260416000001",
"approvalTime": "20260416120000",
"discountedAmount": 0,
"paidAmount": 9900,
"cardCompanyName": "삼성",
"cardCompanyCode": 3,
"cardAuthorizationNo": "87654321",
"salesCheckLinkUrl": "https://pay.toss.im/payfront/web/external/sales-check?payToken=example-payToken",
"noInterest": false,
"cardNumber": "654321******1234",
"cardUserType": "NONE",
"cardBinNumber": "654321",
"cardNum4Print": "1234"
}
}4. 정기결제 환불하기
정기결제 건을 환불해요.
- Content-Type:
application/json - Method:
POST - URL:
/api-partner/v1/apps-in-toss/pay/refund-billing
요청 헤더
결제 대상을 식별하는 헤더는 아래 2가지 중 하나를 사용해요. 두 헤더를 동시에 전달하지 마세요.
| 이름 | 타입 | 필수 | 설명 |
|---|---|---|---|
x-toss-user-key | string | 택 1 | 토스 로그인으로 받은 userKey예요. 사용자 정보 받기를 통해 획득할 수 있어요. |
x-anon-key | string | 택 1 | 사용자 식별키 발급으로 받은 hash 값이에요. |
요청 파라미터
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
payToken | String | Y | 정기결제 실행(3단계) 응답에서 받은 결제 토큰 |
reason | String | Y | 환불 사유 |
isTestPayment | Boolean | Y | 테스트 결제 여부 |
{
"payToken": "string",
"reason": "string",
"isTestPayment": true
}응답 파라미터
| 이름 | 타입 | 설명 |
|---|---|---|
refundNo | String | 환불 번호예요. |
approvalTime | String | 환불 처리 시간이에요. (yyyy-MM-dd HH:mm:ss) |
cashReceiptMgtKey | String | 현금영수증 관리번호 식별값이에요. |
refundableAmount | Integer | 환불 가능 금액이에요. |
discountedAmount | Integer | 할인된 금액이에요. |
paidAmount | Integer | 지불수단 승인금액이에요. |
refundedAmount | Integer | 환불 요청 금액이에요. |
refundedDiscountAmount | Integer | 환불 요청 금액 중 실 차감된 할인 금액이에요. |
refundedPaidAmount | Integer | 환불 요청 금액 중 실 차감된 지불수단 금액이에요. |
payToken | String | 환불된 결제 토큰이에요. |
transactionId | String | 거래 트랜잭션 아이디예요. |
cardMethodType | String | 카드 타입이에요. CREDIT: 신용카드, CHECK: 체크카드, PREPAYMENT: 선불카드 |
cardNumber | String | 마스킹된 카드번호예요. |
cardUserType | String | 카드 사용자 구분이에요. PERSONAL: 본인카드, PERSONAL_FAMILY: 가족카드, CORP_PERSONAL: 법인지정 결제계좌 임직원, CORP_PRIVATE: 법인 공용, CORP_COMPANY: 법인지정 결제계좌 회사(하나카드만) |
cardNum4Print | String | 사용자가 선택한 카드의 끝 4자리예요. |
cardBinNumber | String | 카드 BIN 번호예요. |
accountBankCode | String | 은행 코드예요. 토스머니 결제의 경우 토스가 정의한 은행 코드를 전달해요. |
accountBankName | String | 은행명이에요. |
accountNumber | String | 마스킹된 계좌번호예요. |
{
"resultType": "SUCCESS",
"success": {
"refundNo": "string",
"approvalTime": "string",
"cashReceiptMgtKey": "string",
"refundableAmount": 0,
"discountedAmount": 0,
"paidAmount": 0,
"refundedAmount": 0,
"refundedDiscountAmount": 0,
"refundedPaidAmount": 0,
"payToken": "string",
"transactionId": "string",
"cardMethodType": "string",
"cardNumber": "string",
"cardUserType": "string",
"cardNum4Print": "string",
"cardBinNumber": "string",
"accountBankCode": "string",
"accountBankName": "string",
"accountNumber": "string"
}
}5. 빌링키 상태 조회하기
등록된 정기결제 수단의 상태를 조회해요.
- Content-Type:
application/json - Method:
POST - URL:
/api-partner/v1/apps-in-toss/pay/get-billing-key-status
요청 헤더
결제 대상을 식별하는 헤더는 아래 2가지 중 하나를 사용해요. 두 헤더를 동시에 전달하지 마세요.
| 이름 | 타입 | 필수 | 설명 |
|---|---|---|---|
x-toss-user-key | string | 택 1 | 토스 로그인으로 받은 userKey예요. 사용자 정보 받기를 통해 획득할 수 있어요. |
x-anon-key | string | 택 1 | 사용자 식별키 발급으로 받은 hash 값이에요. |
요청 파라미터
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
wrappedToken | String | Y | 정기결제 토큰 |
isTestPayment | Boolean | Y | 테스트 결제 여부 |
{
"wrappedToken": "550e8400-e29b-41d4-a716-446655440000",
"isTestPayment": false
}응답 파라미터
| 필드 | 타입 | 설명 |
|---|---|---|
code | Int | 응답 코드예요. 0이면 성공이에요. |
billingKeyStatus | String | 빌링키 상태예요. |
cardCompanyName | String | 승인 카드사명이에요. |
cardCompanyNo | String | 승인 카드사 코드예요. |
cardNumber | String | 마스킹된 카드번호예요. 카드번호 16자리 중 중간 자리는 마스킹돼요. |
cardImgUrl | String | 카드 이미지예요. |
accountBankName | String | 은행명이에요. |
accountBankCode | String | 은행 코드예요. 토스머니 결제의 경우 토스가 정의한 은행 코드를 전달해요. |
accountNumber | String | 계좌번호예요. 일부 마스킹이 포함돼요. |
accountName | String | 은행명이에요. |
accountImgUrl | String | 은행 이미지예요. |
6. 빌링키 해지하기
등록된 정기결제 수단을 해지해요.
해지 후에는 해당 wrappedToken으로 결제를 승인할 수 없어요.
- Content-Type:
application/json - Method:
POST - URL:
/api-partner/v1/apps-in-toss/pay/remove-billing-key
요청 헤더
결제 대상을 식별하는 헤더는 아래 2가지 중 하나를 사용해요. 두 헤더를 동시에 전달하지 마세요.
| 이름 | 타입 | 필수 | 설명 |
|---|---|---|---|
x-toss-user-key | string | 택 1 | 토스 로그인으로 받은 userKey예요. 사용자 정보 받기를 통해 획득할 수 있어요. |
x-anon-key | string | 택 1 | 사용자 식별키 발급으로 받은 hash 값이에요. |
요청 파라미터
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
wrappedToken | String | Y | 정기결제 토큰 |
isTestPayment | Boolean | Y | 테스트 결제 여부 |
{
"wrappedToken": "550e8400-e29b-41d4-a716-446655440000",
"isTestPayment": false
}응답 파라미터
| 필드 | 타입 | 설명 |
|---|---|---|
code | Int | 응답 코드예요. 0이면 성공이에요. |
msg | String | 결과 메시지예요. |
코드 및 에러 목록
은행코드 리스트
토스머니 결제의 경우 사용자가 선택한 계좌 정보를 함께 전달해요.
| 은행 코드 | 은행 명 |
|---|---|
| 002 | KDB산업은행 |
| 003 | IBK기업은행 |
| 004 | KB국민은행 |
| 005 | KEB하나은행 |
| 007 | 수협은행 |
| 011 | NH농협은행 |
| 020 | 우리은행 |
| 023 | SC은행 |
| 027 | 씨티은행 |
| 031 | 대구은행 |
| 032 | 부산은행 |
| 034 | 광주은행 |
| 035 | 제주은행 |
| 037 | 전북은행 |
| 039 | 경남은행 |
| 045 | MG새마을금고 |
| 048 | 신협 |
| 050 | 저축은행 |
| 064 | 산림조합 |
| 071 | 우체국 |
| 081 | 하나은행 |
| 088 | 신한은행 |
| 089 | 케이뱅크 |
| 090 | 카카오뱅크 |
| 092 | 토스뱅크 |
| 103 | SBI저축은행 |
| 218 | KB증권 |
| 230 | 미래에셋증권 |
| 238 | 미래에셋증권 |
| 240 | 삼성증권 |
| 243 | 한국투자증권 |
| 247 | NH투자증권 |
| 261 | 교보증권 |
| 262 | 하이투자증권 |
| 263 | 현대차투자증권 |
| 264 | 키움증권 |
| 265 | 이베스트증권 |
| 266 | SK증권 |
| 267 | 대신증권 |
| 269 | 한화투자증권 |
| 270 | 하나증권 |
| 271 | 토스증권 |
| 278 | 신한투자증권 |
| 279 | DB금융투자 |
| 280 | 유진투자 |
| 287 | 메리츠증권 |
| 888 | 토스머니 |
| 889 | 토스포인트 |
카드사코드 리스트
| 카드사 이름 | 카드(매입사) 코드 |
|---|---|
| 신한 | 1 |
| 현대 | 2 |
| 삼성 | 3 |
| 국민 | 4 |
| 롯데 | 5 |
| 하나 | 6 |
| 우리 | 7 |
| 농협 | 8 |
| 씨티(미지원) | 9 |
| 비씨(BC) | 10 |
빌링키 상태 리스트
| 상태 | 빌링키 상태 코드 |
|---|---|
| 빌링키 생성 완료 | CREATED |
| 사용자 인증 진행중 | AUTHENTICATING |
| 사용자 인증 완료 | ACTIVE |
| 빌링키 삭제 | REMOVED |
| 유효하지 않은 빌링키 | FAILED |
에러 케이스
| code | 상황 | 에러 메시지 |
|---|---|---|
| 5001 | 토스페이 청약이 되어 있지 않은 상태 | 토스페이 청약이 되어 있지 않습니다. |
| 5005 | 해지된 토큰으로 결제 시도 | 비활성화된 빌링키에요. |
| 5006 | 유효하지 않은 토큰으로 호출 | 빌링키를 찾을 수 없어요. |
| 40000 | 요청 데이터가 유효하지 않은 경우 | 요청 데이터가 유효하지 않아요. |
| - | 토스페이 측 오류 | 토스페이 에러코드와 메시지가 전달돼요. |

