Skip to content

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;
    }
  },
});
주문 목록 예시
  • 이미지 없음 주문목록-1
  • 이미지 있음 주문목록-2

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 버튼을 통해 다음 화면으로 이동합니다.
  • typepaid는 결제 금액을, 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 스캔 화면 예시

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({...})
  },
});