본문으로 건너뛰기

requestTossPayPaysBilling

토스페이 정기결제 인증창을 띄워 사용자의 동의를 받고 billing key를 발급합니다. 이 함수는 정기결제 등록 인증만 처리하며, 실제 결제 청구는 인증 성공 후 서버에서 별도로 진행해야 합니다.

iap 네임스페이스의 checkoutPayment(단건 결제 인증)와는 다른 흐름입니다 — requestTossPayPaysBilling은 이후 서버 측에서 반복 청구할 수 있는 billing key를 발급받는 것이 목적입니다.

isSupported() 정적 메서드로 현재 환경에서 해당 기능이 지원되는지 먼저 확인할 수 있습니다.

시그니처

import { requestTossPayPaysBilling } from '@apps-in-toss/web-framework';

declare function requestTossPayPaysBilling(options: {
params: { wrappedToken: string };
}): Promise<{ success: boolean; reason?: string } | undefined>;

declare namespace requestTossPayPaysBilling {
function isSupported(): boolean;
}

파라미터

이름타입필수설명
options.params.wrappedTokenstring서버에서 발급한 래핑된 토큰. 토스페이 정기결제 인증창에 전달되어 billing 컨텍스트를 식별합니다.

반환값

  • Promise<{ success: boolean; reason?: string } | undefined> — 인증창에서 사용자 동의가 완료되면 resolve됩니다. 기능을 지원하지 않는 환경에서는 undefined를 반환할 수 있습니다.
    • success: true — 인증이 성공했습니다. 서버 측에서 billing key를 저장하고 이후 정기결제를 실행하세요.
    • success: false + reason — 인증이 실패했습니다. reason을 사용자에게 표시하거나 로깅하세요.
인증 ≠ 결제 완료

success: true는 토스페이 정기결제 인증창에서 사용자 동의가 통과하고 billing key가 발급됐다는 의미입니다. 실제 결제 청구(서버 측 정기결제 실행)는 별도 API 호출로 마무리해야 합니다. 인증 성공만으로 결제가 이루어졌다고 가정하지 마세요.

권한

권한이 필요하지 않습니다. requestTossPayPaysBilling은 별도의 PermissionName에 바인딩되지 않습니다.

예제

최소 예제

import { requestTossPayPaysBilling } from '@apps-in-toss/web-framework';

async function registerBilling(wrappedToken: string) {
if (!requestTossPayPaysBilling.isSupported()) {
console.warn('정기결제 기능이 지원되지 않는 환경입니다.');
return;
}

const result = await requestTossPayPaysBilling({ params: { wrappedToken } });
if (!result) return;

if (result.success) {
// 서버 측 billing key 저장 및 정기결제 등록 완료 처리
await fetch('/api/billing/complete', { method: 'POST' });
} else {
console.warn('정기결제 인증 실패:', result.reason);
}
}

실전 예제 — 정기결제 등록 버튼

import { requestTossPayPaysBilling } from '@apps-in-toss/web-framework';
import { useCallback, useState } from 'react';

export function BillingRegisterButton({ planId }: { planId: string }) {
const [status, setStatus] = useState<'idle' | 'pending' | 'success' | 'error'>('idle');
const [message, setMessage] = useState('');

const handleRegister = useCallback(async () => {
if (!requestTossPayPaysBilling.isSupported()) {
setStatus('error');
setMessage('현재 환경에서는 정기결제 등록을 지원하지 않습니다.');
return;
}

setStatus('pending');
setMessage('');
try {
// 1. 서버에서 래핑된 토큰 발급
const { wrappedToken } = await fetch('/api/billing/prepare', {
method: 'POST',
body: JSON.stringify({ planId }),
headers: { 'Content-Type': 'application/json' },
}).then((res) => res.json());

// 2. 토스페이 정기결제 인증창 띄우기
const result = await requestTossPayPaysBilling({ params: { wrappedToken } });

if (!result) {
setStatus('error');
setMessage('정기결제 인증을 완료할 수 없습니다.');
return;
}

if (!result.success) {
setStatus('error');
setMessage(`정기결제 인증 실패: ${result.reason ?? '알 수 없는 오류'}`);
return;
}

// 3. 서버 측 billing key 저장 및 등록 완료
await fetch('/api/billing/complete', {
method: 'POST',
body: JSON.stringify({ planId }),
headers: { 'Content-Type': 'application/json' },
});

setStatus('success');
setMessage('정기결제가 등록됐어요.');
} catch (error) {
setStatus('error');
setMessage('정기결제 등록 중 오류가 발생했어요.');
console.error(error);
}
}, [planId]);

return (
<div>
<button type="button" onClick={handleRegister} disabled={status === 'pending'}>
{status === 'pending' ? '등록 진행 중…' : '정기결제 등록'}
</button>
{message && <p role="status">{message}</p>}
</div>
);
}

직접 실행해 보기

sdk-example의 Payment 페이지에서 requestTossPayPaysBilling 카드를 실행해 결과를 확인할 수 있습니다.

sdk-example에서 실행해 보기

관련 API

관련 가이드

  • (작성 예정) Guides — "토스페이 정기결제 등록 흐름"

외부 참조