There are two main front ends to initiate a payment: paymentPage and seamless.
The paymentPage (also known as the redirect method) handles payments completely offsite, while seamless keeps the user on site for most of the time, only going off site for 3D Secure or remote service authentication and authorisation.
Both intiation types use the same direct server (known as backend2backend) API methods.
This intiation method handles a number of payment types, some requiring additional PCI checks to use. The most comming credit card method will be token based, with a token being created at the back end first, and a URL related to that token being used to provide an iframe-based credit card form. An example of how this can work is shown below, but there are other ways it can be done, with additional front-end functionality to choose payment types.
First a token is created on the back end. This token will need to be saved for the next stage, either in the session or passed through the order form.
use Omnipay\Omnipay;
$gateway = Omnipay::create('Mpay24_Seamless');
$gateway->setMerchantId('12345');
$gateway->setPassword('AB1234cd56');
$gateway->setTestMode(true);
$request = $gateway->token([
'language' => 'en',
//'customerId' => 'foo',
//'profileId' => 'bar',
//'style' => 'fizz',
]);
$response = $request->send();
if (! $response->isSuccessful()) {
// Token could not be generated.
echo '<p>Error: '.$response->getReturnCode().'</p>';
exit;
}
This gives us a token and an iframe URL:
$response->getRedirectUrl();
$response->getToken();
The payment form can be created as follows, assuming /pay
as the next enpoint in your flow.
The iframe will contain the rendered credit card form.
Add whatever additional customer or order details you want to the form.
The iframe will be submitted with the form, but won't itself make any changes
to your form; the credit card details go straight to the mPAY24 gateway.
With this example, the submit bitton will remain disabled until the credit card
details in the iframe have been completed.
The token does not need to go through the form, but could be carried forward through the session instead.
<?php
<iframe src="<?php echo $response->getRedirectUrl(); ?>" frameBorder="0" width="500"></iframe>
<form action="/pay" method="POST">
<input name="token" type="hidden" value="<?php echo $response->getToken(); ?>" />
<button id="paybutton" name="type" value="TOKEN" type="submit" disabled="true">Pay with creditcard</button>
<button name="type" value="PAYPAL" type="submit">Pay with paypal</button>
</form>
<script>
window.addEventListener("message", checkValid, false);
function checkValid(form) {
var data = JSON.parse(form.data);
if (data.valid === "true") {
document.getElementById("paybutton").disabled=false;
}
}
</script>
The /pay
endpoint handles the actual payment.
The above form does not redirect the user to a payment page. Instead, it sends the card details to the gateway, with the token as a key. So in the next step, the gateway will already have the card details and the merchant site will just use the pre-generated token to reference them when completing the payment.
use Omnipay\Omnipay;
use Omnipay\Common\CreditCard;
$gateway = Omnipay::create('Mpay24_Seamless');
$gateway->setMerchantId('12345');
$gateway->setPassword('AB1234cd56');
$gateway->setTestMode(true);
$card = new CreditCard([
'name' => 'Fred Bloggs',
//
'billingName' => 'Fred Billing',
'billingAddress1' => 'Street 1',
'billingAddress2' => 'Street 2',
'billingCity' => 'City',
'billingPostcode' => 'Postcode',
'billingCountry' => 'GB',
//
'shippingName' => 'Fred Shipping',
'shippingAddress1' => 'Street 1',
'shippingAddress2' => 'Street 2',
'shippingCity' => 'City',
'shippingPostcode' => 'Postcode',
'shippingCountry' => 'GB',
]);
$request = $gateway->purchase([
'paymentType' => 'TOKEN', // or PAYPAL etc. e.g $_POST['type'] in this example.
'amount' => '9.98',
'currency' => 'EUR',
'token' => $token, // e.g. $_POST['token']
'transactionId' => $transactionId,
'description' => 'Test Order',
'returnUrl' => 'https://example.com/complete/success',
'errorUrl' => 'https://example.com/complete/error',
'notifyUrl' => 'https://example.com/notify',
'language' => 'en',
'card' => $card,
]);
$response = $request->send();
If the payment request is succcessful, then a redirect is likely to be needed to complete 3D Secure actions, Paypal or bank authentication and so on:
if (! $response->isSuccessful() && $response->isRedirect()) {
$response->redirect();
exit;
}
After 3D Secure is completed, you will be returned to your /complete
endpoint
where you need to fetch the results of the transation:
use Omnipay\Omnipay;
$gateway = Omnipay::create('Mpay24_Seamless');
$gateway->setMerchantId('12345');
$gateway->setPassword('AB1234cd56');
$gateway->setTestMode(true);
$request = $gateway->completePurchase([
// Will be in $_GET['TID'], but don't trust that; store it in the session.
'transactionId' => $transactionId,
]);
$response = $request->send();
The $response
will contain the normal Omnipay statuses and messages to define
the result.
Note: your complete
endpoint will be given the transaction result when redirected
from the gateway.
This result is not signed, and so can be easily manipulated by an end user.
For this reason, this driver fetches the result from the gateway (a "pull" notification)
to ensure no untrusted user data becomes a part of the process.
The payment page sends the user to the payment gateway to make a payment. The user will have a single payment type chosen for them, or can choose from a range of payment types offered, from a list filtered by the merchant site.
use Omnipay\Omnipay;
use Omnipay\Common\CreditCard;
$gateway = Omnipay::create('Mpay24_PaymentPage');
$gateway->setMerchantId('12345');
$gateway->setPassword('AB1234cd56');
$gateway->setTestMode(true);
$request = $gateway->purchase([
'amount' => '9.98',
'currency' => 'EUR',
'token' => $token, // e.g. $_POST['token']
'transactionId' => $transactionId,
'description' => 'Test Order',
'returnUrl' => 'https://example.com/complete/success',
'errorUrl' => 'https://example.com/complete/error',
'notifyUrl' => 'https://example.com/notify',
'language' => 'en',
'card' => $card, // Names, addresses
'items' => $items,
]);
$response = $request->send();
If all is accepted, the $response
object will be a redirect to
the payment page.
To restrict the user to a single payment method, add the paymentType
and brand
. Example:
'paymentType' => 'CC',
'brand' => 'VISA',
Alternatively a range of payment methods can be supplied as a JSON string:
'paymentMethods' => [
["paymentType" => "CC", "brand" => "VISA"],
["paymentType" => "CC", "brand" => "MASTERCARD"],
["paymentType" => "PAYPAL", "brand" => "PAYPAL"],
],
// Or you can supply 'paymentMethods' as a JSON string.
For some payment types the brand is mandatory and for some it is optional. Examples:
paymentType
"CC" andbrand
"VISA" will offer a visa card payment type only.paymentType
"CC" and nobrand
will offer a choice of all credit card types available.- No
paymentType
and nobrand
will offer a choice from all payment types available.
The transaction is completed in exactly the same way as for the seamless payments.
The gateway supports two types of profile: a single recurring payment profile for a customer, and up to 20 interactive profiles for each customer. The Payment Page API will support only ONE of these profile types at a time. This driver presently support ONLY recurrent payment profiles for Payment Page.
To create or update a customer's recurring payment profile, when making a purchase,
set the createCard
flag and provide a cardReference
:
'createCard' => true,
'cardReference' => 'card-12345',
On completing the payment, you can check if the customer recurring profile was created or updated by checking the profile status:
$profileWasCreatedOrUpdates = $completeResult->isProfileChanged();
If this returns true, then it means the payment details for the current transaction have been saved against the customer ID. Use the customer ID as though it were a card reference when making a backend payment.
A customer ID can be used to make a recurring payment (an offline payment) liek this:
$gateway = Omnipay::create('Mpay24_Backend');
// Set the usual merchant ID and test mode flags.
$request = $gateway->purchase([
'amount' => '9.99',
'currency' => 'EUR',
'transactionId' => 'new-transaction-id',
'description' => 'Recurring Payment Description',
'card' => [
'name' => 'Customer Name',
],
'notifyUrl' => 'https://omnipay.acadweb.co.uk/mpay24/notify.php?foo=bar&fee=fah', // mandatory
'language' => 'de',
'cardReference' => 'card-12345',
]);
This will return the details of the successful payment, or error details if not successful.
The notification handler will accept notification server requests, and provide the status, amounts, payment methods actually used, transactionReference.
$request = $gateway->acceptNotification();
// $request->getTransactionId();
// $request->getTransactionReference();
// $request->getTransactionStatus();
// $request->getMoney();
// $request->isSuccessful();
// $request->getData();