인앱 결제
소모품, 비소모품처럼 한 번 구매로 완료되는 상품에 사용하는 일회성 결제 SDK예요.
서비스 소개와 콘솔 설정 방법은 인앱 결제 소개 문서를 참고해 주세요.


BaseURL
https://apps-in-toss-api.toss.im
연동 흐름은 아래 순서를 따라 주세요.
- 상품 목록 가져오기 —
getProductItemList - 결제 요청하기 —
createOneTimePurchaseOrder - 미결 주문 복원하기 —
getPendingOrders,completeProductGrant - 주문 상태 조회하기 —
getCompletedOrRefundedOrders또는 주문 상태 조회 API
주의하세요
- SDK 1.1.3 버전 이상을 사용해주세요.
- SDK 1.1.3 버전부터는 상품 지급 완료 과정이 추가되어 함수 인터페이스가 변경되었어요.
- SDK 1.2.2 버전부터는 구매 복원 기능이 추가되었어요.
- 사용자의 기기가 변경되더라도 인앱결제 상품이 지급 유지될 수 있도록 반드시 연동해주세요.
- 네이티브 저장소 기능을 활용해 주세요.
- 토스 로그인 연동과 인앱결제 상태 조회 API를 활용해 주세요.
- 인앱결제 상태 조회 API 사용을 위해서는 반드시 토스 로그인 연동을 먼저 진행해 주세요.
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 함수는 인앱 결제 결제창을 띄우고, 사용자가 결제를 진행해요. 만약 결제 중에 에러가 발생하면 에러 유형에 따라 에러 페이지로 이동해요.
참고하세요
결제 성공 후 30초내에 processProductGrant 콜백이 호출되지 않거나 해당 콜백의 결과가 true가 아닌 경우,{appName}에 문제가 생겼어요. 환불을 신청해주세요 페이지가 노출될 수 있어요.
시그니처
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);
}
}주문 상태 조회 API
서버에서 API로 인앱결제 주문 상태를 직접 조회할 수 있어요.
승인 혹은 환불 응답을 받지 못한 경우에도 사용할 수 있어요.
참고하세요
결제 상태 조회 API 사용을 위해서는 토스 로그인 연동을 먼저 진행해 주세요.
- Content-type:
application/json - Method:
POST - URL:
/api-partner/v1/apps-in-toss/order/get-order-status
요청 헤더
| 이름 | 타입 | 필수값 여부 | 설명 |
|---|---|---|---|
| x-toss-user-key | string | N | 토스 로그인으로 획득한 userKey 값 |
- 헤더를 포함하지 않으면 모든 주문 건이 응답돼요.
- 헤더에
x-toss-user-key값을 포함하면 해당 userKey의 주문 건만 응답돼요.
요청 파라미터
| 이름 | 타입 | 필수 | 설명 |
|---|---|---|---|
| orderId | String | Y | 결제 생성 후 취득한 주문번호(uuid v7) |
{
"orderId": "13c9a1ff-2baa-4495-bbfa-a0826ba8c7c0"
}응답
| 이름 | 타입 | 설명 |
|---|---|---|
| orderId | String | 요청한 주문번호 |
| sku | String | 주문한 상품 ID |
| statusDeterminedAt | String | 주문 완료 일시 (yyyy-MM-dd'T'HH:mm:ss, KST 고정) status가 REFUNDED일 경우 환불 완료 일시 |
| status | String | 주문에 대한 상태 (enum) |
| reason | String | 상태에 대한 설명 |
status (enum)
| 상태 | 설명 | 상세 설명 |
|---|---|---|
| PURCHASED | 주문 완료 | 인앱 결제 및 상품 지급이 모두 완료된 상태 |
| PAYMENT_COMPLETED | 결제 완료 | SDK 1.1.3 이상에서 결제는 완료되었으나 상품 지급이 실패한 상태 |
| FAILED | 주문 실패 | 결제가 실패한 경우 |
| REFUNDED | 주문 환불됨 | 환불 완료된 경우 |
| ORDER_IN_PROGRESS | 주문 진행 중 | 주문이 생성되었지만 결제/지급 처리가 완료되지 않은 경우 |
| NOT_FOUND | 주문 없음 | 해당 주문번호를 찾을 수 없는 경우 |
| MINIAPP_MISMATCH | 상품 불일치 | 주문한 상품이 해당 앱의 상품이 아닌 경우 |
| ERROR | 내부 오류 | 시스템 내부 오류 발생 시 |
응답 예제
{
"resultType": "SUCCESS",
"success": {
"orderId": "13c9a1ff-2baa-4495-bbfa-a0826ba8c7c0",
"sku": "ait.0000010000.af647449.3bd55cfd00.0000000475",
"statusDeterminedAt": "2025-09-12T16:57:12",
"status": "PAYMENT_COMPLETED",
"reason": "결제가 완료되었어요."
}
}{
"resultType": "SUCCESS",
"success": {
"orderId": "13c9a1ff-2baa-4495-bbfa-0000000000",
"sku": "ait.0000010000.af647449.00000000000.0000000475",
"statusDeterminedAt": "2025-09-12T16:57:12",
"status": "PURCHASED",
"reason": "완료된 주문이에요."
}
}샌드박스 테스트
출시 전에는 반드시 샌드박스 앱 환경에서 인앱결제가 정상적으로 동작하는지 테스트해 주세요.
샌드박스에서는 실제 결제(과금)는 발생하지 않으며, 모든 결제가 테스트 시나리오로 처리돼요.
참고하세요
현재 샌드박스 테스트는 일회성 결제만 지원해요.
구독결제의 샌드박스 테스트는 현재 지원하지 않아요.
1. 샌드박스에서 상품 목록 조회 시 동작
샌드박스 앱에서 getProductItemList()를 호출하면 콘솔에 등록된 인앱결제 상품 중 노출 상태가 ON인 상품만 조회돼요.
- 실제 콘솔에 등록한 상품 목록이 그대로 내려와요.
- 콘솔에서 노출 OFF인 상품은 샌드박스 앱에서도 보이지 않아요.

