# AppInChina Documentation (full export)

> This file contains the complete AppInChina documentation concatenated into
> a single document. You can paste it into an AI assistant (ChatGPT, Gemini,
> Claude, etc.) to ask questions about Payments, Login, iOS Distribution, Content Review.
>
> Generated automatically at build time.

---



<!-- source: payments/api/reference.md -->


:::info Applies to
Endpoint contracts on this page correspond to the currently supported SDK artifact. See the [Compatibility Matrix & Changelog](../reference/compatibility-and-changelog.md) for the artifact/version and dependency ranges, and review it before copying behaviour if your project uses a different artifact.
:::

## 1. Authentication and base URL

To use the AppInChina Payments API, all requests must include authentication headers that identify your application.

### 1.1 Required headers

Each request must include the following two headers:

| Header | Description |
| --- | --- |
| `APP_ID` | Your **AppInChina App ID** — your application’s unique identifier in the AppInChina IAP system, provided by AppInChina. Not the same as your WeChat App ID. |
| `APP_SECRET` | The secret key associated with your APP_ID. Keep this value secure and do not expose it in client-side code. |

#### Example (Java)

```java
private static final String APP_ID = "your_app_id_here";
private static final String APP_SECRET = "your_app_secret_here";

private static final Headers headers = Headers.of(
    "APP_ID", APP_ID,
    "APP_SECRET", APP_SECRET
);
```

:::caution
Keep your `APP_SECRET` confidential. Do not include it in frontend code or expose it in logs or error messages.
:::

## Related docs

- Identity mapping (`customerIdentity`): [Login → Payments integration (customer identity)](../guides/login-identity.md)
- High-level flow: [Understanding the IAP SDK/API Flow](../concepts/iap-flow.md)
- Android SDK guide: [Payments SDK Integration Guide for Android](../sdk/android.md)
- PC & H5 guide: [PC and H5 Payments Integration Guide](../web/pc-h5.md)
- Troubleshooting errors: [Error Reference](../reference/errors.md)

### 1.2 Base URL

All API requests should be made to the following base URL:

```bash
https://api.appinchinaservices.com
```

You will append specific endpoints (such as `/order.json`, `/detail.json`, etc.) to this base URL.


## 3. Create order

### 3.1 Endpoint

```
POST /order.json
```

This endpoint is used to create a new payment order.

It generates the necessary information to initiate a payment with either **WeChat Pay** or **Alipay**, depending on the selected payment channel and environment.

### 3.2 Purpose

Use this endpoint to:

- Create a unique payment order for a user transaction.
- Initiate payment through the appropriate channel (WeChat or Alipay).
- Receive parameters needed to proceed with payment (e.g., `prepayid`, `sign`, etc. for WeChat).

### 3.3 Required headers

Authentication headers (`APP_ID` and `APP_SECRET`) must be included in the request.

