> ## Documentation Index
> Fetch the complete documentation index at: https://doc.haipay.net/llms.txt
> Use this file to discover all available pages before exploring further.

# Subscription

> Understand HaiPay subscription integration modes, business requirements, launch rules, and core API entry points before you start building recurring card payments.

HaiPay subscription payment supports membership, recurring services, auto-renewal, and other periodic billing scenarios. This page covers integration modes, key business rules, and launch requirements. For detailed API fields and debugging, refer to the corresponding API Reference.

<Columns cols={3}>
  <Card title="Quick Start" icon="rocket" href="#quick-start">
    Review integration steps, prerequisites, and recommended reading path.
  </Card>

  <Card title="Integration Modes" icon="layer-group" href="#integration-modes">
    Compare Checkout Mode and Front-End Component.
  </Card>

  <Card title="Core APIs" icon="list-check" href="#core-apis">
    Jump to subscription apply, query, cancel, and refund endpoints.
  </Card>
</Columns>

<Warning title="Product and Service Requirements Before Launch">
  * Provide clear subscription entry, billing cycle description, and unsubscribe entry.
  * Notify users via email or other off-site channels before and after each charge.
  * Provide a confirmable subscription agreement and only initiate after explicit user authorization.
  * Maintain customer support availability, at least covering service hours in primary operating regions.
</Warning>

<Tip title="Credit Card Disputes and Fee Notice">
  * Consumers may initiate a dispute within 180 days after a credit card charge.
  * Each dispute incurs a \$20 dispute handling fee.
  * If you choose to contest, an additional \$20 representment fee applies.
  * If the representment is successful, HaiPay refunds the representment fee; the original dispute handling fee is non-refundable.
</Tip>

<Danger title="PCI DSS Compliance Requirements">
  PCI DSS strictly prohibits embedding credit card input pages in `WebView` or `iframe`. Always complete card information collection and payment authorization in a trusted browser environment to avoid compliance risks and sensitive data exposure.
</Danger>

<a id="quick-start" />

## Quick Start

<Steps>
  <Step title="Confirm Business Model and Prerequisites">
    First read the [API Description Guide](/docs/en/guide/api_description_guide) and [Subscription Flow](/docs/en/V20260628/api/version2/subscription-process) to confirm your scenario is recurring billing, not one-time payment.
  </Step>

  <Step title="Choose Integration Mode">
    Subscription payment offers two integration modes: **PayUrl Redirect Mode** (server obtains authorization link, redirects to HaiPay hosted page) and **Front-End Component Mode** (embed payment components in your own page using a client token). Choose based on your checkout design and frontend capabilities.
  </Step>

  <Step title="Integrate APIs, Notifications, and Cancellation">
    After completing the subscription apply, you need to query subscription status, handle charge callbacks, and provide a cancellation entry for users. Detailed fields and debugging entry points are in the API Reference cards below.
  </Step>
</Steps>

<a id="integration-modes" />

## Integration Modes

Subscription payment offers two integration modes. The core difference is who hosts the payment page:

| Comparison       | Checkout Mode                         | Front-End Component                       |
| :--------------- | :------------------------------------ | :---------------------------------------- |
| Payment Page     | Redirect to HaiPay hosted page        | Embed payment components in merchant page |
| Frontend Work    | Minimal, just handle redirects        | Requires JS script and event listeners    |
| UI Control       | Low, styled by HaiPay                 | High, fully customizable                  |
| Key Return Field | `payUrl` from response                | `clientToken` from response               |
| Best For         | Quick integration, no custom UI needs | Custom checkout, immersive payment        |

