OpenAPI: https://integrations.yoursafe.com/openapi/flexpay-subscription.json

# Subscription

- https://secure.verotel.com
- https://secure.billing.creditcard
- https://secure.gaycharge.com
- https://secure.yoursafedirect.com

## Create a subscription order

Examples are for [Verotel FlexPay PHP client library](https://github.com/verotel/flexpay-php-client)

```php
$brand = Verotel\FlexPay\Brand::create_from_merchant_id(/* Your customer ID */ '9804000000000000');

$flexpayClient = new Verotel\FlexPay\Client(/* shop ID */ 12345, "FlexPay Signature Key", $brand);

$subscriptionUrl = $flexpayClient->get_subscription_URL([
    "subscriptionType" => "recurring",
    "name" => "Test subscription",
    "trialAmount" => 5,
    "trialPeriod" => 'P7D',
    "priceAmount" => 12.64,
    "priceCurrency" => "EUR",
    "period" => 'P30D',
]);
```

    Examples are for [FlexPay Java client library](https://github.com/verotel/flexpay4j)

```java
URL purchaseUrl = flexPayClient.subscriptionBuilder()
    .withAmount("14".toBigDecimal(), SaleCurrency.EUR)
    .withDescription("test description")
    .withPaymentMethod(PaymentMethod.CC)
    .withSubscriptionType(SubscriptionType.recurring)
    .withPeriod("P10D")
    .build();
```

The “startorder” subscription request is used to redirect buyer to the Verotel Order Page to process subscription with a given amount, duration and currency.

### HTTP request

Verotel

`GET https://secure.verotel.com/startorder?`

CardBilling

`GET https://secure.billing.creditcard/startorder?`

GayCharge

`GET https://secure.gaycharge.com/startorder?`

YoursafeDirect

`GET https://secure.yoursafedirect.com/startorder?`

When processing without Orderpage, at least version 3.3 must be used. |
NOTE: only `EUR` is can be used for `DDEU` payment method system |
NOTE: `DDEU` and `YOURSAFE_DIRECT` only support `one-time` |
recurring only | amount to be processed in nnn.nn format for the initial trial period, minimum is 2 days |
recurring only | duration in ISO8601 format, for example: `P30D` |
NOTE: `DDEU` is available only in DE, AT, CH, BE, IT, NL, ES and FR
If oneClickToken is sent, the payment method must be set to `CC`.
When processing without Orderpage, `IDEAL` must be set. |
NOTE: email is excluded from signature calculations (max 100 chars else it will be ignored) |

`GET /startorder`

### Query parameters

- `version` (number, required)
  version version of the FlexPay call, `4` for this version.
  When processing without Orderpage, at least version 3.3 must be used.
- `shopID` (number, required)
  numerical ID of the website in the Verotel system
- `type` (string, required)
  `subscription`
- `priceAmount` (number, required)
  priceAmount amount to be processed in nnn.nn format
- `priceCurrency` (string, required)
  priceCurrency 3 char ISO code, must be one of the Sale currencies (`USD` `EUR` `GBP` `AUD` `CAD` `CHF` `DKK` `NOK` `SEK`)
  NOTE: only `EUR` is can be used for `DDEU` payment method system
- `period` (string, required)
  duration in ISO8601 format, for example: `P30D`, minimum is 7 days for `recurring` and 2 days for `on-time`
- `subscriptionType` (string, required)
  `one-time` or `recurring`
  NOTE: `DDEU` and `YOURSAFE_DIRECT` only support `one-time`
- `trialAmount` (number)
  amount to be processed in nnn.nn format for the initial trial period, minimum is 2 days
- `trialPeriod` (string)
  duration in ISO8601 format, for example: `P30D`
- `name` (string)
  description of the product. Text is displayed on the order page - max 100 printable characters
- `paymentMethod` (string)
  payment method, `CC`, `YOURSAFE_DIRECT` or `DDEU` (if not set then buyers can choose from available payment methods)
  NOTE: `DDEU` is available only in DE, AT, CH, BE, IT, NL, ES and FR
  If oneClickToken is sent, the payment method must be set to `CC`.
  When processing without Orderpage, `IDEAL` must be set.
- `referenceID` (string)
  merchant’s reference identifier. It must be unique if provided
- `custom1` (string)
  pass-through variable - max 255 printable characters
- `custom2` (string)
  pass-through variable - max 255 printable characters
- `custom3` (string)
  pass-through variable - max 255 printable characters
- `successURL` (string)
  URL for redirect after successful transaction - max 255 characters. Defaults to success landing URL on the website.
- `declineURL` (string)
  URL for redirect after declined transaction - max 255 characters. Defaults to decline landing URL on the website.
- `email` (string)
  email of the buyer. If not set, it will be collected on the Order Page
  NOTE: email is excluded from signature calculations (max 100 chars else it will be ignored)
- `signature` (string, required)
  Signature calculation

## Success redirect

After a successful transaction the buyer is redirected to one of these:

- The default website Flexpay success URL (Setup in Control Center/Setup Websites/Website detail/FlexPay Options)

- The URL set in `successURL` Flexpay parameter – overrides the website Flexpay success URL

<aside class="doc-callout doc-callout--notice">
<p>In case of the default <strong>website Flexpay success URL</strong>, the following GET URL parameters are appended to the URL:</p>
</aside>

`GET`

Your endpoint receives this call.

### Query parameters

- `shopID` (number)
  numerical ID of the website in the Verotel system
- `type` (string)
  `subscription`
- `subscriptionType` (string)
  `one-time` or `recurring`
- `event` (string)
  `initial`
- `referenceID` (string)
  merchant reference identifier. It must be unique if provided
- `saleID` (number)
  identifier of the sale in the Verotel system
- `priceAmount` (number)
  amount to be processed in nnn.nn format
- `priceCurrency` (string)
  3 char ISO code of the Sale currency
- `period` (string)
  subscription duration in ISO8601 format
- `trialAmount` (number)
  amount to be processed (max 2 decimal places, stripped zeroes) for the initial trial period
- `trialPeriod` (string)
  duration in ISO8601 format
- `expiresOn or nextChargeOn` (string)
  date of next rebill or expiry date [yyyy-mm-dd] eq. “2015-04-24”
- `custom1` (string)
  pass-through variable - max 255 printable characters
- `custom2` (string)
  pass-through variable - max 255 printable characters
- `custom3` (string)
  pass-through variable - max 255 printable characters
- `paymentMethod` (string)
  payment method, `CC`, `YOURSAFE_DIRECT`, `DDEU`
- `signature` (string)
  Signature calculation

```http
GET https://example.com/success
    ?shopID=12345
    &type=subscription
    &subscriptionType=recurring
    &event=initial
    &referenceID=order-1001
    &saleID=123456
    &priceAmount=9.99
    &priceCurrency=USD
    &period=P30D
    &trialAmount=5.00
    &trialPeriod=P7D
    &expiresOn or nextChargeOn=value
    &custom1=xxyyzz
    &custom2=custom-2
    &custom3=custom-3
    &paymentMethod=CC
    &signature=abcdef0123456789abcdef0123456789abcdef01
```

```node
const url = new URL("https://example.com/success");
url.searchParams.set("shopID", "12345");
url.searchParams.set("type", "subscription");
url.searchParams.set("subscriptionType", "recurring");
url.searchParams.set("event", "initial");
url.searchParams.set("referenceID", "order-1001");
url.searchParams.set("saleID", "123456");
url.searchParams.set("priceAmount", "9.99");
url.searchParams.set("priceCurrency", "USD");
url.searchParams.set("period", "P30D");
url.searchParams.set("trialAmount", "5.00");
url.searchParams.set("trialPeriod", "P7D");
url.searchParams.set("expiresOn or nextChargeOn", "value");
url.searchParams.set("custom1", "xxyyzz");
url.searchParams.set("custom2", "custom-2");
url.searchParams.set("custom3", "custom-3");
url.searchParams.set("paymentMethod", "CC");
url.searchParams.set("signature", "abcdef0123456789abcdef0123456789abcdef01");
const response = await fetch(url);
```

```python
from urllib.parse import urlencode
from urllib.request import urlopen

params = {
    "shopID": "12345",
    "type": "subscription",
    "subscriptionType": "recurring",
    "event": "initial",
    "referenceID": "order-1001",
    "saleID": "123456",
    "priceAmount": "9.99",
    "priceCurrency": "USD",
    "period": "P30D",
    "trialAmount": "5.00",
    "trialPeriod": "P7D",
    "expiresOn or nextChargeOn": "value",
    "custom1": "xxyyzz",
    "custom2": "custom-2",
    "custom3": "custom-3",
    "paymentMethod": "CC",
    "signature": "abcdef0123456789abcdef0123456789abcdef01",
}
url = "https://example.com/success?" + urlencode(params)
response = urlopen(url)
```

```php
// GET https://example.com/success
$params = [
    "shopID" => "12345",
    "type" => "subscription",
    "subscriptionType" => "recurring",
    "event" => "initial",
    "referenceID" => "order-1001",
    "saleID" => "123456",
    "priceAmount" => "9.99",
    "priceCurrency" => "USD",
    "period" => "P30D",
    "trialAmount" => "5.00",
    "trialPeriod" => "P7D",
    "expiresOn or nextChargeOn" => "value",
    "custom1" => "xxyyzz",
    "custom2" => "custom-2",
    "custom3" => "custom-3",
    "paymentMethod" => "CC",
    "signature" => "abcdef0123456789abcdef0123456789abcdef01",
];
```

```java
// GET https://example.com/success
Map<String, String> params = Map.ofEntries(
    Map.entry("shopID", "12345"),
    Map.entry("type", "subscription"),
    Map.entry("subscriptionType", "recurring"),
    Map.entry("event", "initial"),
    Map.entry("referenceID", "order-1001"),
    Map.entry("saleID", "123456"),
    Map.entry("priceAmount", "9.99"),
    Map.entry("priceCurrency", "USD"),
    Map.entry("period", "P30D"),
    Map.entry("trialAmount", "5.00"),
    Map.entry("trialPeriod", "P7D"),
    Map.entry("expiresOn or nextChargeOn", "value"),
    Map.entry("custom1", "xxyyzz"),
    Map.entry("custom2", "custom-2"),
    Map.entry("custom3", "custom-3"),
    Map.entry("paymentMethod", "CC"),
    Map.entry("signature", "abcdef0123456789abcdef0123456789abcdef01")
);
```

## Postbacks

Examples are for [Verotel FlexPay PHP client library](https://github.com/verotel/flexpay-php-client)

```php
$brand = Verotel\FlexPay\Brand::create_from_merchant_id(/* Your customer ID */ '9804000000000000');

$flexpayClient = new Verotel\FlexPay\Client(/* shop ID */ 12345, "FlexPay Signature Key", $brand);

if (!$flexpayClient->validate_signature($_GET)){
    http_response_code(400);
    echo "ERROR - Invalid signature!";
    exit;
}

// handle correct postback
...

echo "OK";
```

    Examples are for [FlexPay Java client library](https://github.com/verotel/flexpay4j)

```java
// pass GET params received in postback
Boolean paramsAreVerified = flexPayClient.validateSignature(Map.of(...));
```

After every sale or transaction based action a corresponding postback is sent to the registered Postback URL.

Postback data are sent as GET request.

### Verifying postback

As a security measure postback have to be validated that it contains correctly computed `Signature`.

### Responding to postback

Important: The Verotel system expects HTTP status code 200 and plain text “OK” response.
The response must be returned within 30 seconds.

<aside class="doc-callout doc-callout--notice">
<p>For Credit Card payments - If no such response is received, an automatic refund is initiated.</p>
</aside>

## Initial postback

The initial sale postback is sent to the website “Flexpay postback URL” immediately after the sale has
been processed.
The postback is sent only for successfully approved transactions. The data in the postback provide
essential information about the sale. If more information is needed, for example billing address or
email address of the buyer, the merchant should query the status page.

Important: The Verotel system expects HTTP status code 200 and plain text “OK” response.
The response must be returned within 30 seconds.

<aside class="doc-callout doc-callout--notice">
<p>For Credit Card payments - If no such response is received, an automatic refund is initiated.</p>
</aside>

`GET`

Your endpoint receives this call.

### Query parameters

- `shopID` (number)
  numerical ID of the website in the Verotel system
- `type` (string)
  `subscription`
- `subscriptionType` (string)
  `one-time` or `recurring`
- `event` (string)
  `initial`
- `referenceID` (string)
  merchant reference identifier. It must be unique if provided
- `saleID` (number)
  identifier of the sale in the Verotel system
- `transactionID` (number)
  identifier of the transaction in the Verotel system (only avaible for postbacks version 2)
- `priceAmount` (number)
  amount to be processed in nnn.nn format
- `priceCurrency` (string)
  3 char ISO code of the Sale currency
- `period` (string)
  subscription duration in ISO8601 format
- `trialAmount` (number)
  amount to be processed (max 2 decimal places, stripped zeroes) for the initial trial period
- `trialPeriod` (string)
  duration in ISO8601 format
- `expiresOn or nextChargeOn` (string)
  date of next rebill or expiry date [yyyy-mm-dd] eq. “2015-04-24”
- `custom1` (string)
  pass-through variable - max 255 printable characters
- `custom2` (string)
  pass-through variable - max 255 printable characters
- `custom3` (string)
  pass-through variable - max 255 printable characters
- `paymentMethod` (string)
  payment method, `CC`, `YOURSAFE_DIRECT`, `DDEU`
- `signature` (string)
  Signature calculation
- `truncatedPAN` (string)
  Truncated (masked) payment instrument identification, e.g. card number
- `CCBrand` (string)
  Only present if paid via Credit Card, represents the card brand, e.g. VISA

```http
GET https://example.com/postback
    ?shopID=12345
    &type=subscription
    &subscriptionType=recurring
    &event=initial
    &referenceID=order-1001
    &saleID=123456
    &transactionID=987654
    &priceAmount=9.99
    &priceCurrency=USD
    &period=P30D
    &trialAmount=5.00
    &trialPeriod=P7D
    &expiresOn or nextChargeOn=value
    &custom1=xxyyzz
    &custom2=custom-2
    &custom3=custom-3
    &paymentMethod=CC
    &signature=abcdef0123456789abcdef0123456789abcdef01
    &truncatedPAN=411111******1111
    &CCBrand=VISA
```

```node
const url = new URL("https://example.com/postback");
url.searchParams.set("shopID", "12345");
url.searchParams.set("type", "subscription");
url.searchParams.set("subscriptionType", "recurring");
url.searchParams.set("event", "initial");
url.searchParams.set("referenceID", "order-1001");
url.searchParams.set("saleID", "123456");
url.searchParams.set("transactionID", "987654");
url.searchParams.set("priceAmount", "9.99");
url.searchParams.set("priceCurrency", "USD");
url.searchParams.set("period", "P30D");
url.searchParams.set("trialAmount", "5.00");
url.searchParams.set("trialPeriod", "P7D");
url.searchParams.set("expiresOn or nextChargeOn", "value");
url.searchParams.set("custom1", "xxyyzz");
url.searchParams.set("custom2", "custom-2");
url.searchParams.set("custom3", "custom-3");
url.searchParams.set("paymentMethod", "CC");
url.searchParams.set("signature", "abcdef0123456789abcdef0123456789abcdef01");
url.searchParams.set("truncatedPAN", "411111******1111");
url.searchParams.set("CCBrand", "VISA");
const response = await fetch(url);
```

```python
from urllib.parse import urlencode
from urllib.request import urlopen

params = {
    "shopID": "12345",
    "type": "subscription",
    "subscriptionType": "recurring",
    "event": "initial",
    "referenceID": "order-1001",
    "saleID": "123456",
    "transactionID": "987654",
    "priceAmount": "9.99",
    "priceCurrency": "USD",
    "period": "P30D",
    "trialAmount": "5.00",
    "trialPeriod": "P7D",
    "expiresOn or nextChargeOn": "value",
    "custom1": "xxyyzz",
    "custom2": "custom-2",
    "custom3": "custom-3",
    "paymentMethod": "CC",
    "signature": "abcdef0123456789abcdef0123456789abcdef01",
    "truncatedPAN": "411111******1111",
    "CCBrand": "VISA",
}
url = "https://example.com/postback?" + urlencode(params)
response = urlopen(url)
```

```php
// GET https://example.com/postback
$params = [
    "shopID" => "12345",
    "type" => "subscription",
    "subscriptionType" => "recurring",
    "event" => "initial",
    "referenceID" => "order-1001",
    "saleID" => "123456",
    "transactionID" => "987654",
    "priceAmount" => "9.99",
    "priceCurrency" => "USD",
    "period" => "P30D",
    "trialAmount" => "5.00",
    "trialPeriod" => "P7D",
    "expiresOn or nextChargeOn" => "value",
    "custom1" => "xxyyzz",
    "custom2" => "custom-2",
    "custom3" => "custom-3",
    "paymentMethod" => "CC",
    "signature" => "abcdef0123456789abcdef0123456789abcdef01",
    "truncatedPAN" => "411111******1111",
    "CCBrand" => "VISA",
];
```

```java
// GET https://example.com/postback
Map<String, String> params = Map.ofEntries(
    Map.entry("shopID", "12345"),
    Map.entry("type", "subscription"),
    Map.entry("subscriptionType", "recurring"),
    Map.entry("event", "initial"),
    Map.entry("referenceID", "order-1001"),
    Map.entry("saleID", "123456"),
    Map.entry("transactionID", "987654"),
    Map.entry("priceAmount", "9.99"),
    Map.entry("priceCurrency", "USD"),
    Map.entry("period", "P30D"),
    Map.entry("trialAmount", "5.00"),
    Map.entry("trialPeriod", "P7D"),
    Map.entry("expiresOn or nextChargeOn", "value"),
    Map.entry("custom1", "xxyyzz"),
    Map.entry("custom2", "custom-2"),
    Map.entry("custom3", "custom-3"),
    Map.entry("paymentMethod", "CC"),
    Map.entry("signature", "abcdef0123456789abcdef0123456789abcdef01"),
    Map.entry("truncatedPAN", "411111******1111"),
    Map.entry("CCBrand", "VISA")
);
```

## Rebill postback

Rebill postback call is sent to the merchant’s URL immediately after a successful rebill transaction.

`GET`

Your endpoint receives this call.

### Query parameters

- `shopID` (number)
  numerical ID of the website in the Verotel system
- `type` (string)
  `subscription`
- `subscriptionType` (string)
  `recurring`
- `event` (string)
  `rebill`
- `referenceID` (string)
  merchant reference identifier. It must be unique if provided
- `saleID` (number)
  identifier of the sale in the Verotel system
- `transactionID` (number)
  identifier of the transaction in Verotel system
- `amount` (number)
  amount to be processed in nnn.nn format
- `currency` (string)
  3 char ISO code of the Sale currency
- `nextChargeOn` (string)
  date of next rebill [yyyy-mm-dd] eq. “2015-04-24”
- `subscriptionPhase` (string)
  `normal` or `discounted`
- `custom1` (string)
  pass-through variable - max 255 printable characters
- `custom2` (string)
  pass-through variable - max 255 printable characters
- `custom3` (string)
  pass-through variable - max 255 printable characters
- `paymentMethod` (string)
  payment method, `CC`, `YOURSAFE_DIRECT`, `DDEU`
- `signature` (string)
  Signature calculation

```http
GET https://example.com/postback
    ?shopID=12345
    &type=subscription
    &subscriptionType=recurring
    &event=rebill
    &referenceID=order-1001
    &saleID=123456
    &transactionID=987654
    &amount=9.99
    &currency=USD
    &nextChargeOn=2015-04-24
    &subscriptionPhase=terminated
    &custom1=xxyyzz
    &custom2=custom-2
    &custom3=custom-3
    &paymentMethod=CC
    &signature=abcdef0123456789abcdef0123456789abcdef01
```

```node
const url = new URL("https://example.com/postback");
url.searchParams.set("shopID", "12345");
url.searchParams.set("type", "subscription");
url.searchParams.set("subscriptionType", "recurring");
url.searchParams.set("event", "rebill");
url.searchParams.set("referenceID", "order-1001");
url.searchParams.set("saleID", "123456");
url.searchParams.set("transactionID", "987654");
url.searchParams.set("amount", "9.99");
url.searchParams.set("currency", "USD");
url.searchParams.set("nextChargeOn", "2015-04-24");
url.searchParams.set("subscriptionPhase", "terminated");
url.searchParams.set("custom1", "xxyyzz");
url.searchParams.set("custom2", "custom-2");
url.searchParams.set("custom3", "custom-3");
url.searchParams.set("paymentMethod", "CC");
url.searchParams.set("signature", "abcdef0123456789abcdef0123456789abcdef01");
const response = await fetch(url);
```

```python
from urllib.parse import urlencode
from urllib.request import urlopen

params = {
    "shopID": "12345",
    "type": "subscription",
    "subscriptionType": "recurring",
    "event": "rebill",
    "referenceID": "order-1001",
    "saleID": "123456",
    "transactionID": "987654",
    "amount": "9.99",
    "currency": "USD",
    "nextChargeOn": "2015-04-24",
    "subscriptionPhase": "terminated",
    "custom1": "xxyyzz",
    "custom2": "custom-2",
    "custom3": "custom-3",
    "paymentMethod": "CC",
    "signature": "abcdef0123456789abcdef0123456789abcdef01",
}
url = "https://example.com/postback?" + urlencode(params)
response = urlopen(url)
```

```php
// GET https://example.com/postback
$params = [
    "shopID" => "12345",
    "type" => "subscription",
    "subscriptionType" => "recurring",
    "event" => "rebill",
    "referenceID" => "order-1001",
    "saleID" => "123456",
    "transactionID" => "987654",
    "amount" => "9.99",
    "currency" => "USD",
    "nextChargeOn" => "2015-04-24",
    "subscriptionPhase" => "terminated",
    "custom1" => "xxyyzz",
    "custom2" => "custom-2",
    "custom3" => "custom-3",
    "paymentMethod" => "CC",
    "signature" => "abcdef0123456789abcdef0123456789abcdef01",
];
```

```java
// GET https://example.com/postback
Map<String, String> params = Map.ofEntries(
    Map.entry("shopID", "12345"),
    Map.entry("type", "subscription"),
    Map.entry("subscriptionType", "recurring"),
    Map.entry("event", "rebill"),
    Map.entry("referenceID", "order-1001"),
    Map.entry("saleID", "123456"),
    Map.entry("transactionID", "987654"),
    Map.entry("amount", "9.99"),
    Map.entry("currency", "USD"),
    Map.entry("nextChargeOn", "2015-04-24"),
    Map.entry("subscriptionPhase", "terminated"),
    Map.entry("custom1", "xxyyzz"),
    Map.entry("custom2", "custom-2"),
    Map.entry("custom3", "custom-3"),
    Map.entry("paymentMethod", "CC"),
    Map.entry("signature", "abcdef0123456789abcdef0123456789abcdef01")
);
```

## Extend postback

Merchant or Verotel support may grant extra days to an active subscription. This means that the
expiration date or the date of the next planned rebill gets shifted by number of days to the future. The
extend postback is then sent to merchant’s postback URL to notify the merchant about that the
subscription got extended.

<aside class="doc-callout doc-callout--notice">
<p>Please note that the extend postback is also sent when the merchant has &quot;Rebill-retry&quot; enabled and the first rebill is declined. In such situation, the system extends the subscription as if the rebill was approved (sends the extend postback) and rebill retries are scheduled. If any of the retries is successful, the subscription continues normally. If the last rebill retry fails, then the subscription gets terminated early.</p>
</aside>

`GET`

Your endpoint receives this call.

### Query parameters

- `shopID` (number)
  numerical ID of the website in the Verotel system
- `type` (string)
  `subscription`
- `subscriptionType` (string)
  `recurring` or `one-time`
- `event` (string)
  `extend`
- `referenceID` (string)
  merchant reference identifier. It must be unique if provided
- `saleID` (number)
  identifier of the sale in the Verotel system
- `nextChargeOn or expiresOn` (string)
  date when cancelled or one-time subscription expires, or date of the next planned rebill [yyyy-mm-dd] e.g “2015-04-24”
- `subscriptionPhase` (string)
  `trial` `normal` `discounted`
- `custom1` (string)
  pass-through variable - max 255 printable characters
- `custom2` (string)
  pass-through variable - max 255 printable characters
- `custom3` (string)
  pass-through variable - max 255 printable characters
- `signature` (string)
  Signature calculation

```http
GET https://example.com/postback
    ?shopID=12345
    &type=subscription
    &subscriptionType=recurring
    &event=extend
    &referenceID=order-1001
    &saleID=123456
    &nextChargeOn or expiresOn=value
    &subscriptionPhase=terminated
    &custom1=xxyyzz
    &custom2=custom-2
    &custom3=custom-3
    &signature=abcdef0123456789abcdef0123456789abcdef01
```

```node
const url = new URL("https://example.com/postback");
url.searchParams.set("shopID", "12345");
url.searchParams.set("type", "subscription");
url.searchParams.set("subscriptionType", "recurring");
url.searchParams.set("event", "extend");
url.searchParams.set("referenceID", "order-1001");
url.searchParams.set("saleID", "123456");
url.searchParams.set("nextChargeOn or expiresOn", "value");
url.searchParams.set("subscriptionPhase", "terminated");
url.searchParams.set("custom1", "xxyyzz");
url.searchParams.set("custom2", "custom-2");
url.searchParams.set("custom3", "custom-3");
url.searchParams.set("signature", "abcdef0123456789abcdef0123456789abcdef01");
const response = await fetch(url);
```

```python
from urllib.parse import urlencode
from urllib.request import urlopen

params = {
    "shopID": "12345",
    "type": "subscription",
    "subscriptionType": "recurring",
    "event": "extend",
    "referenceID": "order-1001",
    "saleID": "123456",
    "nextChargeOn or expiresOn": "value",
    "subscriptionPhase": "terminated",
    "custom1": "xxyyzz",
    "custom2": "custom-2",
    "custom3": "custom-3",
    "signature": "abcdef0123456789abcdef0123456789abcdef01",
}
url = "https://example.com/postback?" + urlencode(params)
response = urlopen(url)
```

```php
// GET https://example.com/postback
$params = [
    "shopID" => "12345",
    "type" => "subscription",
    "subscriptionType" => "recurring",
    "event" => "extend",
    "referenceID" => "order-1001",
    "saleID" => "123456",
    "nextChargeOn or expiresOn" => "value",
    "subscriptionPhase" => "terminated",
    "custom1" => "xxyyzz",
    "custom2" => "custom-2",
    "custom3" => "custom-3",
    "signature" => "abcdef0123456789abcdef0123456789abcdef01",
];
```

```java
// GET https://example.com/postback
Map<String, String> params = Map.ofEntries(
    Map.entry("shopID", "12345"),
    Map.entry("type", "subscription"),
    Map.entry("subscriptionType", "recurring"),
    Map.entry("event", "extend"),
    Map.entry("referenceID", "order-1001"),
    Map.entry("saleID", "123456"),
    Map.entry("nextChargeOn or expiresOn", "value"),
    Map.entry("subscriptionPhase", "terminated"),
    Map.entry("custom1", "xxyyzz"),
    Map.entry("custom2", "custom-2"),
    Map.entry("custom3", "custom-3"),
    Map.entry("signature", "abcdef0123456789abcdef0123456789abcdef01")
);
```

## Downgrade postback

If Merchant or Verotel support changes the next rebill price the Downgrade postback call is sent

`GET`

Your endpoint receives this call.

### Query parameters

- `shopID` (number)
  numerical ID of the website in the Verotel system
- `type` (string)
  `subscription`
- `subscriptionType` (string)
  `recurring` or `one-time`
- `event` (string)
  `downgrade`
- `referenceID` (string)
  merchant reference identifier. It must be unique if provided
- `saleID` (number)
  identifier of the sale in the Verotel system
- `amount` (number)
  amount to be processed in nnn.nn format
- `currency` (string)
  3 char ISO code of the Sale currency
- `subscriptionPhase` (string)
  `normal`
- `custom1` (string)
  pass-through variable - max 255 printable characters
- `custom2` (string)
  pass-through variable - max 255 printable characters
- `custom3` (string)
  pass-through variable - max 255 printable characters
- `signature` (string)
  Signature calculation

```http
GET https://example.com/postback
    ?shopID=12345
    &type=subscription
    &subscriptionType=recurring
    &event=downgrade
    &referenceID=order-1001
    &saleID=123456
    &amount=9.99
    &currency=USD
    &subscriptionPhase=normal
    &custom1=xxyyzz
    &custom2=custom-2
    &custom3=custom-3
    &signature=abcdef0123456789abcdef0123456789abcdef01
```

```node
const url = new URL("https://example.com/postback");
url.searchParams.set("shopID", "12345");
url.searchParams.set("type", "subscription");
url.searchParams.set("subscriptionType", "recurring");
url.searchParams.set("event", "downgrade");
url.searchParams.set("referenceID", "order-1001");
url.searchParams.set("saleID", "123456");
url.searchParams.set("amount", "9.99");
url.searchParams.set("currency", "USD");
url.searchParams.set("subscriptionPhase", "normal");
url.searchParams.set("custom1", "xxyyzz");
url.searchParams.set("custom2", "custom-2");
url.searchParams.set("custom3", "custom-3");
url.searchParams.set("signature", "abcdef0123456789abcdef0123456789abcdef01");
const response = await fetch(url);
```

```python
from urllib.parse import urlencode
from urllib.request import urlopen

params = {
    "shopID": "12345",
    "type": "subscription",
    "subscriptionType": "recurring",
    "event": "downgrade",
    "referenceID": "order-1001",
    "saleID": "123456",
    "amount": "9.99",
    "currency": "USD",
    "subscriptionPhase": "normal",
    "custom1": "xxyyzz",
    "custom2": "custom-2",
    "custom3": "custom-3",
    "signature": "abcdef0123456789abcdef0123456789abcdef01",
}
url = "https://example.com/postback?" + urlencode(params)
response = urlopen(url)
```

```php
// GET https://example.com/postback
$params = [
    "shopID" => "12345",
    "type" => "subscription",
    "subscriptionType" => "recurring",
    "event" => "downgrade",
    "referenceID" => "order-1001",
    "saleID" => "123456",
    "amount" => "9.99",
    "currency" => "USD",
    "subscriptionPhase" => "normal",
    "custom1" => "xxyyzz",
    "custom2" => "custom-2",
    "custom3" => "custom-3",
    "signature" => "abcdef0123456789abcdef0123456789abcdef01",
];
```

```java
// GET https://example.com/postback
Map<String, String> params = Map.ofEntries(
    Map.entry("shopID", "12345"),
    Map.entry("type", "subscription"),
    Map.entry("subscriptionType", "recurring"),
    Map.entry("event", "downgrade"),
    Map.entry("referenceID", "order-1001"),
    Map.entry("saleID", "123456"),
    Map.entry("amount", "9.99"),
    Map.entry("currency", "USD"),
    Map.entry("subscriptionPhase", "normal"),
    Map.entry("custom1", "xxyyzz"),
    Map.entry("custom2", "custom-2"),
    Map.entry("custom3", "custom-3"),
    Map.entry("signature", "abcdef0123456789abcdef0123456789abcdef01")
);
```

## Cancel postback

Cancel postback call is sent to the merchant’s URL after the subscription is cancelled by the buyer, merchant, Verotel support or by the system.

`GET`

Your endpoint receives this call.

### Query parameters

- `shopID` (number)
  numerical ID of the website in the Verotel system
- `type` (string)
  `subscription`
- `subscriptionType` (string)
  `recurring`
- `event` (string)
  `cancel`
- `referenceID` (string)
  merchant reference identifier. It must be unique if provided
- `saleID` (number)
  identifier of the sale in the Verotel system
- `expiresOn` (string)
  expiry date [yyyy-mm-dd] eq. “2015-04-24”
- `cancelledBy` (string)
  `user` `support` `merchant` `system`
- `custom1` (string)
  pass-through variable - max 255 printable characters
- `custom2` (string)
  pass-through variable - max 255 printable characters
- `custom3` (string)
  pass-through variable - max 255 printable characters
- `signature` (string)
  Signature calculation

```http
GET https://example.com/postback
    ?shopID=12345
    &type=subscription
    &subscriptionType=recurring
    &event=cancel
    &referenceID=order-1001
    &saleID=123456
    &expiresOn=2015-04-24
    &cancelledBy=merchant
    &custom1=xxyyzz
    &custom2=custom-2
    &custom3=custom-3
    &signature=abcdef0123456789abcdef0123456789abcdef01
```

```node
const url = new URL("https://example.com/postback");
url.searchParams.set("shopID", "12345");
url.searchParams.set("type", "subscription");
url.searchParams.set("subscriptionType", "recurring");
url.searchParams.set("event", "cancel");
url.searchParams.set("referenceID", "order-1001");
url.searchParams.set("saleID", "123456");
url.searchParams.set("expiresOn", "2015-04-24");
url.searchParams.set("cancelledBy", "merchant");
url.searchParams.set("custom1", "xxyyzz");
url.searchParams.set("custom2", "custom-2");
url.searchParams.set("custom3", "custom-3");
url.searchParams.set("signature", "abcdef0123456789abcdef0123456789abcdef01");
const response = await fetch(url);
```

```python
from urllib.parse import urlencode
from urllib.request import urlopen

params = {
    "shopID": "12345",
    "type": "subscription",
    "subscriptionType": "recurring",
    "event": "cancel",
    "referenceID": "order-1001",
    "saleID": "123456",
    "expiresOn": "2015-04-24",
    "cancelledBy": "merchant",
    "custom1": "xxyyzz",
    "custom2": "custom-2",
    "custom3": "custom-3",
    "signature": "abcdef0123456789abcdef0123456789abcdef01",
}
url = "https://example.com/postback?" + urlencode(params)
response = urlopen(url)
```

```php
// GET https://example.com/postback
$params = [
    "shopID" => "12345",
    "type" => "subscription",
    "subscriptionType" => "recurring",
    "event" => "cancel",
    "referenceID" => "order-1001",
    "saleID" => "123456",
    "expiresOn" => "2015-04-24",
    "cancelledBy" => "merchant",
    "custom1" => "xxyyzz",
    "custom2" => "custom-2",
    "custom3" => "custom-3",
    "signature" => "abcdef0123456789abcdef0123456789abcdef01",
];
```

```java
// GET https://example.com/postback
Map<String, String> params = Map.ofEntries(
    Map.entry("shopID", "12345"),
    Map.entry("type", "subscription"),
    Map.entry("subscriptionType", "recurring"),
    Map.entry("event", "cancel"),
    Map.entry("referenceID", "order-1001"),
    Map.entry("saleID", "123456"),
    Map.entry("expiresOn", "2015-04-24"),
    Map.entry("cancelledBy", "merchant"),
    Map.entry("custom1", "xxyyzz"),
    Map.entry("custom2", "custom-2"),
    Map.entry("custom3", "custom-3"),
    Map.entry("signature", "abcdef0123456789abcdef0123456789abcdef01")
);
```

## Uncancel postback

Occasionally, buyers wish to revert cancellation of their subscription. Uncancel can be done only by Verotel support. The postback call is sent to the merchant’s postback URL immediately after the subscription was uncancelled.

`GET`

Your endpoint receives this call.

### Query parameters

- `shopID` (number)
  numerical ID of the website in the Verotel system
- `type` (string)
  `subscription`
- `subscriptionType` (string)
  `recurring`
- `event` (string)
  `uncancel`
- `referenceID` (string)
  merchant reference identifier. It must be unique if provided
- `saleID` (number)
  identifier of the sale in the Verotel system
- `nextChargeOn` (string)
  date of the next planned rebill [yyyy-mm-dd] eq. “2015-04-24”
- `subscriptionPhase` (string)
  `trial` `normal` `discounted`
- `uncancelledBy` (string)
  `support`
- `custom1` (string)
  pass-through variable - max 255 printable characters
- `custom2` (string)
  pass-through variable - max 255 printable characters
- `custom3` (string)
  pass-through variable - max 255 printable characters
- `signature` (string)
  Signature calculation

```http
GET https://example.com/postback
    ?shopID=12345
    &type=subscription
    &subscriptionType=recurring
    &event=uncancel
    &referenceID=order-1001
    &saleID=123456
    &nextChargeOn=2015-04-24
    &subscriptionPhase=terminated
    &uncancelledBy=support
    &custom1=xxyyzz
    &custom2=custom-2
    &custom3=custom-3
    &signature=abcdef0123456789abcdef0123456789abcdef01
```

```node
const url = new URL("https://example.com/postback");
url.searchParams.set("shopID", "12345");
url.searchParams.set("type", "subscription");
url.searchParams.set("subscriptionType", "recurring");
url.searchParams.set("event", "uncancel");
url.searchParams.set("referenceID", "order-1001");
url.searchParams.set("saleID", "123456");
url.searchParams.set("nextChargeOn", "2015-04-24");
url.searchParams.set("subscriptionPhase", "terminated");
url.searchParams.set("uncancelledBy", "support");
url.searchParams.set("custom1", "xxyyzz");
url.searchParams.set("custom2", "custom-2");
url.searchParams.set("custom3", "custom-3");
url.searchParams.set("signature", "abcdef0123456789abcdef0123456789abcdef01");
const response = await fetch(url);
```

```python
from urllib.parse import urlencode
from urllib.request import urlopen

params = {
    "shopID": "12345",
    "type": "subscription",
    "subscriptionType": "recurring",
    "event": "uncancel",
    "referenceID": "order-1001",
    "saleID": "123456",
    "nextChargeOn": "2015-04-24",
    "subscriptionPhase": "terminated",
    "uncancelledBy": "support",
    "custom1": "xxyyzz",
    "custom2": "custom-2",
    "custom3": "custom-3",
    "signature": "abcdef0123456789abcdef0123456789abcdef01",
}
url = "https://example.com/postback?" + urlencode(params)
response = urlopen(url)
```

```php
// GET https://example.com/postback
$params = [
    "shopID" => "12345",
    "type" => "subscription",
    "subscriptionType" => "recurring",
    "event" => "uncancel",
    "referenceID" => "order-1001",
    "saleID" => "123456",
    "nextChargeOn" => "2015-04-24",
    "subscriptionPhase" => "terminated",
    "uncancelledBy" => "support",
    "custom1" => "xxyyzz",
    "custom2" => "custom-2",
    "custom3" => "custom-3",
    "signature" => "abcdef0123456789abcdef0123456789abcdef01",
];
```

```java
// GET https://example.com/postback
Map<String, String> params = Map.ofEntries(
    Map.entry("shopID", "12345"),
    Map.entry("type", "subscription"),
    Map.entry("subscriptionType", "recurring"),
    Map.entry("event", "uncancel"),
    Map.entry("referenceID", "order-1001"),
    Map.entry("saleID", "123456"),
    Map.entry("nextChargeOn", "2015-04-24"),
    Map.entry("subscriptionPhase", "terminated"),
    Map.entry("uncancelledBy", "support"),
    Map.entry("custom1", "xxyyzz"),
    Map.entry("custom2", "custom-2"),
    Map.entry("custom3", "custom-3"),
    Map.entry("signature", "abcdef0123456789abcdef0123456789abcdef01")
);
```

## Expiry postback

Expiry postback call is sent to the merchant’s postback URL when the subscription gets terminated. The reason for the termination could be the end of a cancelled subscription, declined rebill transaction or termination by Verotel support or the merchant.

`GET`

Your endpoint receives this call.

### Query parameters

- `shopID` (number)
  numerical ID of the website in the Verotel system
- `type` (string)
  `subscription`
- `subscriptionType` (string)
  `recurring` or `one-time`
- `event` (string)
  `expiry`
- `referenceID` (string)
  merchant reference identifier. It must be unique if provided
- `saleID` (number)
  identifier of the sale in the Verotel system
- `custom1` (string)
  pass-through variable - max 255 printable characters
- `custom2` (string)
  pass-through variable - max 255 printable characters
- `custom3` (string)
  pass-through variable - max 255 printable characters
- `signature` (string)
  Signature calculation

```http
GET https://example.com/postback
    ?shopID=12345
    &type=subscription
    &subscriptionType=recurring
    &event=expiry
    &referenceID=order-1001
    &saleID=123456
    &custom1=xxyyzz
    &custom2=custom-2
    &custom3=custom-3
    &signature=abcdef0123456789abcdef0123456789abcdef01
```

```node
const url = new URL("https://example.com/postback");
url.searchParams.set("shopID", "12345");
url.searchParams.set("type", "subscription");
url.searchParams.set("subscriptionType", "recurring");
url.searchParams.set("event", "expiry");
url.searchParams.set("referenceID", "order-1001");
url.searchParams.set("saleID", "123456");
url.searchParams.set("custom1", "xxyyzz");
url.searchParams.set("custom2", "custom-2");
url.searchParams.set("custom3", "custom-3");
url.searchParams.set("signature", "abcdef0123456789abcdef0123456789abcdef01");
const response = await fetch(url);
```

```python
from urllib.parse import urlencode
from urllib.request import urlopen

params = {
    "shopID": "12345",
    "type": "subscription",
    "subscriptionType": "recurring",
    "event": "expiry",
    "referenceID": "order-1001",
    "saleID": "123456",
    "custom1": "xxyyzz",
    "custom2": "custom-2",
    "custom3": "custom-3",
    "signature": "abcdef0123456789abcdef0123456789abcdef01",
}
url = "https://example.com/postback?" + urlencode(params)
response = urlopen(url)
```

```php
// GET https://example.com/postback
$params = [
    "shopID" => "12345",
    "type" => "subscription",
    "subscriptionType" => "recurring",
    "event" => "expiry",
    "referenceID" => "order-1001",
    "saleID" => "123456",
    "custom1" => "xxyyzz",
    "custom2" => "custom-2",
    "custom3" => "custom-3",
    "signature" => "abcdef0123456789abcdef0123456789abcdef01",
];
```

```java
// GET https://example.com/postback
Map<String, String> params = Map.ofEntries(
    Map.entry("shopID", "12345"),
    Map.entry("type", "subscription"),
    Map.entry("subscriptionType", "recurring"),
    Map.entry("event", "expiry"),
    Map.entry("referenceID", "order-1001"),
    Map.entry("saleID", "123456"),
    Map.entry("custom1", "xxyyzz"),
    Map.entry("custom2", "custom-2"),
    Map.entry("custom3", "custom-3"),
    Map.entry("signature", "abcdef0123456789abcdef0123456789abcdef01")
);
```

## Credit postback

Credit postback call is sent to the merchant’s postback URL when any transaction of the subscription is
credited by merchant, Verotel support or by system (e.g. when an automated refund is performed).
The refund also terminates subscription.

`GET`

Your endpoint receives this call.

### Query parameters

- `shopID` (number)
  numerical ID of the website in the Verotel system
- `event` (string)
  `credit`
- `referenceID` (string)
  merchant reference identifier. It must be unique if provided
- `saleID` (number)
  identifier of the sale in the Verotel system
- `priceAmount` (number)
  amount of refunded transaction
- `priceCurrency` (string)
  refunded transaction currency
- `transactionID` (number)
  transaction id of credit transaction
- `parentID` (number)
  transaction id of transaction which was credited
- `subscriptionType` (string)
  `recurring` or `one-time`
- `subscriptionPhase` (string)
  `terminated` or `normal` (for partial credit without terminate initiated)
- `type` (string)
  `subscription`
- `custom1` (string)
  pass-through variable - max 255 printable characters
- `custom2` (string)
  pass-through variable - max 255 printable characters
- `custom3` (string)
  pass-through variable - max 255 printable characters
- `signature` (string)
  Signature calculation

```http
GET https://example.com/postback
    ?shopID=12345
    &event=credit
    &referenceID=order-1001
    &saleID=123456
    &priceAmount=9.99
    &priceCurrency=USD
    &transactionID=987654
    &parentID=456789
    &subscriptionType=recurring
    &subscriptionPhase=terminated
    &type=subscription
    &custom1=xxyyzz
    &custom2=custom-2
    &custom3=custom-3
    &signature=abcdef0123456789abcdef0123456789abcdef01
```

```node
const url = new URL("https://example.com/postback");
url.searchParams.set("shopID", "12345");
url.searchParams.set("event", "credit");
url.searchParams.set("referenceID", "order-1001");
url.searchParams.set("saleID", "123456");
url.searchParams.set("priceAmount", "9.99");
url.searchParams.set("priceCurrency", "USD");
url.searchParams.set("transactionID", "987654");
url.searchParams.set("parentID", "456789");
url.searchParams.set("subscriptionType", "recurring");
url.searchParams.set("subscriptionPhase", "terminated");
url.searchParams.set("type", "subscription");
url.searchParams.set("custom1", "xxyyzz");
url.searchParams.set("custom2", "custom-2");
url.searchParams.set("custom3", "custom-3");
url.searchParams.set("signature", "abcdef0123456789abcdef0123456789abcdef01");
const response = await fetch(url);
```

```python
from urllib.parse import urlencode
from urllib.request import urlopen

params = {
    "shopID": "12345",
    "event": "credit",
    "referenceID": "order-1001",
    "saleID": "123456",
    "priceAmount": "9.99",
    "priceCurrency": "USD",
    "transactionID": "987654",
    "parentID": "456789",
    "subscriptionType": "recurring",
    "subscriptionPhase": "terminated",
    "type": "subscription",
    "custom1": "xxyyzz",
    "custom2": "custom-2",
    "custom3": "custom-3",
    "signature": "abcdef0123456789abcdef0123456789abcdef01",
}
url = "https://example.com/postback?" + urlencode(params)
response = urlopen(url)
```

```php
// GET https://example.com/postback
$params = [
    "shopID" => "12345",
    "event" => "credit",
    "referenceID" => "order-1001",
    "saleID" => "123456",
    "priceAmount" => "9.99",
    "priceCurrency" => "USD",
    "transactionID" => "987654",
    "parentID" => "456789",
    "subscriptionType" => "recurring",
    "subscriptionPhase" => "terminated",
    "type" => "subscription",
    "custom1" => "xxyyzz",
    "custom2" => "custom-2",
    "custom3" => "custom-3",
    "signature" => "abcdef0123456789abcdef0123456789abcdef01",
];
```

```java
// GET https://example.com/postback
Map<String, String> params = Map.ofEntries(
    Map.entry("shopID", "12345"),
    Map.entry("event", "credit"),
    Map.entry("referenceID", "order-1001"),
    Map.entry("saleID", "123456"),
    Map.entry("priceAmount", "9.99"),
    Map.entry("priceCurrency", "USD"),
    Map.entry("transactionID", "987654"),
    Map.entry("parentID", "456789"),
    Map.entry("subscriptionType", "recurring"),
    Map.entry("subscriptionPhase", "terminated"),
    Map.entry("type", "subscription"),
    Map.entry("custom1", "xxyyzz"),
    Map.entry("custom2", "custom-2"),
    Map.entry("custom3", "custom-3"),
    Map.entry("signature", "abcdef0123456789abcdef0123456789abcdef01")
);
```

## Chargeback postback

Chargeback postback call is sent to the merchant’s postback URL when sale transaction is
chargebacked. This also blacklists the buyer.

`GET`

Your endpoint receives this call.

### Query parameters

- `shopID` (number)
  numerical ID of the website in the Verotel system
- `event` (string)
  `chargeback`
- `referenceID` (string)
  merchant reference identifier. It must be unique if provided
- `saleID` (number)
  identifier of the sale in the Verotel system
- `priceAmount` (number)
  amount of chargebacked transaction
- `priceCurrency` (string)
  chargebacked transaction currency
- `transactionID` (number)
  transaction id of credit transaction
- `parentID` (number)
  transaction id of transaction which was credited
- `subscriptionType` (string)
  `recurring` or `one-time`
- `subscriptionPhase` (string)
  `terminated`
- `type` (string)
  `subscription`
- `custom1` (string)
  pass-through variable - max 255 printable characters
- `custom2` (string)
  pass-through variable - max 255 printable characters
- `custom3` (string)
  pass-through variable - max 255 printable characters
- `signature` (string)
  Signature calculation

```http
GET https://example.com/postback
    ?shopID=12345
    &event=chargeback
    &referenceID=order-1001
    &saleID=123456
    &priceAmount=9.99
    &priceCurrency=USD
    &transactionID=987654
    &parentID=456789
    &subscriptionType=recurring
    &subscriptionPhase=terminated
    &type=subscription
    &custom1=xxyyzz
    &custom2=custom-2
    &custom3=custom-3
    &signature=abcdef0123456789abcdef0123456789abcdef01
```

```node
const url = new URL("https://example.com/postback");
url.searchParams.set("shopID", "12345");
url.searchParams.set("event", "chargeback");
url.searchParams.set("referenceID", "order-1001");
url.searchParams.set("saleID", "123456");
url.searchParams.set("priceAmount", "9.99");
url.searchParams.set("priceCurrency", "USD");
url.searchParams.set("transactionID", "987654");
url.searchParams.set("parentID", "456789");
url.searchParams.set("subscriptionType", "recurring");
url.searchParams.set("subscriptionPhase", "terminated");
url.searchParams.set("type", "subscription");
url.searchParams.set("custom1", "xxyyzz");
url.searchParams.set("custom2", "custom-2");
url.searchParams.set("custom3", "custom-3");
url.searchParams.set("signature", "abcdef0123456789abcdef0123456789abcdef01");
const response = await fetch(url);
```

```python
from urllib.parse import urlencode
from urllib.request import urlopen

params = {
    "shopID": "12345",
    "event": "chargeback",
    "referenceID": "order-1001",
    "saleID": "123456",
    "priceAmount": "9.99",
    "priceCurrency": "USD",
    "transactionID": "987654",
    "parentID": "456789",
    "subscriptionType": "recurring",
    "subscriptionPhase": "terminated",
    "type": "subscription",
    "custom1": "xxyyzz",
    "custom2": "custom-2",
    "custom3": "custom-3",
    "signature": "abcdef0123456789abcdef0123456789abcdef01",
}
url = "https://example.com/postback?" + urlencode(params)
response = urlopen(url)
```

```php
// GET https://example.com/postback
$params = [
    "shopID" => "12345",
    "event" => "chargeback",
    "referenceID" => "order-1001",
    "saleID" => "123456",
    "priceAmount" => "9.99",
    "priceCurrency" => "USD",
    "transactionID" => "987654",
    "parentID" => "456789",
    "subscriptionType" => "recurring",
    "subscriptionPhase" => "terminated",
    "type" => "subscription",
    "custom1" => "xxyyzz",
    "custom2" => "custom-2",
    "custom3" => "custom-3",
    "signature" => "abcdef0123456789abcdef0123456789abcdef01",
];
```

```java
// GET https://example.com/postback
Map<String, String> params = Map.ofEntries(
    Map.entry("shopID", "12345"),
    Map.entry("event", "chargeback"),
    Map.entry("referenceID", "order-1001"),
    Map.entry("saleID", "123456"),
    Map.entry("priceAmount", "9.99"),
    Map.entry("priceCurrency", "USD"),
    Map.entry("transactionID", "987654"),
    Map.entry("parentID", "456789"),
    Map.entry("subscriptionType", "recurring"),
    Map.entry("subscriptionPhase", "terminated"),
    Map.entry("type", "subscription"),
    Map.entry("custom1", "xxyyzz"),
    Map.entry("custom2", "custom-2"),
    Map.entry("custom3", "custom-3"),
    Map.entry("signature", "abcdef0123456789abcdef0123456789abcdef01")
);
```

## Upgrade postback

Upgrade postback call is sent to the merchant’s postback URL when the subscription is switched from
one plan to another. The postback is sent instead of the Successful sale postbacks when the new
subscription the buyer is switching to is successfully created and the previous subscription is
terminated in Verotel system (No Expiry postback is sent). See “FlexPay API Upgrade” document for
more details.

`GET`

Your endpoint receives this call.

### Query parameters

- `shopID` (number)
  numerical ID of the website in the Verotel system
- `type` (string)
  `subscription`
- `subscriptionType` (string)
  `one-time` or `recurring`
- `event` (string)
  `upgrade`
- `referenceID` (string)
  merchant reference identifier if provided in the first sale.
- `saleID` (number)
  identifier of the sale in the Verotel system
- `transactionID` (number)
  identifier of the transaction in the Verotel system (only avaible for postbacks version 2)
- `precededBySaleID` (number)
  Identifier of the previous sale the enduser is switching from
- `priceAmount` (number)
  amount to be processed in nnn.nn format
- `priceCurrency` (string)
  3 char ISO code of the Sale currency
- `period` (string)
  subscription duration in ISO8601 format
- `expiresOn or nextChargeOn` (string)
  date of next rebill or expiry date [yyyy-mm-dd] eq. “2015-04-24”
- `custom1` (string)
  pass-through variable - max 255 printable characters
- `custom2` (string)
  pass-through variable - max 255 printable characters
- `custom3` (string)
  pass-through variable - max 255 printable characters
- `paymentMethod` (string)
  payment method, `CC`, `YOURSAFE_DIRECT`, `DDEU`
- `signature` (string)
  Signature calculation
- `truncatedPAN` (string)
  Truncated (masked) payment instrument identification, e.g. card number
- `CCBrand` (string)
  Only present if paid via Credit Card, represents the card brand, e.g. VISA

```http
GET https://example.com/postback
    ?shopID=12345
    &type=subscription
    &subscriptionType=recurring
    &event=upgrade
    &referenceID=order-1001
    &saleID=123456
    &transactionID=987654
    &precededBySaleID=123450
    &priceAmount=9.99
    &priceCurrency=USD
    &period=P30D
    &expiresOn or nextChargeOn=value
    &custom1=xxyyzz
    &custom2=custom-2
    &custom3=custom-3
    &paymentMethod=CC
    &signature=abcdef0123456789abcdef0123456789abcdef01
    &truncatedPAN=411111******1111
    &CCBrand=VISA
```

```node
const url = new URL("https://example.com/postback");
url.searchParams.set("shopID", "12345");
url.searchParams.set("type", "subscription");
url.searchParams.set("subscriptionType", "recurring");
url.searchParams.set("event", "upgrade");
url.searchParams.set("referenceID", "order-1001");
url.searchParams.set("saleID", "123456");
url.searchParams.set("transactionID", "987654");
url.searchParams.set("precededBySaleID", "123450");
url.searchParams.set("priceAmount", "9.99");
url.searchParams.set("priceCurrency", "USD");
url.searchParams.set("period", "P30D");
url.searchParams.set("expiresOn or nextChargeOn", "value");
url.searchParams.set("custom1", "xxyyzz");
url.searchParams.set("custom2", "custom-2");
url.searchParams.set("custom3", "custom-3");
url.searchParams.set("paymentMethod", "CC");
url.searchParams.set("signature", "abcdef0123456789abcdef0123456789abcdef01");
url.searchParams.set("truncatedPAN", "411111******1111");
url.searchParams.set("CCBrand", "VISA");
const response = await fetch(url);
```

```python
from urllib.parse import urlencode
from urllib.request import urlopen

params = {
    "shopID": "12345",
    "type": "subscription",
    "subscriptionType": "recurring",
    "event": "upgrade",
    "referenceID": "order-1001",
    "saleID": "123456",
    "transactionID": "987654",
    "precededBySaleID": "123450",
    "priceAmount": "9.99",
    "priceCurrency": "USD",
    "period": "P30D",
    "expiresOn or nextChargeOn": "value",
    "custom1": "xxyyzz",
    "custom2": "custom-2",
    "custom3": "custom-3",
    "paymentMethod": "CC",
    "signature": "abcdef0123456789abcdef0123456789abcdef01",
    "truncatedPAN": "411111******1111",
    "CCBrand": "VISA",
}
url = "https://example.com/postback?" + urlencode(params)
response = urlopen(url)
```

```php
// GET https://example.com/postback
$params = [
    "shopID" => "12345",
    "type" => "subscription",
    "subscriptionType" => "recurring",
    "event" => "upgrade",
    "referenceID" => "order-1001",
    "saleID" => "123456",
    "transactionID" => "987654",
    "precededBySaleID" => "123450",
    "priceAmount" => "9.99",
    "priceCurrency" => "USD",
    "period" => "P30D",
    "expiresOn or nextChargeOn" => "value",
    "custom1" => "xxyyzz",
    "custom2" => "custom-2",
    "custom3" => "custom-3",
    "paymentMethod" => "CC",
    "signature" => "abcdef0123456789abcdef0123456789abcdef01",
    "truncatedPAN" => "411111******1111",
    "CCBrand" => "VISA",
];
```

```java
// GET https://example.com/postback
Map<String, String> params = Map.ofEntries(
    Map.entry("shopID", "12345"),
    Map.entry("type", "subscription"),
    Map.entry("subscriptionType", "recurring"),
    Map.entry("event", "upgrade"),
    Map.entry("referenceID", "order-1001"),
    Map.entry("saleID", "123456"),
    Map.entry("transactionID", "987654"),
    Map.entry("precededBySaleID", "123450"),
    Map.entry("priceAmount", "9.99"),
    Map.entry("priceCurrency", "USD"),
    Map.entry("period", "P30D"),
    Map.entry("expiresOn or nextChargeOn", "value"),
    Map.entry("custom1", "xxyyzz"),
    Map.entry("custom2", "custom-2"),
    Map.entry("custom3", "custom-3"),
    Map.entry("paymentMethod", "CC"),
    Map.entry("signature", "abcdef0123456789abcdef0123456789abcdef01"),
    Map.entry("truncatedPAN", "411111******1111"),
    Map.entry("CCBrand", "VISA")
);
```

## Status page request

```php
$brand = Verotel\FlexPay\Brand::create_from_merchant_id(/* Your customer ID */ '9804000000000000');

$flexpayClient = new Verotel\FlexPay\Client(/* shop ID */ 12345, "FlexPay Signature Key", $brand);

$statusURL = $flexpayClient->get_status_URL(['saleID' => 123456]);

$statusPageData = Symfony\Component\Yaml\Yaml::parse(file_get_contents($statusURL));

// handle data fetched from status page
```

```java
URL statusUrl = flexPayClient.getStatusUrlBySale(123456);

// fetch URL content
```

A status of a sale made with a FlexPay API can be reviewed by querying the status page. Status page
provides complete information about the sale, the buyer, and its status.

### HTTP request

Verotel

`GET https://secure.verotel.com/status/order?`

CardBilling

`GET https://secure.billing.creditcard/status/order?`

GayCharge

`GET https://secure.gaycharge.com/status/order?`

YoursafeDirect

`GET https://secure.yoursafedirect.com/status/order?`

`NOTFOUND` - purchase not found
`ERROR` - error (see ‘error’ key) |
Can be one of following: `Credit Card` or `Direct Debit EU` |

`GET /status/order`

### Query parameters

- `version` (number)
  `4`
- `shopID` (number)
  numerical ID of the website in the Verotel system
- `referenceID` (string)
  Merchant’s reference identifier if provided (referenceID OR saleID must be posted - NOT BOTH)
- `saleID` (number)
  Verotel saleID identifier (referenceID OR saleID must be posted - NOT BOTH)
- `signature` (string)
  Signature calculation

### Response

#### 200

- `response` (string)
  `FOUND` - purchase record found and returned
  `NOTFOUND` - purchase not found
  `ERROR` - error (see ‘error’ key)
- `error` (string)
  message (for response=`ERROR`)
- `saleID` (string)
  identifier of the transaction in Verotel System
- `shopID` (string)
  ID of website in Verotel system
- `paymentMethod` (string)
  an identifier of payment method that was used for the transaction.
  Can be one of following: `Credit Card` or `Direct Debit EU`
- `priceAmount` (string)
  amount processed in nnn.nn format
- `priceCurrency` (string)
  3 char ISO code of the Sale currency
- `trialAmount` (string)
  trial period processed amount
- `trialPeriod` (string)
  duration of trial period in ISO8601 format
- `discountAmount` (string)
  reccurring amount after cancel discount confirmation by buyer
- `period` (string)
  duration in ISO8601 format, for example: `P30D`
- `description` (string)
  Product description text - max 100 printable characters
- `type` (string)
  `purchase` or `subscription`
- `subscriptionType` (string)
  `one-time` or `recurring`
- `expired` (string)
  `yes` or `no`
- `expiresOn` (string)
  when subscription will be terminated
- `referenceID` (string)
  Merchant reference identifier - max 100 printable characters
- `name` (string)
  name of the buyer
- `email` (string)
  email address of the buyer
- `country` (string)
  selected or detected country ISO code (ISO 3166-1-alpha-2 code)
- `oneClickToken` (string)
  If the feature is enabled - Currently valid oneClickToken
- `cancelled` (string)
  `yes` or `no`
- `cancelledOn` (string)
  Timestamp of cancellation
- `cancelledBy` (string)
  `user` `support` `merchant` `system`
- `createdOn` (string)
  Timestamp of purchase creation
- `saleResult` (string)
  purchase processing result (APPROVED)
- `billingAddr_fullName` (string)
  billing address: full name field value
- `billingAddr_company` (string)
  billing address: company field value
- `billingAddr_addressLine1` (string)
  billing address: 1st line field value
- `billingAddr_addressLine2` (string)
  billing address: 2nd line field value
- `billingAddr_city` (string)
  billing address: city name
- `billingAddr_zip` (string)
  billing address: zip code / postal code
- `billingAddr_state` (string)
  billing address: US state code (ISO 3166-2)
- `billingAddr_country` (string)
  billing address: country ISO code (ISO 3166-1-alpha-2 code)

## Cancel subscription request

Examples are for [Verotel FlexPay PHP client library](https://github.com/verotel/flexpay-php-client)

```php
$brand = Verotel\FlexPay\Brand::create_from_merchant_id(/* Your customer ID */ '9804000000000000');

$flexpayClient = new Verotel\FlexPay\Client(/* shop ID */ 12345, "FlexPay Signature Key", $brand);

$cancelSubscriptionURL = $flexpayClient->get_cancel_subscription_URL([
    "saleID" => 654321
]);
```

    Examples are for [FlexPay Java client library](https://github.com/verotel/flexpay4j)

```java
URL cancelUrl = flexPayClient.getCancelSubscriptionUrl(1234);
```

To allow your subscribers to cancel their subscriptions on your website you can now generate a
subscription specific cancel URL.

### HTTP request

Verotel

`GET https://secure.verotel.com/cancel-subscription?`

CardBilling

`GET https://secure.billing.creditcard/cancel-subscription?`

GayCharge

`GET https://secure.gaycharge.com/cancel-subscription?`

YoursafeDirect

`GET https://secure.yoursafedirect.com/cancel-subscription?`

`GET /cancel-subscription`

### Query parameters

- `version` (string, required)
  version version of the FlexPay call, `4` for this version
- `shopID` (number, required)
  numerical ID of the website or shop in Verotel system
- `saleID` (number, required)
  Verotel saleID identifier
- `signature` (string, required)
  Signature calculation

## Upgrade subscription request

Examples are for [Verotel FlexPay PHP client library](https://github.com/verotel/flexpay-php-client)

```php
$brand = Verotel\FlexPay\Brand::create_from_merchant_id(/* Your customer ID */ '9804000000000000');

$flexpayClient = new Verotel\FlexPay\Client(/* shop ID */ 12345, "FlexPay Signature Key", $brand);

$upgradeSubscriptionURL = $flexpayClient->get_upgrade_subscription_URL([
    "period" => 'P30D',
    "name" => 'Upgrade to one year subscription'
    "precedingSaleID" => 123456,
    "priceAmount" => 20,
    "priceCurrency" => 'USD',
    "period" => 'P1Y',
    "upgradeOption" => 'extend',
]);
```

    Examples are for [FlexPay Java client library](https://github.com/verotel/flexpay4j)

```java
URL upgradeSubscriptionURL = flexpayClient.getUpgradeSubscriptionUrl(
    1234    // preceding sale ID
    "P12D", // period
    SubscriptionType.recurring,
    BigDecimal.valueOf(24), //  price amount
    SaleCurrency.EUR,       // price currency
);
```

Subscription upgrade allows switching from one currently active subscription to a new one with new pricing and rebill period.
It is possible to switch between recurring and one-time subscriptions, between payment methods and change the periods and amounts.

<aside class="doc-callout doc-callout--notice">
<p>If the upgrade transaction is declined the current subscription stays unchanged</p>
</aside>

If successful  – an `upgrade` postback is sent, the current subscription is terminated in Verotel system
(the expiry postback is not send in this case) and the buyer continues with the new subscription.

### Upgrade Options

The optional `upgradeOption` parameter specifies how the remaining time from the previous sale
is handled:

- `extend` - Any remaining time from previous sale is added to the initial period of the new
  subscription. This is also how the remaining time is handled if the “upgradeOption”
  parameter is not specified.

- `lost` - Any remaining time from previous sale is ignored/lost.

### Constructing the Upgrade request

The “upgrade” request is used to redirect buyer to the Verotel Order Page in order to process
superseding subscription with a given amount, duration and currency.

The upgrade request is like the startorder request but the type needs to be “upgradesubscription”
and there is mandatory precedingSaleID parameter.

Please note that referenceID parameter is not accepted in the upgrade request. If referenceID was
supplied initially in the startorder of the preceding subscription, it is copied over to the new upgraded
subscription.

<aside class="doc-callout doc-callout--notice">
<p>It is possible to switch between recurring and onetime subscriptions, between payment methods and change the periods and amounts.</p>
</aside>

### HTTP request

Verotel

`GET https://secure.verotel.com/startorder?`

CardBilling

`GET https://secure.billing.creditcard/startorder?`

GayCharge

`GET https://secure.gaycharge.com/startorder?`

YoursafeDirect

`GET https://secure.yoursafedirect.com/startorder?`

NOTE: only `EUR` is can be used for `DDEU` payment method system |
NOTE: `DDEU` and `YOURSAFE_DIRECT` only support `one-time` |
NOTE: `DDEU` is available only in DE, AT, CH, BE, IT, NL, ES and FR
If oneClickToken is sent, the payment method must be set to `CC` |
NOTE: email is excluded from signature calculations (max 100 chars else will be ignored) |

`GET /startorder`

### Query parameters

- `version` (number, required)
  version version of the FlexPay call, `4` for this version
- `shopID` (number, required)
  numerical ID of the website in the Verotel system
- `type` (string, required)
  `upgradesubscription`
- `precedingSaleID` (number, required)
  Identificator of sale the buyer is upgrading from
- `priceAmount` (number, required)
  amount to be processed in nnn.nn format
- `priceCurrency` (string, required)
  priceCurrency 3 char ISO code, must be one of the Sale currencies (`USD` `EUR` `GBP` `AUD` `CAD` `CHF` `DKK` `NOK` `SEK`)
  NOTE: only `EUR` is can be used for `DDEU` payment method system
- `period` (string, required)
  duration in ISO8601 format, for example: `P30D`, minimum is 7 days for `recurring` and 2 days for `on-time`
- `subscriptionType` (string, required)
  `one-time` or `recurring`
  NOTE: `DDEU` and `YOURSAFE_DIRECT` only support `one-time`
- `name` (string)
  description of the product. Text is displayed on the order page - max 100 printable characters
- `upgradeOption` (string)
  `lost` or `extend` - – this option defines how to deal with the remaining period from the previous sale, if not provided the remaining period is added to new sale (“same as “extend”)
- `paymentMethod` (string)
  payment method, `CC`, `YOURSAFE_DIRECT`, `DDEU` (if not set then buyers can choose from available payment methods)
  NOTE: `DDEU` is available only in DE, AT, CH, BE, IT, NL, ES and FR
  If oneClickToken is sent, the payment method must be set to `CC`
- `custom1` (string)
  pass-through variable - max 255 printable characters
- `custom2` (string)
  pass-through variable - max 255 printable characters
- `custom3` (string)
  pass-through variable - max 255 printable characters
- `successURL` (string)
  URL for redirect after successful transaction - max 255 characters. Defaults to success landing URL on the website.
- `email` (string)
  email of the buyer. If not set, it will be collected on the Order Page
  NOTE: email is excluded from signature calculations (max 100 chars else will be ignored)
- `signature` (string, required)
  Signature calculation
- `trialAmount` (number)
  amount to be processed (max 2 decimal places, stripped zeroes) for the initial trial period
- `trialPeriod` (string)
  duration in ISO8601 format

## Success redirect

`GET`

Your endpoint receives this call.

### Query parameters

- `shopID` (number)
  numerical ID of the website in the Verotel system
- `type` (string)
  `subscription`
- `subscriptionType` (string)
  `one-time` or `recurring`
- `event` (string)
  `initial`
- `referenceID` (string)
  merchant reference identifier. It must be unique if provided
- `saleID` (number)
  identifier of the sale in the Verotel system
- `priceAmount` (number)
  amount to be processed in nnn.nn format
- `priceCurrency` (string)
  3 char ISO code of the Sale currency
- `period` (string)
  subscription duration in ISO8601 format
- `trialAmount` (number)
  amount to be processed (max 2 decimal places, stripped zeroes) for the initial trial period
- `trialPeriod` (string)
  duration in ISO8601 format
- `expiresOn or nextChargeOn` (string)
  date of next rebill or expiry date [yyyy-mm-dd] eq. “2015-04-24”
- `custom1` (string)
  pass-through variable - max 255 printable characters
- `custom2` (string)
  pass-through variable - max 255 printable characters
- `custom3` (string)
  pass-through variable - max 255 printable characters
- `paymentMethod` (string)
  payment method, `CC`, `YOURSAFE_DIRECT`, `DDEU`
- `signature` (string)
  Signature calculation

```http
GET https://example.com/success
    ?shopID=12345
    &type=subscription
    &subscriptionType=recurring
    &event=initial
    &referenceID=order-1001
    &saleID=123456
    &priceAmount=9.99
    &priceCurrency=USD
    &period=P30D
    &trialAmount=5.00
    &trialPeriod=P7D
    &expiresOn or nextChargeOn=value
    &custom1=xxyyzz
    &custom2=custom-2
    &custom3=custom-3
    &paymentMethod=CC
    &signature=abcdef0123456789abcdef0123456789abcdef01
```

```node
const url = new URL("https://example.com/success");
url.searchParams.set("shopID", "12345");
url.searchParams.set("type", "subscription");
url.searchParams.set("subscriptionType", "recurring");
url.searchParams.set("event", "initial");
url.searchParams.set("referenceID", "order-1001");
url.searchParams.set("saleID", "123456");
url.searchParams.set("priceAmount", "9.99");
url.searchParams.set("priceCurrency", "USD");
url.searchParams.set("period", "P30D");
url.searchParams.set("trialAmount", "5.00");
url.searchParams.set("trialPeriod", "P7D");
url.searchParams.set("expiresOn or nextChargeOn", "value");
url.searchParams.set("custom1", "xxyyzz");
url.searchParams.set("custom2", "custom-2");
url.searchParams.set("custom3", "custom-3");
url.searchParams.set("paymentMethod", "CC");
url.searchParams.set("signature", "abcdef0123456789abcdef0123456789abcdef01");
const response = await fetch(url);
```

```python
from urllib.parse import urlencode
from urllib.request import urlopen

params = {
    "shopID": "12345",
    "type": "subscription",
    "subscriptionType": "recurring",
    "event": "initial",
    "referenceID": "order-1001",
    "saleID": "123456",
    "priceAmount": "9.99",
    "priceCurrency": "USD",
    "period": "P30D",
    "trialAmount": "5.00",
    "trialPeriod": "P7D",
    "expiresOn or nextChargeOn": "value",
    "custom1": "xxyyzz",
    "custom2": "custom-2",
    "custom3": "custom-3",
    "paymentMethod": "CC",
    "signature": "abcdef0123456789abcdef0123456789abcdef01",
}
url = "https://example.com/success?" + urlencode(params)
response = urlopen(url)
```

```php
// GET https://example.com/success
$params = [
    "shopID" => "12345",
    "type" => "subscription",
    "subscriptionType" => "recurring",
    "event" => "initial",
    "referenceID" => "order-1001",
    "saleID" => "123456",
    "priceAmount" => "9.99",
    "priceCurrency" => "USD",
    "period" => "P30D",
    "trialAmount" => "5.00",
    "trialPeriod" => "P7D",
    "expiresOn or nextChargeOn" => "value",
    "custom1" => "xxyyzz",
    "custom2" => "custom-2",
    "custom3" => "custom-3",
    "paymentMethod" => "CC",
    "signature" => "abcdef0123456789abcdef0123456789abcdef01",
];
```

```java
// GET https://example.com/success
Map<String, String> params = Map.ofEntries(
    Map.entry("shopID", "12345"),
    Map.entry("type", "subscription"),
    Map.entry("subscriptionType", "recurring"),
    Map.entry("event", "initial"),
    Map.entry("referenceID", "order-1001"),
    Map.entry("saleID", "123456"),
    Map.entry("priceAmount", "9.99"),
    Map.entry("priceCurrency", "USD"),
    Map.entry("period", "P30D"),
    Map.entry("trialAmount", "5.00"),
    Map.entry("trialPeriod", "P7D"),
    Map.entry("expiresOn or nextChargeOn", "value"),
    Map.entry("custom1", "xxyyzz"),
    Map.entry("custom2", "custom-2"),
    Map.entry("custom3", "custom-3"),
    Map.entry("paymentMethod", "CC"),
    Map.entry("signature", "abcdef0123456789abcdef0123456789abcdef01")
);
```

## Upgrade postback

Upgrade postback call is sent to the merchant’s postback URL when the subscription is switched from
one plan to another. The postback is sent instead of the Successful sale postbacks when the new
subscription the buyer is switching to is successfully created and the previous subscription is
terminated in Verotel system (No Expiry postback is sent). See “FlexPay API Upgrade” document for
more details.

`GET`

Your endpoint receives this call.

### Query parameters

- `shopID` (number)
  numerical ID of the website in the Verotel system
- `type` (string)
  `subscription`
- `subscriptionType` (string)
  `one-time` or `recurring`
- `event` (string)
  `upgrade`
- `referenceID` (string)
  merchant reference identifier if provided in the first sale.
- `saleID` (number)
  identifier of the sale in the Verotel system
- `transactionID` (number)
  identifier of the transaction in the Verotel system (only avaible for postbacks version 2)
- `precededBySaleID` (number)
  Identifier of the previous sale the enduser is switching from
- `priceAmount` (number)
  amount to be processed in nnn.nn format
- `priceCurrency` (string)
  3 char ISO code of the Sale currency
- `period` (string)
  subscription duration in ISO8601 format
- `expiresOn or nextChargeOn` (string)
  date of next rebill or expiry date [yyyy-mm-dd] eq. “2015-04-24”
- `custom1` (string)
  pass-through variable - max 255 printable characters
- `custom2` (string)
  pass-through variable - max 255 printable characters
- `custom3` (string)
  pass-through variable - max 255 printable characters
- `paymentMethod` (string)
  payment method, `CC`, `YOURSAFE_DIRECT`, `DDEU`
- `signature` (string)
  Signature calculation
- `truncatedPAN` (string)
  Truncated (masked) payment instrument identification, e.g. card number
- `CCBrand` (string)
  Only present if paid via Credit Card, represents the card brand, e.g. VISA

```http
GET https://example.com/postback
    ?shopID=12345
    &type=subscription
    &subscriptionType=recurring
    &event=upgrade
    &referenceID=order-1001
    &saleID=123456
    &transactionID=987654
    &precededBySaleID=123450
    &priceAmount=9.99
    &priceCurrency=USD
    &period=P30D
    &expiresOn or nextChargeOn=value
    &custom1=xxyyzz
    &custom2=custom-2
    &custom3=custom-3
    &paymentMethod=CC
    &signature=abcdef0123456789abcdef0123456789abcdef01
    &truncatedPAN=411111******1111
    &CCBrand=VISA
```

```node
const url = new URL("https://example.com/postback");
url.searchParams.set("shopID", "12345");
url.searchParams.set("type", "subscription");
url.searchParams.set("subscriptionType", "recurring");
url.searchParams.set("event", "upgrade");
url.searchParams.set("referenceID", "order-1001");
url.searchParams.set("saleID", "123456");
url.searchParams.set("transactionID", "987654");
url.searchParams.set("precededBySaleID", "123450");
url.searchParams.set("priceAmount", "9.99");
url.searchParams.set("priceCurrency", "USD");
url.searchParams.set("period", "P30D");
url.searchParams.set("expiresOn or nextChargeOn", "value");
url.searchParams.set("custom1", "xxyyzz");
url.searchParams.set("custom2", "custom-2");
url.searchParams.set("custom3", "custom-3");
url.searchParams.set("paymentMethod", "CC");
url.searchParams.set("signature", "abcdef0123456789abcdef0123456789abcdef01");
url.searchParams.set("truncatedPAN", "411111******1111");
url.searchParams.set("CCBrand", "VISA");
const response = await fetch(url);
```

```python
from urllib.parse import urlencode
from urllib.request import urlopen

params = {
    "shopID": "12345",
    "type": "subscription",
    "subscriptionType": "recurring",
    "event": "upgrade",
    "referenceID": "order-1001",
    "saleID": "123456",
    "transactionID": "987654",
    "precededBySaleID": "123450",
    "priceAmount": "9.99",
    "priceCurrency": "USD",
    "period": "P30D",
    "expiresOn or nextChargeOn": "value",
    "custom1": "xxyyzz",
    "custom2": "custom-2",
    "custom3": "custom-3",
    "paymentMethod": "CC",
    "signature": "abcdef0123456789abcdef0123456789abcdef01",
    "truncatedPAN": "411111******1111",
    "CCBrand": "VISA",
}
url = "https://example.com/postback?" + urlencode(params)
response = urlopen(url)
```

```php
// GET https://example.com/postback
$params = [
    "shopID" => "12345",
    "type" => "subscription",
    "subscriptionType" => "recurring",
    "event" => "upgrade",
    "referenceID" => "order-1001",
    "saleID" => "123456",
    "transactionID" => "987654",
    "precededBySaleID" => "123450",
    "priceAmount" => "9.99",
    "priceCurrency" => "USD",
    "period" => "P30D",
    "expiresOn or nextChargeOn" => "value",
    "custom1" => "xxyyzz",
    "custom2" => "custom-2",
    "custom3" => "custom-3",
    "paymentMethod" => "CC",
    "signature" => "abcdef0123456789abcdef0123456789abcdef01",
    "truncatedPAN" => "411111******1111",
    "CCBrand" => "VISA",
];
```

```java
// GET https://example.com/postback
Map<String, String> params = Map.ofEntries(
    Map.entry("shopID", "12345"),
    Map.entry("type", "subscription"),
    Map.entry("subscriptionType", "recurring"),
    Map.entry("event", "upgrade"),
    Map.entry("referenceID", "order-1001"),
    Map.entry("saleID", "123456"),
    Map.entry("transactionID", "987654"),
    Map.entry("precededBySaleID", "123450"),
    Map.entry("priceAmount", "9.99"),
    Map.entry("priceCurrency", "USD"),
    Map.entry("period", "P30D"),
    Map.entry("expiresOn or nextChargeOn", "value"),
    Map.entry("custom1", "xxyyzz"),
    Map.entry("custom2", "custom-2"),
    Map.entry("custom3", "custom-3"),
    Map.entry("paymentMethod", "CC"),
    Map.entry("signature", "abcdef0123456789abcdef0123456789abcdef01"),
    Map.entry("truncatedPAN", "411111******1111"),
    Map.entry("CCBrand", "VISA")
);
```

## Signature calculation

Examples are for [Verotel FlexPay PHP client library](https://github.com/verotel/flexpay-php-client)

```php
$brand = Verotel\FlexPay\Brand::create_from_merchant_id(/* Your customer ID */ '9804000000000000');

$flexpayClient = new Verotel\FlexPay\Client(/* shop ID */ 12345, "FlexPay Signature Key", $brand);

$computed_signature = $flexpayClient->get_signature([
    'description' => 'Super video download',
    'priceAmount' => '9.99',
    'priceCurrency' => 'USD',
    'shopID' => 12345,
    'version' => 4,
]);
```

    Examples are for [FlexPay Java client library](https://github.com/verotel/flexpay4j)

```java
String computedSignature = flexpayClient.getSignature(Map.of(
    "description", "Super video download",
    "priceAmount", "9.99",
    "priceCurrency", "USD",
    "shopID", 12345,
    "version", 4
));
```
If you are using one of our client libraries, signature calculation is handled by the library.

The signature used in FlexPay requests and postbacks is calculated as SHA-256 hash (hexadecimal
output) from the request parameters.

The first parameter has to be your signatureKey, followed by the parameters ordered alphabetically
by their names.

Optional arguments that are used (have value) must be contained in the signature calculation.
Optional arguments that are not used must not be contained in the signature calculation.

The email parameter in “startorder” request is not included in the signature calculations.

It is mandatory to convert arguments values into UTF-8 before computing the signature.

### Example calculation

| Parameter | Value |
| --- | --- |
| (signatureKey) | BddJxtUBkDgFB9kj7Zwguxde4gAqha |
| description | Super video download |
| priceAmount | 9.99 |
| priceCurrency | USD |
| custom1 | xxyyzz |
| shopID | 64233 |
| type | purchase |
| version | `4` |

### Signature calculation using the values above

```
signature = sha256_hex(BddJxtUBkDgFB9kj7Zwguxde4gAqha:custom1=xxyyzz:description=Super video download:priceAmount=9.99:priceCurrency=USD:shopID=64233:type=purchase:version=4) => ccaf2357fe330654322a1b0f3f92984b3fe2a1462d6fc5082650a00c5ada2f2a
```

### The FlexPay purchase request then is

```
https://secure.verotel.com/startorder?custom1=xxyyzz&description=Super+video+download&priceAmount=9.99&priceCurrency=USD&shopID=64233&type=purchase&version=4&signature=ccaf2357fe330654322a1b0f3f92984b3fe2a1462d6fc5082650a00c5ada2f2a
```

## Payment processor

| Processor name | Allowed payment method | Base URL |
| --- | --- | --- |
| Verotel | `CC` `DDEU` | `https://secure.verotel.com/` |
| CardBilling | `CC` | `https://secure.billing.creditcard/` |
| GayCharge | `CC` `DDEU` | `https://secure.gaycharge.com/` |
| YoursafeDirect | `DDEU` `YOURSAFE_DIRECT` | `https://secure.yoursafedirect.com/` |
