API Create plan
Endpoint: /api/v1/subs/plans
Method: POST
Header Params
| Param | Required | Type | Description | Note | 
|---|---|---|---|---|
| X-APPOTAPAY-AUTH | required | String | How to generate JWT_TOKEN | |
| Content-Type | required | String | Value: application/json | |
| X-Request-ID | optional | String | UUIDv4 format. Request ID to check when a problem occurs | max:42 | 
| Language | optional | String | The value vi or en corresponding to the payment link will be Vietnamese or English, (default: vi) | in:vi,en  | 
| X-Account-Ref-ID | optional | String | Iidentifier of the sub account provided by AppotaPay. Mandatory be passed over when processing payment for transactions of owner-type sub account  | 
{
    "X-APPOTAPAY-AUTH": "JWT_TOKEN",
    "Content-Type": "application/json",
    "X-Request-ID": "Your_Unique_id",
    "Language": "vi",
    "X-Account-Ref-ID": "9723f73b-9295-4acb-884b-ab6310c2e653"
}
Request params
| Param | Required | Type | Description | Note | 
|---|---|---|---|---|
| planRefId | Required | String | Unique reference code of partner. Partner-provided identifier for the plan. Requests with a duplicate planRefId will return an error.  | min:1, max: 50, format: alphanumeric | 
| customerId | Required | String | Customer ID | |
| currency | Required | String | Currency unit | in: VND | 
| amount | Required | Integer | Payment amount | min: 5000, max: 100000000 | 
| country | Conditional, if paymentMethods doesn't have information | String | Country code of transaction Accepted value - ID: Indonesia - PH: Philippines - VN: Vietnam - TH: Thailand - MY: Malaysia  | Format ISO 3166-2 Country Code | 
| returnUrl | Conditional, if paymentMethods doesn't have information | String | URL where the end-customer is redirected AppotaPay will send the result via the URL with some parameters like this: LINK  | |
| paymentMethods | Optional | Array | Payment method list (Only show if the integration model is Merchant hosted)  | |
| paymentMethods.*.paymentMethodId | Optional | String | Payment method ID | |
| paymentMethods.*.rank | Optional | Integer | Indicate the order which payments methods will be attempted for a payment cycle instance. Available values - 1 to 5 | min: 1 | 
| paymentLinkForFailedAttempt | Optional | String | Receive payment link in the webhook if payment cycle fails - YES: receive payment link - NO: do not receive payment links  | default: NO, in: YES,NO | 
| immediateActionType | Optional | String | Charge immediately when successfully creating the plan, null: charge at anchorDate time - FULL_AMOUNT: charge when successfully initializing the plan  | in: FULL_AMOUNT | 
| failedCycleAction | Required | String | Action of plan when the payment cycle fails - STOP: Stop the plan - RESUME: Skip the failed cycle and proceed to the next cycle  | in: STOP, RESUME | 
| serviceName | Optional | String | Service name of subscription plan (Only show if the integration model is Checkout Page)  | max:30 | 
| schedule | Required | Object | Object containing the configurations of how Subscriptions cycles will be scheduled | |
| schedule.interval | Required | String | The type of interval between consecutive Subscriptions cycles. | in: DAY, WEEK, MONTH | 
| schedule.intervalCount | Required | Integer | The number of units of interval between consecutive Subscriptions cycles | min: 1 | 
| schedule.totalRecurrence | Optional | Integer | The total number of times the end user will be charged If the parameter is not used, Subscriptions plan will run on indefinitely  | min: 1 | 
| schedule.anchorDate | Optional | String | Time to make recurring payments Default: the date of schedule creation Supported values: Timestamps between 1st to 28th of a month Note: if anchorDate is null or date of schedule creation falls on 29/30/31, anchor date will be defaulted to 1st of next month  | format: ISO-8601 | 
| schedule.retryInterval | Conditional, required if paymentLinkForFailedAttempt = 'YES' | String | The type of interval between failed attempt and retries. | in: DAY | 
| schedule.retryIntervalCount | Conditional, required if paymentLinkForFailedAttempt = 'YES' | Integer | The number of times you will retry a failed Subscriptions cycle. If no value is passed into | min:1 | 
| schedule.totalRetry | Conditional, required if paymentLinkForFailedAttempt = 'YES' | Integer | The number of times you will retry a failed Subscriptions cycle. If no value is passed into total_retry, it will be null by default and no retries will be triggered  | min:1, max: 10 | 
| notificationConfig.[subscription.cycle.retrying] | Optional | Array | Specify which channel you want to notify your customer through when the cycle is unsuccessful, so it's necessary to attempt the next time Accepted value ["EMAIL"]  | |
| notificationConfig.[subscription.cycle.succeeded] | Optional | Array | Specify which channel you want to notify your customer through when the cycle is successfully completed Accepted value ["EMAIL"]  | |
| notificationConfig.[subscription.cycle.failed] | Optional | Array | Specify which channel you want to notify your customer through when the cycle failed Accepted value ["EMAIL"]  | |
| notificationConfig.[subscription.plan.activated] | Optional | Array | Specify which channel you want to notify your customer through when the subscription plan is activated Accepted value ["EMAIL"]  | |
| notificationConfig.[subscription.plan.inactivated] | Optional | Array | Specify which channel you want to notify your customer through when the subscription plan is inactivated Accepted value ["EMAIL"]  | |
| currencyExchange | Optional | Object | ||
| currencyExchange.amount | Optional | Number | Exchange amount Supports 2 decimals, eg: 12.02  | min: 0.10, max: 9999999999 | 
| currencyExchange.currency | Optional | String | Currency unit Support: USD  | 
Example Request
{
    "planRefId": "ASKJLKALK299",
    "customerId": "01HRVGAJSP7SX83X7AQ9QQYMBE",
    "currency": "VND",
    "amount": 85000,
    "paymentMethods": [
        {
            "paymentMethodId": "01HRVJY8ZMZFHRHE3KG2S24KKW",
            "rank": 1
        }
    ],
    "immediateActionType": "FULL_AMOUNT",
    "failedCycleAction": "STOP",
    "schedule": {
        "interval": "DAY",
        "intervalCount": 1,
        "totalRecurrence": 3,
        "anchorDate": "2024-01-13T15:23:40+07:00",
        "retryInterval": "DAY",
        "retryIntervalCount": 1,
        "totalRetry": 1
    }
}
Response data
Success
Http Status Code
200-OK
Success responses will contain a single Plan object
Failure
HTTP Status Code !=
200
Error response params
| Param | Required | Type | Description | 
|---|---|---|---|
| errorCode | required | Integer | Error code | 
| message | required | String | Error message | 
| errors | optional | Array | Detailed error description | 
| errors.*.field | optional | String | Field data is corrupted | 
| errors.*.reason | optional | String | Description of the data field in error | 
{
    "errorCode": 1,
    "message": "Missing or Invalid Params",
    "errors": [
        {
            "field": "planRefId",
            "reason": "The plan ref id field is required."
        }
    ]
}
Common error code table
Full error code, please check this error code list
| Error code | Description | 
|---|---|
| 0 | Success | 
| 1 | Missing or Invalid Params | 
| 11 | Partner is not found | 
| 13 | Partner has been blocked | 
| 14 | API Key is invalid | 
| 15 | API Key is not activated or blocked | 
| 92 | IP is not allowed to access | 
| 99 | Undefined error, please contact AppotaPay for more detailed information | 
| 401 | Unauthorized | 
| 500 | Server error | 
| 3002 | Duplicate reference code of partner, please try again | 
| 3003 | Customer not exist | 
| 3004 | Payment method not exist | 
| 3012 | Payment method is invalid |