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

# Purchase

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

## Create a purchase 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);

$purchaseUrl = $flexpayClient->get_purchase_URL([
    "priceAmount" => 2.64,
    "priceCurrency" => "EUR",
    "description" => "Test purchase",
]);
```

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

```java
FlexPayClient flexPayClient = new FlexPayClient(
    685478,                 // shop ID / website ID
    "d6dToIj2d6YJ1PX2D1W9", // FlexPay signatureKey
    Brand.YOURSAFE_DIRECT
);

URL purchaseUrl = flexPayClient.purchaseBuilder()
    .withAmount(BigDecimal.valueOf(14), SaleCurrency.EUR)
    .withDescription("Purchase of foo")
    .withPaymentMethod(PaymentMethod.IDEAL)
    .withEmail("example@example.com")
    .withDeclineURL("http://example.com/declined")
    .withSuccessURL("http://example.com/back")
    .build();
```

FlexPay purchase call is used to redirect buyer to the Verotel Order Page in order to process the
purchase sale.

### 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` 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: oneClickToken is excluded from signature calculations |
NOTE: email is excluded from signature calculations (max 100 chars else it will be ignored) |

<aside class="doc-callout doc-callout--success">
<p><a href="#success-postback">Success postback</a> is sent after approved order</p>
</aside>

`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)
  `purchase`
- `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
- `description` (string, required)
  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.
- `oneClickToken` (string)
  the one-time oneClickToken from previous purchase
  NOTE: oneClickToken is excluded from signature calculations
- `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)
  `purchase`
- `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
- `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=purchase
    &referenceID=order-1001
    &saleID=123456
    &priceAmount=9.99
    &priceCurrency=USD
    &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", "purchase");
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("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": "purchase",
    "referenceID": "order-1001",
    "saleID": "123456",
    "priceAmount": "9.99",
    "priceCurrency": "USD",
    "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" => "purchase",
    "referenceID" => "order-1001",
    "saleID" => "123456",
    "priceAmount" => "9.99",
    "priceCurrency" => "USD",
    "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", "purchase"),
    Map.entry("referenceID", "order-1001"),
    Map.entry("saleID", "123456"),
    Map.entry("priceAmount", "9.99"),
    Map.entry("priceCurrency", "USD"),
    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>

## Success postback

The successful 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)
  `purchase`
- `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
- `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`
- `oneClickToken` (string)
  if the feature is enabled - oneClickToken valid for next purchase
- `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=purchase
    &referenceID=order-1001
    &saleID=123456
    &transactionID=987654
    &priceAmount=9.99
    &priceCurrency=USD
    &custom1=xxyyzz
    &custom2=custom-2
    &custom3=custom-3
    &paymentMethod=CC
    &oneClickToken=one-click-token
    &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", "purchase");
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("custom1", "xxyyzz");
url.searchParams.set("custom2", "custom-2");
url.searchParams.set("custom3", "custom-3");
url.searchParams.set("paymentMethod", "CC");
url.searchParams.set("oneClickToken", "one-click-token");
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": "purchase",
    "referenceID": "order-1001",
    "saleID": "123456",
    "transactionID": "987654",
    "priceAmount": "9.99",
    "priceCurrency": "USD",
    "custom1": "xxyyzz",
    "custom2": "custom-2",
    "custom3": "custom-3",
    "paymentMethod": "CC",
    "oneClickToken": "one-click-token",
    "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" => "purchase",
    "referenceID" => "order-1001",
    "saleID" => "123456",
    "transactionID" => "987654",
    "priceAmount" => "9.99",
    "priceCurrency" => "USD",
    "custom1" => "xxyyzz",
    "custom2" => "custom-2",
    "custom3" => "custom-3",
    "paymentMethod" => "CC",
    "oneClickToken" => "one-click-token",
    "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", "purchase"),
    Map.entry("referenceID", "order-1001"),
    Map.entry("saleID", "123456"),
    Map.entry("transactionID", "987654"),
    Map.entry("priceAmount", "9.99"),
    Map.entry("priceCurrency", "USD"),
    Map.entry("custom1", "xxyyzz"),
    Map.entry("custom2", "custom-2"),
    Map.entry("custom3", "custom-3"),
    Map.entry("paymentMethod", "CC"),
    Map.entry("oneClickToken", "one-click-token"),
    Map.entry("signature", "abcdef0123456789abcdef0123456789abcdef01"),
    Map.entry("truncatedPAN", "411111******1111"),
    Map.entry("CCBrand", "VISA")
);
```

## Credit postback

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

`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
- `type` (string)
  `purchase`
- `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
    &type=purchase
    &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("type", "purchase");
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",
    "type": "purchase",
    "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",
    "type" => "purchase",
    "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("type", "purchase"),
    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
