> For the complete documentation index, see [llms.txt](https://developers-apps-in-toss.toss.im/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers-apps-in-toss.toss.im/documentation/api-and-sdk-en/common/monetization/iap/in-app-purchase.md).

# In-app Purchases

This is a one-time payment SDK used for products completed with a single purchase, such as consumables and non-consumables. For the service introduction and console setup instructions, see [In-app Purchase Introduction Document](https://developers-apps-in-toss.toss.im/guide/monetization/in-app-payment)Please refer to it.

{% hint style="info" %}
**BaseURL**

`https://apps-in-toss-api.toss.im`
{% endhint %}

{% hint style="info" %}
**An mTLS certificate is required for server-to-server communication**

The order status lookup API for in-app purchases is server-to-server communication called from the partner server to the Apps in Toss server. For security, configure the mTLS certificate on your server before calling it. For how to issue the certificate, see [How to Issue an mTLS Certificate](https://developers-apps-in-toss.toss.im/guide/getting-started/launch/integration-process#mtls-인증서-발급-방법)Please refer to it.
{% endhint %}

Please follow the steps below for the integration flow.

1. [Fetch product list](#getproductitemlist) — `getProductItemList`
2. [Request payment](#createonetimepurchaseorder) — `createOneTimePurchaseOrder`
3. [Restore pending orders](#getpendingorders) — `getPendingOrders`, `completeProductGrant`
4. [Check order status](#getcompletedorrefundedorders) — `getCompletedOrRefundedOrders` or [Order status lookup API](#주문-상태-조회-api)

{% hint style="info" %}
**Important**

* SDK **version 1.1.3 or later**.
* Starting from SDK version 1.1.3, **the product grant completion flow**was added, and the function interface changed.
* SDK **version 1.2.2**and later, **purchase restoration feature**was added.
* **Make sure to integrate it so that in-app purchase products remain granted even if the user's device changes.**
* [Native storage feature](https://developers-apps-in-toss.toss.im/api-and-sdk/common/device/storage)Please use it.
* Please use Toss Login integration and the in-app purchase status lookup API.
* To use the in-app purchase status lookup API, you must first complete [Toss Login integration](https://developers-apps-in-toss.toss.im/guide/user/auth/login)first.
  {% endhint %}

***

## IAP object

`IAP`is an object that groups in-app purchase-related functions.

{% hint style="info" %}
**Supported environment**

* Supported platforms: React Native, WebView
* Runtime environment: Toss App
* SDK versions: WebView v1.0.3, React Native v1.0.3
* Minimum Toss app version: v5.219.0
  {% endhint %}

{% hint style="info" %}
**Important**

Supported starting from Toss app version 5.219.0. In versions that do not support in-app purchase, `undefined`is returned.
{% endhint %}

**Signature**

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

**Property**

| Name                         | Type                                  | Description                                                                  |
| ---------------------------- | ------------------------------------- | ---------------------------------------------------------------------------- |
| getProductItemList           | `typeof getProductItemList`           | A function that fetches the list of products available for in-app purchase.  |
| createOneTimePurchaseOrder   | `typeof createOneTimePurchaseOrder`   | A function that requests an in-app purchase.                                 |
| getPendingOrders             | `typeof getPendingOrders`             | Fetches the list of pending orders.                                          |
| getCompletedOrRefundedOrders | `typeof getCompletedOrRefundedOrders` | Fetches the list of orders purchased or refunded through in-app purchase.    |
| completeProductGrant         | `typeof completeProductGrant`         | Sends a message to the app that product grant processing has been completed. |

## Check product list <a href="#getproductitemlist" id="getproductitemlist"></a>

**SDK function:** `getProductItemList`

{% hint style="info" %}
**Supported environment**

* Supported platforms: React Native, WebView
* Runtime environment: Toss App
* SDK versions: WebView v1.0.3, React Native v1.0.3
* Minimum Toss app version: v5.219.0
  {% endhint %}

`getProductItemList` is a function that contains the list of products available for in-app purchase. Use it when displaying the product list on screen.

**Signature**

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

**Return value**

`Promise<{ products: IapProductListItem[] } | undefined>` Returns a type. It returns an object containing the product list, and if the app version is lower than the minimum supported version (5.219.0), `undefined`is returned.

**Property**

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

| Name          | Required | Type     | Description                                                                                                                     |
| ------------- | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------- |
| sku           | Required | `string` | The product's unique ID. `IAP.createOneTimePurchaseOrder`used when calling `productId`is the same value as.                     |
| displayAmount | Required | `string` | Price information including the currency unit. For example `"1,000 won"`is displayed with both the price and currency together. |
| displayName   | Required | `string` | The product name displayed on screen. The product name is the value set in the Apps in Toss console.                            |
| iconUrl       | Required | `string` | The URL of the product icon image. The icon is the image set in the Apps in Toss console.                                       |
| description   | Required | `string` | A description of the product. The description is the value set in the Apps in Toss console.                                     |

**Example**

Get the list of purchasable in-app purchase products

{% tabs %}
{% tab title="js" %}

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

async function handleGetProductItemList() {
  const response = await IAP.getProductItemList();

  return response?.products ?? [];
}
```

{% endtab %}

{% tab title="React" %}

```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((sku: string) => {
    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();
      },
    });
  }, []);

  useEffect(() => {
    async function fetchProducts() {
      try {
        const response = await IAP.getProductItemList();
        setProducts(response?.products ?? []);
      } catch (error) {
        console.error('Failed to fetch the product list:', 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)}>
              Buy
            </Button>
          }
        />
      ))}
    </List>
  );
}
```

{% endtab %}

{% tab title="React Native" %}

```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((sku: string) => {
    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();
      },
    });
  }, []);

  useEffect(() => {
    async function fetchProducts() {
      try {
        const response = await IAP.getProductItemList();
        setProducts(response?.products ?? []);
      } catch (error) {
        console.error('Failed to fetch the product list:', 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)}>
              Buy
            </Button>
          }
          contents={
            <ListRow.Texts
              type="3RowTypeA"
              top={product.displayName}
              middle={product.description}
              bottom={product.displayAmount}
            />
          }
        />
      ))}
    </List>
  );
}
```

{% endtab %}
{% endtabs %}

**Example response**

```json
{
  "products": [
    {
      "sku": "sku1",
      "displayName": "Remove ads",
      "displayAmount": "4,900 won",
      "iconUrl": "https://cdn.example.com/icons/premium-monthly.png",
      "description": "Ad removal and premium features"
    },
    {
      "sku": "sku2",
      "displayName": "100 coins",
      "displayAmount": "9,900 won",
      "iconUrl": "https://cdn.example.com/icons/coin-100.png",
      "description": "100 coins available for use within the app"
    }
  ]
}
```

**Try the example app**

[apps-in-toss-examples](https://github.com/toss/apps-in-toss-examples) repository [with-in-app-purchase](https://github.com/toss/apps-in-toss-examples/tree/main/with-in-app-purchase) Download the code and try it out.

## Request a one-time payment <a href="#createonetimepurchaseorder" id="createonetimepurchaseorder"></a>

**SDK function:** `createOneTimePurchaseOrder`

{% hint style="info" %}
**Supported environment**

* Supported platforms: React Native, WebView
* Runtime environment: Toss App
* SDK versions: WebView v1.0.3, React Native v1.0.3
* Minimum Toss app version: v5.219.0
  {% endhint %}

`createOneTimePurchaseOrder` The function opens the in-app purchase payment window and lets the user proceed with payment. If an error occurs during payment, it moves to an error page depending on the error type.

{% hint style="info" %}
**Note**

within 30 seconds after payment succeeds `processProductGrant` If the callback is not called or the result of that callback is not true, `{appName} has a problem. Please request a refund` the page may be shown.
{% endhint %}

**Signature**

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

**Parameters**

```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;
}
```

| Name                        | Required | Type                   | Description                                                                                                                                      |
| --------------------------- | -------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| options                     | Required | Payment options object | These are the options required for in-app purchase.                                                                                              |
| options.sku                 | Required | `string`               | The ID of the product to order.                                                                                                                  |
| options.processProductGrant | Required | Product grant callback | Called when actually granting the product after the order is created. `orderId`receives `true` or `Promise<true>`and returns `false`is returned. |
| onEvent                     | Required | Success event callback | Called when payment succeeds.                                                                                                                    |
| onError                     | Required | Error callback         | Called when an error occurs during payment. You can use the error object to log it or run a recovery procedure.                                  |

**SuccessEvent properties**

| Name                | Required | Type                                  | Description                                                                                |
| ------------------- | -------- | ------------------------------------- | ------------------------------------------------------------------------------------------ |
| type                | Required | `"success"`                           | The type of the event.                                                                     |
| data                | Required | `IapCreateOneTimePurchaseOrderResult` | When in-app purchase is completed, it returns the payment details and product information. |
| data.orderId        | Required | `string`                              | The payment order ID. Used to look up the payment status after payment is complete.        |
| data.displayName    | Required | `string`                              | The product name displayed on screen.                                                      |
| data.displayAmount  | Required | `string`                              | Price information including the currency unit.                                             |
| data.amount         | Required | `number`                              | The numeric value of the product price.                                                    |
| data.currency       | Required | `string`                              | The currency unit of the product price.                                                    |
| data.fraction       | Required | `number`                              | The value that determines how many decimal places to show when displaying the price.       |
| data.miniAppIconUrl | Optional | `string` or `null`                    | The URL of the mini app icon image.                                                        |

**Error code**

| Error code                        | Description                                                                                                                                                      |
| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `INVALID_PRODUCT_ID`              | Occurs when the product ID is invalid or the product does not exist.                                                                                             |
| `PAYMENT_PENDING`                 | Occurs when the payment requested by the user is still awaiting approval.                                                                                        |
| `NETWORK_ERROR`                   | Occurs when a network error occurs.                                                                                                                              |
| `INVALID_USER_ENVIRONMENT`        | Occurs when the product cannot be purchased in a specific device, account, or settings environment.                                                              |
| `APP_MARKET_VERIFICATION_FAILED`  | Occurs when the user completed payment, but verification of user information failed in the app market. The user must contact the app store and request a refund. |
| `TOSS_SERVER_VERIFICATION_FAILED` | Occurs when the user completed payment, but payment information cannot be saved because transmission to the server failed.                                       |
| `INTERNAL_ERROR`                  | Occurs when the request cannot be processed due to an internal server problem.                                                                                   |
| `KOREAN_ACCOUNT_ONLY`             | Occurs when the user's account is not a Korean account in the iOS environment.                                                                                   |
| `USER_CANCELED`                   | Occurs when the user leaves the order page without completing payment.                                                                                           |
| `PRODUCT_NOT_GRANTED_BY_PARTNER`  | Occurs when the partner's product grant fails. This occurs only in Toss app 5.230.0 or later.                                                                    |

**Return value**

`() => void` Returns an app bridge cleanup function of type () => void. When the in-app purchase feature is finished, you must call this function to release resources.

**Example**

Navigate to a specific in-app purchase order page

{% tabs %}
{% tab title="js" %}

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

let cleanup;

function handleBuyProduct(sku) {
  cleanup = IAP.createOneTimePurchaseOrder({
    options: {
      sku,
      processProductGrant: ({ orderId }) => {
        console.log('Executing product grant logic:', orderId);
        return true;
      },
    },
    onEvent: (event) => {
      console.log('Event:', event);
      cleanup?.();
    },
    onError: (error) => {
      console.error('In-app purchase failed:', error);
      cleanup?.();
    },
  });
}

window.addEventListener('pagehide', () => {
  cleanup?.();
});
```

