Appearance
Template API
토스 프론트의 UI 컴포넌트를 생성하고 관리하기 위한 템플릿 API입니다. 다양한 화면 유형과 사용자 인터랙션을 구현할 수 있습니다.
공통 파라미터
상단의 네비바가 있는 템플릿에서 사용할 수 있는 공통 파라미터입니다.
js
sdk.template.renderSignPage({
...,
onBack?: () => {}, // 뒤로가기 동작
navbarButton?: { // 커스텀 버튼
label: '우상단버튼',
onClick: () => {},
},
})openToast
상단에 토스트 메시지를 표시하는 API입니다.
사용 예시
js
sdk.template.openToast({
message: "성공했어요",
icon: "success",
});
sdk.template.openToast({
message: "실패했어요",
icon: "error",
});토스트 예시


renderIdlePage
대기 화면을 렌더링하는 API입니다. 세 가지 타입을 지원합니다.
파라미터
typescript
type Params =
| {
type: "default";
}
| {
type: "oneButton";
button: {
text: string;
subText?: string;
onClick: () => void;
};
description?: {
text: string;
subText?: string;
};
}
| {
type: "twoButton";
title: {
text1: string;
text2: string;
text3?: string;
};
description?: {
text: string;
subText?: string;
};
primaryButton: {
text: string;
onClick: () => void;
};
secondaryButton: {
text: string;
onClick: () => void;
};
};기본 화면
- 토스 프론트의 "프론트 꾸미기" 기능을 사용하여 대기화면을 표시합니다.
- 화면 우측 상단을 5회 터치 후 7055를 입력하여 배경화면을 변경할 수 있습니다.
- 매장 이름이 하단에 표시됩니다.
js
sdk.template.renderIdlePage();기본 대기화면 예시

원버튼
- 기본 대기화면 기능과 동일합니다.
- description 영역에 커스텀 문구를 표시할 수 있습니다.
- 하단에 버튼이 표시됩니다.
js
sdk.template.renderIdlePage({
type: 'oneButton',
button: {
text: '주문하기',
subText?: 'Order',
onClick: () => {
console.log('주문하기');
},
},
description?: {
text: `'주문하기' 누르고 아바타와 음성 주문을 시작해보세요`,
subText?: 'Press "Order" and start ordering avatars and voice orders',
},
})원버튼 대기화면 예시

투버튼
- 타이틀을 3줄로 표현할 수 있습니다 (2번째 줄은 강조).
- description 영역이 있으며, 종모양 아이콘은 변경할 수 없습니다.
- 하단에 2개의 버튼이 표시됩니다.
js
sdk.template.renderIdlePage({
type: 'twoButton',
title: {
text1: '여기서',
text2: '출석체크',
text3?: '해주세요',
},
description?: {
text: '수강료 납부 기간 : 9/1 (월) ~ 9/5 (금)',
subText?: '수강료 미납 시 수강이 제한됩니다.',
},
primaryButton: {
text: '출석체크',
onClick: () => {
console.log('출석체크');
},
},
secondaryButton: {
text: '수강료 내기',
onClick: () => {
console.log('수강료 내기');
},
},
})투버튼 대기화면 예시

renderUsePointPage
포인트 사용 화면을 렌더링하는 API입니다.
파라미터
typescript
interface Params {
points: Point[];
summary: Summary;
cta: Cta;
}
interface Point {
name: string;
amount: number;
}
interface Summary {
pointUsedAmount: number;
paymentAmount: number;
}
interface Cta {
cancel: {
onClick: () => void;
};
submit: {
onClick: () => void;
};
}주요 특징
- 현재 포인트는 1개만 표시됩니다.
- 포인트 사용 금액과 최종 결제 금액을 요약하여 보여줍니다.
- "사용 안 함" 및 "전액 사용" 버튼을 통해 사용자 액션을 처리합니다.
사용 예시
js
sdk.template.renderUsePointPage({
points: [{ name: "회원 포인트", amount: 1000 }],
summary: {
pointUsedAmount: 1000,
paymentAmount: 4000,
},
cta: {
cancel: {
onClick: async () => {
console.log("Cancel");
},
},
submit: {
onClick: async () => {
console.log("Submit");
},
},
},
onBack?: () => {},
});포인트 사용 예시