2. 필수 테스트 시나리오
샌드박스에서는 아래 3가지 테스트를 반드시 각각 수행해야 해요.
각 시나리오마다 앱이 올바르게 대응하는지 확인해 주세요.
① 결제 성공 테스트
- 성공 콜백(
event.type: success)이 정상적으로 전달되는지 확인해요. - 실제 결제(과금)는 발생하지 않아요.
- SDK 1.1.3 이상에서는 파트너사의 상품 지급 로직까지 성공해야 최종 성공으로 처리돼요.
확인해야 할 항목
orderId,amount등event.data정상 반환 여부- 내부 지급 로직 정상 동작 여부
- 지급 완료 후 화면/UI 업데이트
② 결제 성공(서버 실패) 테스트
결제는 성공했지만 파트너 서버의 지급 로직이 실패하는 경우를 반드시 테스트해야 해요.
- 앱은 다음 처리를 지원해야 해요:
- 사용자에게 지급 실패 안내
- 앱 재실행 시
getPendingOrders로 미결 주문 복원 - 지급 완료 후
completeProductGrant호출
실서비스에서도 충분히 발생 가능한 시나리오이므로 반드시 테스트해야 해요.
③ 에러 테스트
결제 도중 오류가 발생하는 다양한 상황을 미리 시뮬레이션하세요.
테스트해야 할 대표 상황
- 네트워크 오류
- 사용자가 결제 취소
- 내부 오류
- 파트너사 상품 지급 실패
3. 테스트 체크리스트
| 테스트 항목 | 필수 | 확인 포인트 |
|---|---|---|
| 상품 목록 노출 | ✔️ | 콘솔에서 등록한 상품이 정상적으로 내려오는지 |
| 결제 성공 테스트 | ✔️ | event.data 처리, 지급 로직, UI 처리 |
| 결제 성공 + 서버 지급 실패 (주문 복원) | ✔️ | 미결 주문 복원 및 재지급 처리 |
| 에러 테스트 | ✔️ | 에러 UI, 오류 처리, 재시도 흐름 |
| 주문 상태 조회 API | 권장 | 서버 검증 및 정합성 확인 |
자주 묻는 질문
SDK 1.0.3 버전 이상에서는 승인/실패를 포함한 모든 주문 건에 대해 "orderId" 프로퍼티가 전달돼요.
단, 네트워크 오류 등으로 "orderId"가 발급되기 전에 오류가 발생할 경우 "orderId"가 내려오지 않을 수 있어요.
SDK 1.1.3 버전 이상에서 "errorCode"가 정상적으로 내려오도록 수정되었어요.
최신 SDK로 업데이트해 주세요.
SDK 1.2.2 버전 이상에서 주문 복원 함수를 사용해 연동해 주세요.
getPendingOrders 함수를 사용해 미결 주문을 조회하고, 조회된 주문의 orderId를 사용해 사용자에게 상품을 지급하세요.
completeProductGrant 함수를 호출해 지급 상태를 완료로 변경하세요.
토스앱 5.229.1 버전 이상에서 사용자가 인앱 결제 구매내역을 확인할 수 있어요.
- 구글 결제 건 : "환불받기" 버튼을 눌러 사유 선택 후 환불 요청 가능
- 파트너사 : 콘솔의 환불 내역에서 환불 요청을 승인 또는 반려 가능
- 결과 안내 : 환불 처리 결과는 사용자에게 푸시 알림으로 전달됨