Seamless Checkout
The Connect2Pay Seamless Checkout is a JavaScript library to be included in the merchants checkout page’s HTML. It renders a responsive payment form for seamlessly passing customer’s payment information into Connect2Pay server and process the payment. The objective of this library is to allow merchants to capture user credit card information in the client-side and pass it directly to Connect2Pay API without breaking PCI-DSS standards.
1 - Create token
To be able to use the Seamless Checkout you need to make a Prepare API call and retrieve the customerToken from the API response:
We strongly advise the use of parameter ctrlCallbackURL.
use PayXpert\Connect2Pay\Connect2PayClient;
$url = "https://connect2.payxpert.com";
// This will be provided once your account is approved
$originator = "000000";
$password = "Gr3atPassw0rd!";
$c2pClient = new Connect2PayClient($url, $originator, $password);
// Set all information for the payment
$c2pClient->setOrderID("ABC-123456");
$c2pClient->setPaymentMethod(Connect2PayClient::PAYMENT_METHOD_CREDITCARD);
$c2pClient->setPaymentMode(Connect2PayClient::PAYMENT_MODE_SINGLE);
$c2pClient->setShippingType(Connect2PayClient::SHIPPING_TYPE_VIRTUAL);
// To charge €25.99
$c2pClient->setCurrency("EUR");
$c2pClient->setAmount(2599);
// URL on the merchant site that will receive the callback notification
$c2pClient->setCtrlCallbackURL("https://merchant.example.com/payment/callback");
if ($c2pClient->validate()) {
if ($c2pClient->preparePayment()) {
$_SESSION['customerToken'] = $c2pClient->getCustomerToken();
} else {
echo "error prepareTransaction: ";
echo $c2pClient->getClientErrorMessage() . "\n";
}
} else {
echo "Validation error occurred: " . $c2pClient->getClientErrorMessage() . "\n";
}
// Process a payment of €39.99
PaymentRequest request = new PaymentRequest();
request.setOrderId("1234ABCD").setCurrency("EUR").setAmount(3999);
request.setShippingType(ShippingType.VIRTUAL);
request.setPaymentMode(PaymentMode.SINGLE);
// The payment page will do a callback on this URL after the payment is processed
request.setCtrlCallbackURL("http://my.website/payment-callback");
// Validate the request
try {
request.validate();
} catch (BadRequestException e) {
logger.error("Ooops, an error occurred validating the payment request: " + e.getMessage());
// Handle the error...
}
// Instantiate the client and send the prepare request
// Second argument is the originator ID, third one is the associated API key
Connect2payClient c2p = new Connect2payClient("https://connect2.payxpert.com", "123456", "GreatP4ssw0rd");
PaymentResponse response = null;
try {
response = c2p.preparePayment(request);
} catch (Exception e) {
logger.error("Ooops, an error occurred preparing the payment: " + e.getMessage());
// Handle the error...
}
if (response != null && ResultCode.SUCCESS.equals(response.getCode())) {
String customerToken = response.getCustomerToken();
} else {
// Handle the failure
}
const paymentPage = require("payxpert")("123456", "GreatP4ssw0rd").connect2pay;
const body = {
"shippingType": "virtual",
"paymentMode": "single",
"amount":500,
"currency":"EUR",
"orderID":"NODEJS TEST",
"paymentMethod"; "CreditCard"
"ctrlCallbackURL":"http://my.website/payment-callback"
};
const responseCreatePayment = await paymentPage.createPayment(body);
if (responseCreatePayment.code == "200") {
console.log(responseCreatePayment.customerToken);
}
var client = new Connect2PayClient(OriginatorConfig.ORIGINATOR_ID, OriginatorConfig.ORIGINATOR_PASSWORD);
var request = client.NewRequestCreatePayment();
request.Data.orderID = "ABC-123456";
request.Data.paymentMethod = PaymentMethod.CREDIT_CARD;
request.Data.paymentMode = PaymentMode.SINGLE;
request.Data.shopperID = "RICH_SHOPPER";
request.Data.shippingType = ShippingType.VIRTUAL;
request.Data.operation = Operation.SALE;
request.Data.amount = 1500; // 15 EUR
request.Data.currency = "EUR";
request.Data.ctrlCallbackURL = "https://merchant.example.com/payment/callback";
if (request.Data.Validate())
{
var response = await request.Send();
if (response.IsSuccessfull())
{
Console.WriteLine("Customer token: " + response.customerToken);
}
}
- Response:
{
"code": "200",
"message": "Request processed successfully",
"customerToken": "1234",
"merchantToken": "4321"
}
2 - Prepare your HTML
In your checkout page you should include a div element with a specified attribute id.
<div id="payment-container">
</div>
Outside the div container, include a script tag with source to our Seamless Checkout library, using the customerToken you have received from step 1. You should add the attributes crossorigin=”anonymous”, “integrity=sha384…”, async=true and data-mount-in={DIV CONTAINER ID}
<div id="payment-container">
</div>
<script async="true" src="https://connect2.payxpert.com/payment/{customerToken}/connect2pay-seamless-v1.2.1.js" data-mount-in="#payment-container" integrity="sha384-KoRUPIW3yZfYzkFzrA1D2/qUKXpnNoiyflE7W0V4kDhJtuQJn8BbwkqrzRPdsXx3" crossorigin="anonymous"></script>
Voilà! The credit card form is instantly loaded and rendered into your checkout page.
3 - Process callback
Once payment is successful, your server will receive a server-side notification with a JSON object and all the information regarding the payment. This is why it is very important to use the ctrlCallbackURL parameter in the token creation step!
Customization
The library can be customized in different ways, depending on the merchants’ needs.
<div id="payment-form-container">
<script type="application/json">
{
"payButtonText": "Pay €10.99 now!",
"language": "en,
"fontFamily": "Helvetica"
}
</script>
</div>
Class injection
You can inject external classes directly into the form elements. This is useful is your website is using tools such as Bootstrap.
<div id="payment-form-container">
<script type="application/json">
{
"payButtonText": "Pay €10.99 now!",
"customClasses": {
"cardHolderNameContainer": "form-group",
"cardHolderName": "form-control",
"cardNumberContainer": "form-group",
"cardNumber": "form-control",
"cardExpireDateShortContainer": "form-group",
"cardExpireDateShort": "form-control",
"cardSecurityCodeContainer": "form-group",
"cardSecurityCode": "form-control"
}
}
</script>
</div>
<!-- The configuration above will result: -->
<form class="cardForm__3-0Ac" novalidate="true" id="c2pCreditCardForm">
<div class="form-group" id="c2pCardHolderNameContainer">
<label id="c2pCardHolderNameLabel">
Cardholder Name
</label>
<input type="text" class="formInput__3Sjbj form-control" id="c2pCardHolderName">
</div>
<div class=" form-group" id="c2pCardNumberContainer">
<label id="c2pCardNumberLabel">
Card Number
</label>
<input placeholder="____ ____ ____ ____" pattern="[1-9]/d+" class="formInput__3Sjbj cardNumber__5kHQE form-control" id="c2pCardNumber" type="tel">
</div>
....
....
....
</form>
The skipDefaultStyle parameter will remove any default classes from the elements, so you can freely adapt the form with your own CSS classes.
Using id of top container
You can also customize the form defining the specific CSS for the tags of the container form:
<div id="payment-form-container">
</div>
<style type="text/css">
#payment-form-container > input[type=text] {
background-color: #FFF;
}
</style>
Using ID selector of each element
Every element of the form has its own id, so you can select it and customize and modify as you want:
<style type="text/css">
#c2pCardHolderName {
background-color: blue;
}
</style>
Here’s a list of the elements you can fetch
Element ID |
---|
c2pCreditCardForm |
c2pCardHolderNameContainer |
c2pCardHolderNameLabel |
c2pCardHolderName |
c2pCardNumberContainer |
c2pCardNumberLabel |
c2pCardNumber |
c2pCardIconContainer |
c2pCardInlineFields |
c2pCardExpireDateShortContainer |
c2pCardExpireDateShortLabel |
c2pCardExpireDateShort |
c2pCardSecurityCodeContainer |
c2pCardSecurityCodeLabel |
c2pCardSecurityCode |
c2pSubmitButtonContainer |
c2pSubmitButton |
c2p3DSModal |
c2pResultText |
Client-side callback
Seamless Checkout can trigger a specified callback function and inject the paymentStatus object as parameter.
NEVER use this method for payment confirmation of the order, since the object can be hijacked and values can be modified on the client-side.
ALWAYS rely on server-side callback for this purpose.
The client side Javascript callback should be used to request the real payment status towards the merchant server. To avoid synchronization problem between the client request and the server side callback, the merchant server can use the paymentStatus to actively check the result of the payment.
<div id="payment-container">
</div>
<script type="text/javascript">
function executeMePlease(response) {
// This function could ne used for querying the status of the payment from the server side and update the display accordingly.
console.log(response); // JSON object with the API response
document.getElementById("c2pResultText").appendChild(<p>You did it!!</p>); // You can fetch the result div and modify
}
</script>
Accepted configuration parameters
Parameter | Accepted Values | Description |
---|---|---|
onPaymentResult | String | Callback function to be triggered (don’t use parentheses or semicolons) |
noModal | Boolean | If set, breaks out of modal when 3DSecure authentication step is reached. |
fontFamily | String | Custom font if you like to customize the form |
language | en, fr, es | Language of the labels and placeholders |
labels | Object to change the labels of the form | |
labels.cardHolderName | String | Label for the CardHolderName input |
labels.cardNumber | String | Label for the CardNumber input |
labels.cardExpireDateShort | String | Label for the Expiration Date input |
labels.cardSecurityCode | String | Label for the CSC input |
payButtonText | String | Text for the payment button e.g. “Pay Now €10.99” |
placeholders | Object to change the placeholders of the form’s inputs | |
placeholders.cardHolderName | String | Placeholder for the CardHolderName input |
placeholders.cardNumber | String | Placeholder for the CardNumber input |
placeholders.cardExpireDate | String | Placeholder for the Expiration Date input |
placeholders.cardSecurityCode | String | Placeholder for the CSC input |
customClasses | Object for customization of the elements | |
customClasses.cardHolderNameContainer | String | Classes will be applied into cardHolderName div container |
customClasses.cardHolderNameLabel | String | Classes will be applied into cardHolderName label |
customClasses.cardHolderName | String | Classes will be applied into cardHolderName input |
customClasses.cardNumberContainer | String | Classes will be applied into cardNumber div container |
customClasses.cardNumberLabel | String | Classes will be applied into cardNumber label |
customClasses.cardNumber | String | Classes will be applied into cardNumber input |
customClasses.cardExpireDateShortContainer | String | Classes will be applied into cardExpireDate div container |
customClasses.cardExpireDateShortLabel | String | Classes will be applied into cardExpireDate label |
customClasses.cardExpireDateShort | String | Classes will be applied into cardExpireDate input |
customClasses.cardSecurityCodeContainer | String | Classes will be applied into cardSecurityCode div container |
customClasses.cardSecurityCodeLabel | String | Classes will be applied into cardSecurityCode label |
customClasses.cardSecurityCode | String | Classes will be applied into cardSecurityCode input |