See [Authentication and base URL](#1-authentication-and-base-url) for details.

### 3.4 Request parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `amount` | `long` | Required | Payment amount in **cents**. (e.g., 100 = ¥1 RMB) |
| `bizNo` | `string` | Required | Unique transaction number generated by the client for internal record keeping. |
| `goodsTitle` | `string` | Required | Title or description of the item being purchased (displayed during payment). |
| `payChannel` | `string` | Required | Payment channel: `WECHAT` or `ALIPAY`. |
| `paySource` | `string` | Optional | Payment source: `NATIVE`, `H5`, or `APP`. (Default is `APP` if not specified.) |
| `customerIdentity` | `string` | Required¹ | Stable, non-secret internal user identifier. **Required for account-based apps** unless you use a documented alternate identity design. Not a wallet account, email, card number, or per-attempt value. See [Login → Payments integration (customer identity)](../guides/login-identity.md). |
| `customerName` | `string` | Recommended | User's username, phone number, or other human-readable identifier. |
| `serviceNo` | `string` | Deprecated | Service order number tied to subscription or timed services. |
| `serviceTypeNo` | `string` | Deprecated | Service type identifier created in the AppInChina Dashboard. |
| `attachData` | `string` | Optional | Additional metadata to associate with the order (custom JSON string or plain text). If you use the Android SDK, you may provide a key/value map which the SDK serializes for you. |
| `sourceFrom` | `string` | Optional | Identifier of the app store where the payment was initiated (see below for accepted values). |

¹ **`customerIdentity` and `bizNo` are operational requirements**, not incidental fields. `bizNo` is your client-controlled business reference: it must be **unique** per attempt, **immutable** once created, and **retry-safe** (reusing it re-queries the same order without creating a duplicate). Store both in your backend so a payment attempt can be correlated across verification, entitlement, purchase history, and support. See [Server Verification and Entitlements](../backend/verification-entitlements.md) and [Purchase History & Refunds](../guides/purchase-history-refunds.md).

### 3.4.1 Using `attachData` effectively

`attachData` is your **order metadata** field. AppInChina Payments records it with the transaction and returns it back in order query responses (for example `/detail.json` and `/history.json`).

Use it when you need more than “a transaction happened” — for example, to connect payments to:

- Your **SKU / product ID**
- Subscription **plan ID** / tier
- A **promo / campaign** identifier
- A pricing **version** (useful for A/B tests or regional price tables)
- Any internal IDs your backend needs to **reconcile** and **fulfill** correctly

#### Recommended format

- Keep it small and stable.
- Prefer a compact JSON object encoded as a string (or plain text if you prefer).
- If you use the Android SDK, you can pass a key/value map and the SDK serializes it.

#### Security and privacy

- Do **not** store secrets (tokens, API keys) in `attachData`.
- Avoid raw PII when possible (phone, email, full name).
- Treat `attachData` as metadata for reporting/reconciliation — not as an authorization mechanism.

#### Example (CreateOrder request body)

```json
{
  "amount": 999,
  "bizNo": "ORDER_20260205_0001",
  "goodsTitle": "Pro plan (3 months)",
  "payChannel": "WECHAT",
  "customerIdentity": "user_12345",
  "attachData": "{\"productId\":\"pro_3m\",\"promoId\":\"winter25\",\"priceVersion\":\"v3\"}"
}
```

### Accepted values for `sourceFrom`

| App Store | Value |
| --- | --- |
| Tencent MyApp | `tencent` |
| Huawei App Market | `huawei` |
| Oppo Software Store | `oppo` |
| 360 Mobile Assistant | `360` |
| Baidu Mobile Assistant / 91 Assistant / Himarket | `baidu` |
| MIUI App Store | `miui` |
| VIVO App Store | `vivo` |
| PP Assistant / Wandoujia / Taobao | `pp` |
| China Mobile MM Store | `chinamm` |
| Anzhi Market | `anzhi` |
| Sogou Mobile Assistant | `sogou` |
| Meizu Flyme | `meizu` |
| Coolpad | `coolpad` |
| Lenovo Store | `lenovo` |
| Samsung App Store | `samsung` |
| AppChina | `appchina` |
| Others | `others` |

### 3.5 Successful response examples

#### WeChat Pay example

```json
{
  "msg": "success",
  "traceId": "b7c04e1317476299292752036",
  "code": 0,
  "data": {
    "appid": "wxappidexample",
    "noncestr": "randomString",
    "package": "Sign=WXPay",
    "partnerid": "wechatPartnerId",
    "prepayid": "wechatPrepayId",
    "sign": "generatedSignature",
    "timestamp": 1747629929
  }
}
```

:::caution `appid` here is WeChat's, not yours
In the WeChat response above, `appid` (all lowercase) is your **WeChat App ID** — the WeChat Open Platform Mobile Application AppID that WeChat needs to launch its payment UI. It is **not** your AppInChina App ID.

By contrast, order-query responses (`/detail.json`, `/history.json`, `/payTools.json`) return `appId` (camelCase) = your **AppInChina App ID**. The two differ only by casing, so map them carefully.
:::

#### Alipay example

```json
{
  "msg": "success",
  "traceId": "b7c04e1317476298157356165",
  "code": 0,
  "data": {
    "app_id": "2021001156621375",
    "biz_content": "{\"body\":\"1\",\"out_trade_no\":\"20250519000916970200108462\",\"product_code\":\"QUICK_MSECURITY_PAY\",\"subject\":\"1\",\"total_amount\":\"0.01\"}",
    "charset": "utf-8",
    "format": "json",
    "method": "alipay.trade.app.pay",
    "notify_url": "https://api.appinchinaservices.com/payBackAlipay",
    "return_url": "https://api.appinchinaservices.com/payBackAlipay",
    "sign": "...",
    "sign_type": "RSA2",
    "timestamp": "2025-05-19 12:43:35",
    "version": "1.0"
  },
  "message": "success"
}
```

### 3.6 Error response

```json
{
  "code": "error_code",
  "msg": "error_message"
}
```


## 5. Query order list

### 5.1 Endpoint

```
GET /history.json
```

This endpoint retrieves a paginated list of historical payment orders associated with a given customer.

### 5.2 Request parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `customerIdentity` | `string` | ✅ | Unique identifier of the customer whose order history is being queried |
| `paymentStatus` | `string` | Optional | Filter by status: `PAID`, `PENDING`, `CLOSE`, `REFUND`, etc. |
| `pageNum` | `number` | Optional | Page number to retrieve (default: `1`) |
| `pageSize` | `number` | Optional | Number of records per page (default: `20`) |

### 5.3 Successful response

```json
{
  "msg": "success",
  "code": 0,
  "data": {
    "payOrderList": [
      {
        "amount": 1,
        "appId": "",
        "bizNo": "",
        "extInfo": {},
        "gmtCreate": 1551676154000,
        "gmtModified": 1551676154000,
        "pmtDt": 1551676154000,
        "attachData": {},
        "sourceFrom": "",
        "goodsTitle": "",
        "id": "",
        "payChannel": "",
        "paymentStatus": "PAID"
      }
    ],
    "totalCount": 1
  }
}
```

:::note
Use `totalCount` to support pagination in your UI.
:::


## 7. Error codes and meanings

All API endpoints return a standardized error response format:

```json
{
  "code": "error_code",
  "msg": "error_message"
}
```

For the full list of error codes and their meanings, see the [Error reference](../reference/errors.md).

:::note
Always handle errors based on the `code` field rather than relying on HTTP status codes, as all responses may return HTTP 200 even when the request failed.
:::

---


<!-- source: payments/backend/verification-entitlements.md -->


This guide defines the **authoritative order state**, the retry strategy, and the entitlement contract that turn a completed payment into usable access.

AppInChina Payments processes the payment transaction. **Your backend makes the authoritative entitlement decision** after checking the transaction state through the documented AppInChina interface. The payment result returned to the app is useful for user experience, but it is not, by itself, proof that access should be granted.

:::danger The authoritative payment-completion rule
The app must grant or refresh access **only after** its backend has verified the order's authoritative status and applied the client's entitlement rules. **Neither a successful wallet handoff nor arrival at an Android result/callback Activity proves that payment succeeded.** Your backend must verify the order status through the documented AppInChina interface and apply your entitlement rules idempotently; the app should then refresh access from your backend.
:::

## Related docs

- Scope and ownership: [Start Here: integrate AppInChina IAP](../overview.md)
- Identity mapping: [Login → Payments integration (customer identity)](../guides/login-identity.md)
- Endpoint contract: [Payments API Reference](../api/reference.md)
- History and refunds: [Purchase History & Refund Workflows](../guides/purchase-history-refunds.md)
- Android integration: [Payments SDK Integration Guide for Android](../sdk/android.md)

## 1. The three states you must observe independently

A transaction can be *paid* while the app still shows an error or fails to grant access. Do not collapse these three states into one:

| State | Where it lives | How you observe it |
| --- | --- | --- |
| **Payment processing** | WeChat Pay / Alipay + AppInChina | The wallet returns control to your app; an order exists in the AppInChina backend. |
| **Backend verification** | AppInChina order-status interface | Your backend queries `/detail.json` (or the SDK query) and reads `paymentStatus == PAID`. |
| **Entitlement / UI state** | Your backend + your app | Your backend records the grant; your app refreshes and unlocks the feature. |

All three must pass. A `PAID` transaction with no entitlement grant is an incomplete integration, not a completed payment.

## 2. The single "first purchase" recipe

Follow this recipe end to end. Every payment integration must be able to complete all eight steps before it is considered done.

| Step | Owner | Required behavior | Pass condition |
| --- | --- | --- | --- |
| **1. Authenticate user** | Client app / backend | Only offer payment for a known app account; generate or load a stable internal user ID. | A stable `customerIdentity` is available before initiation. |
| **2. Create client order context** | Client backend | Create a unique client business/order reference (`bizNo`) and record product, user, intended entitlement, and pending state. | The reference is unique and retry-safe. |
| **3. Start payment** | Client app | Call the SDK/API with the required parameters, including the result/callback class where applicable. | Wallet flow opens or produces a diagnosable pre-payment failure. |
| **4. Receive return / callback** | Client app | Return safely to the app and trigger a backend refresh/verification request. Do **not** grant durable access solely from a UI success signal. | App does not crash; verification begins. |
| **5. Verify order state** | Client backend | Use the canonical documented query/verification endpoint; handle retryable states and failures. | Authoritative state is obtained and stored. |
| **6. Grant entitlement** | Client backend | Use an idempotent state transition keyed by the transaction / `bizNo`; store audit fields required for support. | Correct access is active exactly once. |
| **7. Refresh app access** | Client app | Fetch current entitlement state from the client backend and update the UI. | The product is usable without manual restart; relaunch also reflects access. |
| **8. Preserve history** | Client backend / UI | Expose relevant completed orders/purchases and their client references as needed by product support. | A support case can map an app user to `bizNo` / order records. |

:::caution Authoritative state
Treat the AppInChina backend's verified order state and your backend's entitlement record as authoritative. The app's immediate return from the wallet is **not** a substitute for verification. Conversely, a `PAID` transaction is **not** a substitute for granting access: your backend must complete the entitlement update and the app must refresh from that state.
:::

For a fully worked example (login → CreateOrder → verify → fulfill → renew → restore), see [Capabilities and Limitations → fixed-term subscription flow](../concepts/capabilities-limitations.md#example-fixed-term-subscription-flow-where-each-piece-lives).

## 3. Idempotency, retries, and lifecycle behavior

### 3.1 Idempotency

Document and implement the **unique key** that prevents duplicate grants — normally the `bizNo`, or the AppInChina order identifier where returned. Your backend should be able to repeat the same verification request and receive the same entitlement result **without extending or duplicating access**.

- Key the entitlement transition on `bizNo` (or order id), not on "the user tapped pay again".
- A repeated verification for an already-fulfilled order must be a no-op, not a second grant.

### 3.2 Pending or interrupted flows

Payments can be interrupted (the user backgrounds the wallet, loses network, or returns much later). Document:

- **What the app shows while verification is pending** (a neutral "confirming your purchase" state, not "success").
- **How the backend retries** a status query for a `PENDING` order.
- **How a user can refresh purchases** after returning later.

:::note
Do not promise a specific polling frequency in client-facing docs unless Engineering has defined and supports one. Describe the retry *behavior*, not a guaranteed interval.
:::

### 3.3 Restore points

Require an entitlement refresh after each of these events, where the product supports them:

- Payment return
- App relaunch
- Login
- Account switching
- Reinstall / restore

The app should retrieve access from **your backend**, not from a one-time device-local success state. See also [Purchase Restore and SMS Authentication](../guides/purchase-restore-sms.md).

## 4. Minimum support record

State the minimum data your backend should retain for every payment attempt, so a support case is diagnosable:

- Internal user ID
- Product / SKU
- `bizNo`
- AppInChina order identifier (if returned)
- Payment method
- Timestamps
- Latest verified state
- Entitlement action taken
- Error reason (if any)

:::caution Do not store
Never retain wallet credentials, full payment-card data, wallet authentication codes, or other secrets. Keep the support record to non-sensitive correlation fields.
:::

---


<!-- source: payments/concepts/capabilities-limitations.md -->


Clients sometimes expect a “payments system” to also manage products, users, discounts, promo codes, or subscriptions end-to-end.
AppInChina Payments is intentionally **not** that type of platform.

This page clarifies **what AppInChina Payments does**, **what it does not do**, and **where those responsibilities should live** in your architecture.

If your main question is “what sales models can we use (without auto-renew) and who should manage what?”, see: [Sales models in China (and recommended architecture)](./sales-models-and-architecture.md).

## What AppInChina Payments is

AppInChina Payments provides a **single SDK/API surface** to initiate payments with **WeChat Pay** and **Alipay**, and to **record and query transaction status**.

It is designed to be:

- A lightweight wrapper around the official payment providers (WeChat Pay / Alipay)
- A consistent way to create orders, track them, and reconcile outcomes
- A system that stores transaction records enriched with metadata you provide (for example `goodsTitle`, `customerIdentity`, `attachData`)

## Responsibility split (recommended architecture)

### Your system (you own this)

- **Product catalog**: SKUs, pricing, currency rules, availability, inventory, subscription plans, etc.
- **Discounts & promotions**: promo codes, coupons, pricing experiments, eligibility, stacked rules, etc.
- **User management**: registration/login, account recovery, identity linking, admin tools, RBAC, etc.
- **Order model & fulfillment**: internal order IDs, entitlements, content delivery, feature unlocks, subscription lifecycle logic.
- **Business reporting**: revenue analytics, tax/invoice logic, CRM and customer support workflows.
- **Customer Support UI (Required)**: You must implement a "Purchase History" or "Order History" screen in your app. Because AppInChina does not store user phone numbers for privacy reasons, users must be able to find their Order ID (`bizNo`) in your app to provide to customer support when requesting refunds. See [Purchase History & Refund Workflows](../guides/purchase-history-refunds.md) for details.

### AppInChina Payments (we own this)

- **Payment initiation** via SDK/API for WeChat Pay and Alipay
- **Transaction logging** (order creation + recorded payment outcomes)
- **Order querying** (single order and history)
- **Refund operations** via the AppInChina Dashboard (the SDK does not provide refund APIs)
- **Optional purchase restore support** via SMS authentication (for integrations that choose to use it)

## What AppInChina Payments supports

You can treat AppInChina Payments as the “payment rail” layer:

- **Create an order** with the final payable amount and your identifiers
- **Send the user through WeChat Pay or Alipay**
- **Verify the final status** server-side (treat payment as successful only when `paymentStatus == PAID`)
- **Query history** for a given user identity (`customerIdentity`)

Relevant docs:

- [Understanding the IAP SDK/API Flow](./iap-flow.md)
- [Payments API Reference](../api/reference.md)
- [Android SDK Integration](../sdk/android.md)
- [PC & H5 Integration](../web/pc-h5.md)

## What AppInChina Payments does not support (common misconceptions)

AppInChina Payments does **not** provide:

- **Product management**: creating products, managing SKUs, maintaining a price book, inventory, or catalog APIs
- **Discount engines**: promo codes, coupons, rule-based discounts, user segmentation for pricing, or “apply code at checkout”
- **User management**: account systems, user profiles, permissions, or admin management of users
- **Entitlement logic**: granting coins, unlocking features, provisioning services, or managing your subscription lifecycle rules
- **Client-side proof of payment**: return URLs, app callbacks, and “success screens” are not a secure confirmation (always verify server-side)
- **Refund webhooks / push notifications**: no refund webhook is sent unless a separately published interface explicitly states otherwise. Your backend must **query and reconcile** transaction status and apply the corresponding access change under your own policy. See [Refund limitations and reconciliation](../guides/purchase-history-refunds.md#refund-limitations-and-reconciliation).

If you need a managed login/identity system, see the Login docs:

- Login solutions overview: [/login/](/login/)
- Login → Payments integration (identity mapping): [Login → Payments integration (customer identity)](../guides/login-identity.md)

## How to handle users, products, and entitlements (recommended patterns)

Since AppInChina Payments does not manage any of these concepts internally, here is how to represent each one through the fields the API does accept.

### Users

AppInChina Payments does not maintain user accounts. To link transactions to your users:

- **`customerIdentity`** — pass your stable internal user ID (strongly recommended). This is the key used by `/detail.json` and `/history.json` to scope queries.
- **`customerName`** — pass a human-readable identifier (username, phone, etc.) for reference in the Dashboard.

If you need a managed login/identity system for China, see [Login solutions overview](/login/) and [Login → Payments integration (customer identity)](../guides/login-identity.md).

### Products

AppInChina Payments has no product catalog — every order is just an amount with metadata. To keep your products traceable:

- **`goodsTitle`** — set it to a human-readable label (e.g. `"Pro plan – 3 months"`). This is what appears during checkout.
- **`attachData`** — include your internal product/SKU ID so you can map the transaction back to your catalog at fulfillment time.
- **`amount`** — always the final price your backend resolved for that product (in cents).

Your backend owns the catalog; AppInChina Payments just records what you tell it.

### Entitlements

A successful payment (`paymentStatus == PAID`) does **not** automatically grant anything to the user. AppInChina Payments records the transaction — your backend is responsible for fulfillment:

- After verifying the order status via `/detail.json` or the SDK query, **your backend** decides what to unlock (features, content, subscription time, credits, etc.).
- Use `attachData` to carry the context your fulfillment logic needs (e.g. `productId`, `planId`, `tier`) so you can map a paid transaction to the right entitlement without ambiguity.
- If you support "restore purchases" flows, query `/history.json` by `customerIdentity` and re-derive entitlements from your own order records — AppInChina Payments provides the transaction data, not the entitlement state.

The key separation: **payment completion is not fulfillment**. Your system owns the link between "paid" and "granted".

### General principle

Your backend decides **who** is buying, **what** they're buying, and **what to grant** after payment succeeds. AppInChina Payments records the transaction with the identifiers you provide, but it does not interpret them as user accounts, products, or entitlements. See [Using `attachData` effectively](../api/reference.md#341-using-attachdata-effectively) for metadata best practices.

## Example: fixed-term subscription flow (where each piece lives)

This walks through a "3-month Pro plan" purchase — from login to renewal — to show exactly which steps belong to your system and which ones involve AppInChina Payments.

For more sales models (one-time purchases, credit top-ups, bundles, etc.) see [Sales models in China (and recommended architecture)](./sales-models-and-architecture.md).

### First purchase

1. **User logs in** through your login system (e.g. Authing, WeChat Login, or your own). Your backend returns a stable internal `userId`.
2. **App requests the product catalog** from your backend. Your backend returns the available plans (e.g. *Pro 1 month — ¥29*, *Pro 3 months — ¥69*, *Pro 1 year — ¥199*) with their internal IDs and prices.
3. **User selects "Pro 3 months"**. The app sends the selection to your backend.
4. **Your backend creates an internal order**:
   - Generates a unique order ID (this becomes `bizNo`).
   - Resolves the final price — applying any discount logic you own.
   - Records the order as `PENDING` in your database, linked to the `userId` and the plan.
5. **CreateOrder is called** (via your backend calling `POST /order.json`, or via the Android SDK from the client) with:
   - `amount`: `6900` (¥69 in cents)
   - `bizNo`: your order ID
   - `goodsTitle`: `"Pro plan – 3 months"`
   - `payChannel`: `WECHAT` or `ALIPAY`
   - `customerIdentity`: `userId`
   - `attachData`: `{"planId":"pro_3m","internalOrderId":"ORD_20260210_0042"}`
6. **User completes payment** inside WeChat Pay or Alipay.

### Verification and fulfillment

7. **Your backend verifies the payment** by calling `/detail.json` with `bizNo` + `customerIdentity`.
   - Only proceed if `paymentStatus == PAID`. Any other status means the payment is not confirmed.
8. **Your backend fulfills the entitlement**:
   - Reads `attachData` → knows this is `pro_3m`.
   - Sets `subscription.expiresAt = now + 90 days` for this user (or extends the existing expiry if already active).
   - Marks the internal order as `FULFILLED`.
9. **App refreshes entitlement state** from your backend and unlocks Pro features.

AppInChina Payments recorded the transaction. Your backend decided what that transaction *means* (3 months of Pro access) and granted it.

### Renewal (when the term expires)

10. **Your backend detects the subscription is expiring** (e.g. via a scheduled job, or when the app checks entitlement on launch).
11. **App prompts the user to renew**. If the user agrees, repeat from step 3 — your backend creates a new internal order, calls CreateOrder with a new `bizNo`, and on confirmed payment extends `expiresAt` by another term.

There is no auto-renew happening on the AppInChina side. Each renewal is a new, explicit purchase.

### Restore purchases (new device or reinstall)

12. User logs in on a new device. Your backend already has the entitlement record linked to their `userId`, so the app can restore access immediately.
13. If you need to cross-check against payment history, query `/history.json` with `customerIdentity` and filter by `paymentStatus == PAID`. Use the `attachData` on each record to map transactions back to plans — then re-derive the current entitlement state in your backend.

AppInChina Payments provides the transaction data; your backend owns the entitlement state.

---


<!-- source: payments/concepts/iap-flow.md -->


The IAP SDK/API provides a **lightweight, unified way** to integrate in-app payments without having to build and maintain two separate payment integrations (one for Alipay and one for WeChat Pay).

In practice, the AppInChina Payments SDK still **delegates to the official Alipay / WeChat Pay SDKs on the device**, so you will include those dependencies — but you interact with a single, consistent AppInChina SDK/API surface.

It’s important to understand that:

- **Alipay and WeChat Pay are the actual payment processors.**
- **The IAP system is a wrapper** that simplifies integration and ensures transactions are consistently logged with the right metadata (product and user identifiers).
- **Your system manages users and products.** The IAP system only records transactions.
- If you’re unsure whether a feature is in scope (products, discounts, promo codes, user management, etc.), read: [Capabilities and Limitations (Scope)](./capabilities-limitations.md).

## Key concepts

- **Your system (products & users)**: You define products and manage user accounts in your own backend.
- **IAP system (wrapper)**: Provides a single, consistent interface for payments. Internally, it launches the official Alipay or WeChat Pay SDK on the user’s device.
- **Payment providers (Alipay / WeChat Pay)**: They handle the actual transaction — payment authorization, funds transfer, and result confirmation.
- **IAP backend**: Stores the transaction record, enriched with fields you provide (`goodsTitle`, `customerIdentity`, `phoneNumber`).

If you’re unsure what to use for `customerIdentity`, read: [Login → Payments integration (customer identity)](../guides/login-identity.md).

## Typical flow

1. **User selects a product** in your app.
   - Product info comes from your backend (e.g., product ID, price).
2. **You call the IAP SDK** with:
   - `goodsTitle` (product label)
   - `customerIdentity` (your internal user ID)
3. **SDK delegates to payment provider:**
   - If user chooses WeChat → SDK invokes WeChat Pay SDK.
   - If user chooses Alipay → SDK invokes Alipay SDK.
4. **Alipay/WeChat Pay process the payment**
   - They show their native UI on the user’s device.
   - The user completes payment securely within the provider’s system.
5. **Result flows back**
   - Alipay/WeChat Pay return the outcome (success/failure).
   - IAP SDK wraps this result and delivers it to your app.
6. **Transaction is logged in the IAP backend**
   - Stored with product/user identifiers from the request.
   - Can later be grouped by `goodsTitle` or `customerIdentity`.
7. **Your system updates product/user state**
   - Example: unlock premium features, extend subscription, deliver digital goods.

## Why this design?

- **Lightweight**: You only integrate once with the IAP SDK, not twice with Alipay and WeChat Pay.
- **Consistent**: All transactions are stored with uniform metadata for reporting.
- **Flexible**: You remain in control of product catalogs and user management in your own system.
- **Secure**: Payments are always processed by the official Alipay and WeChat Pay SDKs.

---


<!-- source: payments/concepts/integration-options.md -->


We typically recommend one of two approaches, depending on how much control and customization you need.

## Option 1: Direct integration with Alipay and WeChat Pay

In this setup, your team integrates the **Alipay SDK** and **WeChat Pay SDK** directly into your app and backend.

This option is usually suitable if:

- You require **custom or non-standard payment workflows**
- You need **deep control** over payment logic or provider-specific features
- Your system has **special requirements** around order handling or payment states

Things to consider:

- Two separate SDK and API integrations
- Higher development and long-term maintenance effort
- Transaction logging and reconciliation must be handled in your own system

## Option 2: Integration with AppInChina IAP Payments System

Our IAP Payments System provides a **single SDK and API** that wraps both Alipay and WeChat Pay, allowing you to integrate payments once instead of managing each provider separately.

It is important to note that:

- **Alipay and WeChat Pay remain the actual payment processors**
- The IAP system acts as a **wrapper**, launching the official provider SDKs on the user’s device
- Your system continues to manage **users and products**; the IAP system only **records transactions**
- For a detailed scope breakdown (what the system does and does not include), see: [Capabilities and Limitations (Scope)](./capabilities-limitations.md)

### Typical payment flow

1. A user selects a product in your app.
2. Your app calls the IAP SDK with:
   - A product label (for example, `goodsTitle`)
   - Your internal user identifier (for example, `customerIdentity`). See: [Login → Payments integration (customer identity)](../guides/login-identity.md)
3. The SDK invokes either Alipay or WeChat Pay.
4. The user completes the payment in the provider’s native interface.
5. The payment result is returned to your app.
6. The transaction is recorded in the IAP backend with your provided identifiers.
7. Your backend updates the user’s access or entitlement.

This option is well suited for:

- Standard one-time purchases or subscriptions
- Faster integration timelines
- Unified transaction records across Alipay and WeChat Pay
- Reduced integration and maintenance complexity

---


<!-- source: payments/concepts/sales-models-and-architecture.md -->


This page answers a common question:

> “Can AppInChina provide payments **and** user/product management?”

**AppInChina Payments is a payments layer** (WeChat Pay + Alipay wrapper + transaction records). It does **not** replace your user system, product catalog, or entitlement/subscription management.

If you are unsure what is in scope, start with: [Capabilities and Limitations (Scope)](./capabilities-limitations.md).

## Common sales models (alternatives to auto-renew subscriptions)

In Mainland China, many teams avoid “silent” auto-renew and instead ship models that are easier to explain and support.

Typical approaches include:

- **One-time purchase (permanent unlock)**: user buys once, entitlement is permanent.
- **Fixed-term access (manual renewal)**: sell “1 month / 3 months / 1 year access” as *non-auto-renewing* products.
  - The user buys again when the term expires.
  - Your backend extends the entitlement window on confirmed payment.
- **Prepaid top-up / wallet**: user buys credits, then consumes credits for features/content.
  - Your backend tracks credit balance and consumption.
- **Bundles / feature packs**: user purchases a pack that unlocks a group of features.
- **Activation code / voucher**: user redeems a code (sold via a partner channel) that grants entitlement.
  - Your backend validates and redeems the code, then grants entitlement.

Auto-renewing subscriptions can work, but they require extra care: explicit consent, clear renewal rules, cancellation/refund policy, and support handling. AppInChina Payments can record transactions, but **subscription lifecycle policy and user support workflows remain on your side**.

## Responsibility split (who owns what)

| Area | Your system (client app + backend) | AppInChina Payments |
|---|---|---|
| User accounts | Login, account recovery, identity linking, admin tools | Not provided |
| Product catalog | SKUs, pricing, eligibility, promotions | Not provided |
| Orders & entitlements | Internal order model; grant/revoke/extend access; term logic | Records transaction status and history |
| Payment initiation | Trigger payment flow from your app/backend | SDK/API to start WeChat Pay / Alipay |
| Payment confirmation | Verify final status server-side before fulfillment | Query authoritative transaction status |
| Refunds | Your business policy + customer support. **Must provide a Purchase History UI so users can find their `bizNo` for refund requests.** | Refund operations via Dashboard (filtered by `bizNo`). |

For identity mapping, see: [Login → Payments integration (customer identity)](../guides/login-identity.md).

## Recommended implementation pattern

This pattern works for one-time purchases and fixed-term access.

1. **User logs in** (your login system, e.g. Authing / WeChat Login / custom) → your backend returns a stable internal `userId`.
2. **App loads product catalog** from your backend (often hosted in China for latency/compliance, depending on your architecture).
3. **Create internal order** in your backend:
   - Compute the final price (and any discount logic you own).
   - Create an internal order ID (`bizNo`) for idempotency and reconciliation.
4. **Create payment via AppInChina Payments** using the final amount and metadata:
   - Include `customerIdentity = userId`.
   - Optionally include `attachData` (your product ID, plan ID, etc.) for your own reconciliation.
5. **User completes payment** in WeChat Pay / Alipay.
6. **Verify payment server-side** by querying order status.
7. **Fulfill in your backend**:
   - One-time purchase: grant entitlement permanently.
   - Fixed-term access: extend `expiresAt` based on the product term (e.g. +30 days).
8. **App refreshes entitlements** from your backend and unlocks features.

## Checking access when the app opens

When a user opens the app again, the app should ask **your backend** whether the logged-in user currently has access. The app should not query AppInChina Payments directly to decide whether a subscription or fixed-term entitlement is still valid.

Your backend should check its own entitlement state first, such as the user's active plan, `expiresAt`, fulfillment status, and any refund reconciliation you have already recorded. If the backend needs to verify a specific transaction, it can query AppInChina Payments by `bizNo` and `customerIdentity`.

If an order has been refunded, AppInChina will report the order with `paymentStatus == REFUND`. Your backend should then update or revoke the related entitlement according to your refund policy, and return the current access state to the app.

## “Server in China” note (where to store what)

Many clients keep these in their China-region backend:

- User identity mapping (`userId` + external identities)
- Product catalog and pricing rules
- Entitlements (what the user has access to, and until when)
- Internal orders (`bizNo`, product/plan, fulfillment status)

AppInChina Payments stores **transaction records** and provides **query endpoints** for status/history, keyed by identifiers you provide (for example `bizNo` and `customerIdentity`).

---


<!-- source: payments/guides/login-identity.md -->


This guide explains how to integrate your login system with AppInChina Payments so payments, order queries, purchase restoration, and subscriptions can be reliably associated with the correct user—**regardless of which login solution you use** (Authing, WeChat Login, custom backend, or a cloud IdP).

## Key concept: `customerIdentity`

Most AppInChina Payments flows accept a `customerIdentity` field. Treat it as **your stable internal user identifier**.

:::caution Required for account-based apps
For account-based mobile apps, `customerIdentity` is **required** unless your integration uses a documented alternate identity design. It must be a **stable, non-secret client user identifier**. It is **not** a wallet account, an email address, a payment-card number, or an arbitrary per-attempt value — an unstable or per-attempt identity breaks order queries, history, and purchase restoration.
:::

**Recommendation**: use an internal `userId` that is:

- Stable (never changes)
- Unique per user
- Not user-editable
- Not derived from a device identifier

Avoid using raw PII (plain phone/email) as the identity when possible.

## Responsibility split (who owns what)

The easiest way to avoid integration gaps is to be explicit about ownership:

| Area | Your system (client app + backend) | AppInChina Payments | WeChat Pay / Alipay |
|---|---|---|---|
| User accounts | Create accounts, login UX, account recovery, fraud/abuse controls | Not provided | Not provided |
| Identity mapping | Map provider identities (Authing/WeChat/OIDC) → internal `userId` | Records `customerIdentity` you send | Issues provider identities (e.g., WeChat `openid`) within their ecosystem |
| Sessions/tokens | Issue and validate your sessions; keep user signed-in | Not provided | Not provided |
| Product catalog & pricing | Define SKUs, pricing, eligibility, discounts | Not provided | Not provided |
| Order / entitlement model | Create internal orders, grant entitlements after payment is verified | Stores transaction record + status; returns query results | Processes the actual payment |
| Payment UI | Decide when to show paywall/checkout; start the payment flow | Starts payment via SDK/API | Displays native payment UI and authorizes payment |
| Payment confirmation | Verify final status server-side before fulfillment | Provides authoritative transaction status via query endpoints | Is the underlying payment rail |
| Refunds | Your business policy + customer support; decide eligibility | Refund operations via Dashboard (per our product scope) | May be involved as the underlying processor |

## Where `customerIdentity` is used

Depending on your integration path (SDK vs API), `customerIdentity` is typically used for:

- **Order creation metadata** (linking a payment to the user)
- **Order detail queries** (used to prevent unauthorized order lookup)
- **Order history queries**
- **Purchase restoration and subscription management**

## What `customerIdentity` should be (and should not be)

### Recommended

- Your **internal stable `userId`** (database ID or UUID), returned by your backend after login

### Not recommended

- Device identifiers
- Mutable identifiers (email/phone) unless you have a migration strategy
- External provider identifiers as your *primary* identity (WeChat `openid/unionid`, OIDC `sub`, etc.)
  - You can store them, but **map them to your internal `userId`**

## What you must implement (login-solution agnostic)

No matter what login solution you choose, your product should implement:

- **A stable internal user ID** (`userId`)
- **A mapping** from the login provider identity to your internal `userId`
- **Session/token handling** so the user remains signed in and the correct identity is available during checkout
- **Account recovery** so users can regain access and restore purchases on a new device when applicable
- **Account linking strategy** if you support multiple login methods (e.g., WeChat + phone/email)
- **A Purchase History UI (Required)**: You must provide a screen where users can view their past transactions and see their Order ID (`bizNo`). This is strictly required so users can provide their `bizNo` when requesting refunds. You can build this easily using our `/history.json` API endpoint. See [Purchase History & Refund Workflows](./purchase-history-refunds.md) for details.

## Implementation pattern (recommended)

1. **User authenticates** (Authing / WeChat / custom / OIDC).
2. Your backend resolves/creates an internal user record and returns your internal `userId`.
3. Your app stores a session token; whenever the user enters a payment flow, it fetches/uses the internal `userId`.
4. Your app/backend includes `customerIdentity = userId` in AppInChina Payments calls (create order / query / history).

## “Who stores what?” (recommended minimal data model)

At minimum, your backend should store:

- **User**
  - `userId` (internal stable ID)
  - attributes (email/phone/display name as needed)
- **External identities** (one-to-many)
  - `provider` (authing / wechat / oidc / etc.)
  - `providerUserId` (e.g., Authing user ID, WeChat `unionid`, OIDC `sub`)
  - `userId` (your internal stable ID)
- **Orders / entitlements**
  - `bizNo` (your internal order ID)
  - `userId` (who is buying)
  - product/plan identifiers
  - fulfillment status

AppInChina Payments will store the transaction record keyed by the identifiers you provide (including `bizNo` and `customerIdentity`) and allow you to query status/history.

## Provider-specific notes (how to map to internal `userId`)

### Authing

- Store Authing’s user identifier in your database (as an external identity record).
- Map it to your internal `userId`.
- Use internal `userId` as `customerIdentity`.

### WeChat Login

- WeChat identities (e.g., `openid` / `unionid`) are **provider identifiers**, not your internal ID.
- Store them as external identities and map to one internal `userId`.
- If you also support other login methods, implement **account linking** to avoid duplicate user accounts.

### Custom backend (email/phone/password/OTP)

- Generate a stable internal `userId` at account creation time.
- If you use phone/email for login, treat them as attributes, not the primary key.

### Cloud identity / OIDC (Cognito, Firebase, Auth0, Microsoft, etc.)

- Treat the IdP “subject” / provider user ID as an external identity.
- Map it to one internal `userId`.
- Use internal `userId` as `customerIdentity`.

## Common pitfalls

- **Using device ID as identity**: breaks restoration on device change.
- **Using mutable identifiers** (email/phone) as the identity: changes can orphan history unless you migrate carefully.
- **Using a provider identifier directly**: complicates account linking (and can break if you later support multiple login methods).
- **Not persisting identity across sessions**: causes mismatched `customerIdentity` during queries/restoration.

## Support / debugging checklist (what we’ll ask for)

When troubleshooting identity-related issues, have these ready:

- The `bizNo` you created
- The `customerIdentity` you sent for order creation
- The `customerIdentity` you are using for order query (must match)
- The `payChannel` and environment (test vs production)
- Timestamp + device/app version logs around CreateOrder / startPayment / query

## Related docs

- Login solutions overview: [/login/](/login/)
- High-level flow: [Understanding the IAP SDK/API Flow](../concepts/iap-flow.md)
- Payments API reference: [Payments API Reference](../api/reference.md)
- Android SDK guide: [Payments SDK Integration Guide for Android](../sdk/android.md)
- Purchase restore & SMS authentication: [Purchase Restore and SMS Authentication](./purchase-restore-sms.md)

---


<!-- source: payments/guides/purchase-history-refunds.md -->


To process refunds and handle customer support inquiries effectively, **you must implement a Purchase History screen within your app**. 

This guide explains why this is a strict requirement, the minimum UI requirements you must meet, and how to build it using the AppInChina Payments API.

## Why is a Purchase History UI required?

AppInChina Payments is designed with strict data privacy principles. **We do not store Personally Identifiable Information (PII) such as user phone numbers or email addresses in our payment records.** We only store the opaque `customerIdentity` (your internal user ID) and the `bizNo` (your internal order ID).

When a user contacts your support team or our support team to request a refund, they will not know their hidden `customerIdentity`. 

To locate the exact transaction in the AppInChina Dashboard, **support agents must search using the `bizNo` (Order ID)**. Therefore, the user must have a way to view their past transactions and copy the `bizNo` to provide to the support agent.

## Minimum UI Requirements

To ensure a smooth customer support experience, your app's Purchase History screen must include the following for every successful transaction:

1. **The Order ID (`bizNo`)**: This is the most critical piece of information. It must be clearly visible.
2. **A "Copy" Button**: Users are on mobile devices; do not force them to manually type out a long alphanumeric string. Provide a simple tap-to-copy mechanism next to the Order ID.
3. **Product Name (`goodsTitle`)**: What the user purchased (e.g., "Pro Plan - 3 Months").
4. **Purchase Date**: The date and time the transaction was completed.
5. **Amount Paid**: The final price the user paid.

### Example UI Layout

```text
-----------------------------------
Order History
-----------------------------------
Pro Plan - 3 Months
Date: 2026-03-20 14:30
Amount: ¥69.00
Order ID: ORD_20260320_A1B2C3 [COPY]
-----------------------------------
Coins Top-Up (500)
Date: 2026-03-15 09:15
Amount: ¥18.00
Order ID: ORD_20260315_X9Y8Z7 [COPY]
-----------------------------------
```

## How to build it

You can build this UI using one of two approaches:

### Approach 1: Query your own database (Recommended)

Because your backend is responsible for creating the `bizNo` and fulfilling the order, your database is the source of truth for the user's entitlements. 

*   **How:** Your app queries your backend for the user's order history.
*   **Why:** This is the fastest and most robust method. It allows you to show orders that might be "Pending" or "Failed" in addition to "Paid" orders, providing better context to the user.

### Approach 2: Use the AppInChina `/history.json` API

If you prefer not to build a custom history endpoint on your backend, you can use the AppInChina Payments API to retrieve the user's transaction history.

*   **How:** Your backend calls the `GET /history.json` endpoint, passing the user's `customerIdentity`. Your backend then formats this data and sends it to your app to display.
*   **Note:** You should filter the results to only show transactions where `paymentStatus == PAID`.

:::note Canonical method
`/history.json` uses **`GET`**. The [Payments API Reference](../api/reference.md#5-query-order-list) is the single source of truth for the method, parameters, and response schema — always derive your request from it rather than retyping from memory.
:::

## The Customer Support Workflow

Once you have implemented the Purchase History screen, the refund workflow looks like this:

1. **User experiences an issue** and contacts customer support (either your team or AppInChina's team).
2. **Support agent requests the Order ID**, instructing the user to go to *Settings > Purchase History* in the app.
3. **User copies the `bizNo`** and sends it to the support agent.
4. **Support agent searches the AppInChina Dashboard** using the exact `bizNo`.
5. **Support agent processes the refund** directly from the dashboard.

By implementing this screen, you eliminate the need to handle sensitive PII during support requests and ensure that refunds are processed for the exact transaction the user is disputing.

## `bizNo`: the correlation key you own

`bizNo` is the **client-controlled business reference** used to correlate the payment attempt, backend verification, entitlement action, purchase-history entry, and support case. Treat it as an operational requirement, not an optional field:

- **Unique** per order attempt.
- **Immutable** once created — never reassign it.
- **Retry-safe** — reusing the same `bizNo` lets you re-query the same order without creating a duplicate.
- **Stored** in your backend against the internal user and product, and surfaced in your Purchase History UI.

See [Login → Payments integration](./login-identity.md) for how `bizNo` and `customerIdentity` fit together.

## Refund limitations and reconciliation

:::caution No refund webhook
No refund webhook is currently sent unless a separately published interface explicitly states otherwise. **Do not assume a completed refund will automatically update your entitlement system.** Your backend must query/reconcile transaction status and apply the corresponding access change under your refund and subscription policy.
:::

| Section | What you must handle |
| --- | --- |
| **Refund operations** | Refunds are initiated/approved through the AppInChina Dashboard (the SDK provides no refund API). Decide which party performs the operational action. |
| **Status reconciliation** | Your backend queries for updated status (for example, `paymentStatus == REFUND` via `/detail.json` or `/history.json`). This is a client **retry/poll**, not an automatic event notification. |
| **Entitlement policy** | Define what access change happens on refund: full revocation, end-of-term access, partial adjustment, or manual review — per your product rules and applicable policy. |
| **History and support** | Ensure a refunded order appears correctly in your history UI and that support can map the user/account to the transaction via `bizNo`. |
| **Testing** | Only run a real refund test if your team can safely support one in a non-production or controlled production procedure. Do not create unnecessary refunds merely to prove the feature. |

## How your app knows a subscription is still valid

When the user opens the app again, the app should check the user's current entitlement state with **your backend**, not directly with AppInChina Payments.

Your backend should remain the source of truth for whether a user still has access. A typical app launch or resume flow is:

1. User opens the app or returns to the foreground.
2. App calls your backend with the logged-in user session.
3. Your backend checks its own entitlement record, such as subscription status, `expiresAt`, and any refunded orders already reconciled.
4. If your backend needs to confirm a payment or refund, it queries AppInChina using the relevant `bizNo` and `customerIdentity`.
5. If the AppInChina order status is `REFUND`, your backend updates or revokes the related entitlement according to your refund policy.
6. Backend returns the current entitlement state to the app, such as `active: true` or `active: false`.
7. App unlocks or locks paid features based on your backend response.

The app does **not** need to refresh all AppInChina payment history every time it comes online. Instead, it should refresh the user's entitlement state from your backend. Your backend decides how often to reconcile with AppInChina based on your product rules, support workflow, and risk tolerance.

---


<!-- source: payments/guides/purchase-restore-sms.md -->


To support cross-device access to paid content, AppInChina provides a secure authentication system based on SMS verification. This system allows customers to log in across multiple devices while preserving their purchase history. It also enforces a maximum number of simultaneously active sessions per customer.

Using SMS login and token-based authentication, your app can reliably identify returning users and restore previous purchases securely.

If you’re deciding what to use for `customerIdentity` (regardless of your login provider), start with: [Login → Payments integration (customer identity)](./login-identity.md).

## 1. Authentication flow

### 1.1 On app launch

1. Check for a stored token on the device.
2. If a token exists:
   - Call `GET /checkAuth.json` to confirm its validity.
   - If valid, skip login and proceed to the main app.
   - If invalid, proceed to the login screen.
3. If no token exists, display the login screen.

### 1.2 Login flow

1. Display a login screen prompting the user to enter their mobile number.
2. Use `GET /sms.json` to request a verification code.
3. Show a verification code input screen.
4. Authenticate the user using `POST /auth.json`.
5. Store the returned token securely.
6. Proceed to the main application.

### 1.3 UI guidelines

- **Screen 1: Phone number input**
  - Input: phone number field
  - Button: “Send Code”
  - Validation: show message if daily SMS limit is reached
- **Screen 2: Code verification**
  - Input: 6-digit verification code
  - Button: “Log In”
  - Optional: countdown timer and resend option

## 2. API endpoints

### 2.1 Request SMS code

:::note
Each user is limited to a maximum of 5 SMS code requests per day. Additional requests will be denied until the next day.
:::

#### Endpoint

```
GET /sms.json
```

#### Purpose

Send an SMS verification code to the customer.

#### Required headers

| Header | Description |
| --- | --- |
| `APP_ID` | Your AppInChina App ID |
| `APP_SECRET` | Your AppInChina App Secret |

#### Request parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `mobileNo` | string | ✅ | Customer’s phone number |

#### Success response

```json
{
  "msg": "success",
  "code": 0,
  "data": "ok"
}
```

### 2.2 Authenticate with SMS code

#### Endpoint

```
POST /auth.json
```

#### Purpose

Verify the customer’s SMS code and receive a session token.

#### Request parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `mobileNo` | string | ✅ | Customer’s phone number |
| `authCode` | string | ✅ | Verification code from SMS |

#### Success response

```json
{
  "msg": "success",
  "code": 0,
  "data": {
    "customerId": "...",
    "token": "..."
  }
}
```

:::tip
Store the returned token securely for use in future sessions.
:::

### 2.3 Check token validity

#### Endpoint

```
GET /checkAuth.json
```

#### Purpose

Verify whether a previously stored token is still valid.

#### Request parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `token` | string | ✅ | Token stored on the device |

#### Success response

```json
{
  "msg": "success",
  "code": 0,
  "data": true
}
```

- `true`: token is valid
- `false`: token is no longer valid (e.g., expired or invalidated)

## 3. Token and session management

- **Token storage**: store tokens securely using encrypted local storage (e.g., EncryptedSharedPreferences on Android).
- **Validation timing**: always call `/checkAuth.json` when the app launches or resumes from background.
- **Device limit**: when a user exceeds the allowed number of active sessions, older sessions are invalidated.

## 4. Best practices

- Never expose your `APP_SECRET` in frontend code.
- Validate stored tokens before allowing access to protected functionality.
- Prompt users clearly if their session has expired or been invalidated.
- Respect the 5-per-day SMS request limit with appropriate UI feedback for users.
- Implement retry and resend timers on the verification screen.

---


<!-- source: payments/overview.md -->


This is the entry point for integrating AppInChina's payment services. It sets the **scope**, the **client/AppInChina ownership boundary**, the **prerequisites**, and the **required reading path**.

:::danger SDK setup alone is not a completed payment integration
A payment marked `PAID` in AppInChina's system is not, by itself, proof that your app has granted access. Payment acceptance is complete only when the full path — payment, server-side verification, entitlement, and refreshed access — works in your release candidate. See the [Release Checklist / Definition of Done](./release-checklist.md).
:::

## Scope and ownership

AppInChina's SDK/API **initiates and processes** supported payment transactions through the configured payment methods (WeChat Pay and Alipay). **Your app and backend** must implement the user-account, payment-result, order-verification, entitlement, purchase-history, and refund-reconciliation logic appropriate to your product.

| Capability | Client responsibility | AppInChina responsibility |
| --- | --- | --- |
| **Product and user account** | Define products, authenticate the user, supply a stable client identity, and determine access rules. | Provide configured IAP credentials / product support as agreed. |
| **Payment initiation** | Call the SDK/API with validated parameters and handle platform requirements. | Process the payment request and expose order status. |
| **Post-payment return** | Implement and package app-side callback/result handling; update UI only from authoritative entitlement state. | Return the payment result through the SDK/API contract. |
| **Order verification** | Query/verify through the client backend; implement idempotent state transitions. | Expose the documented order-status interface. |
| **Entitlement and restore** | Grant, revoke, and restore access based on your own rules and verified order data. | No ownership of the client's account or content-access system. |
| **Refunds** | Reconcile status and revoke/adjust access according to product policy. | Process supported refunds and expose updated transaction state; no refund webhook unless separately documented. |

For the detailed boundary and worked patterns, see [Capabilities and Limitations](./concepts/capabilities-limitations.md).

## Required reading path

Before beginning implementation, assign an **Android owner**, a **backend owner**, a **product/entitlement owner**, and **one designated tester for each wallet** you plan to offer. Then complete the following path **in order**:

1. **Start Here and prerequisites** (this page) → [Prerequisites & Setup](./sdk/prerequisites.md)
2. **Platform SDK guide** → [Android SDK Integration](./sdk/android.md) (or [PC & H5](./web/pc-h5.md) for web)
3. **Server verification and entitlements** → [Server Verification and Entitlements](./backend/verification-entitlements.md)
4. **Purchase history and refunds** → [Purchase History & Refund Workflows](./guides/purchase-history-refunds.md)
5. **Client payment preflight and acceptance testing** → [Client Payment Preflight and Acceptance Testing](./testing/preflight-acceptance.md)
6. **The release checklist** → [Release Checklist / Definition of Done](./release-checklist.md)

### Owners and required outcomes before handoff

| Role | Required page(s) | Required outcome before handoff |
| --- | --- | --- |
| **Technical lead** | Start Here; Release Checklist | Confirms named owners, supported payment methods, product model, and release plan. |
| **Android developer** | [Android SDK guide](./sdk/android.md); [Troubleshooting](./troubleshooting/support-evidence.md) | Build can start a payment, return safely to the app, and emit usable logs. |
| **Backend developer** | [Server Verification & Entitlements](./backend/verification-entitlements.md); [Purchase History & Refunds](./guides/purchase-history-refunds.md); [API Reference](./api/reference.md) | Backend verifies payment state, updates entitlements idempotently, and supports history/refund reconciliation. |
| **Product / membership owner** | [Server Verification & Entitlements](./backend/verification-entitlements.md); [Release Checklist](./release-checklist.md) | Entitlement rules, restore behavior, and post-payment UX are defined. |
| **Designated tester** | [Client Payment Preflight & Acceptance Testing](./testing/preflight-acceptance.md) | Wallet account and eligible card are ready for the first in-app low-value purchase. |

## Reading paths by role

The required path above is sequential. If you want a role-focused starting point, use these:

### For Product Managers

If you are defining the feature set, sales model, or integration strategy:

1.  **Choose an integration strategy**: Read [Integration Options](./concepts/integration-options.md) to decide between the unified SDK (recommended) or direct integration.
2.  **Understand the scope**: Read [Capabilities & Limitations](./concepts/capabilities-limitations.md) to understand what the system handles (payments) vs what your backend must handle (users, products, entitlements).
3.  **Define your sales model**: Read [Sales Models & Architecture](./concepts/sales-models-and-architecture.md) to understand how to implement subscriptions, one-time purchases, and cross-device entitlements in China.

### For Developers

If you are implementing the solution:

1.  **Start with the flow**: Read [Understanding the IAP Flow](./concepts/iap-flow.md) to see how the SDK wraps Alipay and WeChat Pay.
2.  **Check prerequisites**: Read [Prerequisites & Setup](./sdk/prerequisites.md) to get your credentials (`APP_ID`, `APP_SECRET`) and prepare your environment.
3.  **Handle user identity**: Read [Login & Identity](./guides/login-identity.md) to understand how to link payments to your user accounts using `customerIdentity`.
4.  **Implement the client**:
    *   **Android**: Follow the [Android SDK Guide](./sdk/android.md).
    *   **Web/H5**: Follow the [PC & H5 Guide](./web/pc-h5.md).
5.  **Verify on the server**: Use [Server Verification and Entitlements](./backend/verification-entitlements.md) and the [API Reference](./api/reference.md) to verify orders and grant access.
6.  **Preflight and ship**: Run the [Client Payment Preflight](./testing/preflight-acceptance.md) and complete the [Release Checklist](./release-checklist.md).

---


<!-- source: payments/reference/compatibility-and-changelog.md -->


This page names the SDK artifact each guide applies to, the dependency versions it was validated against, and what has changed. If your project uses a different artifact, review this page before copying behaviour from the integration guides.

## Compatibility matrix

The values below describe the **current** Android Payments SDK artifact (`payments_sdk_v20220912`).

| Item | Value |
| --- | --- |
| **AppInChina Android Payments SDK artifact** | `payments_sdk_v20220912` (internal build `acp-v20220222-prod-production`) |
| **FastJSON 1.x** (`com.alibaba:fastjson`) | Pin **`1.2.83`**. The SDK uses only stable core FastJSON 1.x APIs (no autotype), so it is compatible with **any 1.2.x**; `1.2.83` is chosen as the most-hardened 1.x release. Do **not** use old versions such as `1.1.70.android`. |
| **Alipay SDK** (`com.alipay.sdk:alipaysdk-android`) | `15.8.33` |
| **WeChat SDK** (`com.tencent.mm.opensdk:wechat-sdk-android-with-mta`) | `6.8.0` |
| **Minimum / target Android API** | `minSdkVersion 14` / `targetSdkVersion 30` (from the SDK manifest) |
| **Known device/OS exclusions or caveats** | None published. All FastJSON 1.x is end-of-life; older 1.x builds carry known CVEs. A FastJSON2 + Xiaomi/HyperOS report is under internal review and is **not** a published SDK limitation — see [FastJSON dependency issues](../troubleshooting/support-evidence.md#fastjson-dependency-issues). |

:::caution
FastJSON **1.x** (`com.alibaba:fastjson`) and **FastJSON2** (`com.alibaba.fastjson2:fastjson2`) are different dependency families. This SDK uses FastJSON 1.x. See [Prerequisites §3.2](../sdk/prerequisites.md#32-add-the-required-fastjson-1x-dependency).
:::

## Behaviour confirmed for this artifact

These points are specific to `payments_sdk_v20220912` and should be re-validated if the artifact changes:

- **`startPayment()` does not report a final result.** It creates the order (`POST /order.json`) and launches the wallet; it does not deliver a paid/failed/cancelled result to the host app. Grant access only after backend verification — see [Server Verification and Entitlements](../backend/verification-entitlements.md).
- **Alipay** opens the supplied `nextActivity` unconditionally after the wallet returns; the launch is not a payment confirmation. See [Android §7.6](../sdk/android.md#76-alipay-return-behaviour).
- **WeChat** returns to `WXPayEntryActivity`, not `nextActivity`, and requires a successful `initPayTools()` before the first payment. See [Android §7.7](../sdk/android.md#77-wechat-payment-lifecycle).
- **`queryHistoryOrder(...)`** calls `GET /history.json`. See the [API Reference](../api/reference.md#5-query-order-list).
- **Error `99999`** is a generic client-side exception path, not a specific payment decline. See [Troubleshooting](../troubleshooting/support-evidence.md#understanding-sdk-error-99999).

## Changelog

| Date | Change | Action required |
| --- | --- | --- |
| 2026-08-04 | FastJSON version confirmed: the SDK uses only stable core 1.x APIs (no autotype) → compatible with any 1.2.x; pin `1.2.83`. Android `minSdk 14` / `targetSdk 30`. | Pin `1.2.83`; remove any old FastJSON 1.x (e.g. `1.1.70.android`) from the release graph. |
| 2026-08-04 | Documented artifact-specific behaviour: authoritative payment-completion rule; Alipay `nextActivity` vs WeChat `WXPayEntryActivity` return routes; `initPayTools()` WeChat prerequisite; `99999` as a generic client-side exception. | Re-test post-payment handling against your backend; do not treat wallet return/callback as success. |
| 2026-08-04 | FastJSON guidance corrected: the dependency is required by the AppInChina SDK (legacy FastJSON 1.x), pinned, and distinct from FastJSON2. | Pin the FastJSON 1.x version; keep any FastJSON2 explicit and tested. |
| 2026-08-03 | `/history.json` method corrected to **`GET`** across the API reference, history guide, and examples. | Update any client code that used `POST /history.json`. |

:::note Publication gate
When a new SDK artifact is released, Engineering revalidates the Quick Start, payment-lifecycle diagrams, dependency block, endpoint examples, and troubleshooting/error mapping before the docs mark that version as current.
:::

---


<!-- source: payments/reference/errors.md -->


:::note Scope
This page covers **all server error codes** surfaced by the Payments & SMS API and re-emitted by the Android SDK.

Use it to decide how your app should react (retry, show a toast, log & fail, etc.).
:::

## Related docs

- Android SDK guide: [Payments SDK Integration Guide for Android](../sdk/android.md)
- Payments API reference: [Payments API Reference](../api/reference.md)
- Purchase restore & SMS: [Purchase Restore and SMS Authentication](../guides/purchase-restore-sms.md)

## Error format

All errors are returned as JSON objects in the following format:

```json
{
  "code": "error_code",
  "msg": "error_message"
}
```

## Category cheatsheet

| Category | Code ranges |
| --- | --- |
| **Success** | `0` |
| **Auth / Session** | `1`, `1001`, `10020–10023` |
| **Validation & Integration** | `10001–10019` |
| **User Account** | `20001–20003` |
| **WeChat** | `30001–30003` |
| **Alipay** | `40001` |
| **Payment** | `50001–50022` |
| **Device / Report** | `60001` |
| **Service Config** | `70002–70007` |
| **System** | `99998–99999` |


## Downloads

- [Error Codes by Category (CSV)](/downloads/error-codes-by-category.csv)

:::note
If you encounter undocumented errors or behavior, please contact support with the `traceId` of your request.
:::

---


<!-- source: payments/release-checklist.md -->


This is the final page of the Start Here path and of the acceptance-testing guide. A payment integration is **done** only when every control below passes against the **actual release candidate** — not a debug build, and not the SDK calls compiling in isolation.

SDK setup alone is not a completed payment integration.

## Related docs

- Start of the path: [Start Here: integrate AppInChina IAP](./overview.md)
- Preflight and acceptance: [Client Payment Preflight and Acceptance Testing](./testing/preflight-acceptance.md)
- Backend verification: [Server Verification and Entitlements](./backend/verification-entitlements.md)
- Android components: [Payments SDK Integration Guide for Android](./sdk/android.md)

## Definition of Done

| # | Control | Required proof / acceptance condition | Owner |
| --- | --- | --- | --- |
| 1 | **Products and identity** | Each test product is configured; the app requires a valid authenticated account; `customerIdentity` and `bizNo` handling are implemented as documented. | Client technical lead |
| 2 | **SDK and platform setup** | Dependencies (including the **pinned FastJSON 1.x** version, no dynamic selector), callback receiver(s), client result Activity (where applicable), manifest declarations, and release-artifact configuration are present in the **actual release candidate**. `initPayTools()` is confirmed to succeed before WeChat Pay is offered. | Client mobile developer |
| 3 | **Payment initiation** | The release candidate can initiate each offered payment method and creates a diagnosable order/attempt. | Client mobile developer |
| 4 | **Post-payment return** | The app returns without crash and executes the intended result/callback flow, then requests fresh entitlement state. Tested for **paid, cancelled, failed, and app-resume/relaunch** outcomes, with entitlement state read from the **client backend** — never inferred from the Activity launch or callback arrival. For WeChat, the full **`WXPayEntryActivity` → backend verification → entitlement** route is validated with a real payment. | Client mobile developer |
| 5 | **Backend verification** | The client backend verifies transaction state through the canonical documented interface and handles repeat/retry safely. | Client backend developer |
| 6 | **Entitlement** | A verified paid order grants exactly the intended access; an interrupted/repeated attempt does not create duplicate access. | Client backend / product owner |
| 7 | **Restore behavior** | Access is refreshed correctly after relaunch, login, account switch, and reinstall/restore if relevant to the app. | Client QA |
| 8 | **History and refunds** | Purchase history is implemented if in scope; `bizNo`/support correlation works; refund reconciliation behavior follows the documented limitation and product policy. | Client backend / product owner |
| 9 | **Wallet preflight** | One named tester per wallet completes the low-value release-candidate in-app preflight, or provides a complete, triage-ready failure package. | Client tester |
| 10 | **AppInChina acceptance** | Client submits the exact release candidate, test credentials/context, and preflight result. Final acceptance is completed per the agreed test matrix. | Client + AppInChina Ops |

:::tip Sign-off
Each control should be signed off in your live documentation/issue system before the release candidate is submitted for AppInChina acceptance. Keep the sign-off record with the build's audit trail.
:::

---


<!-- source: payments/sdk/android.md -->


:::info Applies to
**AppInChina Android Payments SDK `payments_sdk_v20220912`** (internal build `acp-v20220222-prod-production`). If your project uses a different artifact, review the [compatibility matrix and changelog](../reference/compatibility-and-changelog.md) before copying this guide — SDK behaviour, dependencies, and callbacks can change between versions.
:::

## Introduction

This guide explains how to integrate the AppInChina Payments SDK into your Android application. With this SDK, you can accept payments through **WeChat Pay** and **Alipay**.

This guide assumes basic familiarity with Android development and Java.

## Before you start: what "payment complete" means

A payment attempt has **three separate stages**, and only the last one grants access:

1. **Order creation and wallet handoff** — your app calls `startPayment()`, which creates the order and opens the wallet.
2. **Payment processing** — the user completes, cancels, or abandons the flow inside WeChat Pay or Alipay.
3. **Your app's verified entitlement update** — your backend verifies the order's authoritative status and applies your entitlement rules; your app then refreshes access from your backend.

:::danger The SDK does not tell your app that a payment succeeded
Do **not** grant access because the app returned from a wallet, or because an Android result/callback Activity was opened. `startPayment()` creates the order and hands off to the wallet — it does **not** deliver a final paid/failed/cancelled result to your app. Your backend must verify the order status through the documented AppInChina interface and apply your entitlement rules **idempotently**; the app should then refresh access from your backend.

See [Server Verification and Entitlements](../backend/verification-entitlements.md) for the authoritative flow.
:::

```text
App creates payment request
  → AppInChina creates order / wallet is launched
  → User completes, cancels, or leaves the wallet flow
  → App-owned callback or return handler runs
  → App asks its backend to verify/reconcile the order
  → Backend records final state and grants/revokes entitlement idempotently
  → App refreshes access from its backend
```

## Related docs

- Setup checklist (required): [Payments SDK Prerequisites and Environment Setup](./prerequisites.md)
- Login → Payments integration (identity mapping): [Login → Payments integration (customer identity)](../guides/login-identity.md)
- Payment verification and flows: [Understanding the IAP SDK/API Flow](../concepts/iap-flow.md)
- Troubleshooting errors: [Error Reference](../reference/errors.md)

:::info Download
Download the latest Android SDK package: [`payments_sdk_latest.zip`](/downloads/payments_sdk_latest.zip)
:::


## 2. Initialize the SDK

In your `Application` class:

1. Import the SDK classes:

```java
import com.mandou.acp.sdk.AcpClient;
import com.mandou.acp.sdk.AcpClientConfig;
```

2. Initialize the SDK in `onCreate()`:

```java
@Override
public void onCreate() {
    super.onCreate();
    AcpClient.sharedInstance().init(
        this,
        // AppInChina App ID + App Secret — NOT your WeChat App ID.
        new AcpClientConfig("YOUR_APP_ID", "YOUR_APP_SECRET")
    );
}
```

To get your **AppInChina App ID** (`APP_ID`) and `APP_SECRET`, start with the credential request step in the [Prerequisites and environment setup](./prerequisites.md) guide. These are distinct from your **WeChat App ID** (the WeChat Open Platform AppID used to initialize the WeChat SDK).


## 4. Create payment buttons and start payment flow

Once the payment environment is initialized, you can create buttons to trigger payments.

Each button will:

- Call `buildPayOrder()` to prepare the payment information.
- Call `startPayment()` to begin the payment process through the SDK.

We recommend creating one button for each payment method your app supports.

### Example — WeChat Pay button

```java
private void initWechat() {
    Button wechatBtn = findViewById(R.id.btn_pay_wechat);
    wechatBtn.setVisibility(View.VISIBLE);

    wechatBtn.setOnClickListener(v -> {
        PayOrder payOrder = buildPayOrder("WECHAT");
        AcpClient.sharedInstance().startPayment(
            PayActivity.this,
            payOrder,
            PayResultActivity.class,
            PayActivity.this
        );
    });
}
```

### Example — Alipay button

```java
private void initAlipay() {
    Button alipayBtn = findViewById(R.id.btn_pay_alipay);
    alipayBtn.setVisibility(View.VISIBLE);

    alipayBtn.setOnClickListener(v -> {
        PayOrder payOrder = buildPayOrder("ALIPAY");
        AcpClient.sharedInstance().startPayment(
            PayActivity.this,
            payOrder,
            PayResultActivity.class,
            PayActivity.this
        );
    });
}
```

:::caution The result Activity is your code, not the SDK's
`PayResultActivity` in the examples above is a **client-owned class**. The SDK does not define or provide it. You may name it anything; `PayResultActivity` is not an SDK class and is not a required name. You must implement it, declare it in `AndroidManifest.xml`, pass that exact class to `startPayment()`, and ship it in the release APK/AAB. See [Section 7: the app-side payment result Activity](#7-the-app-side-payment-result-activity-client-owned).

The third parameter in `startPayment()` (`resultActivityClass`) must not be null if you want to handle payment results visually. If set to null, the SDK **will not** show a result page automatically, and you must handle post-payment behavior manually.
:::

:::note
If WeChat or Alipay is not installed on the user's device, the SDK will automatically detect this and display a helpful message (e.g., \"WeChat not installed\") before attempting to launch the payment app.
:::


If you need help mapping your login system to `customerIdentity`, see: [Login → Payments integration (customer identity)](../guides/login-identity.md).

## 6. Understanding the `startPayment()` method

### Method overview

```java
AcpClient.sharedInstance().startPayment(
    context,
    payOrder,
    resultActivityClass,
    callback
);
```

### Parameters

| Parameter | Description | Required? |
| --- | --- | --- |
| `context` | The current Activity context (e.g., `this`). | ✅ |
| `payOrder` | The PayOrder object with all payment details. | ✅ |
| `resultActivityClass` | Optional Activity for showing a post-payment result screen. If you pass `null`, you should handle post-payment UX yourself. | Optional |
| `callback` | Optional PayResultCallback to receive payment result events in your code. | Optional but recommended |

### What happens after calling `startPayment()`

| Step | Action | Handled By |
| --- | --- | --- |
| 1 | Validate PayOrder fields | SDK |
| 2 | Choose payment channel | SDK |
| 3 | Open WeChat/Alipay app | SDK + Payment App |
| 4 | User completes or cancels payment | Payment App |
| 5 | Control returns to app | SDK |


## 8. Query single order via REST API

In addition to using `querySingleOrder()` on the client side, you can also verify or retrieve order details from your backend using a dedicated HTTP endpoint.

### 8.1 Endpoint

```
GET /detail.json
```

:::note
All requests must include `APP_ID` and `APP_SECRET` headers. See the [Payments API reference](../api/reference.md) for details.
:::

### 8.2 Required headers

| Header Name | Value | Description |
| --- | --- | --- |
| `APP_ID` | Your AppInChina App ID | Provided by AppInChina Dashboard or operations team. |
| `APP_SECRET` | Your App Secret | Provided by AppInChina Dashboard or operations team. |
| `Content-Type` | `application/json` | Optional but recommended. |

### 8.3 Request parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `bizNo` | string | ✅ | The unique order identifier (same value used in `PayOrder.setBizNo()`). |
| `customerIdentity` | string | ✅ | The customer ID used during order creation (`PayOrder.setCustomerIdentity()`). |

### Example request

```bash
GET https://api.appinchinaservices.com/detail.json?bizNo=ORDER_123456789&customerIdentity=user_001
```

### 8.4 Successful response

```json
{
  "msg": "success",
  "code": 0,
  "data": {
    "amount": 1000,
    "appId": "yourAppId",
    "bizNo": "ORDER_123456789",
    "extInfo": {},
    "gmtCreate": 1688000000000,
    "gmtModified": 1688000000000,
    "pmtDt": 1688000300000,
    "attachData": {"EXPIRE_DATE": "2025-05-01"},
    "sourceFrom": "wechat",
    "goodsTitle": "VIP Subscription",
    "id": "orderId123",
    "payChannel": "WECHAT",
    "paymentStatus": "PAID"
  }
}
```

:::tip
Treat payment as successful only if `paymentStatus` is `PAID`.
:::

---


<!-- source: payments/sdk/prerequisites.md -->


This guide outlines the environment setup and configuration steps required before integrating the AppInChina Payments SDK into your Android application.

:::caution
These steps are mandatory. The AppInChina SDK depends on the correct installation and configuration of the official WeChat Pay and Alipay SDKs.
:::

## Related docs

- Android SDK integration: [Payments SDK Integration Guide for Android](./android.md)
- Login → Payments integration (identity mapping): [Login → Payments integration (customer identity)](../guides/login-identity.md)
- Payments API reference (server-side): [Payments API Reference](../api/reference.md)
- Troubleshooting errors: [Error Reference](../reference/errors.md)

## 1. Request your credentials

Getting your credentials is a **single step**. Contact our operations team once; we issue everything you need to start — **both App IDs and the secret** — together. You do **not** need to register anything with WeChat yourself.

Provide the following details:

- **App name**
- **App package name** (e.g., `com.example.myapp`)
- **App signature** (SHA1 and MD5 fingerprints of the release signing certificate)

Once reviewed, we register your app as a **WeChat Open Platform Mobile Application** in our WeChat developer account, bind the WeChat Pay merchant account, and issue all three values:

```
APP_ID:        [AppInChina App ID — provided by AppInChina]
APP_SECRET:    [AppInChina App Secret — provided by AppInChina]
WECHAT_APP_ID: [WeChat App ID — provided by AppInChina]
```

What each value is:

| Credential | Used for |
| --- | --- |
| **AppInChina App ID** (`APP_ID`) | Authenticating SDK/API calls to the AppInChina IAP system. |
| **AppInChina App Secret** (`APP_SECRET`) | The secret paired with `APP_ID`. Keep server-side only. |
| **WeChat App ID** (`wxAppId`) | Initializing the WeChat SDK on-device ([Section 2](#2-install-the-wechat-pay-android-sdk)). This is your app's WeChat identity — the same App ID used for [WeChat Login](/login/solutions/wechat-login) and Share — **not** a payment-specific ID. |

:::caution Do not confuse the two App IDs
`APP_ID` (AppInChina) and `wxAppId` (WeChat) are separate identifiers from different platforms — even though AppInChina provides both to you. Using one where the other is expected is a common cause of initialization failures.
:::

## 2. Install the WeChat Pay Android SDK

### 2.1 Add the WeChat SDK to your `build.gradle`

```
dependencies {
    compile 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:6.8.0'
}
```

### 2.2 Initialize `IWXAPI` in your app

```java
private IWXAPI api;

private void initWechatPay(String wxAppId) {
    api = WXAPIFactory.createWXAPI(getApplicationContext(), wxAppId);
}
```

:::note
`wxAppId` is the **WeChat App ID** from [Section 1](#1-request-your-credentials) — not your **AppInChina App ID** (`APP_ID`).
:::

### 2.3 WeChat integration troubleshooting

- **Error: WeChat app not responding to payment request**
  - Verify WeChat app is installed and up-to-date on the test device
  - Confirm the `wxapi` package name exactly matches your app's package name
  - Ensure `WXPayEntryActivity` is properly registered in `AndroidManifest.xml`
- **Error: Payment initialization fails**
  - Double-check your WeChat App ID format
  - Verify your app's signing certificate matches the one registered with AppInChina
  - Ensure the device has a stable network connection

## 3. Install the Alipay Android SDK

### 3.1 Add the Alipay SDK via Maven Central

Add the following dependency to your app-level `build.gradle` file:

```
dependencies {
    implementation 'com.alipay.sdk:alipaysdk-android:15.8.33'
}
```

### 3.2 Add the required FastJSON 1.x dependency

The Android Payments SDK artifact currently provided by AppInChina directly depends on **legacy FastJSON 1.x** (`com.alibaba:fastjson`) for JSON parsing. This dependency is required by the **AppInChina Payments SDK itself** — not only by Alipay — and it is **not** bundled in the SDK, so your app must supply it. If it is missing or the wrong version, payment initialization can crash with errors such as:

- `NoClassDefFoundError: com/alibaba/fastjson/...`
- `ClassNotFoundException: com.alibaba.fastjson...`

Include the **exact pinned** FastJSON 1.x version in your app-level `build.gradle`. **Do not** use a dynamic version selector such as `+` or "latest":

```gradle
dependencies {
    implementation("com.alibaba:fastjson:1.2.83")

    // Only if the host app independently needs FastJSON2 (separate dependency family):
    // implementation("com.alibaba.fastjson2:fastjson2:<HOST_APP_PINNED_VERSION>")
}
```

:::caution FastJSON 1.x and FastJSON2 are different dependency families
`com.alibaba:fastjson` (FastJSON **1.x**) and `com.alibaba.fastjson2:fastjson2` (**FastJSON2**) have different package namespaces and are **not** interchangeable. The SDK uses FastJSON **1.x**. If your project also pulls in FastJSON2 through another library, keep its version explicit and test the complete release dependency graph — do **not** replace the SDK's required FastJSON 1.x with FastJSON2 unless AppInChina publishes a newer SDK that explicitly supports it.
:::

:::note Why `1.2.83`, and why any 1.2.x works
The Payments SDK uses only **stable core FastJSON 1.x APIs** (`JSON.parseObject`/`parseArray` to known classes, plus `JSONObject`/`JSONArray` getters) and does **not** use autotype deserialization. It therefore works with **any FastJSON 1.2.x** — the version is a **security choice, not a compatibility constraint**. Pin **`1.2.83`**, the final and most-hardened 1.x release, which fixes the autotype RCE issues present in older builds. Do **not** ship an old version such as `1.1.70.android`. All FastJSON 1.x is end-of-life; moving the SDK off 1.x is a separate item on our roadmap. See the [compatibility matrix](../reference/compatibility-and-changelog.md).
:::

#### Inspecting your resolved FastJSON versions

Confirm which version Gradle actually packaged into your **release** graph (adapt the module/configuration names to your project):

```bash
./gradlew :app:dependencyInsight \
  --dependency com.alibaba:fastjson \
  --configuration releaseRuntimeClasspath

./gradlew :app:dependencyInsight \
  --dependency fastjson2 \
  --configuration releaseRuntimeClasspath
```

This is a **diagnostic** check — it identifies the version resolved into the release build. It does not by itself make a version supported. For FastJSON-related crash triage, see [Troubleshooting → FastJSON](../troubleshooting/support-evidence.md#fastjson-dependency-issues).

### 3.3 Alipay integration troubleshooting

- **Error: SDK initialization failure**
  - Verify your AppInChina App ID (`APP_ID`) and App Secret (`APP_SECRET`) are correct
  - Check your network connection
  - Ensure all required permissions are properly declared in `AndroidManifest.xml`
- **Error: Payment callback not received**
  - Verify all required permissions are granted at runtime for Android 6.0+
  - Check if the device has sufficient storage space
  - Ensure Alipay app is installed and updated on the test device

## 4. Configure project repositories

Both the WeChat and Alipay SDKs are hosted on Maven Central. Be sure to include `mavenCentral()` in your root `build.gradle` file to ensure Gradle can resolve both dependencies correctly.

```
allprojects {
    repositories {
        google()
        mavenCentral()
    }
}
```

## 5. Declare required permissions

Add the following permissions to your `AndroidManifest.xml`:

```xml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
```

If `targetSdkVersion >= 23`, request the following permissions **at runtime**:

- `WRITE_EXTERNAL_STORAGE`
- `READ_PHONE_STATE`

## 6. Add WeChat queries entry (Android 11+)

If `targetSdkVersion >= 30`, add this section to your `AndroidManifest.xml`:

```xml
<queries>
    <package android:name="com.tencent.mm" />
</queries>
```

This ensures your app is allowed to query for the WeChat app when launching payment intents.

## 7. Implement the WeChat Pay callback activity

WeChat Pay requires your app to implement a callback receiver for payment results.

### 7.1 Create a `wxapi` package inside your app's base package

For example: `com.yourcompany.yourapp.wxapi`

### 7.2 Add `WXPayEntryActivity` class inside `wxapi`

```java
public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {

    private IWXAPI api;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        api = com.mandou.acp.sdk.PayToolInfo.getApi();
        api.handleIntent(getIntent(), this);
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        api.handleIntent(intent, this);
    }

    @Override
    public void onReq(BaseReq req) {
        // Handle request from WeChat if needed
    }

    @Override
    public void onResp(BaseResp resp) {
        // Handle WeChat payment response
        startActivity(new Intent(this, PayResultActivity.class));
        finish();
    }
}
```

:::note
The package name and class name must match exactly for WeChat to invoke it properly.
:::

:::caution `WXPayEntryActivity` and the result Activity are different components
`WXPayEntryActivity` above is the **WeChat callback receiver** — it must live in a `wxapi` package with the exact naming WeChat requires. The `PayResultActivity` it launches is a **separate, client-owned result Activity** that the AppInChina SDK does **not** provide. You implement, declare, and package both. See [Android SDK §7.4: the four post-payment components](./android.md#74-the-four-post-payment-components-and-who-owns-each) for the full component map.
:::

## 8. Notes and important reminders

- These configurations are **mandatory** for payments to function.
- Failure to set up the WeChat or Alipay SDKs correctly will cause `startPayment()` calls to fail.
- Missing `com.alibaba:fastjson` can cause runtime crashes during Alipay initialization on some SDK combinations.
- The AppInChina SDK depends on these lower-level SDKs to open payment apps and receive callbacks.

Next: continue with the [Android SDK integration guide](./android.md).

---


<!-- source: payments/testing/preflight-acceptance.md -->


This guide defines a normal launch prerequisite: before AppInChina performs final payment acceptance testing, a named client tester completes **one low-value real purchase** inside the release-candidate build for each payment method you intend to offer.

This is a launch readiness step, not a way to push support away. AppInChina still investigates confirmed transaction and integration issues and performs final acceptance testing after the preflight passes.

## Related docs

- Scope and ownership: [Start Here: integrate AppInChina IAP](../overview.md)
- Backend verification: [Server Verification and Entitlements](../backend/verification-entitlements.md)
- Failure triage: [Troubleshooting and Support Evidence](../troubleshooting/support-evidence.md)
- Sign-off: [Release Checklist / Definition of Done](../release-checklist.md)

## 1. Preflight policy

:::info Payment preflight
Before submitting a release-candidate APK for AppInChina payment acceptance testing, nominate **one named tester for each payment method** you intend to offer at launch. Each tester must install the relevant wallet app, complete the wallet's registration and verification steps, link an eligible card, and complete **one low-value real purchase** in the release-candidate APK. That first in-app purchase is the payment preflight; no separate real-world merchant purchase is required.
:::

### 1.1 How to triage a preflight failure

:::caution Triage
If the attempt fails **before an order appears in AppInChina's backend**, treat it initially as a client-side preflight failure. Confirm wallet/card readiness and inspect your app/SDK logs. This does **not** prove the cause is a wallet issue — it may also be an app-side setup or SDK-invocation issue.

If the order reaches AppInChina's backend and is **paid**, confirm the app return/callback, backend verification, entitlement update, and refreshed access state.
:::

### 1.2 Scope: who can test

:::note Chinese national not normally required
A Chinese national should not normally be required to run the preflight. AppInChina may assist in exceptional cases — for example, if a wallet asks the tester for account-security friend verification — but **cannot promise to override or bypass** wallet identity, card-issuer, or risk-control decisions.
:::

## 2. Test stages and ownership

| Stage | Client action | AppInChina action | Exit condition |
| --- | --- | --- | --- |
| **A. Wallet readiness** | Named tester installs WeChat Pay and/or Alipay, registers/signs in, completes prompts, and links an eligible card. | Provide resource links and clarify supported payment methods; exception support only when appropriate. | Wallet can be opened and card appears linked; no promise that a future transaction will be approved. |
| **B. Release-candidate preflight** | Run one low-value in-app transaction and collect the standard evidence package. | Check whether an order reached the backend when asked; help classify confirmed faults. | One test either reaches a clear paid/post-payment outcome or yields enough evidence for triage. |
| **C. Client flow confirmation** | If paid, confirm callback/result, backend verification, entitlement, UI refresh, relaunch behavior, and history as applicable. | Review backend payment record when escalated; investigate AppInChina-side defects. | All client-owned outcomes pass for each method/product type in scope. |
| **D. AppInChina acceptance** | Deliver the exact release-candidate build and required test context after preflight success. | Perform defined final acceptance test and report results. | Acceptance report passed or a reproducible defect is recorded. |
| **E. Release sign-off** | Confirm the submitted build is unchanged from the tested release candidate except for documented non-payment changes. | Retain acceptance evidence per internal process. | Release owner has a complete audit trail. |

The evidence package for Stage B is defined in [Troubleshooting and Support Evidence](../troubleshooting/support-evidence.md).

## 3. Wallet setup resources

The resources below help a non-Chinese tester set up a wallet. They do not imply that AppInChina can control tester eligibility or a card issuer's approval decision.

- **Government guide:** [Payment service guide for overseas visitors to China](https://english.www.gov.cn/news/202404/11/content_WS6617c858c6d0868f4e8e5f4d.html)
- **Card-brand reference:** [Overseas Bank Cards Accepted by Weixin Pay and Alipay](https://english.beijing.gov.cn/specials/paymentservices/howtopaybeijing/202404/t20240429_3647378.html)
- **Practical account/card guidance:** [Mobile Payment — A Guide to Working and Living in China as Business Expatriates](https://english.beijing.gov.cn/specials/aguidetoworkingandlivinginchinaasbusinessexpatriates2024/dailylifeservices/202404/t20240424_3635122.html)
- **WeChat:** [Official WeChat site](https://www.wechat.com/)
- **Alipay:** [Official Alipay site](https://www.alipay.com/)

:::note Eligibility and risk decisions stay with the providers
The wallet provider determines any identity-verification steps and whether a card is eligible. If card binding or a payment is declined, follow the in-app guidance and contact the card issuer where appropriate. Card brands, limits, fees, and risk controls can vary by wallet, issuing bank, user account, region, and transaction.
:::

---


<!-- source: payments/troubleshooting/support-evidence.md -->


This page maps common failures to the checks you should run first and the evidence AppInChina needs to help efficiently. The goal is a path that is neither dismissive nor open-ended.

**Do not classify a failure as a wallet defect before checking whether an AppInChina order exists** and reviewing the relevant client-side evidence. A payment attempt that never created an order is, by default, a client-side preflight matter until the evidence identifies the cause.

## Related docs

- Preflight and stages: [Client Payment Preflight and Acceptance Testing](../testing/preflight-acceptance.md)
- Backend verification: [Server Verification and Entitlements](../backend/verification-entitlements.md)
- Android components: [Payments SDK Integration Guide for Android](../sdk/android.md)
- Endpoint contract: [Payments API Reference](../api/reference.md)
- Server error codes: [Error Reference](../reference/errors.md)

## Failure classification

Use the observed state to classify the problem, run the client-side checks first, and — only if unresolved — send the listed evidence.

| Observed state | Initial classification | Client checks first | What to send AppInChina if unresolved |
| --- | --- | --- | --- |
| Wallet cannot be installed, registered, verified, or linked to a card | Wallet / card readiness | Wallet prompts; country/phone/ID/card eligibility; card issuer response. | Wallet name/version; redacted screenshots; country; card brand/issuer only if the tester is comfortable sharing; exact error and time. |
| Payment attempt does **not** create an AppInChina order | Client-side preflight | Wallet readiness; SDK invocation parameters; app logs; build/version; callback/result configuration. | APK/AAB build ID; device/OS; payment method; timestamp and time zone; sanitized logs around the attempt; screenshots; user/`bizNo` if generated. |
| Order exists but is **not paid** | Transaction state investigation | Order status; displayed wallet outcome; retry/duplicate behavior; network/app logs. | Order/`bizNo`; method; timestamp; sanitized logs; exact UI state; confirmation that the app build matches the test build. |
| Order is **paid** but app reports failure or does not return correctly | Client post-payment handling | Result Activity/callback implementation; release merged manifest; crash/error logs; app navigation. | Order/`bizNo`; APK build; exact stack/log excerpt; manifest / result-Activity verification; screen capture only if needed. |
| Order is **paid**, but entitlement/access is missing | Client backend / entitlement | Backend verification response; idempotency logic; user-to-`customerIdentity` mapping; entitlement update and app refresh. | Order/`bizNo`; sanitized verification records; entitlement audit trail; current client account state; timestamps. |
| Access was granted but history/refund state is wrong | Client history / reconciliation | Canonical history call/method; pagination; latest verified status; refund reconciliation job. | Request/response redacted of secrets; endpoint/method; user/`bizNo`; expected vs actual record; timestamps. |

## Understanding SDK error `99999`

`99999` means the Android SDK **caught an unexpected local exception** while processing the request or payment flow. It can result from a missing Activity, a dependency/configuration problem, a JSON parsing error, or another unhandled runtime failure.

:::caution `99999` is not a payment decline
`99999` is **not** enough to identify the cause and does **not**, by itself, show that AppInChina's backend or a payment provider rejected the transaction. Obtain the underlying **Android exception and surrounding logs**, then classify the failure.
:::

**Evidence to collect for `99999`:**

- Exact timestamp and time zone.
- Application ID, app version, version code, and whether the build is **debug or release**.
- Device brand/model, Android version, and wallet-app version where relevant.
- The **complete exception and surrounding Android log** — not only the error code.
- Whether an AppInChina order was created, plus `bizNo` if available.
- Which wallet/channel was selected.
- Gradle dependency report for FastJSON/FastJSON2 if the exception concerns class loading, JSON parsing, or a compatibility change (see [FastJSON dependency issues](#fastjson-dependency-issues)).
- Final merged manifest for Activity/callback errors.

**Triage rule:**

- If an order **was created or paid**, investigate the post-payment callback, verification, and entitlement path **in parallel** with any client crash.
- If **no order** reached AppInChina, first inspect the local exception, SDK setup, wallet readiness, and request parameters. Do **not** label it a backend payment failure without supporting evidence.

## WeChat-specific failures

| Symptom | First checks | Evidence for support |
| --- | --- | --- |
| WeChat option appears but no wallet handoff occurs | Confirm `initPayTools()` **succeeded in the same process** before `startPayment()`; confirm WeChat is installed and the configured channel is returned. | Timestamp; SDK log; `initPayTools()` result/error; app version/build; device/Android version. |
| Wallet completes but app does not refresh access | Confirm `WXPayEntryActivity` is correctly packaged and declared; trace its route to backend verification and entitlement refresh. | Callback logs; merged manifest; order `bizNo`; backend verification record; current entitlement response. |

See the [WeChat payment lifecycle](../sdk/android.md#77-wechat-payment-lifecycle) for the full init → callback → verification path.

## FastJSON dependency issues

The SDK requires **legacy FastJSON 1.x** (`com.alibaba:fastjson`), which is a different dependency family from **FastJSON2** (`com.alibaba.fastjson2:fastjson2`). See [Prerequisites §3.2](../sdk/prerequisites.md#32-add-the-required-fastjson-1x-dependency).

| Situation | What to do |
| --- | --- |
| `ClassNotFoundException`, `NoClassDefFoundError`, or a crash identifying `com.alibaba.fastjson` | Confirm the approved FastJSON 1.x dependency is declared and resolved into the **release** build. Provide the full exception and `dependencyInsight` output. |
| Another library resolves a different FastJSON 1.x version | Resolve to one Engineering-approved FastJSON 1.x version for that module family; retest the release artifact. Do **not** pick a version solely because it is newer. |
| The app also includes FastJSON2 | Keep FastJSON2 versioning explicit and test the whole app. Do **not** describe it as a replacement for FastJSON 1.x. |
| Device/Android-specific JSON crash | Capture device/OS, app build, SDK artifact version, full exception, and **both** FastJSON/FastJSON2 resolved versions before escalating. |

## Privacy rule

:::caution Never request sensitive data
Never ask a client — and never send AppInChina — passwords, card numbers, wallet authentication codes, full device dumps, access tokens, or production secrets. Request an **excerpt** of a sanitized log covering the attempt, not an unbounded full log, unless Engineering specifically needs it under a secure process.
:::

### Example of a sanitized log excerpt

Send the window around the attempt with secrets removed:

```text
2026-08-03 14:30:01.220 +0800  ACP/pay  startPayment channel=WECHAT bizNo=ORDER_20260803_0001 customerIdentity=user_12345
2026-08-03 14:30:02.880 +0800  ACP/pay  wallet launched
2026-08-03 14:30:19.104 +0800  ACP/pay  return-to-app; querySingleOrder bizNo=ORDER_20260803_0001
2026-08-03 14:30:19.550 +0800  ACP/pay  paymentStatus=PAID pmtDt=1754203818000
2026-08-03 14:30:19.560 +0800  APP/entitlement  grant productId=pro_3m result=OK
```

Redact `APP_SECRET`, tokens, phone numbers, and card data before sharing. Include the timestamp and time zone so the attempt can be correlated with the backend order record.

---


<!-- source: payments/web/pc-h5.md -->


## Introduction

This document explains how to integrate AppInChina’s payment services in **PC** (desktop browsers) and **H5** (mobile web browsers) environments.

Unlike mobile app payments handled through SDKs, PC and H5 payments require redirecting users to external platforms (WeChat Pay or Alipay), and managing the payment session securely.

The correct flow depends on both the payment method and the user’s device.

## Related docs

- Payments API reference (server-side): [Payments API Reference](../api/reference.md)
- Identity mapping (`customerIdentity`): [Login → Payments integration (customer identity)](../guides/login-identity.md)
- High-level flow: [Understanding the IAP SDK/API Flow](../concepts/iap-flow.md)
- Troubleshooting errors: [Error Reference](../reference/errors.md)

## Architecture overview: backend vs frontend

Understanding the separation between server-side and client-side operations is crucial for secure payment integration:

### Backend/server-side (secure operations)

- **API authentication** (APP_ID, APP_SECRET must never reach the browser)
- **CreateOrder API calls** (sensitive business logic)
- **Payment verification** (critical security operations)
- **URL/parameter building** (recommended for better security)

### Frontend/client-side (JavaScript UX)

- **Device detection** (PC vs mobile)
- **QR code display** (visual user interface)
- **Page redirections** (user navigation)
- **Form submissions** (user interactions)

:::caution Security principle
Never expose API credentials or sensitive payment data to the client-side. Always verify payments server-side.
:::


## 5. Payment verification (backend only)

Payment verification must **always** happen server-side for security.

:::danger
Never rely on frontend callbacks or return URLs for payment confirmation. Always verify server-side.
:::

### Backend: payment status check (Java)

```java
@Service
public class PaymentVerificationService {

    public PaymentStatus verifyPayment(String customerIdentity, String bizNo) {
        HttpHeaders headers = new HttpHeaders();
        headers.set("APP_ID", appInChinaAppId);
        headers.set("APP_SECRET", appSecret);
        HttpEntity<Void> entity = new HttpEntity<>(headers);

        try {
            String url = apiEndpoint
                + "/detail.json"
                + "?bizNo=" + URLEncoder.encode(bizNo, "UTF-8")
                + "&customerIdentity=" + URLEncoder.encode(customerIdentity, "UTF-8");

            ResponseEntity<String> response = restTemplate.exchange(
                url,
                HttpMethod.GET,
                entity,
                String.class
            );

            return parsePaymentStatus(response.getBody());

        } catch (Exception e) {
            log.error("Payment verification failed", e);
            return PaymentStatus.ERROR;
        }
    }

    private PaymentStatus parsePaymentStatus(String responseBody) {
        JSONObject result = JSON.parseObject(responseBody);

        if (result.getInteger("code") == 0) {
            JSONObject order = result.getJSONObject("data");
            if (order != null) {
                String status = order.getString("paymentStatus");

                switch (status) {
                    case "PAID": return PaymentStatus.PAID;
                    case "PENDING": return PaymentStatus.PENDING;
                    case "CLOSE": return PaymentStatus.CLOSED;
                    case "REFUND": return PaymentStatus.REFUNDED;
                    default: return PaymentStatus.UNKNOWN;
                }
            }
        }

        return PaymentStatus.ERROR;
    }
}
```


## 7. Complete working example

### Frontend: payment form (HTML)

```html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>AppInChina Payment Demo</title>
</head>
<body>
    <form method="post" action="/pay" id="payment-form">
        <input type="text" name="bizNo" placeholder="Order Number" required>
        <input type="text" name="goodsTitle" placeholder="Product Name" required>
        <input type="text" name="customerIdentity" placeholder="Customer ID" required>

        <select name="payChannel" required>
            <option value="ALIPAY">Alipay 支付宝</option>
            <option value="WECHAT">WeChat Pay 微信支付</option>
        </select>

        <select name="paySource" id="paySource" required>
            <option value="NATIVE">PC Desktop</option>
            <option value="H5">Mobile H5</option>
        </select>

        <input type="number" name="amount" step="1" min="1" required>
        <button type="submit">Pay Now 立即支付</button>
    </form>

    <script>
        // Auto-detect device and set paySource
        function detectDevice() {
            const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
            document.getElementById('paySource').value = isMobile ? 'H5' : 'NATIVE';
        }

        // Enhanced form validation
        document.getElementById('payment-form').addEventListener('submit', function(e) {
            const amount = parseInt(document.querySelector('[name="amount"]').value, 10);
            if (!Number.isFinite(amount) || amount < 1) {
                e.preventDefault();
                alert('Amount must be at least 1 (cent)');
            }
        });

        detectDevice();
    </script>
</body>
</html>
```

### Backend: complete controller (Java)

```java
@Controller
@Slf4j
public class PaymentController {

    @Autowired private RestTemplate restTemplate;
    @Value("${aic.endpoint}") private String apiEndpoint;
    @Value("${aic.app-id}") private String appInChinaAppId;
    @Value("${aic.app-secret}") private String appSecret;

    @PostMapping("/pay")
    public String processPayment(@Valid PayOrderDTO payOrder, Model model) {
        try {
            // Secure API call
            ResponseEntity<String> response = callCreateOrderAPI(payOrder);

            if (response.getStatusCode() != HttpStatus.OK) {
                return handlePaymentError(model, "API call failed");
            }

            JSONObject data = JSON.parseObject(response.getBody()).getJSONObject("data");

            // Route based on payment method
            if ("ALIPAY".equals(payOrder.getPayChannel())) {
                return handleAlipayResponse(data);
            } else if ("WECHAT".equals(payOrder.getPayChannel())) {
                return handleWeChatResponse(data, payOrder.getPaySource(), model);
            }

        } catch (Exception e) {
            log.error("Payment processing failed: bizNo={}", payOrder.getBizNo(), e);
            return handlePaymentError(model, "Payment processing failed");
        }

        return handlePaymentError(model, "Unknown payment method");
    }

    private ResponseEntity<String> callCreateOrderAPI(PayOrderDTO payOrder) {
        HttpHeaders headers = new HttpHeaders();
        headers.set("APP_ID", appInChinaAppId);           // Secure server-side only
        headers.set("APP_SECRET", appSecret);   // Secure server-side only
        headers.setContentType(MediaType.APPLICATION_JSON);

        HttpEntity<String> request = new HttpEntity<>(JSON.toJSONString(payOrder), headers);

        return restTemplate.exchange(
            apiEndpoint + "/order.json",
            HttpMethod.POST,
            request,
            String.class
        );
    }

    private String handleAlipayResponse(JSONObject data) throws UnsupportedEncodingException {
        StringBuilder url = new StringBuilder("https://openapi.alipay.com/gateway.do?");

        for (Map.Entry<String, Object> entry : data.entrySet()) {
            url.append(entry.getKey())
               .append("=")
               .append(URLEncoder.encode(entry.getValue().toString(), "utf-8"))
               .append("&");
        }

        // Server-side redirect (secure)
        return "redirect:" + url.substring(0, url.length() - 1);
    }

    private String handleWeChatResponse(JSONObject data, String paySource, Model model) {
        if ("NATIVE".equals(paySource)) {
            // PC: QR code display
            model.addAttribute("qrCodeUrl", data.getString("code_url"));
            model.addAttribute("paymentType", "wechat_qr");
            return "payment_result";

        } else if ("H5".equals(paySource)) {
            // Mobile: direct redirect
            return "redirect:" + data.getString("mweb_url");
        }

        return handlePaymentError(model, "Invalid payment source");
    }

    private String handlePaymentError(Model model, String message) {
        model.addAttribute("error", message);
        return "error";
    }

    @GetMapping("/payment/status/{bizNo}")
    @ResponseBody
    public Map<String, Object> checkPaymentStatus(@PathVariable String bizNo) {
        // Secure verification (backend only)
        PaymentStatus status = verifyPaymentSecurely(bizNo);

        Map<String, Object> result = new HashMap<>();
        result.put("status", status.toString());
        result.put("timestamp", System.currentTimeMillis());

        return result;
    }
}
```

---



<!-- source: login/introduction.md -->


Most apps and services need a login system to reliably identify users and associate their data, access, and history with a single account over time.

This page explains what a login system needs to do, what legal requirements apply in China, which solutions are available, and what to confirm before choosing one.

:::important
Before beginning any implementation work on your login solution, confirm your plan with the AppInChina team first. This gives us time to align on account setup, compliance requirements, pricing, and any platform-specific considerations. Reaching out early avoids rework.
:::

## What a login system needs to do

A login system is not just a sign-in screen. It is the foundation for everything that ties a user to their account over time.

At minimum, a login system needs to:

* Allow users to create an account
* Allow returning users to authenticate and regain access to the same account
* Allow users to recover access if they lose their credentials
* Maintain a stable user identity that persists across sessions and devices
* Manage sessions or tokens so users stay signed in reliably

These are baseline requirements regardless of which solution is used.

### The stable internal user ID

Every user should be represented by a stable internal user ID in the application's own database. This ID should not change over time, should not be editable by the user, and should not be derived from a device identifier or external provider identifier.

The stable internal user ID is what the application should use for customer records, permissions, order history, entitlements, and any data tied to the user. External identifiers from login providers should be linked to this internal ID, not used in place of it.

## Legal requirement: real-name authentication

If the application includes any social or interactive features — such as posting content, commenting, messaging, or uploading media — Chinese law requires real-name authentication before users can access those features.

In practice, this means verifying the user's identity through a Chinese mobile phone number at registration or before enabling social features. All Chinese mobile phone numbers are tied to a national ID card, which satisfies this requirement.

Email-only registration is not sufficient for applications with user-generated content.

If this applies to your application, it should be confirmed as a requirement before choosing a login solution.

## Choosing a login solution

The right solution depends on the application's requirements, the team's capacity, and the infrastructure already in place.

| Solution | Consider this when | Main trade-off |
|---|---|---|
| [Authing](./solutions/authing) | You want a managed identity platform with low implementation overhead | Vendor dependency |
| [WeChat Login](./solutions/wechat-login) | Users are WeChat-native and you want a China-local login method | Needs backend integration; does not replace a full identity system |
| [China cloud identity (CIAM/IDaaS)](./solutions/china-cloud-identity) | Your infrastructure is on Alibaba Cloud or Tencent Cloud and you want a China-first managed identity platform | Tighter cloud vendor coupling |
| [Custom backend login](./solutions/custom-backend) | You have a backend team and specific requirements a managed platform cannot meet | Highest engineering and security maintenance burden |

For most clients starting from scratch, Authing is the recommended default. It covers the baseline requirements with low implementation overhead and includes an admin console for user management.

## Questions to confirm before choosing a solution

Before selecting a login solution, the following questions should be confirmed:

1. What login methods are required — password, SMS OTP, WeChat Login, or others?

2. Does the application include social or interactive features that require real-name authentication?

3. Should user registration be open, or should users be pre-approved before accessing the service?

4. Does the application need customer accounts, organizations, roles, or permissions?

5. Who can approve, suspend, or remove users?

6. Is there a backend team available to integrate the login system?

7. Does the application need to link multiple login methods to a single user identity?

8. Is there an existing backend or user database the login system needs to integrate with?

9. Is the application hosted on Alibaba Cloud, Tencent Cloud, AWS China, or another platform?

10. Does the application serve users outside Mainland China, and if so, how will login work across regions?

## What AppInChina can help with

Depending on the project scope, AppInChina can help clients understand:

* Which login solution is most appropriate for the application's requirements
* What compliance or legal requirements apply
* What account setup or platform configuration is needed
* What work is required from the client's backend, mobile, or web teams
* How the login solution fits into the broader China launch or localization plan
* What risks or limitations should be considered before implementation

## Related pages

- [Authing](./solutions/authing)
- [WeChat Login](./solutions/wechat-login)
- [China Cloud Identity](./solutions/china-cloud-identity)
- [Custom Backend Login](./solutions/custom-backend)
- [Login → Payments integration](/payments/guides/login-identity)

---


<!-- source: login/solutions/authing.md -->


Authing is a managed identity platform commonly used in China-facing applications. It provides user registration, login, account recovery, session and token management, and an admin console for user management out of the box.

This page explains what Authing does, where it fits, what it does not provide by itself, and what clients should consider before deciding whether to use it.

For detailed SDK integration, API references, and platform-specific implementation steps, clients and developers should refer to the official Authing documentation linked at the end of this page.

## What Authing is

Authing is a managed identity-as-a-service platform.

It handles the infrastructure layer of user authentication so that teams do not need to build and maintain registration flows, login flows, password reset flows, session management, and token issuance from scratch.

In simple terms, Authing helps answer this question:

> Who is this user, and are their credentials valid?

After that, the application still needs to decide what that user is allowed to do.

For example, if a customer portal uses Authing for login, Authing can verify the user's identity and return a token. The portal still needs its own backend logic to decide whether that user is an approved customer, which company or account they belong to, and which files or features they can access.

## Where Authing fits

Authing can be used as the authentication and identity management layer in an application.

It can provide:

* User registration and login
* Password reset and account recovery
* SMS or email OTP verification
* MFA (multi-factor authentication)
* Social login integration, including WeChat
* Session and token management
* Admin console for user management and troubleshooting

However, Authing does not provide the full application-side authorization and access control layer by itself.

If your application requires any of the following, they must be handled separately by your backend or application layer:

* Customer verification and approval workflows
* User-to-customer or user-to-organization mapping
* Roles and permissions beyond basic user authentication
* File or resource access control
* User suspension logic tied to business rules
* Audit logs for compliance or download tracking
* Order history or transactional records
* Enterprise SSO, SAML federation, or organization-level identity governance beyond what Authing's plan supports

In these cases, Authing can still be used, but it should be treated as the authentication layer connected to your own user management and authorization system.

## When Authing is a good fit

Authing may be a good fit when:

* You want to avoid building and maintaining registration, login, and recovery flows from scratch.
* You want common auth features available quickly without significant backend development.
* You want an admin console for managing and troubleshooting user accounts.
* You want to support multiple login methods, such as password login, SMS OTP, and WeChat Login, under one identity platform.
* You have, or plan to build, a backend system that handles permissions, customer records, and access control.
* You want Authing to manage the authentication layer while your application manages everything above it.

## What Authing should be paired with

Authing handles authentication. It should be paired with the application's own backend, user database, and authorization logic for everything beyond confirming who the user is.

For example:

* If users need to be approved before accessing the service, the approval workflow should be handled by the application.
* If users belong to specific customers, companies, or organizations, that mapping should be handled by the application.
* If users have different roles or permissions, those rules should be handled by the application.
* If users need access to specific files, records, or services, access control should be handled by the application.
* If the system needs audit logs, download logs, or compliance records, those should be handled by the application.
* If users need to be suspended or revoked based on business rules, that should be handled by the application.

The application should maintain its own internal user record. Authing's user identifier should be linked to this internal record, not used as the primary key for application data.

## Common Authing use cases

### Registration and login for China-facing apps

Authing is commonly used to provide password-based login, SMS OTP login, or WeChat Login for China-facing applications where a managed identity platform is preferred over building authentication from scratch.

### WeChat Login through Authing

Authing supports WeChat Login as a social login method. This can simplify the WeChat Login integration by routing it through Authing rather than integrating WeChat Login directly into the application backend.

However, the same WeChat Open Platform requirements still apply. The WeChat application setup, AppID, AppSecret, and callback configuration still need to be in place. Authing does not remove those requirements; it provides the integration layer.

For more on WeChat Login requirements, see the [WeChat Login](./wechat-login) page.

### Admin user management

Authing includes an admin console where user accounts can be viewed, searched, and managed. This can be useful for support and operations teams who need to look up or disable user accounts without building a custom admin tool.

### Multi-method login under one identity

If an application needs to support multiple login methods, such as password login, SMS OTP, and WeChat Login, Authing can consolidate these under a single user identity. This reduces the risk of duplicate accounts when users switch between login methods.

## How Authing fits into the application at a high level

```text
User registers or logs in
  |
  v
Authing verifies credentials and issues a token
  |
  v
Application backend receives and validates the token
  |
  v
Application backend looks up the internal user record
  |
  v
Application applies its own permission and access rules
  |
  v
User accesses the permitted resources or features
```

The application backend remains responsible for the application's own user records, permissions, and access control. Authing's token should not be treated as a direct authorization grant for application resources.

## Key concepts

### Authing user identity

Each user in Authing has a unique Authing user ID. This is the identifier returned after successful authentication.

The application should link this Authing user ID to its own internal user record. The internal user record is what should be used for customer data, permissions, organization mapping, and access control.

### Social login and account linking

When a user logs in through WeChat or another social login method, Authing can link that social identity to a single Authing user account. This helps avoid duplicate accounts when the same user logs in through different methods.

The application should still verify that its own internal user record is correctly linked to the Authing identity.

### Tokens

Authing issues tokens after successful authentication. These tokens should be validated by the application backend. The application backend should not rely solely on the presence of a token to make authorization decisions without also checking its own user and permission records.

## What Authing does not replace

Authing is an authentication platform, not a complete identity and access management system for your application.

It does not replace:

* Your application's own user database and customer records
* Your permission and role system
* Your customer approval or onboarding workflow
* Your file and resource access control
* Your audit logging and compliance records
* Your user suspension and revocation logic tied to business rules

These must still be built and maintained by the application.

## Pricing and plan considerations

Authing offers different pricing tiers. The features available, including MFA options, social login integrations, and admin capabilities, may vary by plan.

Before committing to Authing, clients should confirm that the required features are available on the plan they intend to use. Authing's pricing page is linked at the end of this page.

## Ownership and account management

The Authing account and tenant should normally be owned by the client, not by a third party acting on their behalf.

If AppInChina helps set up or configure Authing on behalf of a client, the responsibility model should be agreed in advance.

At minimum, the following should be clarified:

* Who owns the Authing account and tenant
* Who manages the Authing admin console
* Who stores any API keys or secrets used in the integration
* Who handles user support issues that require admin access
* What happens if the client wants to migrate away from Authing later

## Questions to confirm before choosing Authing

Before deciding whether Authing is the right fit, the following questions should be confirmed:

1. What login methods are required?

   * Password-based login
   * SMS OTP
   * WeChat Login
   * Other social login
   * MFA

2. Does the application need user registration to be open, invite-only, or pre-approved?

3. Does the application need to link multiple login methods to a single user identity?

4. Does the application need roles, permissions, or access control beyond basic authentication?

5. Does the application need customer accounts, organizations, companies, or approval workflows?

6. What resources or features should be gated by the user's identity or role?

7. Who can approve, suspend, or remove users?

8. Is there a backend team available to integrate Authing into the application?

9. What should happen after the user is authenticated?

10. Does the application need to integrate with AWS China or another cloud platform?

11. Are the required features available on the Authing pricing plan the client intends to use?

12. Who will own and manage the Authing account and tenant?

## What AppInChina can help with

Depending on the project scope, AppInChina can help clients understand:

* Whether Authing is an appropriate fit for the application's requirements
* Which Authing features are relevant to the use case
* What information and access are needed from the client
* What work is required from the client's backend, mobile, or web teams
* How Authing fits into the broader China launch or localization plan
* What risks or limitations should be considered before implementation

Implementation details, SDK setup, and API-specific behavior should be confirmed against the official Authing documentation.

## Official documentation

* [Authing documentation](https://docs.authing.cn/en/)
* [Authing pricing](https://www.authing.cn/pricing)
* [Authing website](https://www.authing.cn/)

Note: some pages may only be available in Chinese. Browser auto-translate works well for most pages. If anything is unclear after translation, reach out to our team.

---


<!-- source: login/solutions/china-cloud-identity.md -->


China cloud identity platforms are managed identity services offered by major China cloud providers, primarily Alibaba Cloud and Tencent Cloud. They provide user registration, login, account management, and identity access control as a managed service within the China cloud environment.

This page explains what China cloud identity platforms do, where they fit, what they do not provide by itself, and what clients should consider before deciding whether to use one.

For detailed setup steps, SDK references, and API documentation, clients and developers should refer to the official platform documentation linked at the end of this page.

## What China cloud identity platforms are

China cloud identity platforms are managed CIAM (Customer Identity and Access Management) or IDaaS (Identity as a Service) products.

They handle the infrastructure layer of user authentication and identity management so that teams do not need to build and maintain these systems from scratch. Because they run within China cloud infrastructure, they are designed to serve users in Mainland China with low latency and within the regional compliance environment.

In simple terms, these platforms help answer this question:

> Who is this user, and are their credentials valid — within a China-hosted environment?

After that, the application still needs to decide what that user is allowed to do.

## Where China cloud identity fits

China cloud identity platforms can be used as the authentication and identity management layer in an application hosted on Alibaba Cloud or Tencent Cloud.

They can provide:

* User registration and login
* Password reset and account recovery
* SMS OTP verification
* MFA options
* Social login integration, including WeChat
* User directory and profile management
* Session and token management
* Admin console for user management
* Risk controls and access policies

However, they do not provide the full application-side authorization and access control layer by itself.

If your application requires any of the following, they must be handled separately by your backend or application layer:

* Customer verification and approval workflows
* User-to-customer or user-to-organization mapping
* Application-level roles and permissions
* File or resource access control
* User suspension logic tied to business rules
* Audit logs for compliance or transactional records
* Order history or business data records
* Application-level enterprise SSO or federation beyond what the platform supports

## When a China cloud identity platform is a good fit

A China cloud identity platform may be a good fit when:

* Your application is primarily hosted on Alibaba Cloud or Tencent Cloud in a China region.
* You want to keep identity infrastructure close to your China-region user base.
* You want a managed identity platform that integrates naturally with your existing China cloud stack.
* You want to reduce the engineering effort of building registration, login, and recovery flows from scratch.
* You may need enterprise-style features such as SSO, federation, or identity policies in the future.
* You have, or plan to build, a backend system that handles permissions, customer records, and access control.

## What a China cloud identity platform should be paired with

Like other managed identity platforms, China cloud identity platforms handle authentication. They should be paired with the application's own backend, user database, and authorization logic for everything beyond confirming who the user is.

For example:

* If users need to be approved before accessing the service, the approval workflow should be handled by the application.
* If users belong to specific customers, companies, or organizations, that mapping should be handled by the application.
* If users have different roles or permissions, those rules should be handled by the application.
* If users need access to specific files, records, or services, access control should be handled by the application.
* If the system needs audit logs, download logs, or compliance records, those should be handled by the application.

The application should maintain its own internal user record. The cloud identity platform's user identifier should be linked to this internal record, not used as the primary key for application data.

## Key considerations

### Infrastructure alignment

China cloud identity platforms are designed to work within the Alibaba Cloud or Tencent Cloud environment. If your application is not primarily hosted on one of these platforms, a different managed identity solution may be more straightforward to integrate.

### Account linking

If the application supports multiple login methods, such as WeChat Login, SMS OTP, and password login, the identity platform needs to link these to a single user identity. The application should verify that its own internal user record is correctly linked to the platform identity.

### Compliance and data residency

Because these platforms run in China cloud regions, data residency is within Mainland China by default. Clients should confirm whether this aligns with their compliance requirements, particularly if the application also serves users outside Mainland China.

### WeChat Login through a China cloud identity platform

Both Alibaba Cloud IDaaS and Tencent Cloud CIAM support WeChat Login as a social login option. Routing WeChat Login through the cloud identity platform rather than integrating it directly into the backend can simplify the integration.

However, the same WeChat Open Platform requirements still apply. The WeChat application setup, AppID, AppSecret, and callback configuration still need to be in place. The identity platform provides the integration layer, not the WeChat account itself.

For more on WeChat Login requirements, see the [WeChat Login](./wechat-login) page.

## How China cloud identity fits into the application at a high level

```text
User registers or logs in
  |
  v
Cloud identity platform verifies credentials and issues a token
  |
  v
Application backend receives and validates the token
  |
  v
Application backend looks up the internal user record
  |
  v
Application applies its own permission and access rules
  |
  v
User accesses the permitted resources or features
```

## Available platforms

### Alibaba Cloud IDaaS

Alibaba Cloud IDaaS includes CIAM capabilities for customer-facing applications. It is a good fit when the application's infrastructure is centered on Alibaba Cloud.

* [Product page](https://www.aliyun.com/product/idaa)
* [Documentation (Chinese)](https://help.aliyun.com/zh/idaa)
* [Documentation (English)](https://www.alibabacloud.com/help/en/idaa)

### Tencent Cloud CIAM

Tencent Cloud CIAM is a managed identity platform for customer-facing registration, login, and identity access control. It is a good fit when the application's infrastructure is centered on Tencent Cloud.

* [Product documentation](https://cloud.tencent.com/document/product/1441)
* [Console setup guide](https://cloud.tencent.com/document/product/1441/62405)

## Questions to confirm before choosing a China cloud identity platform

Before deciding whether a China cloud identity platform is the right fit, the following questions should be confirmed:

1. Is the application primarily hosted on Alibaba Cloud or Tencent Cloud in a China region?

2. What login methods are required?

   * Password-based login
   * SMS OTP
   * WeChat Login
   * Other social login
   * MFA

3. Does the application need user registration to be open, invite-only, or pre-approved?

4. Does the application need to link multiple login methods to a single user identity?

5. Does the application need roles, permissions, or access control beyond basic authentication?

6. Does the application need customer accounts, organizations, companies, or approval workflows?

7. What resources or features should be gated by the user's identity or role?

8. Who can approve, suspend, or remove users?

9. Is there a backend team available to integrate the identity platform into the application?

10. Are there compliance or data residency requirements that affect which cloud region or provider can be used?

11. Does the application also serve users outside Mainland China, and if so, how will identity be handled across regions?

12. Who will own and manage the cloud identity platform account and configuration?

## What AppInChina can help with

Depending on the project scope, AppInChina can help clients understand:

* Whether a China cloud identity platform is an appropriate fit for the application's requirements
* Which platform aligns better with the existing cloud infrastructure
* What information and access are needed from the client
* What work is required from the client's backend, mobile, or web teams
* How the identity platform fits into the broader China launch or localization plan
* What risks or limitations should be considered before implementation

Implementation details, SDK setup, and API-specific behavior should be confirmed against the official platform documentation.

---


<!-- source: login/solutions/custom-backend.md -->


Custom backend login means the application implements its own authentication system, backed by its own database and APIs. Common forms include email and password login, phone number and SMS OTP login, and magic link login.

This page explains what custom backend login involves, where it fits, what it requires from the client and their team, and what clients should consider before deciding whether to go this route.

## What custom backend login is

Custom backend login means the application owns and operates its own authentication layer rather than delegating it to a managed identity platform.

The application is responsible for:

* Storing user credentials securely
* Verifying credentials at login
* Issuing and managing sessions or tokens
* Handling password reset and account recovery
* Sending SMS or email verification messages
* Protecting login flows against abuse

In simple terms, custom backend login means the application answers this question itself:

> Who is this user, and are their credentials valid?

There is no third-party identity platform handling that step on the application's behalf.

## Where custom backend login fits

Custom backend login can be used when the application already has a backend and the team has the capacity to build and maintain an authentication system.

It gives the application full control over the authentication UX, data model, security rules, and integration with the rest of the system.

However, this control comes with full ownership of the security and operational responsibilities that a managed identity platform would otherwise handle.

## When custom backend login is a good fit

Custom backend login may be a good fit when:

* The application already has a backend and a development team that will own the authentication system.
* There are specific requirements that managed identity platforms do not easily support, such as highly custom login flows, unusual account structures, or deep integration with an existing user database.
* The team has the capacity to implement and maintain password storage, session management, OTP delivery, rate limiting, and abuse prevention.
* Avoiding vendor dependency on a third-party identity platform is a priority.
* The application has already been partially built with custom authentication in place.

Custom backend login is generally more demanding to implement and maintain than a managed solution. For teams that do not have a strong reason to go custom, a managed identity platform such as Authing is usually the lower-risk starting point.

## What custom backend login requires from the team

Unlike a managed identity platform, custom backend login does not come with built-in flows, admin tooling, or infrastructure. The team is responsible for building and maintaining:

* User registration flow
* Login flow with credential verification
* Secure password storage (hashing, salting)
* SMS OTP or email OTP delivery and verification
* Session or token issuance and management
* Token refresh and expiry handling
* Password reset flow
* Account recovery flow
* Rate limiting and brute-force protection
* Abuse and bot prevention
* Monitoring and incident response for authentication failures

Each of these is a security-sensitive component. The team should have experience building secure authentication systems or be willing to invest in getting this right.

## What the application still needs regardless of approach

Whether using a managed platform or a custom backend, the application still needs:

* A stable internal user ID for each user — not derived from credentials, not editable by the user, used as the canonical identifier for all account-bound data
* An account recovery path that allows users to regain access without losing their data
* Logic to decide what each authenticated user is allowed to do, which is always the application's responsibility and is not handled by the authentication layer alone

## Key security considerations

Password storage must use a strong, slow hashing algorithm. Storing plain-text or weakly hashed passwords is a serious security risk.

OTP and magic link delivery depends on SMS or email infrastructure. The team needs a reliable delivery provider and should plan for delivery failures and abuse scenarios.

Sessions and tokens must be managed carefully, including expiry, revocation, and protection against theft.

Rate limiting and abuse prevention are required to protect login and registration endpoints from brute-force attacks and credential stuffing.

These are well-documented problems with established solutions. The OWASP references at the end of this page are a good starting point.

## How custom backend login fits into the application at a high level

```text
User submits credentials
  |
  v
Application backend verifies credentials against its own database
  |
  v
Application backend issues its own session or token
  |
  v
Application backend looks up the internal user record
  |
  v
Application applies its own permission and access rules
  |
  v
User accesses the permitted resources or features
```

## Combining custom backend login with WeChat Login

Some applications use custom backend login as the primary method while also supporting WeChat Login as an additional option. In this case, the WeChat identity should be linked to the same internal user record as the custom login credentials.

The application needs a clear account linking strategy to avoid duplicate accounts when a user logs in with different methods.

For more on WeChat Login requirements, see the [WeChat Login](./wechat-login) page.

## Questions to confirm before choosing custom backend login

Before deciding whether to build a custom backend login system, the following questions should be confirmed:

1. Does the application already have a backend, and does the team have capacity to own an authentication system?

2. What login methods are required?

   * Email and password
   * Phone number and SMS OTP
   * Magic link
   * WeChat Login as an additional method

3. Is there a specific requirement that a managed identity platform cannot meet?

4. Does the team have experience building secure authentication systems, including password storage, rate limiting, and abuse prevention?

5. Is there a plan for SMS or email OTP delivery infrastructure?

6. What is the account recovery flow, and who is responsible for supporting users who lose access?

7. Does the application need to link multiple login methods to a single user identity?

8. Does the application need roles, permissions, or access control beyond basic authentication?

9. Who can approve, suspend, or remove users?

10. Has the cost and timeline of building and maintaining a custom authentication system been accounted for, compared to using a managed platform?

## What AppInChina can help with

Depending on the project scope, AppInChina can help clients understand:

* Whether custom backend login is the right fit, or whether a managed platform would better serve the use case
* What the baseline requirements are for a secure and compliant authentication system
* How custom backend login fits into the broader China launch or localization plan
* What risks or limitations should be considered before committing to a custom approach

Implementation, security architecture, and ongoing maintenance are the responsibility of the client's development team.

## Reference documentation

* [OWASP Authentication Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html)
* [OWASP Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html)

---


<!-- source: login/solutions/wechat-login.md -->


WeChat Login allows users to sign in to an application using their existing WeChat identity. It is commonly used for China-facing apps, websites, customer portals, and services where users are likely to already have WeChat accounts.

This page explains what WeChat Login does, where it fits, what it does not provide by itself, and what clients should consider before deciding whether to use it.

For detailed platform-specific implementation steps, clients and developers should refer to the official WeChat documentation linked at the end of this page.

## What WeChat Login is

WeChat Login is an authentication method.

It allows an application to confirm that a user has authorized login through WeChat and to receive WeChat user identifiers that can be linked to the application's own user account system.

In simple terms, WeChat Login helps answer this question:

> Which WeChat user is trying to log in?

After that, the application still needs to decide what that user is allowed to do.

For example, if a customer portal uses WeChat Login, WeChat can help identify the user. The portal still needs its own backend logic to decide whether that user is an approved customer, which company or account they belong to, and which files or features they can access.

## Where WeChat Login fits

WeChat Login can be used as part of a broader identity and access management system.

It can be used for:

* User authentication
* Social login
* Account binding
* China-localized login experiences
* Reducing the need for users to remember another password
* Linking a WeChat identity to an existing application account

However, WeChat Login does not provide the full application-side identity and access management layer by itself.

If your application requires any of the following, they must be handled separately by your backend, admin system, or identity management system:

* Customer verification
* User approval workflows
* User-to-customer or user-to-organization mapping
* Roles and permissions
* File or resource access control
* User suspension and revocation
* Admin user management
* Audit logs
* Backup login or account recovery
* Enterprise SSO, MFA policies, or organization-level identity governance

In these cases, WeChat Login can still be used, but it should be treated as one authentication method connected to your own user management and authorization system.

## When WeChat Login is a good fit

For China-facing applications, WeChat Login is often considered because many users already have WeChat accounts and are familiar with WeChat-based authorization flows.

WeChat Login may be a good fit when:

* Most target users are expected to have WeChat accounts.
* You want to provide a familiar China-local login method.
* You want to reduce friction compared with password-based login.
* You want users to bind a WeChat identity to an existing application account.
* You have, or plan to build, a backend system that manages users, sessions, permissions, and access control.
* You want WeChat identity to be one part of a broader authentication or account-binding flow.

## What WeChat Login should be paired with

WeChat Login can be used in applications that require customer identity management, roles, permissions, approval workflows, or enterprise access control. However, WeChat Login should not be expected to provide those functions by itself.

In those cases, WeChat Login should be paired with the application's own backend, admin system, or identity management layer.

For example:

* If users need to be approved before accessing the service, the approval workflow should be handled by the application.
* If users belong to specific customers, companies, or organizations, that mapping should be handled by the application.
* If users have different roles or permissions, those rules should be handled by the application.
* If users need access to specific files, records, or services, access control should be handled by the application.
* If users need to be suspended, revoked, or removed, that should be handled by the application.
* If the system needs audit logs, download logs, or compliance records, those should be handled by the application.
* If users may not have WeChat accounts, the application should provide another login or recovery method.
* If the system needs enterprise SSO, MFA policies, or organization-level identity governance, WeChat Login should be integrated as one authentication method within that broader identity architecture.

The key question is not whether WeChat Login can be used in these systems. It can. The key question is whether the required user management, authorization, and governance features will be handled somewhere else in the architecture.

## Common WeChat Login scenarios

The correct WeChat Login setup depends on where users access your service.

### Native Android and iOS app login

This applies when users log in from a native mobile app.

Typical use case:

> A user opens an Android or iOS app, taps "Log in with WeChat," authorizes through the WeChat app, and returns to the mobile app.

This normally requires a WeChat Open Platform Mobile Application setup.

For Android, the setup usually involves the app package name and app signature.

For iOS, the setup usually involves the Bundle ID and Universal Links.

This is the correct option when the login flow happens inside a native Android or iOS app.

### Website QR-code login

This applies when users log in from a browser, especially from a desktop browser.

Typical use case:

> A user opens a website or customer portal, clicks "Log in with WeChat," scans a QR code with WeChat, authorizes login, and is redirected back to the website.

This normally requires a WeChat Open Platform Website Application setup.

This is the correct option for browser-based portals or websites.

### Official Account webpage authorization

This applies when users access a webpage from inside WeChat, usually through a WeChat Official Account menu, article, or message.

Typical use case:

> A user opens a link inside WeChat and the webpage identifies the user through the associated Official Account authorization flow.

This is useful when the user journey starts inside WeChat.

### Mini Program login

This applies when users access the service through a WeChat Mini Program.

Typical use case:

> A user opens a Mini Program and logs in through the Mini Program's WeChat login flow.

This requires a WeChat Mini Program setup and is separate from native mobile app login or website login.

## How WeChat Login works at a high level

Although the details vary depending on the scenario, the general flow is similar:

```text
User starts WeChat Login
  |
  v
User authorizes through WeChat
  |
  v
Application receives a temporary authorization code
  |
  v
Application backend exchanges the code with WeChat
  |
  v
WeChat returns user identifiers
  |
  v
Application backend links the WeChat identity to a local user
  |
  v
Application issues its own session or token
```

The important point is that the application backend remains responsible for the application's own user session, permissions, and access control.

The WeChat access token should not be treated as the application's own session token.

## Key identity concepts

### `openid`

`openid` is a WeChat user identifier within a specific WeChat application context.

The same person may have different `openid` values across different WeChat channels, such as:

* Native mobile app
* Website application
* Official Account
* Mini Program

Because of this, `openid` should normally be stored together with the WeChat application or channel it belongs to.

### `unionid`

`unionid` can identify the same WeChat user across multiple WeChat applications under the same WeChat Open Platform account, when available.

This can be useful when the same service uses multiple WeChat channels, such as a mobile app, website, Official Account, or Mini Program.

However, `unionid` may not always be available. The application should be designed to handle cases where only `openid` is available.

### Local application user

The application should still maintain its own internal user account.

The local application user is what should be used for:

* Customer records
* Permissions
* Organization or company mapping
* File access
* Order history
* Audit logs
* User suspension or revocation

WeChat identifiers should be linked to this local user account, not replace it entirely.

## Backend requirements

A backend is normally required for a secure WeChat Login implementation.

At a high level, the backend is responsible for:

* Receiving the temporary authorization code
* Exchanging the code with WeChat
* Receiving the WeChat user identifiers
* Finding or creating the local application user
* Binding the WeChat identity to the local user
* Applying customer verification and permission rules
* Issuing the application's own session or token

The WeChat AppSecret should only be stored on the backend. It should not be included in mobile app code, frontend JavaScript, Mini Program frontend code, or public repositories.

## Client-side work required

The work required from the client depends on the login scenario.

For native Android and iOS app login, the client or app developer may need to provide:

* Android package name
* Android app signature
* iOS Bundle ID
* iOS Universal Link
* App Store or Android app store links, if available
* App icon and screenshots
* App ownership or authorization information
* Access to update the Android and iOS apps
* A backend endpoint or backend team to support the login integration

For website QR-code login, the client may need to provide:

* Website domain
* Login callback URL
* Website name and description
* Website logo and screenshots
* Backend support for the login callback
* Website ownership or authorization information

For Official Account or Mini Program login, the client may need to provide:

* Official Account or Mini Program ownership information
* Relevant AppID or account access
* Domain and authorization settings
* Backend support for the login flow

## iOS Universal Links

For iOS mobile app login, Universal Links are usually required.

A Universal Link is an HTTPS URL associated with the iOS app. It allows iOS to return the user from WeChat back into the correct app after authorization.

Setting up Universal Links usually requires coordination between:

* The app owner
* The iOS developer
* The team that controls the relevant domain
* The WeChat Open Platform administrator

The client should expect to provide or configure:

* A domain controlled by the app owner
* HTTPS support
* Apple Team ID
* iOS Bundle ID
* Associated Domains configuration in the iOS app
* The required Apple association file on the domain

The exact implementation should follow Apple and WeChat's official documentation.

## Ownership and account management

The WeChat Open Platform application, Official Account, or Mini Program should normally be owned by the same legal entity that owns the app, website, or customer relationship.

Using a third party's WeChat account can create issues such as:

* Incorrect branding on the authorization screen
* Long-term dependency on the third party
* Migration complexity
* Unclear control over AppID and AppSecret
* Unclear responsibility for security and data protection
* Potential issues during client offboarding

If AppInChina helps create or manage the WeChat setup on behalf of a client, the responsibility model should be agreed in advance.

At minimum, the following should be clarified:

* Who owns the WeChat Open Platform account
* Who owns the AppID and AppSecret
* Who manages callback domains or Universal Links
* Who stores the AppSecret
* Who maintains the backend integration
* Who handles user support and access issues
* What happens if the client wants to migrate away later

## Questions to confirm before choosing WeChat Login

Before deciding whether WeChat Login is the right fit, the following questions should be confirmed:

1. Where will users access the service?

   * Android app
   * iOS app
   * Desktop browser
   * Mobile browser
   * Page opened inside WeChat
   * WeChat Mini Program

2. Is WeChat Login expected to be the only login method, or one of several login methods?

3. Should any WeChat user be able to create an account, or should users be pre-approved?

4. Does the application need customer accounts, organizations, companies, or roles?

5. What should happen after the user is authenticated?

6. What resources or features should the user be able to access?

7. Who can approve, revoke, or manage users?

8. Is a backup login or account recovery method required?

9. Does the application need to support users who do not have WeChat accounts?

10. Does the application need to link the same user across mobile app, website, Official Account, or Mini Program?

11. Who will own and manage the WeChat Open Platform, Official Account, or Mini Program setup?

## What AppInChina can help with

Depending on the project scope, AppInChina can help clients understand:

* Which WeChat Login scenario is most appropriate
* What WeChat account or application setup is required
* What information is needed from the client
* What work is required from the client's mobile, web, or backend teams
* How WeChat Login fits into the broader China launch or localization plan
* What risks or limitations should be considered before implementation

Implementation details, SDK integration steps, and API-specific behavior should be confirmed against the official WeChat documentation.

## Official documentation

The following official WeChat documentation should be reviewed depending on the integration type.

### Mobile app login

* [Mobile App WeChat Login Development Guide](https://developers.weixin.qq.com/doc/oplatform/Mobile_App/WeChat_Login/Development_Guide.html)
* [Authorized API calls and UnionID](https://developers.weixin.qq.com/doc/oplatform/Mobile_App/WeChat_Login/Authorized_API_call_UnionID.html)
* [Android access guide](https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Access_Guide/Android.html)
* [iOS access guide](https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Access_Guide/iOS.html)

### Website login

* [Website application WeChat Login](https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html)

### Official Account webpage authorization

* [WeChat webpage authorization](https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html)

### Mini Program login

* [Mini Program login](https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html)

## Summary

WeChat Login is a useful authentication method for China-facing applications, especially when users are expected to already have WeChat accounts.

It can be used as part of a broader identity and access management system, but it should not be treated as the full identity and access management system by itself.

The application still needs its own backend, user database, account mapping, permissions, revocation logic, session management, and audit logging.

The correct WeChat Login setup depends on where users access the service:

* Native Android or iOS app: Mobile Application WeChat Login
* Browser-based portal or website: Website QR-code login
* Page opened inside WeChat: Official Account webpage authorization
* WeChat Mini Program: Mini Program login

Before implementation, clients should confirm the access channel, ownership model, backend requirements, user management requirements, and whether WeChat Login is expected to be the only login method or one part of a broader authentication system.

---


<!-- source: login/summary.md -->


Most apps and services need a login system to reliably identify users and associate their data, access, and history with a single account over time.

This section explains what login systems need to do in China-facing applications, which solutions are available, and what to consider before choosing one.

## Where to start

Read the [Introduction & Requirements](./introduction.md) page first. It covers:

* What a login system needs to do at minimum
* The real-name authentication legal requirement for apps with social or interactive features
* A comparison of available solutions
* Questions to confirm before choosing a solution

Then go to the solution page that best matches your situation.

## Solutions

- [Authing](./solutions/authing.md) — a managed identity platform; the recommended default for most clients starting from scratch
- [WeChat Login](./solutions/wechat-login.md) — authentication via WeChat; commonly used for China-facing apps, often alongside a managed platform or custom backend
- [China Cloud Identity](./solutions/china-cloud-identity.md) — managed identity platforms from Alibaba Cloud and Tencent Cloud; a good fit when infrastructure is already on one of these providers
- [Custom Backend Login](./solutions/custom-backend.md) — building and owning the authentication layer directly; suitable when there is a specific requirement a managed platform cannot meet

## Related

- [Login → Payments integration](/payments/guides/login-identity)

---



<!-- source: ios-distribution/app-review-duplicate-4-3a.md -->


Apple may reject your app under **App Store Review Guideline 4.3(a)** if it believes your app duplicates the content or functionality of another app on the App Store — even if both apps belong to the same company or are authorized copies.

This rejection is commonly referred to as a **“spam rejection.”**

## What triggers this?

- Reusing the same codebase, design, or app template across different App Store accounts
- Submitting multiple similar apps from different developer accounts
- Submitting localized versions of an app without clear differentiation
- Apps submitted by a distributor or agent without proper authorization

## Why this affects you

When we submit your app to the China App Store through our **Apple Developer China account**, Apple may detect that the same app is already available globally under your company’s own developer account.

Even though this distribution is fully authorized, Apple’s automated or manual review process may mistakenly flag it as a duplicate submission—especially if the app design, features, and content are nearly identical.

## How we resolve it

We’ve found two effective solutions:

1. **Exclude Mainland China** from your global App Store Connect listing.

   This avoids duplication by ensuring only our version appears in the China App Store.
2. **Submit an authorization letter.**

   If you prefer to keep Mainland China enabled in your global listing, we can submit a formal authorization letter to Apple confirming that AppInChina is permitted to publish the app in China on your behalf.

:::warning Tell us early
Please let us know upfront if your app is already listed globally so we can apply the correct approach and avoid rejections.
:::

---


<!-- source: ios-distribution/cicd-signing.md -->


This guide explains how to configure your CI/CD pipeline or signing tools to work with AppInChina's managed iOS distribution system.

## The core constraint

:::warning No Apple Developer account access
Your CI/CD pipeline or signing tools must **not** rely on direct access to the Apple Developer account.
:::

Since certificates, provisioning profiles, identifiers, and APNs credentials are centrally managed by AppInChina, your build/signing process must use the files we provide—**without requiring Apple Developer account credentials or API access**.

This means you cannot use tools or workflows that dynamically fetch, create, or modify signing resources from Apple's systems.

## What won't work

The following tools and approaches will **not** work in this setup:

### Fastlane automatic provisioning tools (not supported)

- `fastlane match` - requires read/write access to the Apple Developer Portal
- `fastlane sigh` - attempts to download or create provisioning profiles from Apple
- `fastlane cert` - tries to create or download certificates from Apple
- `fastlane pem` - generates APNs certificates (we provide these)

### Xcode automatic signing (not supported)

- **"Automatically manage signing"** in Xcode - requires Apple Developer account access
- Xcode cloud builds with automatic signing

### Scripts or tools that modify Apple resources (not supported)

- Scripts that register devices via Apple's APIs
- Tools that create App IDs, capabilities, or App Groups programmatically
- Automated APNs certificate generation
- Any tool that requires App Store Connect API keys for signing/provisioning operations

### Third-party services with Apple portal integration (not supported)

- CI/CD services configured to auto-fetch provisioning profiles from Apple
- Build services that require Apple Developer Portal credentials

## What will work: manual signing with provided assets

Your build process should use **manual signing** with the certificates and provisioning profiles we provide.

### Supported approaches

- **Manual signing in Xcode** with our provisioning profiles
- **xcodebuild** with signing options pointing to our files
- **fastlane gym** (build only, not provisioning management)
- **CI/CD pipelines** that reference stored signing assets
- **Local builds** with manually configured signing

## Recommended approach

Your build and signing process should use **manual signing** with the certificates and provisioning profiles we provide via 1Password.

**General principles:**

1. **Receive signing assets** - We'll deliver certificates (`.p12`, `.cer`) and provisioning profiles (`.mobileprovision`) via 1Password
2. **Install locally** - Import certificates into your keychain and install provisioning profiles for local development
3. **Configure manual signing** - In Xcode, disable "Automatically manage signing" and select our provisioning profiles
4. **Store securely in CI/CD** - Add signing assets as encrypted secrets in your CI/CD platform (often base64-encoded)
5. **Reference in builds** - Configure your build commands to use the provided signing assets


## Best practices

1. **Store signing assets securely**:
   - Use your CI/CD platform's encrypted secrets
   - Never commit `.p12` or `.mobileprovision` files to version control
   - Use base64 encoding for storing binary files as secrets

2. **Keep ExportOptions.plist in version control**:
   - This file contains export configuration
   - Safe to commit (no secrets)
   - Update when provisioning profiles change

3. **Document your signing configuration**:
   - Team ID
   - Bundle IDs
   - Provisioning profile names
   - Certificate common name

## Troubleshooting

### "No valid code signing certificates found"

- Certificate not installed in keychain
- Certificate password incorrect
- Keychain locked or not accessible

**Solution**: Verify certificate import and keychain unlock steps.

### "No provisioning profile matches"

- Bundle ID mismatch
- Provisioning profile not installed
- Wrong profile selected in Xcode

**Solution**: Ensure Bundle ID exactly matches provisioning profile, verify profile is installed.

### Build succeeds but IPA export fails

- ExportOptions.plist misconfigured
- Wrong export method
- Provisioning profile doesn't support export method

**Solution**: Verify ExportOptions.plist matches your provisioning profile type.

## When assets are renewed

Certificates and provisioning profiles have expiration dates. When we renew them:

1. You'll receive new files via 1Password
2. Update the files in your CI/CD secrets (re-encode to base64)
3. Update local installations
4. No code changes needed—just replace the files

We'll notify you before expiration and provide updated assets with sufficient lead time.

## Summary

**Do**:
- Use manual signing with provided certificates and provisioning profiles
- Store signing assets securely in CI/CD secrets
- Reference local signing files in your build process
- Use fastlane for building (not provisioning management)

**Don't**:
- Use automatic signing in Xcode or CI/CD
- Use tools that fetch/create provisioning profiles from Apple
- Require Apple Developer account credentials in your pipeline
- Attempt to modify Apple resources programmatically

---


<!-- source: ios-distribution/faq.md -->


## Understanding the system

### What is a distribution certificate, and why is it shared?

A distribution certificate is required to sign and submit apps to the App Store. Our shared certificate approach streamlines management, avoids certificate limits, and simplifies renewals.

### What’s the difference between development and distribution provisioning profiles?

- **Development profiles** allow you to test your app on registered devices.
- **Distribution profiles** are required to release your app on the App Store.

## Setup and access

### Do I need to register test devices?

Yes, for development profiles. Please provide each device’s UDID and name.

### Can I manage my app directly in App Store Connect?

Yes. We’ll assign roles to your team so you can manage your app. Certificates, provisioning profiles, identifiers, and APNs credentials remain managed by AppInChina.

### How do I update my app’s capabilities later?

Inform us of any changes. We’ll update the App Identifier and regenerate the necessary provisioning profiles and APNs certificates if required.

### Can you manage App Groups or Merchant IDs for my app?

Yes. We support App Groups, Merchant IDs, and other Apple service identifiers.

### Can my CI/CD pipeline fetch profiles or certificates automatically from the Apple Developer portal?

No. Configure your pipeline to use the files we provide directly.

### Why can’t I upload my app directly from Xcode?

Uploading a build directly from Xcode requires access to the **Apple Developer Program** account that owns the app’s certificates and provisioning profiles.

In our shared distribution certificate setup, AppInChina centrally manages all Apple Developer account resources to ensure security, consistency, and compliance. Client teams are therefore **not granted Developer Program access**, even if they have App Store Connect roles.

To submit builds without Developer Program access, please **export an IPA from Xcode and upload it using Apple Transporter**.

## Support and communication

### Who do I contact for support with certificates, provisioning profiles, or APNs?

Please reach out to our support team or your account manager.

### What should I include in my support request?

Include a description of the issue, relevant error messages, and affected Bundle IDs.

## Security & data handling

### Is sharing certificates and provisioning profiles via 1Password secure?

Yes. 1Password uses end-to-end encryption. Restrict access to authorized personnel only.

### How can we verify that the certificates and provisioning profiles belong to our app?

You can inspect the `.mobileprovision` file on macOS to confirm the App ID, Team ID, entitlements, and validity period.

## Project lifecycle and admin

### What happens if we stop working with AppInChina?

We’ll revoke App Store Connect access and stop maintaining Apple Developer resources for your app (certificates, profiles, identifiers, APNs).

Note: Apple test device registrations cannot always be removed immediately (Apple restrictions apply, and devices may remain registered until the membership year resets). We will not register new devices for your app after offboarding.

### How long does the setup take?

After receiving all required information, setup typically takes 1–3 business days.

### How often are certificates and provisioning profiles renewed?

Certificates generally have a one-year validity. Shared certificates may have an initial shorter validity (but never less than six months). We handle renewals and distribute updated files proactively.

---


<!-- source: ios-distribution/information-required.md -->


To get started, please provide the following information as completely and accurately as possible. Missing or incomplete information may result in delays during setup, testing, or app submission.

:::tip Verify your information
After gathering your details, use the **[Preparation Checklist](./preparation-checklist.md)** to ensure you have everything ready before submitting.
:::

## 1) App identifiers (Bundle IDs)

For each iOS app you plan to distribute, please provide:

- **Desired Bundle ID** (example: `com.yourcompany.yourapp`)
- **App name**, as it should appear in App Store Connect
- **List of required app capabilities**, such as (but not limited to):
  - Push Notifications
  - In-App Purchases
  - Sign in with Apple
  - Associated Domains
  - App Groups


> **Note:** Capabilities must be listed upfront. Adding or changing capabilities after setup may require updating the App Identifier and regenerating provisioning profiles.


:::caution Ensure Bundle ID is globally available
**Bundle IDs must be globally unique across ALL Apple Developer accounts.** Each Bundle ID can only be registered once worldwide.

If you're already distributing your app globally with your own Apple Developer account, you **cannot reuse the same Bundle ID**. You must provide a different Bundle ID for the China-specific version (e.g., `com.company.appname.china`).
:::

:::warning Submit this early
We cannot proceed with creating App Identifiers, provisioning profiles, or initiating required filings until your Bundle ID and capabilities are confirmed.

If the chosen Bundle ID is unavailable and we are forced to change it after filings have started, we may need to redo registrations such as:

- Mobile App Filing (备案)
- Software Copyright Certificate
- ICP registration
- User-facing documents (privacy policies, terms of service, etc.)

We strongly recommend confirming your desired Bundle ID with us **before** we begin any filing procedures. We can check and reserve your proposed Bundle ID in our Apple Developer account before proceeding.
:::

:::info Global availability (App Store Connect)
Please confirm whether this app is **already listed globally** on the App Store under your own Apple Developer account.

If the same app is already available internationally, Apple may flag the China-specific version as a duplicate submission (Guideline 4.3(a)). We have two standard solutions:

- Exclude Mainland China from your global App Store listing, or
- Provide an authorization letter stating AppInChina is permitted to submit the app in China on your behalf

See also: **[App Review Guideline 4.3(a): Duplicate App Rejection](./app-review-duplicate-4-3a.md)**.
:::

## 2) Provisioning profiles

For each provisioning profile you require, specify:

- **Associated Bundle ID** (must exactly match the App Identifier)
- **Profile type**:
  - **Development**: internal testing and debugging on registered devices
  - **Distribution**: App Store release or other distribution methods
- **Target usage** (local development, CI/CD builds, TestFlight, etc.)
- **Device UDIDs** (required only for development profiles)

Provisioning profiles are generated and managed by AppInChina. Any change to certificates, devices, or app capabilities may require profiles to be regenerated.

## 3) Test devices (development profiles only)

Test devices are required only for **development provisioning profiles**.

Due to Apple’s annual device registration limits, test devices are capped per device type and cannot be removed once registered for the current membership year.

Per app, the default limits are:

- iPhone: up to 3 devices
- iPad: up to 3 devices

Additional devices may be approved subject to availability and with appropriate technical or business justification. Approval is not guaranteed.

For each test device, please provide:

- **Device name** (example: “John’s iPhone 14”)
- **UDID** (Unique Device Identifier)

## 4) App Store Connect access

At least one member of your team must have access to **App Store Connect** to manage app metadata, monitor review status, respond to Apple inquiries, and handle compliance-related requests.

:::tip Access prerequisites (avoid onboarding delays)
Before you request access, confirm each team member:

- Has an active Apple ID they can sign into
- Has **two-factor authentication (2FA)** enabled and access to the trusted device/phone number
- Can receive and accept Apple email invitations promptly
:::

For each user who requires access, please provide:

- **Full name**
- **Email address** (must match the email associated with the user’s Apple ID)
- **Requested role** (example: App Manager, Developer, Marketing)
- **Brief description of responsibilities**

Important notes:

- The highest level of access we can grant is **App Manager**.
- If you are responsible for uploading builds with **Apple Transporter**, request **App Manager** access.
- Please follow the principle of least privilege and request only the permissions strictly necessary.
- Each user must accept the invitation sent by Apple to activate their access.

## 5) App Groups and additional identifiers (if applicable)

If your app requires additional Apple identifiers, please provide details:

- **For App Groups**:
  - Desired App Group name (example: `group.com.yourcompany.yourapp`)
  - Apps and provisioning profiles that should be associated with the App Group
  - Purpose (example: shared storage, app extension communication)
- **For embedded extensions or widgets**:
  - Bundle ID for each embedded target (example: `com.yourcompany.yourapp.todayextension`)
  - Component name (example: “Today Widget”, “Watch Extension”)
  - Whether it is intended to be a standalone app in App Store Connect (Yes/No)

:::tip Placeholder app records to reduce cross-client visibility
In our shared Apple Developer / App Store Connect organization, identifiers like Bundle IDs (including internal-only targets such as widgets or extensions) can appear in dropdowns and selectors.

To reduce accidental exposure, we can create **placeholder app records** for internal-only Bundle IDs so that:

- The identifier is removed from “available identifiers” dropdowns shown to other clients
- We reduce the chance of accidental discovery during setup workflows
- We prevent accidental reuse of identifiers

These placeholder apps are not published and contain no metadata or assets.
:::

Important: please review the disclosure in **[Introduction & Architecture](./introduction.md)** about cross-client visibility in shared App Store Connect organizations.

For other identifiers (such as Merchant IDs), include:

- Identifier type
- Desired name/format (if applicable)
- Purpose and integration details

## 6) Push notifications (APNs)

If your app uses **Apple Push Notification service (APNs)**:

- Clients always send push notifications from their **own backend systems**
- AppInChina manages all APNs configuration within the Apple Developer Account
- We use **certificate-based APNs authentication** in our shared account environment

For each app with push notifications enabled, AppInChina will securely provide:

- **APNs SSL certificate (`.cer`)**
- **APNs private key bundle (`.p12`)**

APNs Auth Keys (`.p8`) are not used or shared in our shared Apple Developer account setup.

If your app requires special push notification types (background notifications, VoIP pushes, Live Activities), inform us upfront so we can configure the App Identifier and provisioning profiles accordingly.

---


<!-- source: ios-distribution/introduction.md -->


This page explains the architecture of our shared distribution model, the responsibility split between AppInChina and your team, and how we manage signing assets securely.

:::warning Shared App Store Connect model: cross-client visibility is possible
Our iOS distribution model uses a **shared App Store Connect organization** (multiple clients access the same organization, with role-based permissions).

Because App Store Connect was **not designed for multi-tenant sharing**, there are workflows where **Client A may be able to see limited information related to Client B’s apps**. This can happen due to how Apple surfaces data across certain screens and request flows.

Examples include:

- App creation flows where app identifiers or related targets appear in selection lists
- Certain App Store Connect request flows (for example, expedited review requests) where app lists or identifiers may be visible

We take practical measures to reduce this (least-privilege roles, internal process controls, and placeholder records where applicable), but **we cannot guarantee zero cross-client visibility in all App Store Connect workflows**.

By proceeding, you confirm you understand and accept that **some cross-client visibility is possible** under this shared-account model.
:::

:::info No direct Apple Developer account access
**Your team will not have direct access to the Apple Developer account.**

This means:

- All certificates, provisioning profiles, App IDs, and related resources are created and managed by AppInChina
- You receive signing assets securely via 1Password
- **Your build tools, CI/CD pipelines, and signing scripts must NOT depend on direct access to the Apple Developer Portal or App Store Connect APIs**
- Tools like `fastlane match`, `fastlane sigh`, or scripts that auto-generate/fetch provisioning profiles from Apple will not work
- You must use the certificates and provisioning profiles we provide

If your current build process requires Apple Developer account access, you'll need to adapt it to work with manually provided signing assets. See **[CI/CD Pipelines and Signing Tools](./cicd-signing.md)** for details.
:::

## Responsibility split (who does what)

To avoid delays and confusion, here’s the typical responsibility split:

- **AppInChina manages (inside Apple Developer / App Store Connect)**:
  - Certificates, provisioning profiles, App IDs, capabilities, APNs certificates
  - App Store Connect role assignment (up to App Manager)
  - Renewals and re-issuing updated signing assets when needed
- **Your team manages (outside of Apple Developer access)**:
  - App code, builds, and CI/CD configuration
  - App metadata/content in App Store Connect (screenshots, descriptions, privacy, compliance responses)
  - Exporting the IPA and uploading builds using **Apple Transporter**

## Our management system (high level)

We use a **Shared Distribution Certificate** system to efficiently manage multiple client apps within our Apple Developer China account. AppInChina takes care of:

- **Distribution certificates**: issue and renew shared certificates for app signing
- **App identifiers (Bundle IDs)**: create and manage your unique App ID
- **Additional identifiers**: App Groups, Merchant IDs, and other related services (when needed)
- **Provisioning profiles**: generate development and distribution profiles
- **Test devices**: register testing devices when required (development profiles only)
- **App Store Connect access**: manage roles and permissions for your team members
- **Push notifications (APNs)**: configure APNs and provide the required credentials

Our team keeps these components up to date and securely managed.

## Onboarding & maintenance process

When onboarding a new app:

1. **Information collection**: we gather your Bundle ID, required capabilities, and any additional identifiers.
2. **Resource setup**: we create your App Identifier, assign a shared certificate, configure APNs (if needed), and generate provisioning profiles.
3. **Secure delivery**: we share the required signing and APNs files (e.g., `.p12`, `.cer`, `.mobileprovision`) via 1Password.
4. **Ongoing maintenance**: as certificates near expiration, we renew and re-issue updated profiles/certificates and send you the updated files.

:::tip 1Password access
We deliver signing assets via 1Password. To avoid delays, ensure at least one person on your team can access the 1Password shared vault we provide.
:::

You integrate these files into your CI/CD pipeline or local environment to build, sign, and distribute your app as usual—without requiring direct Apple Developer account access.

---


<!-- source: ios-distribution/overview.md -->


This documentation explains how AppInChina manages iOS app distribution through our Apple Developer China accounts and what we need from you to onboard your app smoothly.

## Recommended Reading Path

Depending on your role, we recommend starting with different sections of the documentation.

### For Product Managers & Ops

If you are managing the app submission, compliance, or Apple Developer account requirements:

1.  **Understand the model**: Read [Introduction & Architecture](./introduction.md) to understand how our shared account model works and why you won't have direct access.
2.  **Gather requirements**: Review the [Information We Need From You](./information-required.md) guide to understand and gather all the necessary information in the required format.
3.  **Verify readiness**: Use the [Preparation Checklist](./preparation-checklist.md) to ensure you have everything ready before submitting your email.

### For Developers

If you are building, signing, and uploading the app:

1.  **Understand the constraints**: Read [Introduction & Architecture](./introduction.md) (specifically "No direct Apple Developer account access") to understand the manual signing requirement.
2.  **Configure your pipeline**: Read [CI/CD Pipelines and Signing Tools](./cicd-signing.md) to learn how to set up manual signing without API access.
3.  **Upload builds**: Read [Uploading via Transporter](./transporter-upload.md) to learn the correct workflow for submitting builds to App Store Connect.

---


<!-- source: ios-distribution/preparation-checklist.md -->


Before submitting your information, use this checklist to ensure you have everything ready. Gathering these details upfront will help us onboard your app quickly and avoid delays during setup or submission.

## Required Information Checklist

### ✅ App Identifiers (Bundle IDs)

- [ ] **Desired Bundle ID** (e.g., `com.yourcompany.yourapp`)
- [ ] **App name** (as it should appear in App Store Connect)
- [ ] **List of required capabilities**, such as:
  - Push Notifications
  - In-App Purchases
  - Sign in with Apple
  - Associated Domains
  - App Groups
- [ ] **Global App Store status** – Confirm whether this app is already listed globally on the App Store under your own Apple Developer account

:::warning Bundle ID is critical
The Bundle ID is used across multiple regulatory filings (备案, ICP, Software Copyright). Changing it after we start those processes may require restarting them entirely. We recommend confirming your Bundle ID with us **before** we begin any filings.
:::

:::caution Bundle ID must be globally unique
**Bundle IDs must be globally unique across ALL Apple Developer accounts worldwide.** Before submitting your desired Bundle ID, verify that:
- No one on your team has already registered it in another Apple Developer account
- It follows Apple's reverse-DNS naming convention (e.g., `com.company.appname` based on a domain you own)


**Common scenario**: If you already distribute your app globally using your own Apple Developer account. You must use a **different Bundle ID** for the China-specific version (e.g., add `.china` suffix like `com.company.appname.china`).
:::


### ✅ Test Devices (only if requesting Development profiles)

- [ ] **Device name(s)** (e.g., "John's iPhone 14")
- [ ] **Device UDID(s)** for each test device
- [ ] Confirm you need **≤3 iPhones and ≤3 iPads per app** (our standard limits)

:::info Why device limits?
Apple enforces annual device registration limits per Apple Developer account. Once devices are registered, they cannot be removed until the next membership year. We apply per-app limits to ensure fair distribution across all clients.
:::


### ✅ App Groups & Additional Identifiers (if applicable)

Only complete this section if your app uses App Groups, extensions, widgets, or other special identifiers.

- [ ] **For App Groups**:
  - [ ] Desired App Group name (e.g., `group.com.yourcompany.yourapp`)
  - [ ] Apps and provisioning profiles that should be associated
  - [ ] Purpose (e.g., shared storage between app and extension)

- [ ] **For embedded extensions or widgets**:
  - [ ] Bundle ID for each target (e.g., `com.yourcompany.yourapp.widget`)
  - [ ] Component name (e.g., "Today Widget", "Watch Extension")
  - [ ] Whether it should be a standalone app in App Store Connect (Yes/No)

- [ ] **For other identifiers** (Merchant IDs, etc.):
  - [ ] Identifier type
  - [ ] Desired name/format
  - [ ] Purpose and integration details


## Next Steps

Once you've gathered all the required information:

1. **Double-check against requirements**: Ensure your information matches the format in [Information We Need From You](./information-required.md)
2. **Submit your information** via email to your AppInChina Engineering contact
3. **Wait for setup confirmation** – we'll create all necessary resources and deliver signing assets via 1Password

If you have questions about any of these items, refer to:
- **[Introduction & Architecture](./introduction.md)** – understand how our distribution system works
- **[FAQ](./faq.md)** – common questions and answers
- **[Troubleshooting](./troubleshooting-screenshots.md)** – solutions to common issues

Or reach out to your AppInChina Engineering contact for clarification.

---


<!-- source: ios-distribution/transporter-upload.md -->


In our managed distribution setup, **distribution builds must be uploaded using Apple Transporter**, not directly from Xcode.

This approach allows you to submit builds to App Store Connect **without requiring access to the Apple Developer account**.

## Important rules (please read)

- Do **not** upload builds using **Xcode → Distribute App → Upload**
- Do **not** enable “Automatically manage signing”
- Sign your app using the certificate and provisioning profiles provided by AppInChina
- Always **export an IPA** and upload it using **Apple Transporter**

Uploading via Xcode requires Apple Developer Program access, which is not part of this setup.

## Step 1: Export the IPA from Xcode

After building and signing your app with the files we provide:

1. Open your project in **Xcode**
2. Select **Any iOS Device (arm64)** as the run destination
3. From the menu bar, click:

```
Product → Archive
```

4. When **Organizer** opens, select the latest archive
5. Click **Distribute App**
6. Select **Custom** → **Next**
7. Select **App Store Connect** → **Next**
8. Select **Export** (do **not** select Upload)
9. Keep all signing options unchanged
10. Choose a location and export the `.ipa`

You should now have a signed IPA ready for upload.

## Step 2: Upload the IPA using Apple Transporter

1. Install **Apple Transporter** from the macOS App Store
2. Open **Transporter**
3. Sign in using your **App Store Connect Apple ID** (must have **App Manager** access)
   - Ensure you can complete Apple **2FA** prompts during sign-in
4. Click **Add App or Asset Pack** and select the exported `.ipa`
5. Wait for Transporter to validate the build
6. Click **Deliver**
7. Wait for the upload to complete

Once delivered, the build will appear in **App Store Connect** (usually within a few minutes).

## Notes on App Store Connect accounts

- Transporter uploads are tied to the **App Store Connect organization** that owns the app
- If your Apple ID has access to multiple organizations, make sure you’re logged in with the account that has access to the correct app record
- If Transporter reports “no suitable application record”, it usually means:
  - The Apple ID does not have access to the app’s App Store Connect account, or
  - The app exists under a different organization

If you hit this, contact us before retrying.

## Summary

- Build and sign using the files provided by AppInChina
- Export an IPA from Xcode
- Upload via Apple Transporter
- Manage versions, TestFlight, and submissions in App Store Connect

If you run into issues, see **[Troubleshooting and Required Screenshots](./troubleshooting-screenshots.md)**.

---


<!-- source: ios-distribution/troubleshooting-screenshots.md -->


If you encounter issues exporting or uploading your iOS distribution build, please provide the screenshots below. They help us verify **signing**, **export configuration**, and **Transporter behavior**.

## A) Signing configuration (critical)

### 1) Xcode — Signing & Capabilities (Release / Distribution)

Capture:

- Xcode → Project → Target → **Signing & Capabilities**
- **Release** configuration selected

Must show clearly:

- Bundle Identifier
- Team
- Signing certificate (Apple Distribution)
- Selected **Distribution provisioning profile**
- “Automatically manage signing” setting

Why this matters: confirms the app is signed with the correct team, certificate, and provisioning profile.

### 2) Xcode — Build Settings (Code Signing)

Capture:

- Xcode → Target → **Build Settings**
- Filter: `Code Signing`

Must show clearly:

- Code Signing Identity (Release)
- Provisioning Profile (Release)
- Development Team

Why this matters: ensures no conflicting signing settings override the intended configuration.

## B) Archive and export process

### 3) Xcode Organizer — Archive summary

Capture:

- Xcode → Organizer
- Selected archive

Must show clearly:

- App name
- Bundle ID
- Version and build number
- Archive date

Why this matters: verifies the archive was created correctly and matches the intended app.

### 4) Xcode — Distribution method selection

Capture screens from the **Distribute App** flow showing:

- **Custom** selected
- **App Store Connect** selected
- **Export** selected (not Upload)

Why this matters: confirms the correct export path for Transporter.

## C) Transporter upload

### 5) Transporter — App loaded screen

Capture Transporter after the IPA is added.

Must show clearly:

- IPA file name
- App name
- App Store Connect organization name shown at the top

Why this matters: shows which App Store Connect context Transporter is using during upload.

### 6) Transporter — Full error message (if any)

Capture the complete error dialog/panel so we can see all error text.

Why this matters: Transporter errors usually pinpoint permission, bundle ID, or account mismatches.

## Notes on sensitive information

- Do **not** share passwords, API keys, or private keys
- Do **not** share certificate or provisioning profile files as screenshots
- Screenshots may include app names, bundle IDs, and version numbers (this is OK)

## Minimum required screenshots (if time is limited)

If you can’t provide everything, please send at least:

1. Signing & Capabilities (Release)
2. Organizer archive summary
3. Transporter error message

This set is usually sufficient for initial diagnosis.

---



<!-- source: content-review/api-integration.md -->


# API Integration Guidelines

For **User-Generated Content (UGC)** and **Customer-Generated Content (CGC)**, your application must evaluate dynamic content in real-time. To achieve this, you must integrate a Content Review API directly into your backend architecture. 

AppInChina strongly recommends the **Alibaba Cloud Content Moderation API** due to its high detection accuracy for text, images, videos, and audio in the Chinese market.

## Direct Integration Workflow

When integrating the API directly, your engineering team builds the connection, and your internal moderation team handles the review queue. 

Here is the standard integration workflow:

### 1. Account Provisioning
* AppInChina will create an Alibaba Cloud account for your company.
* This account will be strictly limited to Content Moderation functionality to ensure security.
* We will securely provide your engineering team with the necessary **AccessKey ID** and **AccessKey Secret** to authenticate your API requests.

### 2. Backend Integration
* Your backend servers will make API calls to Alibaba Cloud whenever a user attempts to post or send content.
* The API supports scanning text, images, audio, and video.
* **Important:** API calls must be made from your backend, not directly from the client application, to protect your API keys and prevent tampering.

### 3. Implementing Risk-Based Routing
When content is scanned by the API, Alibaba Cloud returns specific risk levels. Your backend must be programmed to handle these responses appropriately:

* **Without risk (Pass)**: The content is safe. Your backend should publish the content immediately.
* **Low Risk (Review)**: The content is likely safe but triggered a minor flag. To avoid disrupting the user experience, you should publish the content immediately, but simultaneously flag it in your internal system for manual review.
* **Medium or High Risk (Block)**: The content contains clear violations. Your backend must **block** the publication immediately and hold the content in a queue for manual review.

### 4. Manual Review Queue
Because the API will inevitably flag content that requires human judgment, a manual review process must be established for any content flagged as Low, Medium, or High risk. You have two options for handling this manual review queue:

#### Option A: AppInChina Managed Review (Recommended)
By default, AppInChina's compliance team will handle the manual review of any content flagged by the API.
* **Initial Routing**: Your backend handles the initial API integration. When content is flagged as Low, Medium, or High risk, your system temporarily blocks or flags the content.
* **Forwarding to AppInChina**: Your backend must automatically forward the flagged content details (including the `data_id`, content payload or URL, and the API's risk label) to AppInChina's moderation system via our designated webhook/API.
* **Manual Review**: Our Chinese-speaking moderation staff will review the forwarded content in the AppInChina admin dashboard and make the final publish/block decision.
* **Callback & Resolution**: Once a decision is made, our system will send an asynchronous webhook callback to your backend with the final `approved` or `rejected` status. Your system must listen for this callback to automatically publish the approved content or permanently delete the rejected content.

#### Option B: Internal Client Review
If your company has a dedicated Chinese-speaking moderation team, you may choose to handle the manual review queue internally.
* You will need to build or configure an internal dashboard/queue where your staff can review flagged content.
* If a "Low Risk" item is manually determined to be a violation, your team must take it down.
* If a "Medium/High Risk" item is manually determined to be a false positive, your team can manually approve and publish it.
* **Compliance Requirement:** If you choose to handle manual reviews internally, you **must maintain strict records** of all completed reviews, including the reviewer's decision and timestamp. AppInChina or Chinese regulators may request these records at any time to verify compliance.

## Alternative Cloud Providers

If your global infrastructure is already deeply integrated with a different cloud provider, you may prefer to use their corresponding services in China. While we strongly recommend Alibaba Cloud, the following alternatives are also acceptable and follow a similar integration logic:

* [Tencent Cloud Content Moderation](https://cloud.tencent.com/solution/content-moderation)
* [Azure China Content Moderator](https://docs.azure.cn/zh-cn/ai-services/content-moderator/)
* [Baidu Content Review](https://cloud.baidu.com/doc/ANTIPORN/s/dkk6wyt3z)
* [Huawei Cloud Moderation](https://www.huaweicloud.com/intl/en-us/product/moderation.html)
* [Volcengine Content Moderation](https://www.volcengine.com/product/cms)

---


<!-- source: content-review/overview.md -->


# Content Review Overview

As an essential part of compliance, content review is a regulatory safeguard that prevents the publication of sensitive, illegal, or politically risky content that could result in suspension of products, removal from app stores, or even legal consequences in China. This process protects AppInChina, our clients, and end-users by ensuring that all content—text, images, video, audio, and interactive elements (whether hard-coded or dynamically generated)—complies with the full scope of Chinese regulations.

## Documentation Index

- **Implementation guidance**: [API Integration Guidelines](/content-review/api-integration)
- **Submission workflow**: [Tasks Submission Guide](/content-review/submission-guide)
- **High-risk content catalog**: [Sensitive Topics Catalog](/content-review/sensitive-topics)

## Recommended Reading Path

To help you get started with Content Review integration, we recommend the following path:

1. **Understand the Requirements**: Read this Overview to understand the types of content that need review and the legal requirements.
2. **Choose a Solution**: Review the [API Integration Guidelines](/content-review/api-integration) guide to understand how to connect your backend to the Content Moderation API.
3. **Prepare Your Content**: Follow the [Tasks Submission Guide](/content-review/submission-guide) to format your content correctly for review.

## Legal Requirements

Content review is mandated by the **Cybersecurity Law of the PRC (2017)**. Articles 12, 47, and 48 require internet service providers to prevent the dissemination of prohibited content and assume responsibility for information security management. Failure to do so may lead to suspension of services or administrative penalties.

## Content Types and Reviewing Processes

There are three main content types, each with distinct review processes:

### 1. User-Generated Content (UGC - Public)
This refers to **public-facing** content created by users that other people can see, such as social media posts, public forum comments, public reviews, or in-game public chats.
* **Why it matters**: Because this content is broadcasted to the public, the Chinese government considers it high-risk for the dissemination of illegal or sensitive information.
* **Prerequisite (Real Identity Verification)**: If your solution includes social functions (e.g., comments, replies, posting), Chinese law (Cybersecurity Law, Article 24) requires you to verify the user's real identity *before* they can post. In China, this is typically achieved by requiring a Chinese mobile phone number during registration. For more information, please refer to our [Login documentation](/login/introduction).
* **Requirement**: Must be filtered using a Content Review API *before* publication. Failure to implement the API before public release may result in agreement termination.
* **Process**: 
  1. **Submission**: A user attempts to post content.
  2. **Automated Review**: The content is immediately scanned by the Content Review API.
  3. **Risk-Based Routing**:
     * **No Risk**: The content is published immediately.
     * **Low Risk**: The content is published immediately to avoid disrupting the user experience, but it is simultaneously flagged for manual review by the AppInChina team. If the manual review confirms it violates regulations, it will be taken down.
     * **Medium or High Risk**: Publication is blocked. The content is held in a queue for manual review by the AppInChina team and will *only* be published if it is manually cleared.

### 2. Developer-Generated Content (DGC - Official)
This is the **official, static content** of the app or website itself, created by your team. It includes UI text, official articles, hardcoded images, marketing banners, and localization strings.
* **Requirement**: Since you control this content and it doesn't change dynamically every second, it does not require a real-time API. Instead, it requires a one-time (or per-update) hybrid review: you first filter the content, and then AppInChina verifies the high-risk portions.
* **Process**: 
  1. **Self-Assessment & Filtering**: To ensure an efficient review process, you do not need to submit every single string of text in your app. Please apply common sense and filter out undoubtedly safe, standard UI elements (e.g., navigation bar labels like "Home" or "Settings", standard footers, basic button text).
  2. **Identify High-Risk Content**: Carefully review your remaining content against our [**Sensitive Topics Catalog**](/content-review/sensitive-topics). Any content touching on these areas must be isolated for our review.
  3. **Formatting & Submission**: Compile the filtered, potentially sensitive text into a CSV file for *every* language version of your solution. For images and videos, prepare them according to our [Tasks Submission Guide](/content-review/submission-guide). Submit these files to the AppInChina team.
  4. **AppInChina Verification**: Our compliance team will review the submitted high-risk content to ensure it adheres to Chinese regulations.
  5. **Revisions (If Necessary)**: If any sensitive or non-compliant content is found, we will provide a detailed report. You must edit the flagged content and resubmit it for verification.
  6. **Written Confirmation & Publication**: Once the content is fully compliant, AppInChina will issue a formal written confirmation of legality, and you may proceed with publishing the update. **Important:** Publishing unverified high-risk DGC without prior written confirmation is a compliance violation.


### 3. Customer-Generated Content (CGC - Private)
This refers to **private or inbound** content sent from a user directly to your team or company, such as private customer support tickets, direct feedback forms, or private 1-on-1 messages to your business.
* **Why it matters**: Because this content is *not* broadcasted to the public, the risk of mass dissemination of illegal content is very low. However, storing or processing illegal content on Chinese servers still carries inherent regulatory risks.
* **Requirement**: While a strict pre-publication review is not legally mandated for private content, **AppInChina highly recommends that CGC be reviewed** using automated methods to ensure content safety and compliance. This protects your company, your support staff, and AppInChina from potential legal or reputational risks.
* **Process**: You have two options for handling CGC:
  * **Option A: Automated Review (Recommended)**
    1. **Integration**: Connect your customer support or feedback channels to the Content Review API.
    2. **Automated Scanning**: The API scans incoming private messages in real-time.
    3. **Internal Routing**: Clean messages are routed to your support team normally. Flagged messages (Medium/High risk) can be blocked, redacted, or quarantined for internal review by your team, protecting your staff and servers from handling illegal content.
  * **Option B: Formal Opt-Out**
    1. **Waiver**: If you prefer not to implement API review for private inbound content, you must formally opt out by acknowledging the associated risks.
    2. **Reactive Management**: If legal issues arise from unmonitored CGC, AppInChina and your team will collaborate to address the concerns immediately. This may require retroactively introducing API-based or manual review processes to your support channels.

---


<!-- source: content-review/pricing.md -->


# Pricing Examples

Pricing will vary depending on the amount of content you are producing and whether or not the review is conducted manually. You can use the [Alibaba Cloud China pricing calculator](https://www.aliyun.com/price/product?spm=a2c4g.11186623.0.0.65831f559tc2Dk#/lvwang/detail/cdibag) (available in Chinese) for estimates. 

Below is a cost breakdown for a 30-minute review, acting as an example:

## Cost Breakdown for a Single 30-Minute Video

**Assumptions:**
* **Video Duration**: 30 minutes (1,800 seconds).
* **Frames Reviewed**: 360 frames (1 frame every 5 seconds).
* **Subtitles**: 250 characters per minute, totalling 7,500 characters per video.

**Cost Components:**
* **Video Image Review**: CNY 0.0015 per frame × 360 frames = CNY 0.54.
* **Audio Review**: CNY 1.35 per hour, prorated for 30 minutes = CNY 0.675.
* **Subtitles Review**: CNY 0.000005 per character × 7,500 characters = CNY 0.0375.

| Component | Calculation (CNY) | Cost (CNY) |
| :--- | :--- | :--- |
| Video Image Review | 360 frames × 0.0015 per frame | 0.54 |
| Audio Review | 1.35 per hour ÷ 2 (30 min) | 0.675 |
| Subtitles Review | 7,500 characters × 0.000005 per character | 0.0375 |
| Total (before tax) | 0.54 + 0.675 + 0.0375 | 1.2525 |
| Tax (6.72%) | 1.2525 × 0.0672 | 0.0842 |
| Total (with tax) | 1.2525 + 0.0842 | 1.3367 |

In this example, the total cost for 1,000 videos would be 1,000 × CNY 1.3367 = **CNY 1,336.70**.

## Other Pricing

* **Manual Review by AppInChina**: Billed at an hourly rate or as a package with a set number of hours for reviewing flagged content.
* **Real-Name Verification**: Required for user-generated content with social functions. Costs range from CNY 0.3 to CNY 0.18 per API call, depending on usage.
* **Discounts**: AppInChina can assist clients in negotiating lower prices with Alibaba Cloud.

---


<!-- source: content-review/sensitive-topics.md -->


# Sensitive Topics Catalog

When filtering your Developer-Generated Content (DGC) for submission, or when reviewing flagged User-Generated Content (UGC), pay special attention to the following high-risk categories. 

The Chinese internet is heavily regulated, and content involving any of the topics below **must** be submitted to AppInChina for review. Failure to properly moderate these topics can result in immediate app suspension or removal from Chinese app stores.

## Sovereignty and Territory
This is one of the most strictly enforced areas of content regulation in China.
* **Maps of China**: Any map displaying China must be officially approved and correctly show all territorial claims, including the nine-dash line in the South China Sea, Taiwan, and the Aksai Chin region.
* **Taiwan, Hong Kong, and Macau**: These must always be represented as regions or special administrative regions of China, **never** as independent countries. Dropdown menus for "Country" should be changed to "Country/Region" if these are included.
* **Tibet and Xinjiang**: Content must not support separatism or independence movements in these regions.

## Politics and Government
* **National Leaders**: Mentions, images, or caricatures of current or former Chinese political figures and national leaders.
* **Government Policies**: Criticism or unauthorized interpretation of national policies, laws, or the Chinese Communist Party (CCP).
* **National Institutions**: Unauthorized use of the national flag, national emblem, national anthem, or military insignia.

## Historical Events
* **Sensitive History**: References to sensitive Chinese historical events, political movements, or protests (e.g., the Cultural Revolution, the 1989 Tiananmen Square protests).
* **Historical Figures**: Defamation or mockery of recognized national heroes or martyrs.

## Regulated Industries & Activities
Content promoting or facilitating illegal or heavily restricted activities in China:
* **Gambling**: Online casinos, sports betting, lotteries, or games of chance involving real money.
* **Cryptocurrency**: Trading, mining, or promoting Bitcoin and other decentralized cryptocurrencies (which are banned in China).
* **Circumvention Tools**: VPNs, proxies, or software designed to bypass the Great Firewall.
* **Financial Services**: Unauthorized lending, peer-to-peer (P2P) lending platforms, or pyramid schemes.

## Cultural and Social Sensitivities
* **Pornography and Obscenity**: Explicit sexual content, nudity, or sexually suggestive material.
* **Violence and Terror**: Content depicting extreme violence, gore, self-harm, or promoting terrorism and religious extremism.
* **Illicit Drugs**: Promotion, sale, or glorification of illegal drugs and narcotics.
* **Superstition and Cults**: Promotion of feudal superstitions, fortune-telling, or banned religious cults (e.g., Falun Gong).
* **Social Disruption**: Content that incites ethnic hatred, discrimination, or disrupts social order and stability.

---


<!-- source: content-review/submission-guide.md -->


# Content Review Tasks Submission Guide

This document outlines the format requirements for submitting content lists for review. Ensuring your files meet these standards will help streamline the review process and avoid delays.

The system supports three types of content for review:
- **Images**
- **Videos**
- **Text**

To ensure smooth processing, please adhere to the formatting guidelines detailed below.

## General Guidelines

- Your submission files must be in **CSV** or **JSON** format.
- Each row (in CSV) or entry (in JSON) represents a separate content review task.
- The **first field must be** `data_id`, a unique identifier you can use to track each content item. While the system does not enforce uniqueness, it is **highly recommended** to use a unique `data_id` for each entry.
- For **image and video** submissions, content must be provided as a **publicly accessible URL** so our system can download and process it.
- For **text** submissions, the content must be included as a text string.
- You may include up to **five metadata fields** per entry to provide additional context.
- **A single file must only contain one type of content** (e.g., all images, all videos, or all text). Mixing different content types in the same file is not allowed.
- **To ensure smooth processing, always provide URLs that use HTTPS for security and reliability.**

## Metadata Fields

You may include up to **5 metadata fields** per entry. These fields can have any name that best suits your needs, but the total number of metadata fields **must not exceed five**. Metadata fields provide additional context for the content being reviewed and should always come after the required fields (`data_id`, `url` or `content`). Examples include:

- `language` (for text content)
- `category` (e.g., political, violence, gambling, illegal activities)
- `priority` (e.g., low, medium, high)
- `tags` (e.g., NSFW, advertisement)
- `custom fields` relevant to your submission

## Image Submission Requirements

### Supported Formats
Your images must be in one of the following formats: PNG, JPG, JPEG, BMP, WEBP, SVG.

### Size & Resolution Limits
- **Maximum file size:** 20 MB
- **Maximum dimensions:** No single dimension can exceed **16,384 pixels**
- **Maximum total pixel count:** **1.67 billion pixels**
- **Recommended minimum resolution:** **200 × 200 pixels** (lower resolutions may reduce the effectiveness of the content security detection algorithm)

### Download Time Limit
- Images must be downloadable within **7 seconds**.
- If an image exceeds this limit, the system will return a **download timeout** error.

### Format Examples

**CSV Format Example:**
```csv
data_id,url,metadata1,metadata2,metadata3
example_img_001,https://your-public-url.com/example_img_001.jpg,tag1,category_a,medium_priority
```

**JSON Format Example:**
```json
{
  "tasks": [
    {
      "data_id": "example_img_001",
      "url": "https://your-public-url.com/example_img_001.jpg",
      "metadata1": "tag1",
      "metadata2": "category_a",
      "metadata3": "medium_priority"
    }
  ]
}
```

## Video Submission Requirements

### Supported Formats
The system accepts video files in the following formats: **MP4, AVI, MOV, WMV, FLV**.

### Size Limit
- The maximum file size for a single video is **500 MB**.
- If your video exceeds this limit, you can either:
  - **Split the video into smaller segments** before submission.
  - **Contact our support team** to discuss adjusting the size limit.

### Download & Processing Time
- The time required for video review depends on the download speed.
- To ensure smooth processing, we recommend storing videos on **high-availability cloud storage services**.

### Format Examples

**CSV Format Example:**
```csv
data_id,url,metadata1,metadata2,metadata3
example_vid_001,https://your-public-url.com/example_vid_001.mp4,tag1,category_b,high_priority
```

**JSON Format Example:**
```json
{
  "tasks": [
    {
      "data_id": "example_vid_001",
      "url": "https://your-public-url.com/example_vid_001.mp4",
      "metadata1": "tag1",
      "metadata2": "category_b",
      "metadata3": "high_priority"
    }
  ]
}
```

## Text Submission Requirements

### Format Examples

**CSV Format Example:**
```csv
data_id,content,language,category
text_001,"This is an example text for review.",en,social_media
text_002,"Another example comment that requires moderation.",en,comments
```

**JSON Format Example:**
```json
{
  "tasks": [
    {
      "data_id": "text_001",
      "content": "This is an example text for review.",
      "language": "en",
      "category": "social_media"
    },
    {
      "data_id": "text_002",
      "content": "Another example comment that requires moderation.",
      "language": "en",
      "category": "comments"
    }
  ]
}
```

## Summary of Submission Requirements

| Content Type | Required Fields |
| --- | --- |
| **Video** | `data_id`, `url` (public) |
| **Image** | `data_id`, `url` (public) |
| **Text** | `data_id`, `content` |

- Metadata fields (max 5) should always follow the required fields.
- URLs for images and videos must be **publicly accessible**.
- Text content should be in **UTF-8 encoding**.
- CSV files must use **comma separators**.
- JSON files must follow **standard JSON syntax**.
- **Each file must contain only one content type (Image, Video, or Text).**

---

