앱인토스 개발자센터 로고
Skip to content

인앱 결제

IAP

지원환경: React NativeReact Native SDKv1.0.3WebViewWebView SDKv1.0.3
실행환경: Toss App최소버전v5.219.0

IAP는 인앱 결제 관련 함수를 모아둔 객체예요.

주의하세요

토스앱 5.219.0 버전부터 지원해요. 인앱 결제를 지원하지 않는 버전에서는 undefined를 반환해요.

시그니처

typescript
IAP {
  getProductItemList: typeof getProductItemList;
  createOneTimePurchaseOrder: typeof createOneTimePurchaseOrder;
  getPendingOrders: typeof getPendingOrders;
  getCompletedOrRefundedOrders: typeof getCompletedOrRefundedOrders;
  completeProductGrant: typeof completeProductGrant;
}

프로퍼티

  • getProductItemListtypeof getProductItemList

    인앱 결제로 구매할 수 있는 상품 목록을 가져오는 함수예요. 자세한 내용은 getProductItemList를 참고하세요.

  • createOneTimePurchaseOrdertypeof createOneTimePurchaseOrder

    인앱 결제를 요청하는 함수예요. 자세한 내용은 createOneTimePurchaseOrder를 참고하세요.

  • getPendingOrderstypeof getPendingOrders

    대기 중인 주문 목록을 가져와요. 자세한 내용은 getPendingOrders 문서를 참고하세요.

  • getCompletedOrRefundedOrderstypeof getCompletedOrRefundedOrders

    인앱결제로 구매하거나 환불한 주문 목록을 가져와요. 자세한 내용은 getCompletedOrRefundedOrders 문서를 참고하세요.

  • completeProductGranttypeof completeProductGrant

    상품 지급 처리를 완료했다는 메시지를 앱에 전달해요. 자세한 내용은 completeProductGrant 문서를 참고하세요.

getProductItemList

지원환경: React NativeReact Native SDKv1.0.3WebViewWebView SDKv1.0.3
실행환경: Toss App최소버전v5.219.0

getProductItemList 는 인앱 결제로 구매할 수 있는 상품 목록을 담은 함수예요. 상품 목록을 화면에 표시할 때 사용해요.

시그니처

typescript
function getProductItemList(): Promise<{ products: IapProductListItem[] } | undefined>;

반환값

  • Promise<{ products: IapProductListItem[] } | undefined>

    상품 목록을 포함한 객체를 반환해요. 앱 버전이 최소 지원 버전(5.219.0)보다 낮으면 undefined를 반환해요.

프로퍼티

typescript
interface IapProductListItem {
  sku: string;
  displayAmount: string;
  displayName: string;
  iconUrl: string;
  description: string;
}
  • IapProductListItem

    인앱결제로 구매할 수 있는 상품 하나의 정보를 담은 객체예요. 상품 목록을 화면에 표시할 때 사용해요.

  • sku필수 · string

    상품의 고유 ID예요. IAP.createOneTimePurchaseOrder를 호출할때 사용하는 productId와 동일한 값이에요.


    displayAmount필수 · string

    화면에 표시할 상품 이름이에요. 상품 이름은 앱인토스 콘솔에서 설정한 값이에요.


    displayName필수 · string

    통화 단위가 포함된 가격 정보예요. 예를 들어 "1,000원"으로 가격과 통화가 함께 표시돼요.


    iconUrl필수 · string

    상품 아이콘 이미지의 URL이에요. 아이콘은 앱인토스 콘솔에서 설정한 이미지예요.


    description필수 · string

    상품에 대한 설명이에요. 설명은 앱인토스 콘솔에서 설정한 값이에요.


예제

구매 가능한 인앱결제 상품목록 가져오기

js
import { IAP } from "@apps-in-toss/web-framework";

async function handleGetProductItemList() {
  const response = await IAP.getProductItemList();
  
  return response?.products ?? [];
}
tsx
import { IAP, IapProductListItem } from "@apps-in-toss/web-framework";
import { Button, List, ListRow } from "@toss/tds-mobile";
import { useEffect, useState, useCallback } from "react";