{% endtab %}

{% tab title="React" %}

```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}>Buy</Button>;
}
```

{% endtab %}

{% tab title="React Native" %}

```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();
      },
    });
  }, [sku]);

  return <Button onPress={handleClick}>Buy</Button>;
}
```

{% endtab %}
{% endtabs %}

**Try the example app**

[apps-in-toss-examples](https://github.com/toss/apps-in-toss-examples) repository [with-in-app-purchase](https://github.com/toss/apps-in-toss-examples/tree/main/with-in-app-purchase) Download the code and try it out.

## Check pending orders <a href="#getpendingorders" id="getpendingorders"></a>

**SDK function:** `getPendingOrders`

{% hint style="info" %}
**Supported environment**

* Supported platforms: React Native, WebView
* Runtime environment: Toss App, Sandbox App
* SDK versions: WebView v1.4.8, React Native v1.4.8
* Minimum Toss app version: iOS v5.231.0, Android v5.235.0
* Sandbox app version: iOS 2025-10-28, Android 2025-10-22
  {% endhint %}

`getPendingOrders` is **A list of orders for which payment is complete but the product has not yet been granted**is a function that fetches them. Check the retrieved order information and grant the product to the user. `createOneTimePurchaseOrder` Even if you do not receive a result after calling the function, you can still query that order.

If the app version is lower than the minimum supported version (Android 5.234.0, iOS 5.231.0), `undefined`is returned.

**Signature**

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

**Return value**

`Promise<{ orders: Order[] } | undefined>` Returns a type. It returns an object containing the list of pending orders, and if the app version is lower than the minimum supported version (Android 5.234.0, iOS 5.231.0), `undefined`is returned.

**Returned object properties**

```tsx
interface Order {
  orderId: string;
  sku: string;
  paymentCompletedDate?: string;
}
```

| Name                           | Required | Type      | Description                                                                                 |
| ------------------------------ | -------- | --------- | ------------------------------------------------------------------------------------------- |
| orders                         | Required | `Order[]` | It's an array of pending orders. If there are no pending orders, it returns an empty array. |
| orders\[].orderId              | Required | `string`  | This is the unique ID of the order.                                                         |
| orders\[].sku                  | Required | `string`  | This is the unique ID of the ordered product.                                               |
| orders\[].paymentCompletedDate | Optional | `string`  | Indicates when payment was completed.                                                       |

{% hint style="info" %}
**Field update notice**

* **SDK 1.4.2**: `sku` The field has been added. This field **Android 5.234.0 or later, iOS 5.231.0 or later**is returned only in.
* **SDK 1.4.8**: `paymentCompletedDate` The field has been added. You can check the payment completion time.
  {% endhint %}

**Example**

{% tabs %}
{% tab title="js" %}

```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);
  }
}
```

{% endtab %}

{% tab title="React" %}

```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);
  }
}
```

{% endtab %}

{% tab title="React Native" %}

```tsx
import { IAP } from '@apps-in-toss/framework';

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

{% endtab %}
{% endtabs %}

## Complete product grant <a href="#completeproductgrant" id="completeproductgrant"></a>

**SDK function:** `completeProductGrant`

{% hint style="info" %}
**Supported environment**

* Supported platforms: React Native, WebView
* Runtime environment: Toss App
* SDK versions: WebView v1.2.2, React Native v1.2.2
* Minimum Toss app version: iOS v5.231.0, Android v5.231.0
  {% endhint %}

`completeProductGrant` The function **is a function that completes the product grant for pending orders**for pending orders. Grant the product to the user and `completeProductGrant` call the function to change the grant status to complete.

If the app version is lower than the minimum supported version (Android 5.231.0, iOS 5.231.0), `undefined`is returned.

**Signature**

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

**Parameters**

| Name           | Required | Type                  | Description                                                                                              |
| -------------- | -------- | --------------------- | -------------------------------------------------------------------------------------------------------- |
| params         | Required | `{ orderId: string }` | This is an object containing information about an order whose payment has been completed.                |
| params.orderId | Required | `string`              | This is the order's unique ID. Use it to specify the order for which you want to complete product grant. |

**Return value**

`Promise<boolean | undefined>` It returns a type. It returns whether the product grant has been completed, and if the app version is lower than the minimum supported version (Android 5.233.0, iOS 5.233.0), `undefined`is returned.

**Example**

{% tabs %}
{% tab title="js" %}

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

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

{% endtab %}

{% tab title="React" %}

```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);
  }
}
```

{% endtab %}

{% tab title="React Native" %}

```tsx
import { IAP } from '@apps-in-toss/framework';

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