- `type` (string)
  `purchase`
- `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
    &type=purchase
    &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("type", "purchase");
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",
    "type": "purchase",
    "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",
    "type" => "purchase",
    "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("type", "purchase"),
    Map.entry("custom1", "xxyyzz"),
    Map.entry("custom2", "custom-2"),
    Map.entry("custom3", "custom-3"),
    Map.entry("signature", "abcdef0123456789abcdef0123456789abcdef01")
);
```

## 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(1234);
```

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 formatt
- `priceCurrency` (string)
  3 char ISO code of the Sale currency
- `description` (string)
  Product description text - max 100 printable characters
- `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
- `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)

## One Click Purchase

The One Click functionality allows buyers to pay instantly without any type
of confirmation.
The instant One Click will try to charge their previously saved
credit card without the need to re-enter the CVV code
or any other additional information.
This allows the FlexPay purchase sales to be processed quickly
without distracting the buyer unnecessarily.

### Security

The One Click functionality has been designed to be as secure as possible
to minimize any risks of misuse and to protect both merchants and buyers alike.
The same fraud prevention measures apply as per standard Order Page
interactions.

### Enabling the One Click

The One Click feature is disabled by default and is a subject
of approval by Verotel. Please contact [merchantsupport@verotel.com](mailto:merchantsupport@verotel.com) to enquire.
This document assumes the feature is enabled.

### Limitations

- In case the Order Page requires the buyers to enter their billing address,
  the full order page is displayed.

### Interaction

### Initial sale

In order to charge the buyer again with One Click the “oneClickToken”
is required.

The token is generated with the first successful sale
(normal FlexPay purchase sale with full Order Page interaction
initiated by “[purchase order](#create-a-purchase-order)” request)
when the buyer chooses to “Remember my card for future purchases”.

The [Successful sale postback](#success-postback) returns
the “oneClickToken” to merchant’s system.

### One Click sale

    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);

$purchaseUrl = $flexpayClient->get_purchase_URL([
    "priceAmount" => 2.64,
    "priceCurrency" => "EUR",
    "description" => "Test purchase",
    "oneClickToken" => "1FD5F342-48DB-11E6-B445-A19150BFB283"
]);
```

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

```java
URL purchaseUrl = flexPayClient.purchaseBuilder()
    .withAmount(BigDecimal.valueOf(14), SaleCurrency.EUR)
    .withDescription("Purchase of foo")
    .withPaymentMethod(PaymentMethod.IDEAL)
    .withEmail("example@example.com")
    .withDeclineURL("http://example.com/declined")
    .withSuccessURL("http://example.com/back")
    .withOneClickToken("foo-token")
    .build();
```

To perform a One Click sale, the currently active token has to be included
in the next “[purchase order](#create-a-purchase-order)“ request.

If the token is [valid](#validity-of-the-oneclicktoken),
the “[purchase order](#create-a-purchase-order)” request
is processed without any further buyer interaction.

If the order is approved, the buyer receives a standard receipt email,
an approval page is displayed and 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

The new valid “oneClickToken” is passed with
the [Successful sale postback](#success-postback) call
to the merchant’s system for use in the next sale.

<aside class="doc-callout doc-callout--notice">
<p>Every &quot;oneClickToken&quot; used to perform the &quot;<a href="#create-a-purchase-order">purchase order</a>&quot; request is <em>invalidated</em></p>
</aside>

### Validity of the oneClickToken

<aside class="doc-callout doc-callout--notice">
<p>If the provided &quot;oneClickToken&quot; in &quot;<a href="#create-a-purchase-order">purchase order</a>&quot; request is not valid, the buyer gets the standard order page and has to enter at least the CVV code for a remembered card (or can use a different card). Again, the merchant’s system receives a new valid token in the <a href="#success-postback">Successful sale postback</a> for next use.</p>
</aside>

1. The “oneClickToken” can be only be used once.
   It is invalidated in case the transaction is either approved or declined.

   This means that the merchant’s system has to manage storage and update
   the active tokens for users upon receiving
   [Successful sale postback](#success-postback) calls but
   also in case of declines.
   A user can be identified by e.g. custom1-3 fields or referenceID
   passed by the merchant’s system in
   the “[purchase order](#create-a-purchase-order)” request
   and returned in the [Successful sale postback](#success-postback).

2. The “oneClickToken” expires automatically after 30 days.
   The buyer will need to enter CVV code to generate a
   new one and to resume the One Click functionality.

3. The “oneClickToken” is linked to a website and to
   the buyer’s remembered card information stored in the form
   of a cookie in the browser.

This means that:

- the token is not valid for other websites

- the token will not work in case the buyer uses a different browser

- the token expires if the buyer chooses to forget the stored card

## 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/` |