<Tabs sync={false}>
  <Tab title="Checkout Mode" icon="arrow-up-right-from-square">
    The simplest integration method. After the merchant server calls the subscription apply API, use the returned `payUrl` to redirect the user to the HaiPay hosted page for authorization and first payment.

    **Integration Flow**

    <Steps>
      <Step title="Server calls subscription apply API">
        The merchant server sends a [subscription apply](/docs/en/api-reference/subscription/api/subscriptionApply) request to HaiPay, including subscription amount, cycle, Callback URL, and other required parameters.
      </Step>

      <Step title="Get payUrl and redirect">
        The response includes a `payUrl` field. Redirect the user's browser to this URL.
      </Step>

      <Step title="User completes payment">
        The user completes credit card entry and payment authorization on the HaiPay hosted page. After payment, HaiPay redirects the user back to the merchant's `callBackUrl` and sends an async notification to `notifyUrl`.
      </Step>
    </Steps>

    **Example code (frontend redirect after server obtains payUrl)**

    ```javascript theme={null}
    // Assume your server has called the subscription apply API and returned payUrl
    const payUrl = response.data.payUrl;

    // Redirect in current window
    window.location.href = payUrl;

    // Or open in new window
    // window.open(payUrl, '_blank');
    ```

    **Recommendations**

    * Fastest subscription integration with minimal frontend changes.
    * No strong custom UI requirements for the payment page.
    * Redirect experience usually works well for mobile H5 scenarios.
  </Tab>

  <Tab title="Front-End Component Mode" icon="code">
    By including the HaiPay Front-End Component script, embed payment components in the merchant's own page. After calling the subscription apply API, use the returned `clientToken` to initialize the frontend component, allowing users to pay without leaving your page.

    Best for modern subscription checkout that displays `Google Pay`, `Apple Pay`, and `Credit Card` in a single container.

    **Recommended Script**

    `https://cashier.haipay.top/js/paymentMethodsSubscribe_1.0.0.min.js`

    **Key Parameters**

    | Parameter             | Required | Description                                                                    |
    | :-------------------- | :------- | :----------------------------------------------------------------------------- |
    | `sandbox`             | Yes      | `true` for test, `false` for production                                        |
    | `clientToken`         | Yes      | Client token                                                                   |
    | `themeMode`           | No       | Theme mode, default `light`                                                    |
    | `paymentMethodConfig` | No       | Payment method combination, default `["GOOGLE_PAY","APPLE_PAY","CREDIT_CARD"]` |
    | `applePayButtonType`  | No       | Apple Pay button text, e.g. `buy`, `subscribe`                                 |
    | `googlePayButtonType` | No       | Google Pay button text, e.g. `buy`, `subscribe`                                |

    **Key Events**

    * `ready`: Buttons rendered
    * `error`: Initialization or payment error
    * `paymentStatus`: Payment result callback (if not listened, the component handles the result by default)

    **Recommendations**

    * Recommended for new checkout pages — clearer information architecture.
    * If only some payment methods are needed, pass only the required combination.
    * Reduces frontend customization effort.
    * When using Front-End Component, pass `paymentMethods` instead of `inBankCode` in the Subscription Apply API, e.g. `CREDIT_CARD,GOOGLE_PAY,APPLE_PAY`.

    ```javascript theme={null}
    <script src="https://cashier.haipay.top/js/paymentMethodsSubscribe_1.0.0.min.js"></script>

    <div>
      <div id="paymentId"></div>
    </div>

    const elements = paymentMethodsSubscribe.create({
      sandbox: true,
      clientToken: 'your-client-token',
      themeMode: 'light',
      paymentMethodConfig: ['GOOGLE_PAY', 'APPLE_PAY', 'CREDIT_CARD']
    });

    elements.mount('#paymentId');

    elements.on('ready', (data) => {
      console.log('rendered successfully:', data);
    });

    elements.on('error', (data) => {
      console.error('Payment error:', data);
    });

    elements.on('paymentStatus', (data) => {
      console.log('payment status:', data);
    });
    ```
  </Tab>
</Tabs>

<a id="core-apis" />

## Core APIs

For detailed request fields, response structures, and online debugging, go directly to the API Reference:

<Columns cols={2}>
  <Card title="Subscription Apply" icon="circle-plus" href="/docs/en/api-reference/subscription/api/subscriptionApply">
    Create a subscription order, initiate user authorization, and complete the first payment.
  </Card>

  <Card title="Subscription Query" icon="magnifying-glass" href="/docs/en/api-reference/subscription/api/subscriptionQuery">
    Query subscription status, platform subscription number, and charge records.
  </Card>

  <Card title="Subscription Cancel" icon="ban" href="/docs/en/api-reference/subscription/api/subscriptionCancel">
    Merchant-initiated cancellation to stop future recurring charges.
  </Card>
</Columns>

## Async Notifications

When subscription status changes or a recurring charge completes, HaiPay pushes async notifications to the `notifyUrl` provided during subscription apply.

<Tip title="Receiving Recommendations">
  To ensure API extensibility and compatibility, follow these callback parameter receiving practices:

  1. **Do NOT** declare specific POJO objects to receive callback parameters.
  2. **MUST** use generic data structures (e.g. JSONObject, Map) for parameter parsing.
  3. This design ensures that future callback field extensions will not affect signature verification.
</Tip>

After receiving a notification, return **SUCCESS** (uppercase) in the response body.