function IapProductList() {
  const [products, setProducts] = useState<IapProductListItem[]>([]);

  const handleBuy = useCallback(() => {
    const cleanup = IAP.createOneTimePurchaseOrder({
      options: {
        sku,
        processProductGrant: ({ orderId }) => {
          // 상품 지급 로직을 작성해요.
          return true; // 상품 지급 여부를 반환해요.
        }
      },
      onEvent: (event) => {
        console.log(event);
        
        if(event.type === 'success') {
          cleanup();
        }
      },
      onError: (error) => {
        console.error(error);
        cleanup();
      },
    });
  }, [sku]);

  useEffect(() => {
    async function fetchProducts() {
      try {
        const response = await IAP.getProductItemList();
        setProducts(response?.products ?? []);
      } catch (error) {
        console.error("상품 목록을 가져오는 데 실패했어요:", error);
      }
    }

    fetchProducts();
  }, []);

  return (
    <List>
      {products.map((product) => (
        <ListRow
          key={product.sku}
          left={<ListRow.Image type="square" src={product.iconUrl} />}
          contents={
            <ListRow.Texts
              type="3RowTypeA"
              top={product.displayName}
              middle={product.description}
              bottom={product.displayAmount}
            />
          }
          right={
            <Button size="medium" onClick={() => handleBuy(product.sku)}>
              구매하기
            </Button>
          }
        />
      ))}
    </List>
  );
}
tsx
import { IAP, IapProductListItem } from "@apps-in-toss/framework";
import { Button, List, ListRow } from "@toss/tds-react-native";
import { useEffect, useState, useCallback } from "react";

function IapProductList() {
  const [products, setProducts] = useState<IapProductListItem[]>([]);

  const handleBuy = useCallback(() => {
    const cleanup = IAP.createOneTimePurchaseOrder({
      options: {
        sku,
        processProductGrant: ({ orderId }) => {
          // 상품 지급 로직을 작성해요.
          return true; // 상품 지급 여부를 반환해요.
        }
      },
      onEvent: (event) => {
        console.log(event);

        if(event.type === 'success') {
          cleanup();
        }
      },
      onError: (error) => {
        console.error(error);
        cleanup();
      },
    });
  }, [sku]);

  useEffect(() => {
    async function fetchProducts() {
      try {
        const response = await IAP.getProductItemList();
        setProducts(response?.products ?? []);
      } catch (error) {
        console.error("상품 목록을 가져오는 데 실패했어요:", error);
      }
    }

    fetchProducts();
  }, []);

  return (
    <List>
      {products.map((product) => (
        <ListRow
          key={product.sku}
          left={<ListRow.Image type="square" source={{ uri: product.iconUrl }} />}
          right={
            <Button size="medium" onPress={() => handleBuy(product.sku)}>
              구매하기
            </Button>
          }
          contents={
            <ListRow.Texts
              type="3RowTypeA"
              top={product.displayName}
              middle={product.description}
              bottom={product.displayAmount}
            />
          }
        />
      ))}
    </List>
  );
}

예제 응답

json
{
  "products": [
    {
      "sku": "sku1",
      "displayName": "광고 제거",
      "displayAmount": "4,900원",
      "iconUrl": "https://cdn.example.com/icons/premium-monthly.png",
      "description": "광고 제거 및 프리미엄 기능 제공"
    },
    {
      "sku": "sku2",
      "displayName": "코인 100개",
      "displayAmount": "9,900원",
      "iconUrl": "https://cdn.example.com/icons/coin-100.png",
      "description": "앱 내에서 사용할 수 있는 코인 100개"
    }
  ]
}

예제 앱 체험하기

apps-in-toss-examples 저장소에서 with-in-app-purchase 코드를 내려받아 체험해 보세요.

createOneTimePurchaseOrder

지원환경: React NativeReact Native SDKv1.0.3WebViewWebView SDKv1.0.3
실행환경: Toss App최소버전v5.219.0

