정기결제 개발하기
시작 전에 확인해 주세요
- 기존에 토스페이를 사용하고 있더라도, 앱인토스에서는 별도의 토스페이 가맹점 키 발급이 필요해요.
- 앱인토스에서 토스페이를 사용 중이더라도, 정기결제(자동결제)는 추가 청약이 필요해요.
- 토스페이 연동 절차와 계약, 정기결제 수수료는 토스페이 소개 문서에서 확인할 수 있어요.
미니앱에서 토스페이 정기결제를 연동하는 방법을 안내해요.
빌링키 생성 → 사용자 인증 → 결제 승인 → 해지 순서로 전체 플로우를 설명해요.

기본 정보
| 항목 | 값 |
|---|---|
| Base URL | https://apps-in-toss-api.toss.im |
| 인증 | mTLS (클라이언트 인증서) + userKey |
| Content-Type | application/json |
유의사항
- 테스트 키로 생성한
wrappedToken은 운영 환경에서 사용할 수 없어요. - 테스트 키는 빌링키 생성(1단계)까지만 가능하고, 결제 승인(3단계)은 불가해요.
- 실제 결제 흐름 검증은 운영 키로 전환한 뒤 진행해야 해요.
- 모든 API에
isTestPayment: true를 설정하면 샌드박스 환경에서 동작해요. - 샌드박스에서 생성된 토큰은 운영 환경에서 사용할 수 없어요.
1. 빌링키 생성
사용자의 정기결제 수단을 등록해요. 응답으로 받은 wrappedToken을 클라이언트에 전달해서 사용자 인증을 진행해요.
- Content-Type:
application/json - Method:
POST - URL:
/api-partner/v1/apps-in-toss/pay/create-billing-key
요청 파라미터
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
productDesc | String | Y | 정기결제 상품명 (예: "월간 구독") |
isTestPayment | Boolean | Y | 테스트 결제 여부 |
json
{
"productDesc": "월간 구독",
"isTestPayment": false
}응답 파라미터
| 필드 | 타입 | 설명 |
|---|---|---|
wrappedToken | String | 정기결제 토큰이에요. 이후 모든 API 호출 시 사용해요. |
json
{
"resultType": "SUCCESS",
"success": {
"wrappedToken": "550e8400-e29b-41d4-a716-446655440000"
}
}꼭 확인해 주세요
wrappedToken은 결제 승인, 상태 조회, 해지 시 모두 사용되므로 반드시 저장해야 해요.
2. 사용자 인증
SDK를 통해 연동해 주세요.
빌링키 생성 응답으로 받은 wrappedToken을 클라이언트에 전달해요.
클라이언트는 앱인토스 SDK를 사용해서 토스페이 인증을 수행해요.
typescript
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
요청 파라미터
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
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 | 테스트 결제 여부 |
json
{
"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자리예요. |
json
{
"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/get-billing-key-status
요청 파라미터
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
wrappedToken | String | Y | 정기결제 토큰 |
isTestPayment | Boolean | Y | 테스트 결제 여부 |
json
{
"wrappedToken": "550e8400-e29b-41d4-a716-446655440000",
"isTestPayment": false
}응답 파라미터
| 필드 | 타입 | 설명 |
|---|---|---|
code | Int | 응답 코드예요. 0이면 활성이에요. |
msg | String | 상태 메시지예요. |
5. 빌링키 해지
등록된 정기결제 수단을 해지해요.
해지 후에는 해당 wrappedToken으로 결제를 승인할 수 없어요.
- Content-Type:
application/json - Method:
POST - URL:
/api-partner/v1/apps-in-toss/pay/remove-billing-key
요청 파라미터
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
wrappedToken | String | Y | 정기결제 토큰 |
isTestPayment | Boolean | Y | 테스트 결제 여부 |
json
{
"wrappedToken": "550e8400-e29b-41d4-a716-446655440000",
"isTestPayment": false
}응답 파라미터
| 필드 | 타입 | 설명 |
|---|---|---|
code | Int | 응답 코드예요. 0이면 성공이에요. |
msg | String | 결과 메시지예요. |
에러 케이스
| code | 상황 | 에러 메시지 |
|---|---|---|
| - | 유효하지 않은 토큰으로 호출 | 빌링키를 찾을 수 없어요 |
| 5005 | 해지된 토큰으로 결제 시도 | 비활성화된 빌링키에요 |
| - | 토스페이 청약이 되어 있지 않은 상태 | NOT_JOINED_TOSSPAY |
| - | 토스페이 측 오류 | 토스페이 에러코드와 메시지가 전달돼요 |