인앱 결제
IAP
IAP는 인앱 결제 관련 함수를 모아둔 객체예요.
주의하세요
토스앱 5.219.0 버전부터 지원해요. 인앱 결제를 지원하지 않는 버전에서는 undefined를 반환해요.
시그니처
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
getProductItemList 는 인앱 결제로 구매할 수 있는 상품 목록을 담은 함수예요. 상품 목록을 화면에 표시할 때 사용해요.
시그니처
function getProductItemList(): Promise<{ products: IapProductListItem[] } | undefined>;반환값
- Promise<{ products: IapProductListItem[] } | undefined>
상품 목록을 포함한 객체를 반환해요. 앱 버전이 최소 지원 버전(5.219.0)보다 낮으면
undefined를 반환해요.
프로퍼티
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상품에 대한 설명이에요. 설명은 앱인토스 콘솔에서 설정한 값이에요.
예제
구매 가능한 인앱결제 상품목록 가져오기
import { IAP } from "@apps-in-toss/web-framework";
async function handleGetProductItemList() {
const response = await IAP.getProductItemList();
return response?.products ?? [];
}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>
);
}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>
);
}예제 응답
{
"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
createOneTimePurchaseOrder 함수는 인앱 결제 결제창을 띄우고, 사용자가 결제를 진행해요. 만약 결제 중에 에러가 발생하면 에러 유형에 따라 에러 페이지로 이동해요.
시그니처
function createOneTimePurchaseOrder(params: IapCreateOneTimePurchaseOrderOptions): () => void;파라미터
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를 반환해요.
- params.sku필수 · string
- 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이에요.
- event.data.orderId필수 · string
- event.type필수 · "success"
- 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 함수를 반환해요. 인앱결제 기능이 끝나면 반드시 이 함수를 호출해서 리소스를 해제해야 해요.
예제
특정 인앱결제 주문서 페이지로 이동하기
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?.();
});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>;
}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
getPendingOrders 는 결제는 완료되었지만 상품이 아직 지급되지 않은 주문 목록을 가져오는 함수예요.
조회된 주문 정보를 확인하여 사용자에게 상품을 지급하세요.createOneTimePurchaseOrder 함수 호출 후 결과를 받지 못한 경우에도 해당 주문을 조회할 수 있어요.
앱 버전이 최소 지원 버전(안드로이드 5.234.0, iOS 5.231.0)보다 낮으면 undefined를 반환해요.
시그니처
function getPendingOrders(): Promise<{ orders: Order[] } | undefined>;반환값
- Promise<{ orders: Order[] } | undefined>
대기 중인 주문 목록(orders)을 포함한 객체를 반환해요.
앱 버전이 최소 지원 버전(안드로이드 5.234.0, iOS 5.231.0)보다 낮으면undefined를 반환해요.
반환 객체 프로퍼티
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필드가 추가되었어요. 결제 완료 시점을 확인할 수 있어요.
예제
import { IAP } from '@apps-in-toss/web-framework';
async function fetchOrders() {
try {
const pendingOrders = await IAP.getPendingOrders();
return pendingOrders;
} catch (error) {
console.error(error);
}
}import { IAP } from '@apps-in-toss/web-framework';
async function fetchOrders() {
try {
const pendingOrders = await IAP.getPendingOrders();
return pendingOrders;
} catch (error) {
console.error(error);
}
}import { IAP } from '@apps-in-toss/framework';
async function fetchOrders() {
try {
const pendingOrders = await IAP.getPendingOrders();
return pendingOrders;
} catch (error) {
console.error(error);
}
}completeProductGrant
completeProductGrant 함수는 대기 중인 주문의 상품 지급을 완료 처리하는 함수예요.
사용자에게 상품을 지급하고 completeProductGrant 함수를 호출하여 지급 상태를 완료로 변경하세요.
앱 버전이 최소 지원 버전(안드로이드 5.231.0, iOS 5.231.0)보다 낮으면 undefined를 반환해요.
시그니처
function completeProductGrant(params: {
params: {
orderId: string;
};
}): Promise<boolean | undefined>;파라미터
- { params: { orderId: string } }
결제가 완료된 주문 정보를 담은 객체예요.
- params.orderIdstring
주문의 고유 ID예요. 상품 지급을 완료할 주문을 지정할 때 사용해요.
- params.orderIdstring
반환값
- Promise<boolean | undefined>
상품 지급이 완료됐는지 여부를 반환해요. 앱 버전이 최소 지원 버전(안드로이드 5.233.0, iOS 5.233.0)보다 낮으면
undefined를 반환해요.
예제
import { IAP } from '@apps-in-toss/web-framework';
async function handleCompleteProductGrant(orderId) {
try {
await IAP.completeProductGrant({ params: { orderId } });
} catch (error) {
console.error(error);
}
}import { IAP } from '@apps-in-toss/web-framework';
async function handleCompleteProductGrant(orderId: string) {
try {
await IAP.completeProductGrant({ params: { orderId } });
} catch (error) {
console.error(error);
}
}import { IAP } from '@apps-in-toss/framework';
async function handleCompleteProductGrant(orderId: string) {
try {
await IAP.completeProductGrant({ params: { orderId } });
} catch (error) {
console.error(error);
}
}getCompletedOrRefundedOrders
getCompletedOrRefundedOrders 는 인앱결제로 구매하고 환불한 주문 목록을 가져와요.
인앱결제 결제 및 상품 지급이 완료된 주문건와 환불된 주문건을 조회할 수 있어요.
결제는 완료되었지만 상품이 아직 지급되지 않은 주문건은 조회되지 않아요.getPendingOrders함수를 통해 orderId를 조회하여 사용자에게 상품을 지급한 후 completeProductGrant함수를 통해 상품 지급을 완료 처리하세요.
앱 버전이 최소 지원 버전(안드로이드 5.231.0, iOS 5.231.0)보다 낮으면 undefined를 반환해요.
페이지네이션
- 한 페이지당 최대 50개 의 주문이 반환돼요.
- 다음 페이지가 있을 때는
hasNext가true이며, 응답의nextKey를 다음 호출의key파라미터로 전달해 이어서 조회하세요.
시그니처
function getCompletedOrRefundedOrders(params?: {
key?: string | null;
}): Promise<CompletedOrRefundedOrdersResult | undefined>;반환값
- Promise<{ CompletedOrRefundedOrdersResult } | undefined>
페이지네이션을 포함한 주문 목록 객체를 반환해요.
앱 버전이 최소 지원 버전(안드로이드 5.231.0, iOS 5.231.0)보다 낮으면undefined를 반환해요.
반환 객체 프로퍼티
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`라면 환불한 날짜를 나타내요.
예제
import { IAP } from '@apps-in-toss/web-framework';
async function fetchOrders() {
try {
const orders = await IAP.getCompletedOrRefundedOrders();
return orders;
} catch (error) {
console.error(error);
}
}import { IAP } from '@apps-in-toss/web-framework';
async function fetchOrders() {
try {
const orders = await IAP.getCompletedOrRefundedOrders();
return orders;
} catch (error) {
console.error(error);
}
}import { IAP } from '@apps-in-toss/framework';
async function fetchOrders() {
try {
const orders = await IAP.getCompletedOrRefundedOrders();
return orders;
} catch (error) {
console.error(error);
}
}