createOneTimePurchaseOrder 함수는 인앱 결제 결제창을 띄우고, 사용자가 결제를 진행해요. 만약 결제 중에 에러가 발생하면 에러 유형에 따라 에러 페이지로 이동해요.

시그니처

typescript
function createOneTimePurchaseOrder(params: IapCreateOneTimePurchaseOrderOptions): () => void;

파라미터

typescript

interface IapCreateOneTimePurchaseOrderOptions {
  options: {sku: string; processProductGrant: (params: { orderId: string }) => boolean | Promise<boolean> };
  onEvent: (event: SuccessEvent) => void | Promise<void>;
  onError: (error: unknown) => void | Promise<void>;
}

interface IapCreateOneTimePurchaseOrderResult {
  orderId: string;
  displayName: string;
  displayAmount: string;
  amount: number;
  currency: string;
  fraction: number;
  miniAppIconUrl: string | null;
}

interface SuccessEvent {
  type: 'success';
  data: IapCreateOneTimePurchaseOrderResult;
}
  • options필수

    인앱 결제를 필요한 옵션이에요.

    • params.sku필수 · string

      주문할 상품의 ID예요.

    • params.processProductGrant필수 · (params: { orderId: string }) => boolean | Promise<boolean>

      주문이 만들어진 뒤 실제로 상품을 지급할 때 호출해요. `orderId`를 받아서 지급 성공 여부를 true 또는 Promise<true>로 반환해요. 지급에 실패하면 false를 반환해요.

  • onEvent필수 · (event: SuccessEvent) => void | Promise<void>

    결제가 성공했을 때 호출해요.

    • event.type필수 · "success"

      이벤트의 타입이에요. "success"를 반환해요.

    • event.data필수 · IapCreateOneTimePurchaseOrderResult

      인앱 결제가 완료되면 결제 세부 정보와 상품 정보를 담아 반환해요. 반환된 정보로 결제한 상품의 정보를 화면에 표시할 때 사용할 수 있어요.

      • event.data.orderId필수 · string

        결제 주문 ID이에요. 결제 완료 후 결제 상태를 조회할 때 사용해요.

      • event.data.displayName필수 · string

        화면에 표시할 상품 이름이에요.

      • event.data.displayAmount필수 · string

        통화 단위가 포함된 가격 정보예요.

      • event.data.amount필수 · number

        상품 가격 숫자 값이에요.

      • event.data.currency필수 · string

        상품 가격 통화 단위예요.

      • event.data.fraction필수 · number

        가격을 표시할 때 소수점 아래 몇 자리까지 보여줄지 정하는 값이에요.

      • event.data.miniAppIconUrlstring | null

        미니앱 아이콘 이미지의 URL이에요.

  • onError필수 · (error: unknown) => void | Promise<void>

    결제 과정에서 에러가 발생했을 때 호출해요. 에러 객체를 받아서 로깅하거나 복구 절차를 실행할 수 있어요.

에러코드

  • INVALID_PRODUCT_ID : 유효하지 않은 상품 ID이거나, 해당 상품이 존재하지 않습니다. 상품 ID를 확인해주세요.

    유효하지 않은 상품 ID이거나, 해당 상품이 존재하지 않을 때 발생해요.


    PAYMENT_PENDING : 결제 승인이 대기 중입니다. 결제 승인을 기다려주세요.

    사용자가 요청한 결제가 아직 승인을 기다리고 있을 때 발생해요.


    NETWORK_ERROR : 네트워크 오류가 발생했습니다. 잠시 후 다시 시도해주세요.

    서버 내부 문제로 요청을 처리할 수 없을 때 발생해요.


    INVALID_USER_ENVIRONMENT : 이 상품은 현재 기기, 계정 또는 설정 환경에서는 구매가 지원되지 않습니다.

    특정 기기, 계정 또는 설정 환경에서 구매할 수 없는 상품일 때 발생해요.


    APP_MARKET_VERIFICATION_FAILED : 앱스토어에서 사용자 정보 검증에 실패했습니다. 환불이 필요합니다.

    사용자가 결제를 완료했지만, 앱스토어에서 사용자 정보 검증에 실패했을 때 발생해요. 사용자가 앱스토어에 문의해서 환불을 요청해야해요.


    TOSS_SERVER_VERIFICATION_FAILED : 결제가 완료되었지만, 서버 전송에 실패했습니다.

    사용자가 결제를 완료했지만, 서버 전송에 실패해서 결제 정보를 저장할 수 없을 때 발생해요.


    INTERNAL_ERROR : 내부 오류가 발생했습니다. 잠시 후 다시 시도해주세요.

    서버 내부 문제로 요청을 처리할 수 없을 때 발생해요.


    KOREAN_ACCOUNT_ONLY : 한국 계정만 사용 가능합니다. 다른 계정을 사용해주세요.

    iOS 환경에서 사용자의 계정이 한국 계정이 아닐 때 발생해요.


    USER_CANCELED : 사용자가 결제를 취소했습니다.

    사용자가 결제를 완료하지 않고 주문서 페이지를 이탈했을 때 발생해요.


    PRODUCT_NOT_GRANTED_BY_PARTNER : 파트너사의 상품 지급이 실패했습니다

    파트너사의 상품 지급이 실패했을 때 발생해요. 토스앱 5.230.0 이상에서만 발생해요.