renderOrderPage
주문 내역을 표시하는 API입니다.
파라미터
typescript
interface Params {
order: {
items: {
label: string;
value: number;
quantity?: number;
options?: {
type: "option" | "discount";
label: string;
value: number;
}[];
imageUrl?: string;
}[];
discounts: {
label: string;
value: number;
};
[]; // 최대 3개
summary: {
totalAmount: number;
discountAmount: number;
earned?: {
label: string;
value: number;
suffix: string;
};
};
};
localeCode?: "ko" | "en";
onClick: () => void;
}주요 특징
localeCode가 "en"일 경우 텍스트가 영어로 표시됩니다.order.items는 직접 영어로 요청해야 합니다.- 할인 항목은 최대 3개까지 표시됩니다.
사용 예시
js
sdk.template.renderOrderPage({
localeCode: "ko",
order: {
items: [
{
label: '아메리카노',
value: 3000,
imageUrl?: "https://example.com/image.jpg",
options?: [
{
type: 'option',
label: 'ICE',
value: 0,
},
{
type: 'option',
label: '샷추가',
value: 500,
},
{
type: 'discount',
label: '이벤트',
value: 100,
},
],
},
{
label: '카페라떼',
quantity?: 2,
value: 6000,
},
],
discounts: [
{
label: '전체할인 10%',
value: 940,
},
],
summary: {
totalAmount: 15400,
discountAmount: 1040,
earned: {
label: '매장 포인트 적립',
value: 100,
suffix: 'P',
},
},
},
onClick: async () => {
const price = order.summary.totalAmount;
const tax = Math.floor(price / 11);
const supplyValue = price - tax;
const result = await sdk.payment.requestPayment({
paymentKey: 'paymentKey',
tax,
supplyValue,
tip: 0,
});
if (result.type === 'CANCELED' || result.type === 'TIMEOUT') {
return;
}
switch (result.response.paymentMethod) {
case 'CARD':
console.log(result.response.card);
break;
case 'BARCODE':
console.log(result.response.barcode);
break;
case 'CASH':
console.log(result.response.cash);
break;
}
},
});주문 목록 예시
- 이미지 없음

- 이미지 있음

renderOrderResultPage
주문 결과를 표시하는 API입니다.
파라미터
typescript
interface Params {
type?: "paid" | "cancelled"; // default: 'paid'
order: {
items: {
label: string;
value?: number;
quantity?: number;
options?: {
type: "option" | "discount";
label: string;
value: number;
}[];
imageUrl?: string;
}[];
summary: {
totalAmount: number;
items?: {
label: string;
value: string;
theme: "blue" | "red";
}[];
};
};
cta: {
text: string;
onClick: () => void;
};
}주요 특징
- 결제 완료 후 결과를 보여주는 용도입니다.
order.items는 직접 명시합니다.summary.items를 통해 추가 정보를 표시할 수 있으며,theme으로 색상을 지정할 수 있습니다.cta버튼을 통해 다음 화면으로 이동합니다.type의paid는 결제 금액을,cancelled는 취소 금액을 나타냅니다.
사용 예시
js
sdk.template.renderOrderResultPage({
order: {
items: [
{
label: "손 젤 케어",
quantity: 1,
value: 50_000,
},
{
label: "젤 기본",
quantity: 1,
value: 50_000,
},
],
summary: {
totalAmount: 100_000,
items: [
{
label: "포인트",
value: "10,000P",
theme: "blue",
},
{
label: "금액권",
value: "30,000원",
theme: "blue",
},
{
label: "젤네일",
value: "5회",
theme: "blue",
},
{
label: "VIP 회원권",
value: "2026-11-04",
theme: "blue",
},
],
},
},
cta: {
text: "확인했어요",
onClick: () => {
location.href = "./home";
},
},
});주문 결과 예시
- paid

- cancelled

