Server Side Notifications
When the ctrlCallbackURL
parameter is present in the merchant payment creation request, after the payment completion, the application issues an HTTP POST request towards this address.
The body of this POST request will contain the JSON data structure described in the Payment Status Response section.
The callback script must return a JSON data structure to acknowledge or not the payment status notification.
If the data return does not conform with the below JSON structure, the payment will nevertheless be considered acknowledged if the HTTP return code is 20x.
In case automatic status resending is enabled, the status will be regularly posted to the ctrlCallbackURL
until it returns a successful HTTP status or a OK
JSON status.
The format of the JSON structure to be returned by the callback:
Name | Type | Description |
---|---|---|
status | String | Status of the notification: OK to indicate success. Anything else will be considered as failure. |
message | String | Optional message to give more information about the status. |
Code samples
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);
if ($c2pClient->handleCallbackStatus()) {
// Get the PaymentStatus object
$status = $c2pClient->getStatus();
// Custom data that could have been provided in ctrlCustomData when creating
// the payment
$merchantData = $status->getCtrlCustomData();
// The unique token, known only by the payment page and the merchant
$merchantToken = $status->getMerchantToken();
// Get the last initial transaction processed for this payment
$transaction = $status->getLastInitialTransactionAttempt();
$transactionId = null;
if ($transaction !== null) {
// The transaction identifier generated for this transaction
$transactionId = $transaction->getTransactionID();
// The last transaction attempt status code
$errorCode = $transaction->getResultCode();
}
// /!\ /!\
// The received callback *must* be authenticated by checking that the merchant
// token matches with a previous known transaction. If this check is not done,
// anyone can manipulate the payment status by providing fake data to this
// script.
// For example the merchant token can be stored with the application order
// system (ctrlCustomData could also be used to authenticate in other ways)
if ($errorCode == '000') {
// errorCode = 000 => transaction is successful
// If we reach this part of the code the payment succeeded
// Do the required stuff to validate the payment in the application.
// Be careful as some payment types are asynchronous (like direct debit),
// the initial operation (submission) is not the final confirmation of the payment,
// the confirmation is received later as a collection operation, another callback is
// triggered at this moment so the payment type and operation must be checked and the
// payment status set accordingly
$this->order->updatePaymentStatus("paid");
// Send back a response to mark this transaction as notified on the payment server
$response = array("status" => "OK", "message" => "Status recorded");
header("Content-type: application/json");
echo json_encode($response);
} else {
// Add here the code in case the payment is denied
}
} else {
// Send back a default error response
// For non 20x code, the payment server will not mark the payment as notified
http_response_code(500);
$response = array("status" => "KO", "message" => "Error handling the callback");
header("Content-type: application/json");
echo json_encode($response);
}
// Instantiate the client and handle the redirection
Connect2payClient c2p = new Connect2payClient("https://connect2.payxpert.com", "123456", "GreatP4ssw0rd");
PaymentStatusResponse response = null;
try {
// request is either the body of the received request as a string or an InputStream pointing to the received body
response = c2p.handleCallbackStatus(request);
} catch (Exception e) {
logger.error("Ooops, an error occurred handling the callback: " + e.getMessage());
// Handle the error...
}
if (response != null && ResultCode.SUCCESS.equals(response.getCode())) {
// Check the payment status: 000 means success
if ("000".equals(response.getErrorCode())) {
// Handle the payment success case
// ...
// Access the payment mean information
CreditCardPaymentMeanInfo pmInfo = response.getCCPaymentMeanInfo();
logger.info("Successful payment done by " + pmInfo.getCardHolderName() + "with card " + pmInfo.getCardNumber());
} else {
// Handle the payment failure case
}
if (handledSuccessfully) {
out.write(CallbackStatusResponse.getDefaultSuccessResponse().toJson()); // out is the output stream
} else {
out.write(CallbackStatusResponse.getDefaultFailureResponse().toJson()); // out is the output stream
}
} else {
// Handle the failure
out.write(CallbackStatusResponse.getDefaultFailureResponse().toJson()); // out is the output stream
}