반환값

  • () => void

    앱브릿지 cleanup 함수를 반환해요. 인앱결제 기능이 끝나면 반드시 이 함수를 호출해서 리소스를 해제해야 해요.

예제

특정 인앱결제 주문서 페이지로 이동하기

js
import { IAP } from "@apps-in-toss/web-framework";

let cleanup; 

function handleBuyProduct(sku) {
  cleanup = IAP.createOneTimePurchaseOrder({
    options: {
      sku,
      processProductGrant: ({ orderId }) => {
        console.log('상품 지급 로직 실행:', orderId);
        return true;
      },
    },
    onEvent: (event) => {
      console.log('이벤트:', event);
      cleanup?.();
    },
    onError: (error) => {
      console.error('인앱결제에 실패했어요:', error);
      cleanup?.();
    },
  });
}

window.addEventListener('pagehide', () => {
  cleanup?.();
});
tsx
import { IAP } from "@apps-in-toss/web-framework";
import { Button } from "@toss/tds-mobile";
import { useCallback } from "react";
 
interface Props {
  sku: string;
}
 
function IapCreateOneTimePurchaseOrderButton({ sku }: Props) { 
  const handleBuy = useCallback(() => {
    const cleanup = IAP.createOneTimePurchaseOrder({
      options: {
        sku,
        processProductGrant: ({ orderId }) => {
          // 상품 지급 로직을 작성해요.
          return true; // 상품 지급 여부를 반환해요.
        }
      },
      onEvent: (event) => {
        console.log(event);
        cleanup();
      },
      onError: (error) => {
        console.error(error);
        cleanup();
      },
    });
  }, [sku]);

  return <Button onClick={handleBuy}>구매하기</Button>;
}
tsx
import { IAP } from "@apps-in-toss/framework";
import { Button } from "@toss/tds-react-native";
import { useCallback } from "react";
 
interface Props {
  sku: string;
}
 
function IapCreateOneTimePurchaseOrderButton({ sku }: Props) {
  const handleClick = useCallback(() => {
    const cleanup = IAP.createOneTimePurchaseOrder({
      options: {
        sku,
        processProductGrant: ({ orderId }) => {
          // 상품 지급 로직을 작성해요.
          return true; // 상품 지급 여부를 반환해요.
        }
        },
      onEvent: (event) => {
        console.log(event);
        cleanup();
      },
      onError: (error) => {
        console.error(error);
        cleanup();
      },
    });
  }, []);

  return <Button onPress={handleClick}>구매하기</Button>;
}

예제 앱 체험하기

apps-in-toss-examples 저장소에서 with-in-app-purchase 코드를 내려받아 체험해 보세요.

getPendingOrders

지원환경: React NativeReact Native SDKv1.4.8WebViewWebView SDKv1.4.8
실행환경: Toss AppiOSv5.231.0Androidv5.235.0Sandbox AppiOS2025-10-28Android2025-10-22