renderOnboardingPage
온보딩 화면을 렌더링하는 API입니다.
파라미터
typescript
interface Params<T extends string> {
title: string;
inputs: Record<T, InputScheme>;
onSubmit: (data: Record<T, string>) => Promise<void>;
logoUrl?: string;
}
interface InputScheme {
label: string;
type: "text" | "password";
mode?: "numeric"; // default: 'text'
placeholder?: string;
maxLength?: number;
onChange?: (value: string) => void;
}사용 예시
js
sdk.template.renderOnboardingPage({
title: "___ 로그인",
inputs: {
id: {
label: "매장 아이디",
type: "text",
placeholder?: "매장 아이디를 입력해주세요",
},
password: {
label: "숫자 비밀번호",
type: "password",
mode?: 'numeric', // numeric 키패드 모드 지원 (default: 'text')
placeholder?: "비밀번호를 입력해주세요",
maxLength?: 4,
onChange?: (value) => { console.log(value) },
},
},
onSubmit: async (values) => {
try {
const { serialNumber } = await sdk.app.getSerialNumber();
const response = await fetch("https://example.com", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ ...values, serialNumber }),
});
const { token } = await response.json();
await sdk.storage.set({ key: "token", value: token });
location.href = "./home";
} catch (e) {
throw new Error("서버 오류가 발생했습니다.");
}
},
logoUrl?: '' // 커스텀 로고 URL
})온보딩 화면 예시

renderSelectPage
단일 선택 화면을 렌더링하는 API입니다.
파라미터
typescript
interface Params {
title: string;
subtitle: string;
options: {
title: string;
subtitle?: string;
description?: string;
iconUrl?: string;
onClick: () => void;
}[];
}사용 예시
js
sdk.template.renderSelectPage({
title: '반가워요',
subtitle: '언어를 선택해주세요',
options: [
{
title: '한국어로 주문',
onClick: () => {
console.log('한국어로 주문');
},
iconUrl?: '', // 이미지 URL
},
{
title: 'Order English',
onClick: () => {
console.log('Order English');
},
iconUrl?: '', // 이미지 URL
},
],
onBack?: () => {},
})선택 화면 예시

renderMultiSelectPage
다중 선택 화면을 렌더링하는 API입니다.
파라미터
typescript
interface Params {
title: string;
description: string;
options: MultiSelectOption[];
button: {
text: string | ((items: MultiSelectOption[]) => string);
onClick: (items: MultiSelectOption[]) => void;
topAddon?: string;
};
}
interface MultiSelectOption {
title: string;
subtitle?: string;
description?: string;
iconUrl?: string;
defaultSelected?: boolean;
}주요 특징
- 하단 버튼의 text에 함수를 넣으면 선택 항목에 따라 버튼 텍스트가 동적으로 변경됩니다.
사용 예시
js
sdk.template.renderMultiSelectPage({
title: 'OOO님',
description: '결제할 청구서를 선택해주세요',
options: [
{
title: '240,000원',
subtitle: '9월 | 학원비',
description?: '1개월',
defaultSelected?: true,
iconUrl?: '',
},
{
title: '240,000원',
subtitle?: '8월 | 학원비',
description?: '1개월',
defaultSelected?: true,
iconUrl?: '',
},
],
button: {
text: '결제하기',
// 또는
text: selectedOptions => {
const totalAmount = selectedOptions.reduce((acc, item) =>
acc + Number(item.title.replace(/\D/g, '')), 0);
return `총 ${totalAmount.toLocaleString()}원 결제하기`;
},
onClick: selectedItems => {
console.log(selectedItems);
},
},
onBack?: () => {},
});다중 선택 화면 예시

renderQRScanPage
QR/바코드 스캔 화면을 렌더링하는 API입니다.
파라미터
typescript
interface Params {
title: string;
onSuccess: (data: { value: string }) => void;
}주요 특징
- 결제 이외의 QR/바코드 스캔에 사용됩니다.
- 스캔 성공 시
onSuccess콜백이 호출됩니다.
사용 예시
js
sdk.template.renderQRScanPage({
title: 'QR을 화면에 스캔해주세요',
onSuccess: data => {
console.log(data.value); // 스캔된 바코드 값
},
onBack?: () => {}
});QR 스캔 화면 예시

