Subscription change deal
Overview
Use the changeDeal method to change the existing deal for a given subscription and operate the amendment order necessary to transition to the proposed deal immediately. The amendment order will use the due now prices returned by the getDealInfo method when called with the same relevant request parameters.
Request parameters
Parameter name | Type | Required/Optional | Description |
---|---|---|---|
Currency |
String |
Required |
The currency. |
Country |
String |
Required |
The country. |
Language |
String |
Required |
The language. |
CustomerIp |
String |
Optional |
The customer's IP address. |
Items |
Array |
Required |
Each item corresponds to a subscription. |
Items.DealDate |
String |
Required |
The date when the deal is set to come into effect. |
Items.SubscriptionReference |
String |
Required |
The subscription code. |
Items.ProductCode |
String |
Required |
The product code. |
Items.Quantity |
String |
Required |
The product quantity. |
Items.DealPriceScenario |
String |
Required |
The upgrade scenario to be applied. Must be one of: using_last_order_price, using_last_product_price, price_total, product_price_difference. |
Items.DealSubscriptionScenario |
String |
Required |
The scenario for price calculation. Must be one of prolong, does_not_affect, disable_existing. |
Items.PriceOptions |
Array |
optional |
The array of price options. |
Items.PriceOptions.Code |
String |
Required |
The price options group code. |
Items.PriceOptions.Options |
Array |
Required |
The list of price option value (if the group is of type interval) or the price option code (otherwise). |
Items.Price |
Object |
Required |
The product price. |
Items.Price.Amount |
Float |
Required |
The actual numeric amount. |
Items.Price.Type |
String |
Required |
Describes if the price type is catalog or custom. Can be only CUSTOM. |
Items.Price.AmountType |
String |
Required |
Describes if the price is NET or GROSS. Can be on of NET, GROSS. |
Items.SubscriptionCustomSettings |
Object |
Required |
Product license custom settings. |
Items.SubscriptionCustomSettings.CycleLength |
Int |
Required |
The length of a single billing cycle. |
Items.SubscriptionCustomSettings.CycleUnit |
String |
Required |
The unit of a single billing cycle. Can be one of MONTH, DAY. |
Items.SubscriptionCustomSettings.CycleAmount |
Float |
Required |
The price of a single billing cycle. |
Items.SubscriptionCustomSettings.CycleAmountType |
String |
Required |
Describes the price type. Can be one of NET, GROSS. |
Items.SubscriptionCustomSettings.ContractLength |
Int |
Required |
The number of billing cycles contained in a single contract. |
Items.SubscriptionCustomSettings.ClientDealAutoRenewal |
Boolean |
Optional |
CDAR value (default false). |
Items.SubscriptionCustomSettings.MerchantDealAutoRenewal |
Boolean |
Optional |
MDAR value (default false). |
BillingDetails |
Object |
required |
The billing details. |
BillingDetails.FirstName |
String |
Required |
The first name. |
BillingDetails.LastName |
String |
Required |
The last name. |
BillingDetails.CountryCode |
String |
Required |
The country code. Must be one of the seller's associated country codes. |
BillingDetails.State |
String |
Optional |
Required only if the business model requires it. |
BillingDetails.City |
String |
Required |
The city name. |
BillingDetails.Address1 |
String |
Required |
The address. |
BillingDetails.Zip |
String |
Required |
The zip code. |
BillingDetails.Email |
String |
Required |
The email address. |
BillingDetails.Phone |
String |
Required |
The phone number. |
BillingDetails.Company |
String |
Required |
The company's legal name. |
BillingDetails.FiscalCode |
String |
Required |
The fiscal code. |
DeliveryDetails |
Object |
Required |
The delivery details. |
DeliveryDetails.FirstName |
String |
Required |
The first name. |
DeliveryDetails.LastName |
String |
Required |
The last name. |
DeliveryDetails.CountryCode |
String |
Required |
The country code. Must be one of the seller's associated country codes. |
DeliveryDetails.State |
String |
Optional |
Required only if the business model requires it. |
DeliveryDetails.City |
String |
Required |
The city name. |
DeliveryDetails.Address1 |
String |
Required |
The address. |
DeliveryDetails.Zip |
String |
Required |
The zip code. |
DeliveryDetails.Email |
String |
Required |
The email address. |
DeliveryDetails.Phone |
String |
Required |
The phone number. |
DeliveryDetails.Company |
String |
Required |
The company's legal name. |
PaymentDetails |
Object |
Optional |
The payment details. |
PaymentDetails.Type |
String |
Required |
Payment type. Can be CC (credit card) or EES_TOKEN_PAYMENT (2payJs token). |
PaymentDetails.Currency |
String |
Required |
Payment currency code. |
PaymentDetails. CustomerIP |
String |
Required |
Payment customer IP. |
PaymentDetails.PaymentMethod |
Object |
Required |
The payment method information. |
PaymentDetails.PaymentMethod.EesToken |
String |
Optional |
EES token (required when payment type is EES_TOKEN_PAYMENT). |
PaymentDetails.PaymentMethod.CardNumber |
Int |
Optional |
CC number (required when payment type is CC). |
PaymentDetails.PaymentMethod.CardType |
String |
Optional |
CC type (ex: VISA, MC; required when payment type is CC). |
PaymentDetails.PaymentMethod.ExpirationYear |
Int |
Optional |
4 digits CC expiration year (required when payment type is CC). |
PaymentDetails.PaymentMethod.ExpirationMonth |
Int |
Optional |
CC expiration month (required when payment type is CC). |
PaymentDetails.PaymentMethod.CCID |
String |
Optional |
CC CVV value (required when payment type is CC). |
PaymentDetails.PaymentMethod.HolderName |
String |
Optional |
CC holder name. |
PaymentDetails.PaymentMethod.Vendor3DSReturnURL |
String |
Required |
Merchant 3DS return URL. |
PaymentDetails.PaymentMethod.Vendor3DSCancelURL |
String |
Required |
Merchant 3DS cancel URL. |
PaymentDetails.PaymentMethod.RecurringEnabled |
Boolean |
Optional |
Flag to enable recurring on the new license when set true. |
ExtraInformation |
Object |
Optional |
Order extra information. |
ExtraInformation.ProposalId |
String |
Optional |
Related proposal object ID. |
ExtraInformation.PurchaseOrderDownloadLink |
String |
Optional |
PO Download link. |
ExtraInformation.AMEmailB2B |
String |
Optional |
AM email for B2B. |
ExtraInformation.RetryFailedPaymentLink |
String |
Optional |
Retry failed payment link. |
Request example
<?php
declare(strict_types=1);
class Configuration
{
public const MERCHANT_CODE = '1234554321';
public const MERCHANT_KEY = 'D+~=z5R+R4])4D5&p56%';
public const URL = 'http://api.avangate.local/rpc/6.0';
public const ACTION = 'getDealInfo';
//array or JSON
public const PAYLOAD = <<<JSON
{
"Currency": "usd",
"Country": "us",
"Language": "en",
"CustomerIp": "91.220.121.21",
"Source": "salesforce_cpq",
"Items": [
{
"DealDate": "2021-03-18 13:36:47",
"SubscriptionReference": "GUC9PFSIH8",
"ProductCode": "PAV2019",
"Quantity": 1,
"DealPriceScenario": "using_last_order_price",
"DealSubscriptionScenario": "prolong",
"Price": {
"Amount": 50,
"Type": "CUSTOM",
"AmountType": "GROSS"
},
"PriceOptions": [
{
"Code": "interval_scale_grp1",
"Options": [
"25"
]
},
{
"Code": "OPTGRP1",
"Options": [
"OptGrp1Code1"
]
}
],
"SubscriptionCustomSettings": {
"CycleLength": 1,
"CycleUnit": "MONTH",
"CycleAmount": 50,
"CycleAmountType": "GROSS",
"ContractLength": 12,
"ClientDealAutoRenewal": true,
"MerchantDealAutoRenewal": true
}
}
],
"BillingDetails": {
"FirstName": "Donald",
"LastName": "Wilson",
"CountryCode": "us",
"State": "Texas",
"City": "Dallas",
"Address1": "4519 BlueBridge Road",
"Zip": "02199",
"Email": "dwilson@test.com",
"Phone": "6172938133",
"Company": "Integra Wealth",
"FiscalCode": "85421564"
},
"DeliveryDetails": {
"FirstName": "Gerard",
"LastName": "Butler",
"CountryCode": "us",
"State": "Texas",
"City": "Austin",
"Address1": "2033 Nuzum Court",
"Zip": "14216",
"Email": "gerard.butler@integrawealth.net",
"Phone": "7165708136",
"Company": "Integra Wealth"
},
"PaymentDetails": {
"Type": "EES_TOKEN_PAYMENT",
"Currency": "usd",
"CustomerIP": "91.220.121.21",
"PaymentMethod": {
"EesToken": "7886eebb-0aa0-482c-8636-28394e2b714d",
"RecurringEnabled": true
}
},
"ExtraInformation": {
"ProposalId": "1de36a0a-a7b6-4cb7-9de5-34c802e4243b",
"PurchaseOrderDownloadLink": "http://secure.avangate.local/proposal/po/342322/dl",
"AMEmailB2B": "test@email.org",
"RetryFailedPaymentLink": "http://secure.avangate.local/proposal/po/342322/retry?ref=[REFNO]"
}
}
JSON;
}
class Client
{
private const LOGIN_METHOD = 'login';
private $calls = 1;
private $sessionId;
private function generateAuth(): array
{
$merchantCode = Configuration::MERCHANT_CODE;
$key = Configuration::MERCHANT_KEY;
$date = gmdate('Y-m-d H:i:s');
$string = strlen($merchantCode) . $merchantCode . strlen($date) . $date;
$hash = hash_hmac('md5', $string, $key);
return compact('merchantCode', 'date', 'hash');
}
public function login(string $url)
{
$payload = $this->generateAuth();
$response = $this->call($url, array_values($payload), self::LOGIN_METHOD);
$this->sessionId = $response['result'];
}
public function call(
string $url = Configuration::URL,
$payload = Configuration::PAYLOAD,
string $action = Configuration::ACTION
): ?array {
if (empty($this->sessionId) && $action !== self::LOGIN_METHOD) {
$this->login($url);
}
if(is_string($payload)) {
$payload = json_decode($payload, true);
}
if (!empty($this->sessionId)) {
$payload = [$this->sessionId, $payload];
}
$payload = array_filter($payload);
$request = json_encode([
'jsonrpc' => '2.0',
'method' => $action,
'params' => $payload,
'id' => $this->calls++,
]);
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($curl, CURLOPT_SSLVERSION, 0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json', 'Accept: application/json', 'Cookie: XDEBUG_SESSION=PHPSTORM'));
curl_setopt($curl, CURLOPT_POSTFIELDS, $request);
$response = curl_exec($curl);
if(empty($response)) {
die('Server unavailable');
}
echo $response . '</br>';
return json_decode($response, true);;
}
}
$client = new Client();
$result = $client->call();
var_dump($result);
Response
The changeDeal method has (almost) the same response parameters as the getDealInfo method, plus the deal order details returned under the DealOrder key. These order details have the same structure as any placeOrder API method response (see here).
[
{
"SubscriptionReference": "GUC9PFSIH8",
"DealPriceScenario": "using_last_order_price",
"DealSubscriptionScenario": "prolong",
"DealDate": "2021-03-18 13:36:47",
"DealDueNowPriceNet": 47.06,
"DealDueNowPriceGross": 50,
"DealTaxAmount": 2.94,
"DealTaxPercent": 6.25,
"CurrentInfo": {
"ProductCode": "BKG20193",
"ProductName": "Backgammon 2019.3",
"ProductDescription": "",
"BillingPriceNet": 45,
"UnitBillingPriceNet": 45,
"BillingPriceGross": 47.81,
"UnitBillingPriceGross": 47.81,
"NoOfBillingCycles": 13,
"CurrentBillingCycle": 1,
"PayedBillingCycles": 1,
"RemainingBillingCycles": 11,
"CurrentBillingCycleEndDate": "2021-03-15 11:35:02",
"ClientDealAutoRenewal": false,
"MerchantDealAutoRenewal": false,
"Quantity": 1,
"CurrencyCode": "usd",
"TaxAmount": 2.81,
"TaxPercent": 6.25,
"BillingCyclesFrequency": 1,
"BillingCycleFrequencyUnit": "MONTH",
"ContractLength": 12,
"ContractLengthUnit": "MONTH",
"ProductOptions": []
},
"NewDealInfo": {
"ProductCode": "PAV2019",
"ProductName": "Pipera AntiVirus 2019",
"ProductDescription": "",
"BillingPriceNet": 47.06,
"BillingPriceGross": 50,
"NoOfBillingCycles": 12,
"CurrentBillingCycle": 1,
"PayedBillingCycles": 0,
"RemainingBillingCycles": 12,
"CurrentBillingCycleEndDate": "2021-04-18 13:36:47",
"TaxAmount": 2.94,
"TaxPercent": 6.25,
"CurrencyCode": "usd",
"BillingCyclesFrequency": 1,
"BillingCycleFrequencyUnit": "MONTH",
"ContractLength": 12,
"ContractLengthUnit": "MONTH",
"ProductOptions": [
{
"Code": "interval_scale_grp1",
"Options": [
"25"
]
},
{
"Code": "OPTGRP1",
"Options": [
"OptGrp1Code1"
]
}
]
},
"TotalsDealInfo": {
"DealsNumber": 0,
"ContractsNumber": 1,
"PaidBillingCycles": 1,
"ElapsedBillingCycles": 1
},
"DealOrder": {
"RefNo": "11591805",
"OrderNo": 0,
"ExternalReference": null,
"ShopperRefNo": null,
"Status": "AUTHRECEIVED",
"ApproveStatus": "WAITING",
"VendorApproveStatus": "OK",
"MerchantCode": "120000589445",
"Language": "en",
"OrderDate": "2021-02-15 13:39:29",
"FinishDate": null,
"Source": null,
"Affiliate": {
"AffiliateCode": null,
"AffiliateSource": null,
"AffiliateName": null,
"AffiliateUrl": null
},
"HasShipping": true,
"BillingDetails": {
"FiscalCode": "85421564",
"TaxOffice": null,
"Phone": "6172938133",
"FirstName": "Donald",
"LastName": "Wilson",
"Company": "Integra Wealth",
"Email": "dwilson@test.com",
"Address1": "4519 BlueBridge Road",
"Address2": null,
"City": "Dallas",
"Zip": "02199",
"CountryCode": "us",
"State": "Texas"
},
"DeliveryDetails": {
"Phone": "7165708136",
"FirstName": "Gerard",
"LastName": "Butler",
"Company": "Integra Wealth",
"Email": "gerard.butler@integrawealth.net",
"Address1": "2033 Nuzum Court",
"Address2": null,
"City": "Austin",
"Zip": "14216",
"CountryCode": "us",
"State": "Texas"
},
"PaymentDetails": {
"Type": "CC",
"Currency": "usd",
"PaymentMethod": {
"FirstDigits": "4111",
"LastDigits": "1111",
"CardType": "visa",
"RecurringEnabled": true,
"Vendor3DSReturnURL": null,
"Vendor3DSCancelURL": null,
"InstallmentsNumber": null
},
"CustomerIP": "91.220.121.21"
},
"DeliveryInformation": {
"ShippingMethod": {
"Code": null,
"TrackingUrl": null,
"TrackingNumber": null,
"Comment": null
}
},
"CustomerDetails": null,
"Origin": "API",
"AvangateCommission": 4.4,
"OrderFlow": "REGULAR",
"GiftDetails": null,
"PODetails": null,
"ExtraInformation": {
"RetryFailedPaymentLink": "http:\/\/secure.avangate.local\/proposal\/po\/342322\/retry?ref=11591805",
"ProposalId": "1de36a0a-a7b6-4cb7-9de5-34c802e4243b",
"PurchaseOrderDownloadLink": "http:\/\/secure.avangate.local\/proposal\/po\/342322\/dl",
"B2B": true,
"AMEmailB2B": "test@email.org"
},
"PartnerCode": null,
"PartnerMargin": null,
"PartnerMarginPercent": null,
"ExtraMargin": null,
"ExtraMarginPercent": null,
"ExtraDiscount": null,
"ExtraDiscountPercent": null,
"LocalTime": null,
"TestOrder": false,
"FxRate": 0.76357124584292,
"FxMarkup": 10.456,
"PayoutCurrency": "EUR",
"DeliveryFinalized": false,
"Errors": null,
"Items": [
{
"ProductDetails": {
"Name": "Pipera AntiVirus 2019",
"ShortDescription": "",
"Tangible": false,
"IsDynamic": false,
"ExtraInfo": null,
"RenewalStatus": false,
"Subscriptions": null,
"DeliveryInformation": {
"Delivery": "NO_DELIVERY",
"DownloadFile": null,
"DeliveryDescription": "",
"CodesDescription": "",
"Codes": []
}
},
"PriceOptions": [
{
"Code": "OPTGRP1",
"Name": "OptGrp1",
"Required": false,
"Options": [
{
"Name": "2 users",
"Value": "OptGrp1Code1",
"Surcharge": "5.00"
}
]
},
{
"Code": "interval_scale_grp1",
"Name": "Interval scale group1",
"Required": false,
"Options": [
{
"Name": "Interval scale group1: 25",
"Value": "interval_scale_grp1=25",
"Surcharge": "125.00"
}
]
}
],
"Price": {
"UnitNetPrice": 47.06,
"UnitGrossPrice": 50,
"UnitVAT": 2.94,
"UnitDiscount": 0,
"UnitNetDiscountedPrice": 47.06,
"UnitGrossDiscountedPrice": 50,
"UnitAffiliateCommission": 0,
"ItemUnitNetPrice": null,
"ItemUnitGrossPrice": null,
"ItemNetPrice": null,
"ItemGrossPrice": null,
"VATPercent": 6.25,
"HandlingFeeNetPrice": 0,
"HandlingFeeGrossPrice": 0,
"Currency": "usd",
"NetPrice": 47.06,
"GrossPrice": 50,
"NetDiscountedPrice": 47.06,
"GrossDiscountedPrice": 50,
"Discount": 0,
"VAT": 2.94,
"AffiliateCommission": 0
},
"LineItemReference": "f703af791bca619bbd42cc6964192456dc243f27",
"PurchaseType": "PRODUCT",
"Code": "PAV2019",
"ExternalReference": "PAV2019QWE",
"Quantity": 1,
"SKU": null,
"CrossSell": null,
"Trial": null,
"AdditionalFields": null,
"Promotion": null,
"RecurringOptions": null,
"SubscriptionStartDate": null,
"SubscriptionCustomSettings": {
"CycleUnit": "MONTH",
"CycleLength": 1,
"CycleAmount": 50,
"CycleAmountType": "GROSS",
"ContractLength": 12,
"MerchantDealAutoRenewal": true,
"ClientDealAutoRenewal": true
}
}
],
"Promotions": [],
"AdditionalFields": null,
"CustomParameters": null,
"Currency": "usd",
"NetPrice": 47.06,
"GrossPrice": 50,
"NetDiscountedPrice": 47.06,
"GrossDiscountedPrice": 50,
"Discount": 0,
"VAT": 2.94,
"AffiliateCommission": 0
}
}
]
Error handling
Whenever there is a validation error, this will trigger an error response is returned, like below:
{
"error_code": "INVALID_EES_TOKEN",
"message": "The token is not valid. In order to proceed with the place order a valid token is required"
}
In this case, the deal order is not created, and you must correct the request parameters, as indicated, and retry the API call.
Most of the validation errors are common with the ones listed for the getDealInfo method (see the Errors handling).
Whenever there is a payment level error encountered, the amendment order is still created, and the payment processing error will be returned in the DealOrder.Errors element, in the usual format used by the placeOrder response as well, for example:
[
{
"SubscriptionReference": "GUC9PFSIH8",
……
"DealOrder": {
"RefNo": "11662596",
……
"Errors": {
"ORDER_PAYMENT_METHOD_CARD_PROCESS_ERROR": "Couldn't complete the payment validation process: Error processing the credit card transaction. Please contact the issuer bank for more details, or enter another card."
}
}
}
]
You can check the list of possible order-level errors on this page.