getPendingOrders결제는 완료되었지만 상품이 아직 지급되지 않은 주문 목록을 가져오는 함수예요.
조회된 주문 정보를 확인하여 사용자에게 상품을 지급하세요.
createOneTimePurchaseOrder 함수 호출 후 결과를 받지 못한 경우에도 해당 주문을 조회할 수 있어요.

앱 버전이 최소 지원 버전(안드로이드 5.234.0, iOS 5.231.0)보다 낮으면 undefined를 반환해요.

시그니처

typescript
function getPendingOrders(): Promise<{ orders: Order[] } | undefined>;

반환값

  • Promise<{ orders: Order[] } | undefined>

    대기 중인 주문 목록(orders)을 포함한 객체를 반환해요.
    앱 버전이 최소 지원 버전(안드로이드 5.234.0, iOS 5.231.0)보다 낮으면 undefined를 반환해요.

반환 객체 프로퍼티

tsx
interface Order {
  orderId: string;
  sku: string;
  paymentCompletedDate?: string;
}
  • orders필수 · Order[]

    대기 중인 주문의 배열이에요. 대기 중인 주문이 없으면 빈 배열을 반환해요.

  • orders[].orderId필수 · string

    주문의 고유 ID 예요.

  • orders[].sku필수 · string

    주문 상품의 고유 ID 예요.

  • orders[].paymentCompletedDate필수 · string

    결제가 완료된 시점을 나타내요.

필드 업데이트 안내

  • SDK 1.4.2: sku 필드가 추가되었어요. 이 필드는 안드로이드 5.234.0 이상, iOS 5.231.0 이상에서만 반환돼요.
  • SDK 1.4.8: paymentCompletedDate 필드가 추가되었어요. 결제 완료 시점을 확인할 수 있어요.

예제

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

async function fetchOrders() {
  try {
    const pendingOrders = await IAP.getPendingOrders();
    return pendingOrders;
  } catch (error) {
    console.error(error);
  }
}
tsx
import { IAP } from '@apps-in-toss/web-framework';

async function fetchOrders() {
  try {
    const pendingOrders = await IAP.getPendingOrders();
    return pendingOrders;
  } catch (error) {
    console.error(error);
  }
}
tsx
import { IAP } from '@apps-in-toss/framework';

async function fetchOrders() {
  try {
    const pendingOrders = await IAP.getPendingOrders();
    return pendingOrders;
  } catch (error) {
    console.error(error);
  }
}

completeProductGrant

지원환경: React NativeReact Native SDKv1.2.2WebViewWebView SDKv1.2.2
실행환경: Toss AppiOSv5.231.0Androidv5.231.0

completeProductGrant 함수는 대기 중인 주문의 상품 지급을 완료 처리하는 함수예요.
사용자에게 상품을 지급하고 completeProductGrant 함수를 호출하여 지급 상태를 완료로 변경하세요.

앱 버전이 최소 지원 버전(안드로이드 5.231.0, iOS 5.231.0)보다 낮으면 undefined를 반환해요.

시그니처

typescript
function completeProductGrant(params: {
  params: {
    orderId: string;
  };
}): Promise<boolean | undefined>;

파라미터

  • { params: { orderId: string } }

    결제가 완료된 주문 정보를 담은 객체예요.

    • params.orderIdstring

      주문의 고유 ID예요. 상품 지급을 완료할 주문을 지정할 때 사용해요.

반환값

  • Promise<boolean | undefined>

    상품 지급이 완료됐는지 여부를 반환해요. 앱 버전이 최소 지원 버전(안드로이드 5.233.0, iOS 5.233.0)보다 낮으면 undefined를 반환해요.

예제

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

async function handleCompleteProductGrant(orderId) {
  try {
    await IAP.completeProductGrant({ params: { orderId } });
  } catch (error) {
    console.error(error);
  }
}
tsx
import { IAP } from '@apps-in-toss/web-framework';

async function handleCompleteProductGrant(orderId: string) {
  try {
    await IAP.completeProductGrant({ params: { orderId } });
  } catch (error) {
    console.error(error);
  }
}
tsx
import { IAP } from '@apps-in-toss/framework';

