# Create Change Request
The merchant business system initiates an upgrade (UPGRADE) or downgrade (DOWNGRADE) of a user's subscription plan via the Create Change Request API. The change uses a two-phase confirmation model: this API only creates a change reservation and generates a cashier confirmation link. The actual change is executed only after the user confirms on the cashier page.
# API Description
API
Request API: /api/subscription/change/create
Request Method: POST
Request Type: application/json or application/x-www-form-urlencoded
# Request Parameters
| Field Name | Variable Name | Required | Type | Example Value | Description |
|---|---|---|---|---|---|
| Merchant No | mchNo | Yes | String(30) | M1621873433953 | Merchant Number |
| App ID | appId | Yes | String(24) | 60cc09bce4b0f1c0b83761c9 | App ID |
| Subscription ID | subscriptionId | Yes | String(32) | SUB_20210618164232 | Subscription ID to be changed |
| Target Plan ID | newPlanId | No | String(32) | PLAN_002 | Target subscription plan ID for upgrade/downgrade; mutually exclusive with newPlanCode |
| Target Plan Code | newPlanCode | No | String(64) | PRO_MONTH | Target subscription plan code for upgrade/downgrade; mutually exclusive with newPlanId |
| Change Type | changeType | Yes | String(20) | UPGRADE | Change type: UPGRADE / DOWNGRADE |
| Effective Type | effectiveType | No | String(20) | IMMEDIATE | Effective type: IMMEDIATE / NEXT_PERIOD. Optional for downgrade (defaults to NEXT_PERIOD); required for upgrade |
| Change Return URL | returnUrl | No | String(256) | https://merchant.com/changeReturn | Change-level return URL for cashier cancel/supplement redirect.
Notification URL reuses the subscription-level notifyUrl |
| Request Time | reqTime | Yes | long | 1622016572190 | Request timestamp (13 digits) |
| API Version | version | Yes | String(3) | 1.0 | API version, fixed: 1.0 |
| Sign | sign | Yes | String(32) | C380BEC2BFD727A4B6845133519F3AD6 | Signature value, see signature algorithm |
| Sign Type | signType | Yes | String(32) | MD5 | Signature type, currently only supports MD5 |
# Request Example Data
{
"mchNo": "M1623984572",
"appId": "60cc09bce4b0f1c0b83761c9",
"subscriptionId": "SUB_20210618164232",
"newPlanId": "PLAN_002",
"changeType": "UPGRADE",
"effectiveType": "IMMEDIATE",
"returnUrl": "https://merchant.com/changeReturn",
"reqTime": "1622016572190",
"version": "1.0",
"signType": "MD5",
"sign": "84F606FA25A6EC4783BECC08D4FDC681"
}
Target Plan Parameter
Provide either newPlanId or newPlanCode. The example uses newPlanId; merchants may instead pass newPlanCode (e.g. "newPlanCode": "PRO_MONTH") to identify the target plan — the system resolves it to the corresponding planId using the subscription's mchNo/appId/currency.
# Response Parameters
| Field Name | Variable Name | Required | Type | Example Value | Description |
|---|---|---|---|---|---|
| Return State | code | Yes | int | 0 | 0-Success, others-Error, see error codes |
| Return Msg | msg | No | String(128) | Signature failed | Specific error reason |
| Sign Info | sign | No | String(32) | CCD9083A6DAD9A2DA9F668C3D4517A84 | Signature for data |
| Return Data | data | No | Object | {} | Returned change data |
# Data Format (SubscriptionChangeRS)
| Field Name | Variable Name | Type | Example Value | Description |
|---|---|---|---|---|
| Change ID | changeId | String | CHG_20210618164201 | Unique change record ID, used for subsequent confirm/query/reconciliation |
| Diff Amount | diffAmount | Long | 1500 | Difference in cents, computed from new vs original plan proration; positive means supplement required at confirmation for immediate upgrade |
| Currency | currency | String | USD | Subscription currency, pair with diffAmount for amount display |
| Cashier Confirm URL | confirmUrl | String | https://cashier.enjoypayment.com/change/CHG_xxx/TOKEN | Cashier link guiding user to confirm the change, expires after 1 hour |
| Change State | changeState | Integer | 0 | 0-Pending, 1-Effective, 2-Canceled, 3-Failed |
| Replaced Change ID | replacedChangeId | String | CHG_20210618160001 | Returned when an unconfirmed old change is auto-replaced on creation, for reconciliation |
# Response Example Data
{
"code": 0,
"msg": "SUCCESS",
"data": {
"changeId": "CHG_20210618164201",
"diffAmount": 1500,
"currency": "USD",
"confirmUrl": "https://cashier.enjoypayment.com/change/CHG_20210618164201/a1b2c3d4-e5f6",
"changeState": 0
},
"sign": "F4DA202C516D1F33A12F1E547C5004FD"
}
# Business Rules
Note
- Subscription State: Only
ActiveorOverduesubscriptions can initiate a change. - Target Plan: Must be in PUBLISHED state, and belong to the same app (appId), merchant (mchNo), and currency as the current subscription. Changing to the same current plan is not allowed.
- Upgrade (UPGRADE):
effectiveTypeis required.- Immediate (IMMEDIATE): Prohibited when less than 24 hours remain in the current period; diff amount must be greater than 0; the subscription must have a bound payment method (paymentMethodToken). A supplement pay order is created on confirmation and charged; the plan switches after successful payment.
- Next Period (NEXT_PERIOD): Writes the pending plan on confirmation and switches at the next renewal deduction.
- The target plan amount must be higher than the current (dual validation on first phase and landing tier).
- Downgrade (DOWNGRADE): Only supports next period (NEXT_PERIOD); passing IMMEDIATE is rejected. The target plan amount must be lower than the current.
- Cross-subscription plan occupation: The system checks whether the target plan is already occupied by another subscription of the same user (active subscription, unconfirmed change, confirmed next-period change); changes are rejected if occupied.
- Concurrent replacement: If an unconfirmed pending change exists, the new change auto-cancels and replaces the old one (returns
replacedChangeId; the old change receives aSUBSCRIPTION_CHANGE_CANCELEDnotification). If a confirmed immediate change is in-flight (funds in transit), creation is rejected.
# Change Flow
1. Merchant calls [Create Change Request] → obtains changeId + confirmUrl
2. Guide user to open confirmUrl (cashier confirm page)
├─ User confirms → [Confirm Change] executes the actual change
└─ User cancels → [Cashier Cancel Change] cancels the reservation
3. Change result is asynchronously notified via [Subscription Notification]
Tip
The confirmation link is valid for 1 hour. After expiration, a new change request must be initiated. Unconfirmed changes are automatically cleaned up by the system after expiration.