<Tabs sync={false}>
  <Tab title="Subscription Status Notification" icon="bell">
    Triggered when subscription status changes (e.g. success, cancel, failure).

    | Parameter                | Type    | Description                                                                            |
    | :----------------------- | :------ | :------------------------------------------------------------------------------------- |
    | `type`                   | String  | Notification type, fixed as `SUBSCRIPTION`                                             |
    | `appId`                  | Long    | Business ID                                                                            |
    | `currency`               | String  | Currency                                                                               |
    | `subscriptionOrderId`    | String  | Merchant subscription order ID                                                         |
    | `subscriptionNo`         | String  | Platform subscription number                                                           |
    | `amount`                 | String  | Subscription amount                                                                    |
    | `status`                 | Integer | Subscription status (1: processing, 2: success, 3: failed, 4: cancelled, 5: completed) |
    | `recurringInterval`      | String  | Recurring interval type (D/W/M/Y)                                                      |
    | `recurringIntervalCount` | Integer | Recurring interval count                                                               |
    | `subject`                | String  | Subscription title                                                                     |
    | `sign`                   | String  | Signature (use the business key corresponding to the currency for verification)        |
  </Tab>

  <Tab title="Subscription Charge Notification" icon="money-bill-wave">
    Triggered when a recurring charge succeeds or fails.

    | Parameter             | Type    | Description                                                                     |
    | :-------------------- | :------ | :------------------------------------------------------------------------------ |
    | `type`                | String  | Notification type, fixed as `SUBSCRIPTIONS_DEDUCT`                              |
    | `appId`               | Long    | Business ID                                                                     |
    | `currency`            | String  | Currency                                                                        |
    | `subscriptionOrderId` | String  | Merchant subscription order ID                                                  |
    | `subscriptionNo`      | String  | Platform subscription number                                                    |
    | `deductNo`            | String  | Charge number                                                                   |
    | `orderNo`             | String  | Platform order number                                                           |
    | `amount`              | String  | Charge amount                                                                   |
    | `status`              | Integer | Charge status (2: success, 3: failed)                                           |
    | `startTime`           | String  | Current charge cycle start time, format: yyyy-MM-dd HH:mm:ss                    |
    | `endTime`             | String  | Current charge cycle end time, format: yyyy-MM-dd HH:mm:ss                      |
    | `sign`                | String  | Signature (use the business key corresponding to the currency for verification) |
  </Tab>
</Tabs>

## Key Business Rules

| Item                     | Description                                                                                                                                                                                                                              |
| :----------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Transaction Limit        | Subscription amount range: `0.99 - 1000 USD`                                                                                                                                                                                             |
| Max Duration             | Maximum subscription duration is 3 years regardless of interval unit                                                                                                                                                                     |
| Interval Unit            | Apple Pay does not support `W`; use `D` + `7` days for weekly                                                                                                                                                                            |
| Payment Type             | Fixed as `SUBSCRIPTION` for subscription scenarios                                                                                                                                                                                       |
| User Notification        | Recommended to send off-site notifications after subscription success, before and after charges                                                                                                                                          |
| Unsubscribe              | Production must provide a clear, accessible cancellation entry                                                                                                                                                                           |
| Payment Method Parameter | Pass either `inBankCode` or `paymentMethods` in the Subscription Apply API: `inBankCode` for a single payment method, `paymentMethods` for a comma-separated list. `paymentMethods` currently only supports the Front-End Component Mode |

<Tip title="Test Card Numbers">
  For test card numbers, see [Test Card Numbers](/docs/en/V20260628/api/version2/test-cards)
</Tip>

## Frequently Asked Questions

<AccordionGroup>
  <Accordion title="When should I use this page vs. the API Reference?" defaultOpen>
    This page helps you understand product capabilities, choose integration modes, and learn business rules. For development and debugging, go directly to the [Subscription API Reference](/docs/en/api-reference/subscription/api/subscriptionApply) for complete fields, sample payloads, and debugging tools.
  </Accordion>

  <Accordion title="Why must subscription businesses emphasize unsubscribe entry and off-site notifications?">
    Subscription transactions are more prone to user disputes. Clear authorization, notification, and cancellation capabilities significantly reduce chargebacks, complaints, and risk control issues — key prerequisites for stable subscription operations.
  </Accordion>

  <Accordion title="How to handle Unsupported region: CN in production?">
    This usually means the production environment does not support the region, or the test configuration does not match the target region. Verify merchant configuration, target market, and payment method combination, then contact HaiPay support to confirm production availability.
  </Accordion>

  <Accordion title="How to choose between Checkout Mode and Front-End Component?">
    For fastest launch with minimal frontend changes, choose Checkout Mode. For custom checkout UI where users stay on your page, choose Front-End Component Mode. Both modes use the same Subscription Apply API — the only difference is whether you use the returned `payUrl` or `clientToken`.
  </Accordion>

  <Accordion title="Should I pass inBankCode or paymentMethods?">
    Choose one — they cannot be passed together or both empty. For a single payment method, pass `inBankCode`. For multiple payment methods (e.g. Front-End Component Mode), pass `paymentMethods`. Note: `paymentMethods` currently only supports the Front-End Component Mode; other modes should continue using `inBankCode`.
  </Accordion>

  <Accordion title="What mode is recommended for a quick modern subscription page?">
    If using Front-End Component Mode, it displays multiple payment methods in a single container for a more complete page, lower user cognitive load, and more manageable frontend development.
  </Accordion>
</AccordionGroup>

## Related Topics

* [Apple Pay Subscription](/docs/en/V20260628/api/version2/ApplePay)
* [Google Pay Subscription](/docs/en/V20260628/api/version2/GooglePay)
* [Merchant Initiated Transaction (MIT)](/docs/en/V20260628/api/version2/creditcard-mit)
* [VISA/MASTER Payment](/docs/en/V20260628/api/version2/creditcard)