async function handleCompleteProductGrant(orderId: string) {
  try {
    await IAP.completeProductGrant({ params: { orderId } });
  } catch (error) {
    console.error(error);
  }
}

getCompletedOrRefundedOrders

지원환경: React NativeReact Native SDKv1.2.2WebViewWebView SDKv1.2.2
실행환경: Toss AppiOSv5.231.0Androidv5.231.0

getCompletedOrRefundedOrders 는 인앱결제로 구매하고 환불한 주문 목록을 가져와요.
인앱결제 결제 및 상품 지급이 완료된 주문건와 환불된 주문건을 조회할 수 있어요.

결제는 완료되었지만 상품이 아직 지급되지 않은 주문건은 조회되지 않아요.
getPendingOrders함수를 통해 orderId를 조회하여 사용자에게 상품을 지급한 후 completeProductGrant함수를 통해 상품 지급을 완료 처리하세요.

앱 버전이 최소 지원 버전(안드로이드 5.231.0, iOS 5.231.0)보다 낮으면 undefined를 반환해요.

페이지네이션

  • 한 페이지당 최대 50개 의 주문이 반환돼요.
  • 다음 페이지가 있을 때는 hasNexttrue이며, 응답의 nextKey를 다음 호출의 key 파라미터로 전달해 이어서 조회하세요.

시그니처

typescript
function getCompletedOrRefundedOrders(params?: {
  key?: string | null;
}): Promise<CompletedOrRefundedOrdersResult | undefined>;

반환값

  • Promise<{ CompletedOrRefundedOrdersResult } | undefined>

    페이지네이션을 포함한 주문 목록 객체를 반환해요.
    앱 버전이 최소 지원 버전(안드로이드 5.231.0, iOS 5.231.0)보다 낮으면 undefined를 반환해요.

반환 객체 프로퍼티

tsx
interface CompletedOrRefundedOrdersResult {
  hasNext: boolean;
  nextKey?: string | null;
  orders: {
    orderId: string;
    sku: string;
    status: 'COMPLETED' | 'REFUNDED';
    date: string;
  }[];
}
  • hasNext필수 · boolean

    다음 페이지가 있는지 여부예요. `true`면 더 많은 주문이 남아 있어요.

  • nextKey선택 · string | null · null

    다음 페이지 조회를 위한 커서 키예요. 이전 응답의 nextKey 값을 사용해요. 첫 호출 시에는 생략하거나 null로 전달해요.

  • orders필수 · Array

    주문 정보를 담은 배열이에요. 각 요소는 하나의 주문을 나타내요.

    • orders[].orderId필수 · string

      주문의 고유 ID 예요.

    • orders[].sku필수 · string

      주문 상품의 고유 ID 예요.

    • orders[].status필수 · {'COMPLETED' | 'REFUNDED'}

      주문의 상태예요. 'COMPLETED'는 주문이 완료된 상태, 'REFUNDED'는 환불된 상태를 의미해요.

    • orders[].date필수 · string

      주문의 날짜 정보예요. ISO 8601 형식(YYYY-MM-DDTHH:mm:ss)을 사용해요.
      예를 들어 "2025-09-22T00:00:00" 형식으로 제공돼요.
      주문 상태가 `COMPLETED`라면 주문한 날짜를, `REFUNDED`라면 환불한 날짜를 나타내요.

예제

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

async function fetchOrders() {
  try {
    const orders = await IAP.getCompletedOrRefundedOrders();
    return orders;
  } catch (error) {
    console.error(error);
  }
}
tsx
import { IAP } from '@apps-in-toss/web-framework';

async function fetchOrders() {
  try {
    const orders = await IAP.getCompletedOrRefundedOrders();
    return orders;
  } catch (error) {
    console.error(error);
  }
}
tsx
import { IAP } from '@apps-in-toss/framework';

async function fetchOrders() {
  try {
    const orders = await IAP.getCompletedOrRefundedOrders();
    return orders;
  } catch (error) {
    console.error(error);
  }
}