renderResultPage
결과 화면을 렌더링하는 API입니다.
파라미터
typescript
type Params = ImageResultPage | TextResultPage;
interface ImageResultPage {
type: "image";
status: "success" | "error";
title: string;
description?: string;
onTimeout: () => void;
buttons?: {
label: string;
onClick: () => void;
closeOnClick?: boolean;
}[];
timerMs?: number; // 3-10초 (default: 5000)
localeCode?: "ko" | "en";
}
interface TextResultPage {
type: "text";
text: string;
title: string;
description?: string;
onTimeout: () => void;
buttons?: {
label: string;
onClick: () => void;
closeOnClick?: boolean;
}[];
timerMs?: number; // 3-10초 (default: 5000)
localeCode?: "ko" | "en";
}주요 특징
- 성공/실패 이미지 또는 텍스트 타입을 지원합니다.
- 3-10초 후 자동으로
onTimeout이 호출됩니다. - 최대 2개의 버튼을 표시할 수 있습니다.
localeCode가 'en'일 경우 영어 텍스트가 표시됩니다.
사용 예시
js
// 성공 이미지
sdk.template.renderResultPage({
type: 'image',
status: 'success',
title: 'OOO님 입장 완료',
description?: '오전 11시 00분 입장',
timerMs?: 10000,
buttons?: [
{
label: '확인1',
onClick: () => {
console.log('click1');
},
},
{
label: '확인2',
closeOnClick?: true, // 클릭 시 화면 닫힘
onClick: () => {
console.log('click2');
},
},
],
onTimeout: () => {},
localeCode: 'ko',
})
// 실패 이미지
sdk.template.renderResultPage({
type: 'image',
status: 'error',
title: '유효기간이 만료되었어요',
description?: '다시 발급해주세요',
onTimeout: () => {},
localeCode: 'ko',
})
// 텍스트
sdk.template.renderResultPage({
type: 'text',
text: '001번',
title: '주문 완료',
description?: '대기번호로 알려드릴게요',
onTimeout: () => {},
localeCode: 'ko',
});결과 화면 예시
- 성공

- 실패

- 텍스트

renderInputPage
사용자 입력 화면을 렌더링하는 API입니다. 4가지 입력 타입을 지원합니다.
파라미터
typescript
type Params =
| TextInputPage
| NumberInputPage
| PhoneInputPage
| IdentificationInputPage;
interface TextInputPage {
type: "text";
top: {
title: string;
subtitle?: string;
};
input: {
placeholder: string;
type?: "password"; // default: 'text'
maxLength?: number;
onChange?: (value: string) => void;
};
button: {
label: string;
};
disclaimer?: string;
onSubmit: (value: string) => Promise<void> | void;
}
interface NumberInputPage {
type: "number";
top: {
title: string;
subtitle?: string;
};
input: {
placeholder: string;
type?: "password"; // default: 'number'
maxLength?: number;
onChange?: (value: string) => void;
};
button: {
label: string;
};
disclaimer?: string;
onSubmit: (value: string) => Promise<void> | void;
}
interface PhoneInputPage {
type: "phone";
top: {
title: string;
subtitle?: string;
};
input: {
placeholder: string;
onChange?: (value: string) => void;
};
disclaimer?: string;
onSubmit: (value: string) => Promise<void> | void;
}
interface IdentificationInputPage {
type: "identification";
top: {
title: string;
subtitle?: string;
};
input: {
onChange?: (value: string) => void;
};
disclaimer?: string;
onSubmit: (value: string) => Promise<void> | void;
}타입별 특징 및 예시
text
일반 텍스트 입력을 위한 화면입니다.
js
sdk.template.renderInputPage({
type: 'text',
top: {
title: '접수할 이름을 입력해주세요',
subtitle?: '처음 오셨네요!',
},
disclaimer?: '병원 진료 업무 외 다른 용도로 사용하지 않아요.',
input: {
type?: 'password', // password 타입 지원 (default: text)
placeholder: '이름 입력',
maxLength?: 4,
onChange?: value => {
console.log(value);
},
},
button: {
label: '확인',
},
onSubmit: async value => {
await new Promise(resolve => setTimeout(resolve, 1000));
console.log(value);
},
onBack?: () => {},
});텍스트 입력 화면 예시

number
숫자 키패드를 지원하는 입력 화면입니다.
js
sdk.template.renderInputPage({
type: 'number',
top: {
title: '휴대전화 뒷자리 4자리를 입력해주세요',
subtitle?: '반가워요',
},
input: {
type?: 'password', // password 타입 지원 (default: number)
placeholder: '4자리 입력',
onChange?: value => {
console.log(value);
},
},
disclaimer?: '병원 진료 업무 외 다른 용도로 사용하지 않아요.',
button: {
label: '확인',
},
onSubmit: async value => {
await new Promise(resolve => setTimeout(resolve, 1000));
console.log(value);
},
onBack?: () => {},
});숫자 입력 화면 예시