{% endtab %}
{% endtabs %}

## Look up completed/refunded orders <a href="#getcompletedorrefundedorders" id="getcompletedorrefundedorders"></a>

**SDK function:** `getCompletedOrRefundedOrders`

{% hint style="info" %}
**Supported environment**

* Supported platforms: React Native, WebView
* Runtime environment: Toss App
* SDK versions: WebView v1.2.2, React Native v1.2.2
* Minimum Toss app version: iOS v5.231.0, Android v5.231.0
  {% endhint %}

`getCompletedOrRefundedOrders` gets the list of orders purchased and refunded through in-app payment. You can look up orders whose in-app payment and product grant have been completed, as well as refunded orders.

Orders for which payment has been completed but the product has not yet been granted are not returned. [`getPendingOrders`](#getpendingorders)through the function `orderId`look up and grant the product to the user, then [`completeProductGrant`](#completeproductgrant)use the function to complete the product grant.

If the app version is lower than the minimum supported version (Android 5.231.0, iOS 5.231.0), `undefined`is returned.

{% hint style="info" %}
**Pagination**

* **Up to 50 per page**orders are returned.
* When there is a next page, `hasNext`is `true`and in the response, `nextKey`use `key` as a parameter for the next call to continue the lookup.
  {% endhint %}

**Signature**

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

**Return value**

`Promise<CompletedOrRefundedOrdersResult | undefined>` It returns a Promise\<CompletedOrRefundedOrdersResult | undefined> type. It returns an order-list object including pagination, and if the app version is lower than the minimum supported version (Android 5.231.0, iOS 5.231.0), `undefined`is returned.

**Returned object properties**

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

| Name              | Required | Type                      | Description                                                                                                                                                                             |
| ----------------- | -------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| hasNext           | Required | `boolean`                 | Indicates whether there is a next page. `true`If so, there are more orders left.                                                                                                        |
| nextKey           | Optional | `string` or `null`        | This is the cursor key for looking up the next page. Use the `nextKey` value from the previous response. `null`For the first call, omit it or                                           |
| orders            | Required | `pass it as.`             | It's an array containing order information. Each element represents one order.                                                                                                          |
| orders\[].orderId | Required | `string`                  | This is the unique ID of the order.                                                                                                                                                     |
| orders\[].sku     | Required | `string`                  | This is the unique ID of the ordered product.                                                                                                                                           |
| orders\[].status  | Required | `COMPLETED` or `REFUNDED` | This is the order status. `COMPLETED`means the order is completed, `REFUNDED`means it has been refunded.                                                                                |
| orders\[].date    | Required | `string`                  | This is the order date information. Use ISO 8601 format (`YYYY-MM-DDTHH:mm:ss`). If the order status is `COMPLETED`it indicates the order date, `REFUNDED`it indicates the refund date. |

**Example**

{% tabs %}
{% tab title="js" %}

```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);
  }
}
```

{% endtab %}

{% tab title="React" %}

```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);
  }
}
```

{% endtab %}

{% tab title="React Native" %}

```tsx
import { IAP } from '@apps-in-toss/framework';

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

{% endtab %}
{% endtabs %}

***

## Order status lookup API

You can directly look up in-app payment order status through the API from the server. You can use it even if you did not receive an approval or refund response.

{% hint style="info" %}
**Note**

To use the payment status lookup API, [Toss Login integration](https://developers-apps-in-toss.toss.im/guide/user/auth/login)first.
{% endhint %}

* Content-type: `application/json`
* Method: `POST`
* URL: `/api-partner/v1/apps-in-toss/order/get-order-status`

**Request headers**

| Name            | Type   | Whether required | Description                               |
| --------------- | ------ | ---------------- | ----------------------------------------- |
| x-toss-user-key | string | N                | userKey value obtained through Toss login |

* If the header is not included, all orders are returned.
* In the header, `x-toss-user-key` If you include a value, only orders for that userKey are returned.

**Request parameters**

| Name    | Type   | Required | Description                                            |
| ------- | ------ | -------- | ------------------------------------------------------ |
| orderId | String | Y        | Order number (uuid v7) obtained after payment creation |

```json
{
  "orderId": "13c9a1ff-2baa-4495-bbfa-a0826ba8c7c0"
}
```

**Response**

| Name               | Type   | Description                                                                                                                       |
| ------------------ | ------ | --------------------------------------------------------------------------------------------------------------------------------- |
| orderId            | String | Requested order number                                                                                                            |
| sku                | String | Ordered product ID                                                                                                                |
| statusDeterminedAt | String | Order completion date/time (`yyyy-MM-dd'T'HH:mm:ss`, fixed to KST). `status`is `REFUNDED`This is the refund completion date/time. |
| status             | String | Order status (enum)                                                                                                               |
| reason             | String | Description of the status                                                                                                         |

**status (enum)**

| Status              | Description       | Detailed description                                                                     |
| ------------------- | ----------------- | ---------------------------------------------------------------------------------------- |
| `PURCHASED`         | Order completed   | State in which both in-app payment and product grant are complete                        |
| `PAYMENT_COMPLETED` | Payment completed | In SDK 1.1.3 and later, the state where payment is complete but product grant has failed |
| `FAILED`            | Order failed      | When payment has failed                                                                  |
| `REFUNDED`          | Order refunded    | When the refund is completed                                                             |
| `ORDER_IN_PROGRESS` | Order in progress | When the order has been created but payment/grant processing has not been completed      |
| `NOT_FOUND`         | No order found    | When the specified order number cannot be found                                          |
| `MINIAPP_MISMATCH`  | Product mismatch  | When the ordered product is not a product for this app                                   |
| `ERROR`             | Internal error    | When an internal system error occurs                                                     |

**Response example**

```json
{
  "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": "Payment completed."
  }
}
```

```json
{
  "resultType": "SUCCESS",
  "success": {
    "orderId": "13c9a1ff-2baa-4495-bbfa-0000000000",
    "sku": "ait.0000010000.af647449.00000000000.0000000475",
    "statusDeterminedAt": "2025-09-12T16:57:12",
    "status": "PURCHASED",
    "reason": "This is a completed order."
  }
}
```

***

## Sandbox test

Before launch, be sure to **sandbox app environment**Please test whether in-app payments work properly in the sandbox app environment. In the sandbox, no actual payment (billing) occurs, and all payments are handled as test scenarios.

{% hint style="info" %}
**Note**

Currently, sandbox testing **one-time payment**Only is supported. Sandbox testing for subscription payments is not currently supported.
{% endhint %}

**1. Behavior when looking up product list in sandbox**

In the sandbox app, `getProductItemList()`when you call it, only the in-app payment products registered in the console with **display status ON**are returned.

* The product list actually registered in the console is returned as is.
* In the console, **display OFF**Products with are not visible in the sandbox app either.

**2. Required test scenarios**

In the sandbox, you must perform the following three tests separately. Please check that the app responds correctly for each scenario.

**① Payment success test**

* Success callback (`event.type: success`) is delivered properly.
* No actual payment (billing) occurs.
* In SDK 1.1.3 and later, the partner's **It is treated as final success only if the product grant logic also succeeds**as success.

{% hint style="info" %}
**Items to check**

* `orderId`, `amount` etc. `event.data` Whether it returns normally
* Whether the internal grant logic works properly
* Screen/UI update after grant completion
  {% endhint %}

**② Payment success (server failure) test**

You must test the case where payment succeeds but the partner server's grant logic fails.

The app should support the following handling.

* Notify the user of the grant failure
* When the app is restarted `getPendingOrders`Restore pending orders with
* After grant completion `completeProductGrant` call

This is a scenario that can occur often in live service as well, so you must test it.

**③ Error test**

Simulate various situations in which errors occur during payment in advance.

{% hint style="info" %}
**Representative situations to test**

* Network error
* User cancels payment
* Internal error
* Partner product grant failure
  {% endhint %}

**3. Test checklist**

| Test item                                                  | Required    | Check point                                                      |
| ---------------------------------------------------------- | ----------- | ---------------------------------------------------------------- |
| Product list display                                       | Required    | Whether products registered in the console are returned properly |
| Payment success test                                       | Required    | `event.data` Processing, grant logic, UI handling                |
| Payment success + server grant failure (order restoration) | Required    | Restoration of pending orders and re-grant processing            |
| Error test                                                 | Required    | Error UI, error handling, retry flow                             |
| Order status lookup API                                    | Recommended | Server validation and consistency check                          |

***

## Frequently asked questions

**When in-app payment fails `orderId` The property is not returned.**

In SDK 1.0.3 and later, the property is passed for all orders, including approvals and failures. However, if an error occurs before it is issued due to a network error, `orderId` it may not be returned. `orderId`errorCode `orderId`In SDK 1.1.3 and later,

**When in-app payment fails `errorCode` The property is not returned.**

It has been fixed so that it is returned properly. Please update to the latest SDK. `errorCode`It has been fixed so that it is returned properly. Please update to the latest SDK.

**How should I handle a failed order?**

Please integrate using the order restoration function in SDK 1.2.2 or later. `getPendingOrders` Use the function to look up pending orders, and use the `orderId`to grant the product to the user. `completeProductGrant` Call the function to change the grant status to complete.

**How do I check my in-app purchase history in the Toss app?**

Toss app **Version 5.229.1 or later**Users can view their in-app purchase history.

* **Google payments**: You can request a refund after selecting a reason by pressing the "Request refund" button
* **Partner company**: You can approve or reject refund requests in the refund history in the console
* **Result notification**: The refund processing result is delivered to the user via push notification


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developers-apps-in-toss.toss.im/documentation/api-and-sdk-en/common/monetization/iap/in-app-purchase.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
