The BSS API allows an external system to issue and activate various types of orders to perform certain commercial operations, including the creation and cancellation of subscriptions, ordering of more resources, and so on.
In this document:
The platform uses the OrderManagementApplication APS type to create a singleton APS resource presenting the order management service that provides several custom operations to manage orders in BSS. This document covers the following custom operations:
orderInfo
: gets a list of orders or some data of a specified order by sending a GET request.
placeOrder
: creates an order by sending a POST request. The type of a new order
must be specified by the mandatory type
property in the request body.
estimateOrder
: allows the provider or a reseller to estimate price details of an order without placing that
order.
estimateCosts
: enables a reseller to estimate the cost of an order without placing that order.
termsConditions
: returns a list of Terms and Conditions that a customer must accept when purchasing
specified service plans.
reasonCodes
: gets a list of pre-defined reasons to be used in a cancellation order.
The APS controller returns the APS ID of the new order if the request is processed successfully,
regardless of the order type in a placeOrder
request. For example:
{
"orderId": "f0817852-282c-4047-a4d3-f6501939d5a6"
}
A sales order is the only order type that creates a subscription from a service plan for a specified customer.
In a POST request body, this is defined as "type":"SALES"
.
The procedure consists of the following steps:
Identify a customer. Find the APS ID of the account that you want to subscribe to the selected service plans.
Identify service plans. Find the APS IDs of the required service plans, subscription periods, and add-on resources to purchase.
Identify a payment method. From the available payment methods that the chosen account owns, select the one that will be applied to the new order.
Create a sales order. Request a new sales order with input parameters discovered in the previous steps. If everything is OK, the platform creates a sales order and starts the order processing.
Verify the order status. Get the order details to verify if the ordered services are provisioned for the customer.
There are several order types that change a subscription. In a POST request body, an order type is specified by
the type
property:
RENEWAL: creates a renewal order for a specified subscription and starts the renewal process for the next subscription period.
CHANGE: creates a change order to switch a subscription to another period of a specified service plan or to change resource limits in the subscription.
CANCELLATION: creates a cancellation order to cancel a specified subscription.
Since the main object in those orders is an existing subscription, the order management sequence is slightly different from the case with a sales order.
The procedure consists of the following steps:
Identify a customer. Find the APS ID of the account whose subscription to be changed.
Identify a subscription. Find the APS ID of the subscription to be changed, and, if necessary, the subscription period to be changed.
Identify a payment method. From the available payment methods that the chosen account owns, select the one that will be applied to the new order.
Create an order. Request a new order with the input parameters discovered in the previous steps. If everything is OK, the platform creates the order and starts the order processing.
Verify the order status. Get the order details to verify if the ordered updates in the specified subscription are completed.
To be able to call the above-mentioned custom operations, an external system must be authorized to use the GET
and
POST
methods on the OrderManagementApplication APS type whose APS ID is
http://www.odin.com/billing/order-management
. To add this permission, follow the instructions in
the Set Up the User’s Credentials section.
After an order that requires payment from an account (a customer or reseller) is placed in BSS, the latter starts the order processing, which consists of at least the following two phases:
Order payment.
This phase requires the account to have an automated payment method, for example, a bank card. The paymentMethodId
property, if used, specifies a payment method explicitly. Otherwise, the platform will seek the default
payment method (marked as Auto Payments) for that account. When you verify
an order status, pay attention to the returned paymentStatus
property that
shows whether the order is payed for or there are any issues with it.
Warning
If the platform cannot find a relevant payment method, it places the required order without a payment attached.
Order provisioning.
BSS creates a subscription and requires the provisioning system, usually OSS, to perform a required operation,
for example, provisioning of the services marked as “auto-provisioning”. When you verify
an order status, pay attention to the returned provisioningStatus
property that
shows whether the ordered services were provisioned successfully or whether there were any issues with it.
When creating an order, it might be necessary to pass the following optional properties:
paymentMethodId
is the platform internal ID of a payment method belonging to the customer for whom an order
is requested. This method will be used to pay for the requested order. If this property is omitted, the platform will be
seeking a method declared as the default for the customer.
attributes
is an array of BSS specific order attributes preliminary configured by the provider as custom attributes
in the platform. Each entry is a pair of attributeID
and value
properties. If an attribute is configured to be
propagated to subscriptions and an updated value for this attribute is passed with a change, renewal or cancellation order,
then this attribute will be updated on the subscription as well.
parameters
is used to initialize properties of resources that are created during the processing of a sales
or change order. Send parameters
if your sales or change order creates resources whose parameters must be
initialized at the provisioning stage.
changeParameters
is used to update properties of existing resources during the processing of a change order.
Send changeParameters
if you need to update some properties of existing resources during the processing of your change order.
upgradeStartType
is used to specify which subscription period start date is set when placing a change order that
switches a subscription from one service plan to another or from one subscription period to another within
the same service plan.
Depending on the order type, an external system must preliminary collect the following data before sending REST requests:
The following properties of the service plan if you want to order it:
The APS ID of the service plan
A subscription period identified by its length consisting of the measurement unit, typically “MONTHS” or “YEARS”, and the number of the units
The APS ID of the resources if you want to order more of those resources than the service plan includes
The APS ID of the account if you want to subscribe the latter to a service plan
The APS ID of the subscription if you want to manage a subscription, for example, to renew, switch or cancel it
Identify an account that you want to subscribe to service plans or an account whose subscription you are going to change.
An order must specify the APS ID of the account to be subscribed to service plans or the account whose subscription must be changed.
Find the APS ID of the account as explained in the Account Lookup section, for example:
GET /aps/2/collections/accounts?eq(id,1000001)
Pay attention to the aps
section in the response:
HTTP/1.1 200 OK
[{
"aps": {
"id": "3fef9702-b2ad-419a-9924-a56882e5f06c",
"type": "http://parallels.com/aps/types/pa/account/1.2",
"status": "aps:ready",
/* ... */
},
/* ... */
}]
If you want the order to be paid for automatically, ensure the account has an automatic payment method such as a bank card, configured as the default method (marked as Auto Payments):
Note
If a request for order creation does not specify a payment method, the order management service will try to apply the payment method configured as default (marked as Auto Payments). This requires the customer to have a payment method configured as default.
To subscribe an account to service plans, identify them first.
Get a list of service plans as explained in the Service Plans section, for example:
GET /aps/2/collections/service-plans
In the response, find the service plans and subscription periods you want to order as well as the resources that you can buy in addition to the included amount:
HTTP/1.1 200 OK
[
/* ... */
{
"aps": {
"id": "ae0e6e84-0d37-4b17-8f6c-5709633529ab",
"type": "http://www.odin.com/billing/ServicePlan/1.0",
"status": "aps:ready",
/* ... */
},
"name": {
"en_US": "Offer-Counter-User Management Project"
},
"billingTerms": {
"pricingModel": "PM_FIXED_PRICE",
"period": {
"duration": 1,
"unit": "MONTHS"
},
"autorenewal": {
"days": 0,
"type": "DISABLED"
},
"model": "CHARGE_BEFORE_BILLING_PERIOD",
"recurringPricesEvery": "MONTH"
},
"subscriptionPeriods": [
{
"autoRenewalPeriod": {
"unit": "MONTHS",
"duration": 1
},
"numberOfBillingPeriods": 1,
"trial": false,
"defaultPeriod": false,
"fees": {
"setup": {
"price": {
"value": "10.0",
"code": "USD"
},
/* ... */
},
"recurring": {
"price": {
"value": "4.25",
"code": "USD"
},
/* ... */
},
"renewal": {
"price": {
"value": "0.0",
"code": "USD"
},
/* ... */
},
"deposit": { /* ... */ },
},
"refund": { /* ... */ }
},
/* ... */
],
"resourceRates": [
{
"resourceId": "1c3ab0be-3160-45a1-a9b4-7824f74673ff",
/* ... */
"units": {
"included": 20.0,
"min": 0.0,
"max": -1.0
},
"fees": {
"setup": {
"price": {
"value": "0.0",
"code": "USD"
},
/* ... */
},
"recurring": {
"price": {
"value": "1.5",
"code": "USD"
},
"chargePerUnit": true,
/* ... */
}
},
/* ... */
},
{
"resourceId": "7205fd93-9768-480c-956b-58f54aac7247",
/* ... */
"units": {
"included": 10.0,
"min": 0.0,
"max": -1.0
},
"fees": {
"setup": {
"price": {
"value": "0.0",
"code": "USD"
},
/* ... */
},
"recurring": {
"price": {
"value": "1.5",
"code": "USD"
},
"chargePerUnit": true,
/* ... */
}
},
/* ... */
},
/* ... */
],
/* ... */
},
/* ... */
]
The returned service plan representation contains the APS ID (aps.id
) of the plans as well as the subscription periods
identified by the measurement unit (subscriptionPeriods.autoRenewalPeriod.unit
) and the number of the units
(subscriptionPeriods.autoRenewalPeriod.duration
). A list of resource rates allows a customer
or a system to order more amount of resources than the service plan includes.
Find a payment method to pay for a new order.
Get a list of the payment methods owned by the account as explained in the Get Payment Methods section, for example:
GET /aps/2/services/payment-method-manager/paymentMethods?accountId=3fef9702-b2ad-419a-9924-a56882e5f06c
In the response, find the id
property of the payment method to be applied to the new order:
[
{
"id": 3,
"paymentSystemId": "Demo.Redirect",
"paymentSystem": "Demo Payment Gateway",
"ownerAccountId": null,
"number": null,
"name": "Demo Payment Gateway",
"type": "EXTERNAL",
"perCustomer": false,
"status": "ACTIVE",
"ratified": "NOT_REQUIRED",
"defaultMethod": true
},
{
"id": 0,
"paymentSystemId": "Check/Cash",
"paymentSystem": "Check/Cash",
"ownerAccountId": null,
"number": null,
"name": "Check/Cash",
"type": "MANUAL",
"perCustomer": false,
"status": "ACTIVE",
"ratified": "NOT_REQUIRED",
"defaultMethod": false
}
]
Since service plans are generally accompanied by certain terms and conditions that must be accepted by a customer, a requester can get the contents of those terms and conditions before subscribing that customer to the service plan. The request must contain the APS IDs of the service plans and the customer as in the following example:
POST /aps/2/services/order-manager/orders/termsconditions
{
"type": "SALES",
"accountId": "3fef9702-b2ad-419a-9924-a56882e5f06c",
"products": [
{
"planId": "ebf17799-6a39-4133-ab9c-0afa40dcd6ae",
"period": {
"unit": "MONTHS",
"duration": 1
}
}
]
}
If the requested terms and conditions are included, the platform returns their IDs and contents:
[
{
"termId": "1",
"name": "Terms and Conditions",
"content": "<h1>Cloud SaaS</h1>\r\n<h2>Introduction</h2>\r\n
Lorem ipsum ut porttitor sagittis.\r\n
<h2>Intellectual Properties</h2>\r\n
Convallis interdum porttitor ante hendrerit.\r\n
<h2>Restrictions</h2>\r\n
Ac auctor duis curae magna."
}
]
When placing a sales order to subscribe a customer to the service plans, the request must confirm the acceptance of the respective terms and conditions.
To subscribe a customer to a list of service plans, an external management system must request the creation of a sales order in the platform.
In a request, specify the parameters you have collected in the previous steps. Optionally, the request can contain the following groups of properties:
If you want your customer to have more resources than assigned by the units.included
values in
the resourceRates
array of a service plan, add the resources
array containing a pair of the APS ID and
total amount for every such resource.
To pass the activation parameters required by the ordered application services, add them to the parameters
array.
To assign order attributes, send those attributes in the attributes
array.
To accept the terms and conditions required by the service plans, send the acceptedTerms
array containing the IDs
of the accepted terms and conditions.
The following example illustrates how to subscribe a specified customer to a list of specified service plans and demonstrates a request for an extended amount of a resource:
POST /aps/2/services/order-manager/orders
{
"type": "SALES",
"accountId" : "3fef9702-b2ad-419a-9924-a56882e5f06c",
"promoCode": "123",
"paymentMethodId": "3",
"products" : [{
"planId" : "ae0e6e84-0d37-4b17-8f6c-5709633529ab",
"period" : {
"unit" : "MONTHS",
"duration" : 1
},
"resources" : [{
"resourceId" : "1c3ab0be-3160-45a1-a9b4-7824f74673ff",
"amount" : 40
}],
"parameters": [
{
"aps": {
"type": "http://aps-standard.org/samples/vpsdemo/management/1.0"
},
"client": "1st APS, inc.",
"mail": "jsmith@aps.test"
}
],
"childProducts": [
{ // Another service plan - upsell
}
]
},
{ // Another service plan
}
],
"attributes": [
{
"attributeID": "comments",
"value": "Requested by the ERP system."
}
],
"acceptedTerms": [
"1"
],
"dealPrices" : { // See the "Set Special Prices in a Sales Order" section for details
}
}
Key:
For every service plan specified in the request, a separate subscription must be created on completion of the order processing.
In the resources
set, a required resource amount
must be higher than the included
amount of
the resource, since the former includes the latter plus the additional amount.
An entry in the parameters
array contains a set of properties required by an auto-provisioning APS resource
whose APS type is specified by the aps
section.
Refer to the Set Special Prices section for details about special prices.
The response must contain the APS ID of the created order, as specified earlier in the APS Type and Operations section.
If all is configured correctly, the platform will process the created sales order, including:
Order payment
Creation of the customer subscription
Provisioning of the services
In BSS, you can verify if a subscription is created from the requested service plan for the specified account:
The total amount of the ordered resource in the subscription is the same as requested (20):
To get the APS IDs of the subscriptions related to a particular order, refer to the Get List of Orders process.
To change a subscription, find its APS ID, subscription period and resources to be changed.
Note
Typically, subscription services are provisioned by OSS (one of exceptions are subscriptions providing the reseller status). In this case, the platform keeps two coupled subscriptions: one in OSS (OSS subscription) and the other in BSS (BSS subscription). Use the APS ID of the latter when managing these subscriptions through the orders.
You can search for a subscription in various ways, as shown in the following examples.
Get the full list of subscriptions:
GET /aps/2/collections/bss-subscriptions
Get all subscriptions of a customer using the subscriptions
link of the account
APS type:
GET /aps/2/collections/bss-subscriptions?eq(account.aps.id,d7dd06ef-20a0-41f5-b89f-768ef373ae44)
Find the subscription you want to process (for example, to renew or cancel) in the response that will look similar to the following:
HTTP/1.1 200 OK
[
{
"aps": {
"id": "456808a0-b5a6-4092-ab67-b77e33743a07",
"type": "http://www.odin.com/billing/Subscription/1.0",
"status": "aps:ready",
/* ... */
},
"billingTerms": {
"billingPeriod": {
"duration": 1,
"unit": "MONTHS"
},
"billingModel": "CHARGE_BEFORE_BILLING_PERIOD",
"freezePrices": false,
"autoRenewal": {
"type": "DISABLED"
}
},
"serviceGate": "PEMGATE",
"trial": false,
"nextBillDate": "2019-04-12",
"subscriptionPeriod": {
"duration": 1,
"unit": "MONTHS"
},
"serviceStatus": "ACTIVE",
"name": "VPS Demo Services",
"lastBillDate": "2019-03-12",
"subscriptionId": 1000001,
"autoRenewEnabled": false,
"startDate": "2019-03-12",
"expirationDate": "2019-04-12",
"status": "ACTIVE"
} /*,
...other subscriptions */
]
When a subscription is close to its expiration date, the platform will renew it automatically for the next subscription period if the subscription configuration inherited from the service plan allows it. Alternatively, a staff member or an external management system can renew the subscription period including the upgrade of the subscription from a trial to a paid period.
To renew a subscription, an external management system must call the placeOrder
custom operation as in the
following example:
POST /aps/2/services/order-manager/orders
{
"type": "RENEWAL",
"subscriptionId": "456808a0-b5a6-4092-ab67-b77e33743a07",
"paymentMethodId": "11",
"period": {
"unit": "MONTHS",
"duration": 1
},
"attributes": [
{
"attributeID": "comments",
"value": "Requested by the ERP system."
}
]
}
Note
The period
structure is needed only if you are going to change the period, otherwise the subscription will be
renewed for the next period equal the current period.
The response must contain the APS ID of the created order, as specified earlier in the APS Type and Operations section.
A change order allows a requester to switch a subscription and change resource limits in a subscription as explained in the following two sections.
Note
A change request can combine both of the above operations: switching a subscription and changing resource limits.
The platform allows a customer to switch a subscription from their current service plan to another one or to another
subscription period within the current service plan. Alternatively, an external management system can call
the placeOrder
custom operation to start a switching process.
POST /aps/2/services/order-manager/orders
{
"type": "CHANGE",
"subscriptionId": "456808a0-b5a6-4092-ab67-b77e33743a07",
"planId": "ae0e6e84-0d37-4b17-8f6c-5709633529ab",
"paymentMethodId": "11",
"period": {
"unit": "MONTHS",
"duration": 3
},
"parameters": [
{
"aps": {
"type": "http://aps-standard.org/samples/vpsdemo/management/1.0"
},
"client": "1st APS, inc.",
"mail": "jsmith@aps.test"
}
],
"attributes": [
{
"attributeID": "comments",
"value": "Requested by the ERP system."
}
]
}
If successful, the response contains the APS ID of the created order, as specified earlier in the APS Type and Operations section.
When placing a change order that switches a subscription from one service plan to another or from one subscription
period to another within the same service plan, you can use the upgradeStartType
parameter to specify
which start date is set for the new subscription period of that subscription: the start date of the old subscription
period (FROM_OLD_START_DATE) or the date this change order is placed (FROM_DATE_OF_UPGRADE). If you do not use
this parameter, the start date is set depending on your billing configuration.
Example:
POST /aps/2/services/order-manager/orders
{
"type": "CHANGE",
"subscriptionId": "1f8538a3-8679-449e-a9b9-f249ae496df3",
"planId": "ae48fbb2-76f1-4dc9-9241-3b8420b0fa9e",
"period": {
"unit": "MONTHS",
"duration": 3
},
"upgradeStartType": "FROM_OLD_START_DATE"
}
To buy an additional amount of resources within a subscription, an external management system can call
the placeOrder
custom operation as in the following example:
POST /aps/2/services/order-manager/orders
{
"type": "CHANGE",
"subscriptionId": "4c867c87-fbf7-49e8-9f7e-0d06e8f7a003",
"paymentMethodId": "11",
"resources": [
{
"resourceId": "bf8ea705-3f2b-4f3c-b445-a11ec100da82",
"amount": 10
}
],
"changeParameters": [
{
"aps": {
"type": "http://vendor.example.com/app/dropboxbusiness/team"
},
"deal_id": "new_deal_id_value",
}
],
"attributes": [
{
"attributeID": "comments",
"value": "Requested by the ERP system."
}
]
}
Every entry in the resources
array corresponds to a resource rate in the respective service plan and consists of
the resource APS ID and a new limit (amount
) for the resource.
If successful, the response contains the APS ID of the created order, as specified earlier in the APS Type and Operations section.
A cancellation order is used to request the termination of a subscription.
If there is unused time, the subscriber’s balance must be adjusted by the refundType
property:
"refundType":"CREDIT_MEMO"
- create a credit memo to be used by the subscriber to pay for other services.
"refundType":"REFUND"
- refund directly using the specified payment method.
To cancel a subscription, an external management system must call the placeOrder
custom operation as
in the following example:
POST /aps/2/services/order-manager/orders
{
"type": "CANCELLATION",
"subscriptionId": "456808a0-b5a6-4092-ab67-b77e33743a07",
"refundType": "CREDIT_MEMO",
"attributes": [
{
"attributeID": "comments",
"value": "Requested by the ERP system."
}
]
}
If successful, the response must contain the APS ID of the created order, as specified earlier in the APS Type and Operations section.
If the customer must be paid for the unused period of time, whether by creating a credit memo or by refund, the new
cancellation order will be in the “New” status waiting for further action. If you request
the Get Order Details, pay attention to the ofStatus
(order flow status) property in the response;
it will be "NW"
. In the BSS control panel, the canceled subscription must look as follows:
To continue the normal order processing and make it finally “completed”,
the external system must open the order by sending a push
request for the order to transition to the "OP"
status (meaning “Open” status) as in the following example:
POST /aps/2/services/order-manager/orders/4449abb3-f760-4bd8-98cc-c8e36352c3a7/push
{
"ofStatus": "OP"
}
If successful, the response only contains the header HTTP/1.1 200 OK (without body). If you request the
order details, the returned order flow status will be "ofStatus":"CP"
(“Completed”).
The respective subscription is now terminated.
When a customer or their sales vendor cancels a subscription in a user panel (whether in the reseller or customer panel), they must choose a reason for this operation. A reason is selected from the list of available reasons configured in the platform by the provider.
An external system can request the platform to provide the list of possible reasons for all operations or for a specific one as in the following examples.
Get the full list of the configured reasons:
GET /aps/2/services/order-manager/reasonCodes
The response will be as follows:
HTTP/1.1 200 OK
[
{
"reasonId": 1,
"description": {
"en_US": "Customer Request"
},
"operationType": "START_SERVICE"
},
{
"reasonId": 2,
"description": {
"en_US": "Released from Credit Hold"
},
"operationType": "START_SERVICE"
},
{
"reasonId": 3,
"description": {
"en_US": "Other"
},
"operationType": "START_SERVICE"
},
{
"reasonId": 4,
"description": {
"en_US": "Not Applicable"
},
"operationType": "START_SERVICE"
},
{
"reasonId": 5,
"description": {
"en_US": "Customer Request"
},
"operationType": "STOP_SERVICE"
},
{
"reasonId": 6,
"description": {
"en_US": "Fraud"
},
"operationType": "STOP_SERVICE"
},
{
"reasonId": 7,
"description": {
"en_US": "Account overdue"
},
"operationType": "STOP_SERVICE"
},
{
"reasonId": 8,
"description": {
"en_US": "AUP Violation"
},
"operationType": "STOP_SERVICE"
},
{
"reasonId": 9,
"description": {
"en_US": "Other"
},
"operationType": "STOP_SERVICE"
},
{
"reasonId": 10,
"description": {
"en_US": "Not Applicable"
},
"operationType": "STOP_SERVICE"
},
{
"reasonId": 17,
"description": {
"en_US": "Cost"
},
"operationType": "CANCEL_BY_CUSTOMER"
},
{
"reasonId": 18,
"description": {
"en_US": "Poor Performance"
},
"operationType": "CANCEL_BY_CUSTOMER"
},
{
"reasonId": 19,
"description": {
"en_US": "Poor Service"
},
"operationType": "CANCEL_BY_CUSTOMER"
},
{
"reasonId": 20,
"description": {
"en_US": "No Longer Used"
},
"operationType": "CANCEL_BY_CUSTOMER"
},
{
"reasonId": 21,
"description": {
"en_US": "New Provider"
},
"operationType": "CANCEL_BY_CUSTOMER"
},
{
"reasonId": 22,
"description": {
"en_US": "Change in Company Circumstance"
},
"operationType": "CANCEL_BY_CUSTOMER"
},
{
"reasonId": 23,
"description": {
"en_US": "Other"
},
"operationType": "CANCEL_BY_CUSTOMER"
},
{
"reasonId": 13,
"description": {
"en_US": "Customer Request"
},
"operationType": "CANCEL_BY_VENDOR"
},
{
"reasonId": 14,
"description": {
"en_US": "Other"
},
"operationType": "CANCEL_BY_VENDOR"
},
{
"reasonId": 15,
"description": {
"en_US": "Customer Request"
},
"operationType": "ACCOUNT_CANCELLATION"
},
{
"reasonId": 16,
"description": {
"en_US": "Other"
},
"operationType": "ACCOUNT_CANCELLATION"
},
{
"reasonId": 61,
"description": {
"en_US": "Account overdue"
},
"operationType": "DESTROY_SERVICE"
},
{
"reasonId": 69,
"description": {
"en_US": "Other"
},
"operationType": "DESTROY_SERVICE"
},
{
"reasonId": 107,
"description": {
"en_US": "Automatical Synchronization: Stop Service"
},
"operationType": "AUTOMATIC_SYNCHRONIZATION"
},
{
"reasonId": 161,
"description": {
"en_US": "Automatical Synchronization: Destroy Service"
},
"operationType": "AUTOMATIC_SYNCHRONIZATION"
}
]
Get the list of reasons applicable for the cancellation operation:
GET /aps/2/services/order-manager/reasonCodes?operationType=CANCEL_BY_VENDOR
With the default platform configuration, the response will be as follows:
HTTP/1.1 200 OK
[
{
"reasonId": 13,
"description": {
"en_US": "Customer Request"
},
"operationType": "CANCEL_BY_VENDOR"
},
{
"reasonId": 14,
"description": {
"en_US": "Other"
},
"operationType": "CANCEL_BY_VENDOR"
}
]
Note
When creating a cancellation order, an external system can specify a reason for it and a comment, for example:
POST /aps/2/services/order-manager/orders
{
"type": "CANCELLATION",
"refundType":"CREDIT_MEMO",
"subscriptionId" : "a63078fb-7af8-417e-88c3-e7af37e08e59",
"reasonId": 14,
"comment": "Requested through the ERP system."
}
If the comment
is not specified in the request, the default string is assigned to the order comment field based
on the following conditions:
“No comment”: if a reason is specified
“Cancelled from API”: if no reason is specified
Similarly to sales orders, a migration order creates a subscription from a service plan for a specified customer. The difference is that when placing a migration order, you need to provide additional information about the subscription that is to be migrated.
In a POST request body, this order is defined as "type":"MIGRATION"
.
A migration order is used to migrate a subscription from an external system to the platform.
Before placing such an order, make sure that there is a service plan to which the migrated subscription will be bound. Its ID must be specified in the payload.
When placing a migration order, you need to specify how to bill the customer for the current billing period. Use the migrationProgram
property as follows:
count_migration_billing_period
to bill customer for the current billing period fully.
do_not_count_migration_billing_period
not to bill the customer for the current billing period.
prorate_migration_billing_period
to bill the customer only for a part of the current billing period: from the date
of migration till the period end.
In the request, specify the parameters you have collected in the previous steps. Optionally, the request can contain the following groups of properties:
When migrating a subscription whose start and expiration dates are not aligned, specify:
"specialCase": "COTERMING"
, if the migrated subscription is co-termed with another subscription or with the calendar month end. This type of migration requires that the service plan to which the subscription will be bound to is configured to align billing periods with subscription expiration date.
"specialCase": "PLAN_CHANGE"
, if the migrated subscription’s plan was changed during the current subscription period.
"periodStartDate": "YYYY-MM-DD"
, to indicate the date when the current subscription period started.
{
"migrationProgram": "prorate_migration_billing_period",
"startDate": "2027-12-02",
"dealPrices": [
{
"agreements": [
{
"buyer": {
"id": "ae274083-220f-4fc5-937f-8ff771711278"
},
"price": {
"resources": [
{
"recurring": {
"code": "USD",
"value": 20
},
"resource": {
"id": "84ecf4ef-ee94-4bc0-b3cc-130e524aaa4d"
}
}
]
}
},
{
"buyer": {
"id": "4c32efa4-c0a3-491a-b82c-8b77923dac0e"
},
"price": {
"resources": [
{
"recurring": {
"code": "USD",
"value": 20.1
},
"resource": {
"id": "84ecf4ef-ee94-4bc0-b3cc-130e524aaa4d"
}
}
]
},
"seller": {
"id": "ae274083-220f-4fc5-937f-8ff771711278"
}
},
{
"buyer": {
"id": "bc93c277-cf5f-49c1-9a6c-28a0d7f5a53e"
},
"price": {
"resources": [
{
"recurring": {
"code": "USD",
"value": 20.2
},
"resource": {
"id": "84ecf4ef-ee94-4bc0-b3cc-130e524aaa4d"
}
}
]
},
"seller": {
"id": "4c32efa4-c0a3-491a-b82c-8b77923dac0e"
}
}
],
"freezePrices": false,
"plan": {
"id": "a57750d9-0712-4398-9b82-a3f5f57dbeec"
},
"period": {
"duration": 1,
"unit": "YEARS"
}
}
],
"expirationDate": "2028-12-02",
"migrationDate": "2028-03-04",
"planId": "a57750d9-0712-4398-9b82-a3f5f57dbeec",
"type": "MIGRATION",
"period": {
"duration": 1,
"unit": "YEARS"
},
"resources": [
{
"resourceId": "84ecf4ef-ee94-4bc0-b3cc-130e524aaa4d",
"amount": 3
}
],
"accountId": "bc93c277-cf5f-49c1-9a6c-28a0d7f5a53e",
"acceptedTerms": [10, 11],
"acceptedTermsDate": "2019.02.10T15:02:00Z",
"acceptedTermsUserId": 1000009
}
The response must contain the APS ID of the created order:
{
"orderId": "f0817852-282c-4047-a4d3-f6501939d5a6"
}
After placing the order, if any manual actions are required to ensure provisioning of the subscription, make sure to complete them.
Note
Note that the time part in the provisioning date of the migrated subscription will be reset to the start of the day.
Typically, an external management system verifies whether the placed orders were processed successfully.
An external management system can get a list of all orders by calling the listOrders
custom operation:
GET /aps/2/services/order-manager/orders
The response contains the list of orders:
HTTP/1.1 200 OK
[
{
"orderId": "18131926-c152-4652-8a29-3fe076929f4b",
"internalId": 1000024,
"orderNumber": "SO000014",
"type": "SO",
"total": 308.0,
"taxTotal": 0.0,
"exclusiveTaxTotal": 0.0,
"subTotal": 308.0,
"status": "COMPLETED",
"paymentStatus": "FINISHED",
"provisioningStatus": "COMPLETED",
"ofStatus": "CP",
"sellerId": "c0d43087-da72-472a-a176-84a34608979f",
"buyerId": "d7dd06ef-20a0-41f5-b89f-768ef373ae44",
"orderDate": "2019-04-04T21:00:00Z",
"expirationDate": "2019-04-07T21:00:00Z",
"creationTime": "2019-04-05T13:22:14Z"
"orderAttributes": [],
"accountAttributes": [],
"endCustomerName": "John Smith",
"endCustomerType": "CUSTOMER"
},
{ // Another order
}
]
A returned order representation contains the results of the two order processing
steps (paymentStatus
and provisioningStatus
) and the status
of the order.
Similar to other requests for a collection of resources, by default,
the returned Content-Range
header contains the total number of found orders in accordance with
the pagination rules. This calculation requires a substantial amount of time
when the orders number several million. To turn off this calculation, send
the header APS-Skip-Content-Range.
Note
The orderAttributes
and accountAttributes
arrays show only those attributes whose configuration
parameter Show in the List of Resellers is checked in the provider control panel.
To select the list of orders by particular criteria, the listOrders
operation provides custom filters similar
to Resource Query Language. In this case, a request will look as follows:
GET /aps/2/services/order-manager/orders?in({property},{value}),select({linkToResources}),ge(creationDate,{fromDate}),le(creationDate,{toDate}),like(number,*000001),limit({from},{to})
The following functions can be used:
in
verifies whether a property is in a specified list, for example, request only sales orders and billing orders:
in(type,(SO,BO))
The following properties are allowed in the function:
resellerId
is the APS ID of the reseller that provides the ordered services.
customerId
is the APS ID of the customer that placed the order.
endCustomerName
is a customer name.
endCustomerType
is an account type (“PROVIDER”, “RESELLER”, or “CUSTOMER”).
ID of an order or account attribute.
internalId
is and integer showing an order unique ID in the platform.
orderId
is a string showing an order unique APS ID.
orderNumber
is a string ID assigned by the platform to an order, for example, “SO000004”.
status
is an order status.
type
is an order type. The most common types for API are in the following list:
BO
is a billing order generated at the end of a billing period usually to bill an account for resources consumed
during the passed billing period.
CL
is a cancellation order generated when a subscription is cancelled and the sales vendor owns money to the
customer.
CF
is a cancellation order generated when a subscription is cancelled and the customer owns money to the sales
vendor.
RN
is a renewal order created when a subscription must be renewed for the next period.
SO
is a sales order that contains a request for certain service plans.
CH
is a change order that a subscriber uses to change a subscription.
provisioningStatus
is an order provisioning status.
paymentStatus
is the payment status of an order.
subscriptionId
is the APS ID of the subscription whose orders are requested.
Note
A list of order attribute IDs and account attribute IDs is created by the provider using the control panel. Those IDs are unique within the platform.
like
verifies if a property matches a wildcard mask that uses the wildcard symbols *
and ?
. Currently,
this function is applicable to orderNumber
, endCustomerName
, and attribute IDs (either account or order
attributes).
Example of filtering by order number:
like(orderNumber,*00001)
Example of filtering by attribute ID:
like(ORDER_ID1,test1234)
ge
and le
(respectively “Greater or Equal” and “Lower or Equal”) functions are applicable to the internal ID
and the date-time properties to select the orders in a certain date and time interval:
internalId
creationTime
orderDate
expirationDate
For example, seek for orders created in the specified time period:
ge(creationTime,2018-04-26T16:00:00Z),le(creationTime,2018-04-26T18:00:00Z)
limit
fetches orders in a range of numbers, for example get orders in the range of 0 to 9:
limit(0,9)
Note
limit(0,0)
requires the APS controller to return only the total number of orders matching the requested
filters. In this case, the response contains the Content-Range
header that shows
the requested number and does not contain the body.
To get the full JSON representation of an order, a request must specify the order APS ID in the URL as in the following example:
GET /aps/2/services/order-manager/orders/18131926-c152-4652-8a29-3fe076929f4b
If successful, the response looks similar to the following:
HTTP/1.1 200 OK
{
"orderId": "18131926-c152-4652-8a29-3fe076929f4b",
"internalId": 1000002,
"orderNumber": "SO000001",
"type": "SO",
"total": {
"value": 308.0,
"code": "USD"
},
"taxTotal": {
"value": 0.0,
"code": "USD"
},
"exclusiveTaxTotal": {
"value": 0.0,
"code": "USD"
},
"subTotal": {
"value": 308.0,
"code": "USD"
},
"status": "COMPLETED",
"subscriptions": [
"4c867c87-fbf7-49e8-9f7e-0d06e8f7a003"
],
"bssSubscriptions": [
"456808a0-b5a6-4092-ab67-b77e33743a07"
],
"paymentStatus": "FINISHED",
"provisioningStatus": "COMPLETED",
"ofStatus": "CP",
"sellerId": "8265e3d7-cdf5-4acc-8ca4-267268a79aae",
"buyerId": "9d086478-d00b-40c2-86df-7bc9b862e667",
"orderDate": "2019-02-26",
"expirationDate": "2019-03-01",
"creationTime": "2019-02-26T10:01:17Z",
"orderAttributes": [],
"endCustomerAttributes": [
{
"attributeID": "external_id",
"value": "Smith-123"
}
],
"details": [
{
"type": "RESOURCE_RECURRING",
"planId": "67216414-6490-4588-bef9-7f6acf5e6a63",
"period": {
"unit": "YEARS",
"duration": 1
},
"resourceId": "6cc3ccc6-0571-4c16-8e41-3916e1136284",
"duration": {
"unit": "MONTHS",
"duration": 1.0
},
"description": "Disk Space Recurring",
"quantity": 90.0,
"lowerBound": 0.0,
"unitOfMeasure": "GB",
"unitPrice": {
"value": 1.0,
"code": "USD"
},
"extendedPrice": {
"value": 90.0,
"code": "USD"
}
"discount": {
"type": "PERCENT",
"value": 0.0,
"amount": 0.0
},
"taxAmount": {
"value": 0.0,
"code": "USD"
}
"exclusiveTaxAmount": {
"value": 0.0,
"code": "USD"
}
},
{
"type": "PLAN_RECURRING",
"planId": "67216414-6490-4588-bef9-7f6acf5e6a63",
"period": {
"unit": "YEARS",
"duration": 1
},
"duration": {
"unit": "MONTHS",
"duration": 1.0
},
"description": "VIP Maintenance and Support Recurring",
"quantity": 1.0,
"unitOfMeasure": "item",
"unitPrice": {
"value": 199.0,
"code": "USD"
}
"extendedPrice": {
"value": 199.0,
"code": "USD"
}
"discount": {
"type": "PERCENT",
"value": 0.0,
"amount": 0.0
},
"taxAmount": {
"value": 0.0,
"code": "USD"
}
"exclusiveTaxAmount": {
"value": 0.0,
"code": "USD"
}
},
{
"type": "PLAN_SETUP",
"planId": "67216414-6490-4588-bef9-7f6acf5e6a63",
"period": {
"unit": "YEARS",
"duration": 1
},
"description": "VIP Maintenance and Support Setup",
"quantity": 1.0,
"unitOfMeasure": "item",
"unitPrice": {
"value": 19.0,
"code": "USD"
}
"extendedPrice": {
"value": 19.0,
"code": "USD"
}
"discount": {
"type": "PERCENT",
"value": 0.0,
"amount": 0.0
},
"taxAmount": {
"value": 0.0,
"code": "USD"
}
"exclusiveTaxAmount": {
"value" 0.0,
"code": "USD"
}
}
],
"endCustomerName": "John Smith",
"endCustomerType": "CUSTOMER"
}
From the response, the external management system will get the following data that it can subject to further processing:
The APS ID of the order;
The order status (“NOT_STARTED”, “IN_PROGRESS”, “PROBLEM”, “CANCELED”, or “COMPLETED”);
The order number generated by the platform internally. This attribute allows a staff member to find an order in the user panel;
A list of subscriptions (APS IDs) the order is bound to. As it was mentioned earlier, when managing subscriptions through orders, use the BSS
The order management API allows an external system to estimate prices and costs using the following custom operations:
estimateOrder
: provides detailed structured pricing for a customer’s order.
estimateCosts
: given a similar customer’s order, returns the detailed structured cost of that order for
the customer’s reseller.
An estimation request sends the same payload as the creation operation for the same order type. An external system can estimate the following order types:
Sales
Renewal
Change
Cancellation
The following examples are based on the provider-reseller-customer chain:
The configuration of such a sales scheme is similar to the one described in concepts. In addition, it requires configuration of discounts and taxes (which we suppose is already done).
The estimateOrder
custom operation calculates the price details for an order without
the order creation.
Typically, resellers use it to estimate the price for a customer whose APS ID must be in the request.
The estimation operation takes into account the discounts, promos, and taxes valid for a specified customer.
It is possible to exclude the tax calculation by adding the includeTaxes=false
input
query parameter.
POST /aps/2/services/order-manager/orders/estimate
{
"type": "SALES",
"accountId" : "00b60056-8b0a-4981-8ca4-d114346cd652",
"promoCode" : "123",
"products" : [{
"planId" : "6b64da9a-f8e6-4cbd-8aef-de304a27b627",
"period" : {
"unit" : "MONTHS",
"duration" : 1
},
"resources" : [{
"resourceId" : "2f8905f8-4302-49d7-ab7f-65c9036addf0",
"amount" : 20
}]
}]
}
Note
Refer to the Set Special Prices section for details about special prices.
A response looks like this:
HTTP/1.1 200 OK
{
"promoResult": "APPLIED",
"total": 20.839999999999996,
"subTotal": 18.939999999999998,
"taxTotal": 1.9,
"exclusiveTaxTotal": 1.9,
"details": [
{
"type": "PLAN_SETUP",
"planId": "6b64da9a-f8e6-4cbd-8aef-de304a27b627",
"period": {
"unit": "MONTHS",
"duration": 1
},
"description": "Cloud VPSes Setup",
"quantity": 1.0,
"lowerBound": 0.0,
"unitOfMeasure": "item",
"unitPrice": 2.0,
"extendedPrice": 1.5,
"discount": {
"type": "PERCENT",
"value": 25.0,
"amount": 0.5
},
"taxAmount": 0.15,
"exclusiveTaxAmount": 0.15
},
{
"type": "PLAN_RECURRING",
"planId": "6b64da9a-f8e6-4cbd-8aef-de304a27b627",
"period": {
"unit": "MONTHS",
"duration": 1
},
"duration": {
"unit": "MONTHS",
"duration": 1.0
},
"description": "Cloud VPSes Recurring",
"quantity": 1.0,
"lowerBound": 0.0,
"unitOfMeasure": "item",
"unitPrice": 4.25,
"extendedPrice": 3.19,
"discount": {
"type": "PERCENT",
"value": 25.0,
"amount": 1.06
},
"taxAmount": 0.32,
"exclusiveTaxAmount": 0.32
},
{
"type": "RESOURCE_RECURRING",
"planId": "6b64da9a-f8e6-4cbd-8aef-de304a27b627",
"period": {
"unit": "MONTHS",
"duration": 1
},
"resourceId": "2f8905f8-4302-49d7-ab7f-65c9036addf0",
"duration": {
"unit": "MONTHS",
"duration": 1.0
},
"description": "null Recurring",
"quantity": 19.0,
"lowerBound": 0.0,
"unitOfMeasure": "unit",
"unitPrice": 1.0,
"extendedPrice": 14.25,
"discount": {
"type": "PERCENT",
"value": 25.0,
"amount": 4.75
},
"taxAmount": 1.43,
"exclusiveTaxAmount": 1.43
}
]
}
Note
1. There are two types of taxes, those that are included in the initial price (inclusive taxes) and those that are added to the initial price (exclusive taxes).
In the response, the total estimated price total
is the sum of subtotal
and exclusiveTaxTotal
.
The estimateCosts
operation is similar to the estimateOrder
operation: it accepts
the same input data, that is, a structured order for a customer, and returns data using the same output structure as
estimateOrder
. The difference is that estimateCosts
returns data that shows how much the customer’s
reseller pays to its direct parent reseller or the provider, whereas estimateOrder
returns the price for
the specified customer.
When calling a custom operation that creates a Sales Orders or estimates an order as described
in the Estimate the Order Price section, it is possible to add the specialPricing
structure inside the main input OrderRequest
structure. The added structure is applicable to the list of specified
order types and it redefines some spot prices of the service plans specified in those order types:
"specialPricing" : {
"applicableTo" : [ /* "RENEWAL" or empty */ ],
"products" : [ /* One or more service plans with redefined prices and costs */ ]
}
Note
The applicableTo
property must comply with Special Pricing.
If at least one special price is applicable to a subscription, the final prices in that subscription are adjusted by automatically creating a promo bound to the subscription. Unlike other promos, such a promo is not included in the marketing configuration (Products > Marketing) and it is applicable only to its bound subscription.
For example, when creating a sales order with special prices applicable to RENEWAL, the auto-generated new promo will influence both the price of the first period and all subsequent subscription periods.
An entry in the products
list is a service plan with the new spot (special) prices and costs. The general format
of an entry is:
{
"planId": "<UUID>",
"period": {
"unit": "<string>", // DAYS MONTHS YEARS
"duration": "<int>",
},
"prices": {
"setup": "<number>",
"recurring": "<number>",
"renewal": "<number>",
"transfer": "<number>"
},
"costs": {
"setup": "<number>",
"recurring": "<number>",
"renewal": "<number>",
"transfer": "<number>"
}
"resources": [
{
"resourceId": "<UUID>",
"prices": {
"setup": "<number>",
"recurring": "<number>",
"overuse": "<number>"
},
"costs": {
"setup": "<number>",
"recurring": "<number>",
"overuse": "<number>"
}
},
/* ... more resource rates */
]
}
The cost is the price that a reseller pays their parent for a delegated service plan. For example, an L1 reseller delegates a service plan to an L2 reseller and gives a 10% discount for every spot price in that service plan. So, if a subscription price for a customer of the L2 reseller is $100, it will cost $90 for the L2 reseller.
Note
The cost of a service plan for a reseller (for example, an L2 reseller) can be changed only by the reseller’s ancestors (L1 reseller or the provider).
In the example below, the provider estimates the cost of a service plan delegated to a reseller and the price for a customer of the reseller. This is assuming a sales order contains special prices for the customer and special costs for the reseller:
POST /aps/2/services/order-manager/orders/estimate
{
"type": "SALES",
"accountId" : "00b60056-8b0a-4981-8ca4-d114346cd652",
"promoCode" : "123",
"products" : [{
"planId" : "6b64da9a-f8e6-4cbd-8aef-de304a27b627",
"period" : {
"unit" : "MONTHS",
"duration" : 1
},
"resources" : [{
"resourceId" : "2f8905f8-4302-49d7-ab7f-65c9036addf0",
"amount" : 20
}]
}],
"specialPricing": {
"applicableTo" : [ ],
"products": [
{
"planId": "6b64da9a-f8e6-4cbd-8aef-de304a27b627",
"period": {
"unit": "MONTHS",
"duration": 1
},
"prices": {
"setup": 1.2
},
"costs": {
"setup": 1.0,
"recurring": 14.0
},
"resources": [
{
"resourceId": "2f8905f8-4302-49d7-ab7f-65c9036addf0",
"prices": {
"recurring": 0.5
},
"costs": {
"recurring": 0.3
}
}
]
}
]
}
}
The response looks as follows:
HTTP/1.1 200 OK
{
"promoResult": "APPLIED",
"total": 16.45,
"subTotal": 14.95,
"taxTotal": 1.5,
"exclusiveTaxTotal": 1.5,
"details": [
{
"type": "PLAN_SETUP",
"planId": "6b64da9a-f8e6-4cbd-8aef-de304a27b627",
"period": {
"unit": "MONTHS",
"duration": 1
},
"description": "Cloud VPSes Setup",
"quantity": 1.0,
"lowerBound": 0.0,
"unitOfMeasure": "item",
"unitPrice": 1.2,
"extendedPrice": 1.2,
"discount": {
"type": "FIXED",
"value": 1.2,
"amount": 0.8
},
"taxAmount": 0.12,
"exclusiveTaxAmount": 0.12
},
{
"type": "PLAN_RECURRING",
"planId": "6b64da9a-f8e6-4cbd-8aef-de304a27b627",
"period": {
"unit": "MONTHS",
"duration": 1
},
"duration": {
"unit": "MONTHS",
"duration": 1.0
},
"description": "Cloud VPSes Recurring",
"quantity": 1.0,
"lowerBound": 0.0,
"unitOfMeasure": "item",
"unitPrice": 4.25,
"extendedPrice": 4.25,
"taxAmount": 0.43,
"exclusiveTaxAmount": 0.43
},
{
"type": "RESOURCE_RECURRING",
"planId": "6b64da9a-f8e6-4cbd-8aef-de304a27b627",
"period": {
"unit": "MONTHS",
"duration": 1
},
"resourceId": "2f8905f8-4302-49d7-ab7f-65c9036addf0",
"duration": {
"unit": "MONTHS",
"duration": 1.0
},
"description": "null Recurring",
"quantity": 19.0,
"lowerBound": 0.0,
"unitOfMeasure": "unit",
"unitPrice": 0.5,
"extendedPrice": 9.5,
"discount": {
"type": "FIXED",
"value": 0.5,
"amount": 9.5
},
"taxAmount": 0.95,
"exclusiveTaxAmount": 0.95
}
]
}
Once the order estimation satisfies the requesting system, the latter can place a sales order with the same configuration, that is:
POST /aps/2/services/order-manager/orders
{
"type": "SALES",
"accountId" : "00b60056-8b0a-4981-8ca4-d114346cd652",
"promoCode" : "123",
"products" : [{
"planId" : "6b64da9a-f8e6-4cbd-8aef-de304a27b627",
"period" : {
"unit" : "MONTHS",
"duration" : 1
},
"resources" : [{
"resourceId" : "2f8905f8-4302-49d7-ab7f-65c9036addf0",
"amount" : 20
}]
}],
"specialPricing": {
"applicableTo" : [ "RENEWAL" ],
"products": [
{
"planId": "6b64da9a-f8e6-4cbd-8aef-de304a27b627",
"period": {
"unit": "MONTHS",
"duration": 1
},
"prices": {
"setup": 1.2
},
"costs": {
"setup": 1.0,
"recurring": 14.0
},
"resources": [
{
"resourceId": "2f8905f8-4302-49d7-ab7f-65c9036addf0",
"prices": {
"recurring": 0.5
},
"costs": {
"recurring": 0.3
}
}
]
}
]
}
}
As usual, the response must contain the ID of the created order. On completion of the order processing, you can find the new customer subscription with a special promo attached to it:
Note
When the provider has an agreement with a service vendor on discount for a certain service, the agreed price
can be registered in the platform by adding the providerCosts
to sales orders as described in
Setting Special Price as a Discount Percent for the Original Price.
Warning
The order management API does not accept an empty specialPricing
structure. If you are not going to
use special prices, do not pass an empty specialPricing
structure.
The platform rejects sales orders and change orders which do not comply with resource dependencies when the dependency type is REQUIRES or PROVIDED_BY. When an order is rejected, the response code is “500 Internal Server Error” and the error message contains the cause of rejection and the solution. This is valid when creating, upgrading, or downgrading a subscription.
If a resource called ‘Child Resource’ requires two units of a resource called ‘Parent Resource’, the error message contains:
The order cannot be accepted: Resource 'Child Resource' requires resource 'Parent Resource'.
Please add necessary resource(s) to the order. Lack of resource 'Parent Resource': 2.0.
In a downgrade request, if there is an attempt to remove a resource required by another resource, the error message contains:
The order cannot be accepted: Resource 'Parent Resource' is required for
resource 'Child Resource'. Please downgrade necessary resource(s).
If a resource called ‘Child Resource’ is provided by a resource called ‘Parent Resource’, the platform does not fulfill an order that requests a creation, upgrade, or downgrade of the ‘Child Resource’. It rejects such a request with an error message containing:
The order cannot be accepted: Resource 'Child Resource' is provided by Resource 'Parent Resource'.
Amount of resource 'Parent Resource' cannot be less than amount of resource 'Child Resource'.