> 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/toss-pay/toss-pay-subscription.md).

# Developing subscriptions

We guide you on how to integrate Toss Pay recurring payments in a mini app. We explain the full flow in order: billing key creation → user authentication → payment approval → cancellation.

### Prerequisites

#### Console setup is required

You must first complete the steps below before calling the API.

1. Please proceed with the subscription.
2. Please register the Toss Pay key values in the console.

{% hint style="info" %}
**Please make sure to check**

* Even if you already use Toss Pay, **you need to issue a separate Toss Pay merchant key in Apps in Toss.**
* Even if you are already using Toss Pay in Apps in Toss, **recurring payments (automatic payments) require an additional subscription.**
  {% endhint %}

Subscription, fees, and setup methods are [Toss Pay introduction](https://developers-apps-in-toss.toss.im/documentation/common/monetization/toss-pay) please refer to the document.

#### Identify the payment target user

Toss Pay identifies the payment target using one of the two methods below. Do not pass both values at the same time; choose only one.

| Category          | Issuance method                                                                                                                                  |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `x-toss-user-key` | [Toss login](https://developers-apps-in-toss.toss.im/documentation/common/authentication/toss-login)obtained from `userKey` value.               |
| `x-anon-key`      | [User identification key issuance](https://developers-apps-in-toss.toss.im/documentation/common/authentication/hash-key)hash value obtained from |

Please choose according to your purpose.

* If you have already integrated Toss Login, or if you want to manage member information such as name and email together, use Toss Login.
* If you want to identify only the user lightly without login integration, use the user identification key issuance feature.

`x-anon-key`If you want to check in advance whether the (hash) is a valid value, [Please use the Identify Key Validation](https://developers-apps-in-toss.toss.im/documentation/common/authentication/hash-key#식별키-검증하기) API.

***

### Basic information

| Item                  | Value                                  |
| --------------------- | -------------------------------------- |
| Base URL              | `https://pay-apps-in-toss-api.toss.im` |
| Server authentication | mTLS (client certificate)              |
| Content-Type          | `application/json`                     |

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

The recurring payment API is server-to-server communication called from the partner server to the Apps in Toss server. For security, please set up an mTLS certificate on the server before calling. For how to issue a certificate, [mTLS certificate issuance method](https://developers-apps-in-toss.toss.im/documentation/integration/getting-started)please refer to
{% endhint %}

***

### Testing

When requesting payment creation `isTestPayment: true`If set to that, you can test payments in the sandbox environment. You don't need to set it separately in the console, and you can test even before subscribing.

However, the sandbox environment has the following limitations.

* Only billing key creation (step 1) is possible, and payment approval (step 3) is not supported.
* Created in the sandbox `wrappedToken`cannot be used in the production environment.
* Real payment flow verification must be done after switching to the production key.

***

### 1. Create a billing key

Register the user's recurring payment method. Pass the `wrappedToken`received in the response to the client to proceed with user authentication.

* Content-Type: `application/json`
* Method: `POST`
* URL: `/api-partner/v1/apps-in-toss/pay/create-billing-key`

**Request headers**

For the header that identifies the payment target, use one of the two below. Do not send both headers at once.

| Name              | Type   | Required   | Description                                                                                                                                                                                                                                                                     |
| ----------------- | ------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `x-toss-user-key` | string | Choose one | [Toss login](https://developers-apps-in-toss.toss.im/documentation/common/authentication/toss-login)obtained from `userKey`It is. [You can obtain it through](https://developers-apps-in-toss.toss.im/documentation/common/authentication/toss-login#_4-사용자-정보-받기)Get user info |
| `x-anon-key`      | string | Choose one | [User identification key issuance](https://developers-apps-in-toss.toss.im/documentation/common/authentication/hash-key)obtained from `hash` value.                                                                                                                             |

**Request parameters**

| Field           | Type    | Required | Description                                                   |
| --------------- | ------- | -------- | ------------------------------------------------------------- |
| `productDesc`   | String  | Y        | Recurring payment product name (e.g., "Monthly subscription") |
| `isTestPayment` | Boolean | Y        | Whether it is a test payment                                  |

```json
{
  "productDesc": "Monthly subscription",
  "isTestPayment": false
}
```

**Response parameters**

| Field          | Type   | Description                                                           |
| -------------- | ------ | --------------------------------------------------------------------- |
| `wrappedToken` | String | It is a recurring payment token. Use it for all subsequent API calls. |

```json
{
  "resultType": "SUCCESS",
  "success": {
    "wrappedToken": "550e8400-e29b-41d4-a716-446655440000"
  }
}
```

{% hint style="info" %}
**Please make sure to check**

`wrappedToken`It is used for payment approval, status inquiries, and cancellation, so it must be saved.
{% endhint %}

***

### 2. Authenticate the user

**Please integrate through the SDK.**

Pass the `wrappedToken`received in the billing key creation response to the client. The client uses the Apps in Toss SDK to perform Toss Pay authentication.

```typescript
import { TossPay } from '@apps-in-toss/web-framework';

const { success, reason } = await TossPay.requestTossPayPaysBilling({ wrappedToken });

if (success) {
  // Authentication successful → request payment approval from the server
} else {
  // Authentication failed (failure reason in reason)
}
```

**Return value**

| Field     | Type    | Description                      |
| --------- | ------- | -------------------------------- |
| `success` | boolean | Whether authentication succeeded |
| `reason`  | string? | Reason for failure               |

{% hint style="info" %}
**Minimum supported SDK version**

* Android: `5.256.0`
* iOS: `5.256.0`
  {% endhint %}

***

### 3. Execute recurring payment

Approve payment with the registered payment method.

* Content-Type: `application/json`
* Method: `POST`
* URL: `/api-partner/v1/apps-in-toss/pay/execute-billing`

**Request headers**

For the header that identifies the payment target, use one of the two below. Do not send both headers at once.

| Name              | Type   | Required   | Description                                                                                                                                                                                                                                                                     |
| ----------------- | ------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `x-toss-user-key` | string | Choose one | [Toss login](https://developers-apps-in-toss.toss.im/documentation/common/authentication/toss-login)obtained from `userKey`It is. [You can obtain it through](https://developers-apps-in-toss.toss.im/documentation/common/authentication/toss-login#_4-사용자-정보-받기)Get user info |
| `x-anon-key`      | string | Choose one | [User identification key issuance](https://developers-apps-in-toss.toss.im/documentation/common/authentication/hash-key)obtained from `hash` value.                                                                                                                             |

**Request parameters**

| Field                    | Type    | Required | Description                                                    |
| ------------------------ | ------- | -------- | -------------------------------------------------------------- |
| `wrappedToken`           | String  | Y        | Token received when creating the billing key                   |
| `orderNo`                | String  | Y        | Order number                                                   |
| `productDesc`            | String  | Y        | product description                                            |
| `spreadOut`              | Int     | Y        | Installment months (0 = lump sum)                              |
| `amount`                 | Long    | Y        | Payment amount                                                 |
| `amountTaxFree`          | Long    | Y        | Tax-free amount                                                |
| `amountTaxable`          | Long    | N        | Taxable amount                                                 |
| `amountVat`              | Long    | N        | VAT                                                            |
| `amountServiceFee`       | Long    | N        | Service charge                                                 |
| `cashReceipt`            | Boolean | N        | Whether to issue a cash receipt (default: true)                |
| `sendFailPush`           | Boolean | N        | Whether to send a push notification on failure (default: true) |
| `cashReceiptTradeOption` | String  | N        | Cash receipt type (default: GENERAL)                           |
| `isTestPayment`          | Boolean | Y        | Whether it is a test payment                                   |

```json
{
  "wrappedToken": "550e8400-e29b-41d4-a716-446655440000",
  "orderNo": "ORDER-20260416-001",
  "productDesc": "Monthly subscription payment",
  "spreadOut": 0,
  "amount": 9900,
  "amountTaxFree": 0,
  "isTestPayment": false
}
```

**Response parameters**

| Field                 | Type   | Description                                                                                                                                                                                                                                                |
| --------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `code`                | Int    | This is the response code. If it is 0, it means success.                                                                                                                                                                                                   |
| `mode`                | String | This is the payment mode.                                                                                                                                                                                                                                  |
| `payToken`            | String | The payment token.                                                                                                                                                                                                                                         |
| `orderNo`             | String | This is the order number.                                                                                                                                                                                                                                  |
| `payMethod`           | String | This is the payment method. (CARD, TOSS\_MONEY, etc.)                                                                                                                                                                                                      |
| `amount`              | Int    | This is the approved amount.                                                                                                                                                                                                                               |
| `transactionId`       | String | This is the transaction ID.                                                                                                                                                                                                                                |
| `approvalTime`        | String | This is the approval time.                                                                                                                                                                                                                                 |
| `discountedAmount`    | Int    | This is the discount amount.                                                                                                                                                                                                                               |
| `paidAmount`          | Int    | This is the actual payment amount.                                                                                                                                                                                                                         |
| `cardCompanyName`     | String | Approved card company name.                                                                                                                                                                                                                                |
| `cardCompanyCode`     | String | Approved card company code.                                                                                                                                                                                                                                |
| `cardAuthorizationNo` | String | Card company approval number that the buyer can check. Available in live key payments.                                                                                                                                                                     |
| `salesCheckLinkUrl`   | String | Credit card sales receipt URL.                                                                                                                                                                                                                             |
| `noInterest`          | String | Whether card no-interest installment is applied. `true`: no-interest, `false`: normal                                                                                                                                                                      |
| `cardNumber`          | String | Masked card number. The middle digits of the 16-digit card number are masked.                                                                                                                                                                              |
| `cardUserType`        | String | Card user type. `PERSONAL`: personal card, `PERSONAL_FAMILY`: family card, `CORP_PERSONAL`: corporate-designated payment account employee, `CORP_PRIVATE`: corporate shared, `CORP_COMPANY`: corporate-designated payment account company (Hana Card only) |
| `cardBinNumber`       | String | Card BIN number.                                                                                                                                                                                                                                           |
| `cardNum4Print`       | String | The last 4 digits of the card selected by the user.                                                                                                                                                                                                        |

```json
{
  "resultType": "SUCCESS",
  "success": {
    "code": 0,
    "mode": "LIVE",
    "payToken": "7W3000019000001",
    "orderNo": "ORDER-20260416-001",
    "payMethod": "CARD",
    "amount": 9900,
    "transactionId": "20260416000001",
    "approvalTime": "20260416120000",
    "discountedAmount": 0,
    "paidAmount": 9900,
    "cardCompanyName": "Samsung",
    "cardCompanyCode": 3,
    "cardAuthorizationNo": "87654321",
    "salesCheckLinkUrl": "https://pay.toss.im/payfront/web/external/sales-check?payToken=example-payToken",
    "noInterest": false,
    "cardNumber": "654321******1234",
    "cardUserType": "NONE",
    "cardBinNumber": "654321",
    "cardNum4Print": "1234"
  }
}
```

***

### 4. Refund a recurring payment

Refund a recurring payment.

* Content-Type: `application/json`
* Method: `POST`
* URL: `/api-partner/v1/apps-in-toss/pay/refund-billing`

**Request headers**

For the header that identifies the payment target, use one of the two below. Do not send both headers at once.

| Name              | Type   | Required   | Description                                                                                                                                                                                                                                                                     |
| ----------------- | ------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `x-toss-user-key` | string | Choose one | [Toss login](https://developers-apps-in-toss.toss.im/documentation/common/authentication/toss-login)obtained from `userKey`It is. [You can obtain it through](https://developers-apps-in-toss.toss.im/documentation/common/authentication/toss-login#_4-사용자-정보-받기)Get user info |
| `x-anon-key`      | string | Choose one | [User identification key issuance](https://developers-apps-in-toss.toss.im/documentation/common/authentication/hash-key)obtained from `hash` value.                                                                                                                             |

**Request parameters**

| Field           | Type    | Required | Description                                                                 |
| --------------- | ------- | -------- | --------------------------------------------------------------------------- |
| `payToken`      | String  | Y        | Payment token received in the recurring payment execution (step 3) response |
| `reason`        | String  | Y        | Reason for refund                                                           |
| `isTestPayment` | Boolean | Y        | Whether it is a test payment                                                |

```json
{
  "payToken": "string",
  "reason": "string",
  "isTestPayment": true
}
```

**Response parameters**

| Name                     | Type    | Description                                                                                                                                                                                                                                                |
| ------------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `refundNo`               | String  | Refund number.                                                                                                                                                                                                                                             |
| `approvalTime`           | String  | Refund processing time. (yyyy-MM-dd HH:flag\_mm:ss)                                                                                                                                                                                                        |
| `cashReceiptMgtKey`      | String  | Cash receipt management number identifier.                                                                                                                                                                                                                 |
| `refundableAmount`       | Integer | Refundable amount.                                                                                                                                                                                                                                         |
| `discountedAmount`       | Integer | Discounted amount.                                                                                                                                                                                                                                         |
| `paidAmount`             | Integer | Amount approved by payment method.                                                                                                                                                                                                                         |
| `refundedAmount`         | Integer | Refund request amount.                                                                                                                                                                                                                                     |
| `refundedDiscountAmount` | Integer | The actual deducted discount amount from the refund request amount.                                                                                                                                                                                        |
| `refundedPaidAmount`     | Integer | The actual deducted payment-method amount from the refund request amount.                                                                                                                                                                                  |
| `payToken`               | String  | Refunded payment token.                                                                                                                                                                                                                                    |
| `transactionId`          | String  | Transaction ID.                                                                                                                                                                                                                                            |
| `cardMethodType`         | String  | Card type. `CREDIT`: credit card, `CHECK`: debit card, `PREPAYMENT`: prepaid card                                                                                                                                                                          |
| `cardNumber`             | String  | Masked card number.                                                                                                                                                                                                                                        |
| `cardUserType`           | String  | Card user type. `PERSONAL`: personal card, `PERSONAL_FAMILY`: family card, `CORP_PERSONAL`: corporate-designated payment account employee, `CORP_PRIVATE`: corporate shared, `CORP_COMPANY`: corporate-designated payment account company (Hana Card only) |
| `cardNum4Print`          | String  | The last 4 digits of the card selected by the user.                                                                                                                                                                                                        |
| `cardBinNumber`          | String  | Card BIN number.                                                                                                                                                                                                                                           |
| `accountBankCode`        | String  | Bank code. In the case of Toss Money payments, pass the bank code defined by Toss.                                                                                                                                                                         |
| `accountBankName`        | String  | Bank name.                                                                                                                                                                                                                                                 |
| `accountNumber`          | String  | Masked account number.                                                                                                                                                                                                                                     |

```json
{
  "resultType": "SUCCESS",
  "success": {
    "refundNo": "string",
    "approvalTime": "string",
    "cashReceiptMgtKey": "string",
    "refundableAmount": 0,
    "discountedAmount": 0,
    "paidAmount": 0,
    "refundedAmount": 0,
    "refundedDiscountAmount": 0,
    "refundedPaidAmount": 0,
    "payToken": "string",
    "transactionId": "string",
    "cardMethodType": "string",
    "cardNumber": "string",
    "cardUserType": "string",
    "cardNum4Print": "string",
    "cardBinNumber": "string",
    "accountBankCode": "string",
    "accountBankName": "string",
    "accountNumber": "string"
  }
}
```

***

### 5. Check billing key status

Check the status of the registered recurring payment method.

* Content-Type: `application/json`
* Method: `POST`
* URL: `/api-partner/v1/apps-in-toss/pay/get-billing-key-status`

**Request headers**

For the header that identifies the payment target, use one of the two below. Do not send both headers at once.

| Name              | Type   | Required   | Description                                                                                                                                                                                                                                                                     |
| ----------------- | ------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `x-toss-user-key` | string | Choose one | [Toss login](https://developers-apps-in-toss.toss.im/documentation/common/authentication/toss-login)obtained from `userKey`It is. [You can obtain it through](https://developers-apps-in-toss.toss.im/documentation/common/authentication/toss-login#_4-사용자-정보-받기)Get user info |
| `x-anon-key`      | string | Choose one | [User identification key issuance](https://developers-apps-in-toss.toss.im/documentation/common/authentication/hash-key)obtained from `hash` value.                                                                                                                             |

**Request parameters**

| Field           | Type    | Required | Description                  |
| --------------- | ------- | -------- | ---------------------------- |
| `wrappedToken`  | String  | Y        | Recurring payment token      |
| `isTestPayment` | Boolean | Y        | Whether it is a test payment |

```json
{
  "wrappedToken": "550e8400-e29b-41d4-a716-446655440000",
  "isTestPayment": false
}
```

**Response parameters**

| Field              | Type   | Description                                                                        |
| ------------------ | ------ | ---------------------------------------------------------------------------------- |
| `code`             | Int    | This is the response code. If it is 0, it means success.                           |
| `billingKeyStatus` | String | This is the billing key status.                                                    |
| `cardCompanyName`  | String | Approved card company name.                                                        |
| `cardCompanyNo`    | String | Approved card company code.                                                        |
| `cardNumber`       | String | Masked card number. The middle digits of the 16-digit card number are masked.      |
| `cardImgUrl`       | String | This is the card image.                                                            |
| `accountBankName`  | String | Bank name.                                                                         |
| `accountBankCode`  | String | Bank code. In the case of Toss Money payments, pass the bank code defined by Toss. |
| `accountNumber`    | String | Account number. Partial masking is included.                                       |
| `accountName`      | String | Bank name.                                                                         |
| `accountImgUrl`    | String | This is the bank image.                                                            |

***

### 6. Cancel billing key

Cancel the registered recurring payment method. After cancellation, the corresponding `wrappedToken`cannot be used to approve payments.

* Content-Type: `application/json`
* Method: `POST`
* URL: `/api-partner/v1/apps-in-toss/pay/remove-billing-key`

**Request headers**

For the header that identifies the payment target, use one of the two below. Do not send both headers at once.

| Name              | Type   | Required   | Description                                                                                                                                                                                                                                                                     |
| ----------------- | ------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `x-toss-user-key` | string | Choose one | [Toss login](https://developers-apps-in-toss.toss.im/documentation/common/authentication/toss-login)obtained from `userKey`It is. [You can obtain it through](https://developers-apps-in-toss.toss.im/documentation/common/authentication/toss-login#_4-사용자-정보-받기)Get user info |
| `x-anon-key`      | string | Choose one | [User identification key issuance](https://developers-apps-in-toss.toss.im/documentation/common/authentication/hash-key)obtained from `hash` value.                                                                                                                             |

**Request parameters**

| Field           | Type    | Required | Description                  |
| --------------- | ------- | -------- | ---------------------------- |
| `wrappedToken`  | String  | Y        | Recurring payment token      |
| `isTestPayment` | Boolean | Y        | Whether it is a test payment |

```json
{
  "wrappedToken": "550e8400-e29b-41d4-a716-446655440000",
  "isTestPayment": false
}
```

**Response parameters**

| Field  | Type   | Description                                              |
| ------ | ------ | -------------------------------------------------------- |
| `code` | Int    | This is the response code. If it is 0, it means success. |
| `msg`  | String | This is the result message.                              |

***

### Code and error list

**Bank code list**

For Toss Money payments, the account information selected by the user is also sent.

| Bank code | Bank name                       |
| --------- | ------------------------------- |
| 002       | Korea Development Bank          |
| 003       | Industrial Bank of Korea        |
| 004       | KB Kookmin Bank                 |
| 005       | Hana Bank                       |
| 007       | Suhyup Bank                     |
| 011       | NH NongHyup Bank                |
| 020       | Woori Bank                      |
| 023       | SC Bank                         |
| 027       | Citibank                        |
| 031       | Daegu Bank                      |
| 032       | Busan Bank                      |
| 034       | Gwangju Bank                    |
| 035       | Jeju Bank                       |
| 037       | Jeonbuk Bank                    |
| 039       | Gyeongnam Bank                  |
| 045       | MG Community Credit Cooperative |
| 048       | Credit Union                    |
| 050       | Savings Bank                    |
| 064       | Forestry Cooperative            |
| 071       | Post Office                     |
| 081       | Hana Bank                       |
| 088       | Shinhan Bank                    |
| 089       | K Bank                          |
| 090       | KakaoBank                       |
| 092       | Toss Bank                       |
| 103       | SBI Savings Bank                |
| 218       | KB Securities                   |
| 230       | Mirae Asset Securities          |
| 238       | Mirae Asset Securities          |
| 240       | Samsung Securities              |
| 243       | Korea Investment & Securities   |
| 247       | NH Investment & Securities      |
| 261       | Kyobo Securities                |
| 262       | Hi Investment & Securities      |
| 263       | Hyundai Motor Securities        |
| 264       | Kiwoom Securities               |
| 265       | Ebest Securities                |
| 266       | SK Securities                   |
| 267       | Daishin Securities              |
| 269       | Hanwha Investment & Securities  |
| 270       | Hana Securities                 |
| 271       | Toss Securities                 |
| 278       | Shinhan Investment & Securities |
| 279       | DB Financial Investment         |
| 280       | Eugene Investment               |
| 287       | Meritz Securities               |
| 888       | Toss Money                      |
| 889       | Toss Point                      |

**Card issuer code list**

| Card issuer name     | Card (acquiring company) code |
| -------------------- | ----------------------------- |
| Shinhan              | 1                             |
| Hyundai              | 2                             |
| Samsung              | 3                             |
| Kookmin              | 4                             |
| Lotte                | 5                             |
| Hana                 | 6                             |
| Woori                | 7                             |
| NongHyup             | 8                             |
| Citi (not supported) | 9                             |
| BC                   | 10                            |

**Billing key status list**

| Status                          | Billing key status code |
| ------------------------------- | ----------------------- |
| Billing key creation complete   | CREATED                 |
| User authentication in progress | AUTHENTICATING          |
| User authentication complete    | ACTIVE                  |
| Delete billing key              | REMOVED                 |
| Invalid billing key             | FAILED                  |

**Error cases**

| code  | Situation                            | Error message                                           |
| ----- | ------------------------------------ | ------------------------------------------------------- |
| 5001  | Toss Pay subscription not completed  | Toss Pay subscription has not been completed.           |
| 5005  | Attempt to pay with a canceled token | It is a deactivated billing key.                        |
| 5006  | Call with an invalid token           | Cannot find the billing key.                            |
| 40000 | When the request data is invalid     | The request data is invalid.                            |
| -     | Error on Toss Pay's side             | The Toss Pay error code and message are passed through. |


---

# 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/toss-pay/toss-pay-subscription.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.