phone
전화번호 입력을 위한 화면입니다. 11자리 입력 시 자동으로 onSubmit이 실행됩니다.
js
sdk.template.renderInputPage({
type: 'phone',
top: {
title: '접수를 위해\n휴대폰 번호를 입력해주세요',
subtitle?: '반가워요',
},
disclaimer?: '병원 진료 업무 외 다른 용도로 사용하지 않아요.',
input: {
placeholder: '전화번호 입력',
onChange?: value => {
console.log(value);
},
},
onSubmit: async value => {
await new Promise(resolve => setTimeout(resolve, 1000));
console.log(value);
},
onBack?: () => {},
});전화번호 입력 화면 예시

identification
주민등록번호 입력을 위한 화면입니다. 앞자리 6자리/뒷자리 7자리 입력 시 자동으로 onSubmit이 실행됩니다.
js
sdk.template.renderInputPage({
type: 'identification',
top: {
title: '접수할 주민등록번호를\n입력해주세요',
subtitle?: '반가워요',
},
input: {
onChange?: value => {
console.log(value);
},
},
disclaimer?: '병원 진료 업무 외 다른 용도로 사용하지 않아요.',
onSubmit: async value => {
await new Promise(resolve => setTimeout(resolve, 1000));
console.log(value);
},
onBack?: () => {},
});주민등록번호 입력 화면 예시

renderSearchPage
검색 화면을 렌더링하는 API입니다.
파라미터
typescript
interface Params {
top: {
title: string;
subtitle?: string;
};
input: {
placeholder: string;
};
getOptions: (params: { keyword: string }) => Promise<OptionParams[]>;
onSubmit: (item: OptionParams) => void;
}
interface OptionParams {
id: string | number;
title: string;
subtitle?: string;
description?: string;
disabled?: boolean;
}주요 특징
- 검색어는 debounce 처리됩니다.
- 검색어 변경 시
getOptions가 실행되어 결과를 표시합니다. - 옵션 선택 시
onSubmit이 실행됩니다.
사용 예시
js
sdk.template.renderSearchPage({
top: {
title: "취소할 결제 내역을\n선택해주세요",
subtitle?: "결제 취소",
},
input: {
placeholder: "이름, 카드, 날짜 검색",
},
getOptions: async ({ keyword }) => {
await new Promise((resolve) => setTimeout(resolve, 1000));
console.log(keyword);
return [
{
id: 0,
title: `김토스 (${keyword})`,
subtitle?: "김토스 | 삼성카드",
description?: "납부일: 2024.12.12 오전 09:00:00",
},
{
id: 1,
title: "김토스 (0002)",
subtitle?: "김토스 | 현대카드",
description?: "납부일: 2024.12.12 오전 10:00:00",
disabled?: true,
},
// ... 추가 옵션
];
},
onSubmit: (items) => {
alert(JSON.stringify(items, null, 2));
},
});검색 화면 예시

renderSignPage
서명 입력 화면을 렌더링하는 API입니다.
파라미터
typescript
interface Params {
top: {
title: string;
subtitle?: string;
};
button: {
label: string;
};
disclaimer?: string;
onSubmit: (base64str: string) => void | Promise<void>;
}주요 특징
- 서명 완료 시 base64 형식의 이미지가 반환됩니다.
- 이미지는
data:image/png;base64,<base64str>형식으로 확인할 수 있습니다.
사용 예시
js
sdk.template.renderSignPage({
top: {
title: "서명 후 확인을 눌러주세요",
subtitle?: "처음 방문하고 한 번만 필요해요",
},
button: {
label: "서명 완료",
},
disclaimer?: "병원 진료 업무 외 다른 용도로 사용하지 않아요.",
onSubmit: async (base64Str) => {
await new Promise(resolve => setTimeout(resolve, 1000));
console.log(base64Str);
},
onBack: () => {},
});startTimer
렌더링된 페이지 내에서 타이머를 실행하는 API입니다.
파라미터
typescript
interface Params {
title: string;
duration: number;
warnAt: number;
onTimeout: () => void;
}주요 특징
- 함수 호출 즉시 타이머가 실행됩니다. 중복 호출에 유의해주세요.
duration(sec)시간이 되면,onTimeout콜백 함수가 호출되며, 타이머가 종료됩니다.warnAt(sec)시간이 되면, 경고 모달이 노출됩니다. 경고 모달의 제목만title로 제어가 가능합니다.
사용 예시
js
sdk.template.startTimer({
title: "주문을 그만할까요?",
duration: 60,
warnAt: 10,
onTimeout: () => {
renderIdlePage({...})
},
});