I’m using the 2C2P payment gateway.
public function process_payment( $order_id ) {
$result = $this->request->result( $order );
error_log( print_r( $result, true ) );
if ( in_array( $result->response->ApiResponse->ResponseCode, array( 'PC-B050000', 'PC-B050001', 'PC-B050002' ) ) ) {
// Success but pending, requires account verification like OTP.
if ( isset( $result->response->Data->paymentIncompleteResult->aresACSChallenge->transStatus ) && 'C' === $result->response->Data->paymentIncompleteResult->aresACSChallenge->transStatus ) {
// Handle OTP verification etc.
}
return;
}
}
How do I handle OTP Verification? It gives the response like:
[05-Apr-2024 09:03:58 UTC] stdClass Object
(
[response] => stdClass Object
(
[Data] => stdClass Object
(
[paymentIncompleteResult] => stdClass Object
(
[notificationURLs] =>
[aresACSChallenge] => stdClass Object
(
[transStatus] => C
[acsURL] => https://paysecure.nicasiabank.com/3dsAcs2FrontOfficeWeb/paymentAuthentication
[CReq] => PGh0bWw-PGhlYWQ-PC9oZWFkPjxib2R5Pgo8Zm9ybSBuYW1lPSdjcmVxRm9ybScgbWV0aG9kPSdQT1NUJyBhY3Rpb249J2h0dHBzOi8vcGF5c2VjdXJlLm5pY2FzaWFiYW5rLmNvbS8zZHNBY3MyRnJvbnRPZmZpY2VXZWIvcGF5bWVudEF1dGhlbnRpY2F0aW9uJz4KICAgIDxpbnB1dCB0eXBlPSdoaWRkZW4nIG5hbWU9J2NyZXEnIHZhbHVlPSdleUp0WlhOellXZGxWSGx3WlNJNklrTlNaWEVpTENKamFHRnNiR1Z1WjJWWGFXNWtiM2RUYVhwbElqb2lNRE1pTENKMGFISmxaVVJUVTJWeWRtVnlWSEpoYm5OSlJDSTZJbUZoTVdWbE5HUm1MVFprT0RZdE5Ea3lZUzA0WVdVNUxUWXdPV05rWkRjelltTXlPQ0lzSW1GamMxUnlZVzV6U1VRaU9pSTBOelF5WWpBM1lTMW1NekppTFRFeFpXVXRPV1V4WXkweE0yVXhaREppWm1Fd09USWlMQ0p0WlhOellXZGxWbVZ5YzJsdmJpSTZJakl1TWk0d0luMCc-CiAgICA8aW5wdXQgdHlwZT0naGlkZGVuJyBuYW1lPSd0aHJlZURTU2Vzc2lvbkRhdGEnIHZhbHVlPSdZV0V4WldVMFpHWXRObVE0TmkwME9USmhMVGhoWlRrdE5qQTVZMlJrTnpOaVl6STQnPgogICAgPG5vc2NyaXB0PjxidXR0b24-UGxlYXNlIGNsaWNrIGhlcmUgdG8gY29udGludWU8L2J1dHRvbj48L25vc2NyaXB0Pgo8L2Zvcm0-CiAgICA8c2NyaXB0IHR5cGU9J3RleHQvamF2YXNjcmlwdCc-ZG9jdW1lbnQuY3JlcUZvcm0uc3VibWl0KCk7PC9zY3JpcHQ-PC9ib2R5PjwvaHRtbD4
[rawCreq] => eyJtZXNzYWdlVHlwZSI6IkNSZXEiLCJjaGFsbGVuZ2VXaW5kb3dTaXplIjoiMDMiLCJ0aHJlZURTU2VydmVyVHJhbnNJRCI6ImFhMWVlNGRmLTZkODYtNDkyYS04YWU5LTYwOWNkZDczYmMyOCIsImFjc1RyYW5zSUQiOiI0NzQyYjA3YS1mMzJiLTExZWUtOWUxYy0xM2UxZDJiZmEwOTIiLCJtZXNzYWdlVmVyc2lvbiI6IjIuMi4wIn0
[ChallengeHtml] => PGh0bWw-PGhlYWQ-PC9oZWFkPjxib2R5Pgo8Zm9ybSBuYW1lPSdjcmVxRm9ybScgbWV0aG9kPSdQT1NUJyBhY3Rpb249J2h0dHBzOi8vcGF5c2VjdXJlLm5pY2FzaWFiYW5rLmNvbS8zZHNBY3MyRnJvbnRPZmZpY2VXZWIvcGF5bWVudEF1dGhlbnRpY2F0aW9uJz4KICAgIDxpbnB1dCB0eXBlPSdoaWRkZW4nIG5hbWU9J2NyZXEnIHZhbHVlPSdleUp0WlhOellXZGxWSGx3WlNJNklrTlNaWEVpTENKamFHRnNiR1Z1WjJWWGFXNWtiM2RUYVhwbElqb2lNRE1pTENKMGFISmxaVVJUVTJWeWRtVnlWSEpoYm5OSlJDSTZJbUZoTVdWbE5HUm1MVFprT0RZdE5Ea3lZUzA0WVdVNUxUWXdPV05rWkRjelltTXlPQ0lzSW1GamMxUnlZVzV6U1VRaU9pSTBOelF5WWpBM1lTMW1NekppTFRFeFpXVXRPV1V4WXkweE0yVXhaREppWm1Fd09USWlMQ0p0WlhOellXZGxWbVZ5YzJsdmJpSTZJakl1TWk0d0luMCc-CiAgICA8aW5wdXQgdHlwZT0naGlkZGVuJyBuYW1lPSd0aHJlZURTU2Vzc2lvbkRhdGEnIHZhbHVlPSdZV0V4WldVMFpHWXRObVE0TmkwME9USmhMVGhoWlRrdE5qQTVZMlJrTnpOaVl6STQnPgogICAgPG5vc2NyaXB0PjxidXR0b24-UGxlYXNlIGNsaWNrIGhlcmUgdG8gY29udGludWU8L2J1dHRvbj48L25vc2NyaXB0Pgo8L2Zvcm0-CiAgICA8c2NyaXB0IHR5cGU9J3RleHQvamF2YXNjcmlwdCc-ZG9jdW1lbnQuY3JlcUZvcm0uc3VibWl0KCk7PC9zY3JpcHQ-PC9ib2R5PjwvaHRtbD4
[threeDSSessionData] => YWExZWU0ZGYtNmQ4Ni00OTJhLThhZTktNjA5Y2RkNzNiYzI4
)
[failedReason] =>
[availablePaymentTypes] =>
[untokenizedStoredCardList] =>
[storedCardUniqueID] =>
[paymentExpiryDateTime] => 2024-04-05T09:48:40.0051453Z
[merchantIdForMcp] =>
[mcpDetails] =>
[preferredPaymentTypes] => Array
(
[0] => CC
)
[transactionDateTime] => 2024-04-05T09:03:42.987867Z
[orderNo] => 297
[productDescription] => Another Product - 3
[InvoiceNo2C2P] => HBL0000000047
[pspReferenceNo] =>
[controllerInternalID] => e40bc631b7a447afb42574998de7b380
[paymentStatusInfo] => stdClass Object
(
[PaymentStatus] => I
[PaymentStep] => AC
[LastUpdatedDateTime] => 2024-04-05T09:03:39.9619103Z
)
[paymentType] => CC
[channelCode] =>
[agentCode] =>
[mcpFlag] => N
[transactionAmount] => stdClass Object
(
[AmountText] => 000000000003
[CurrencyCode] => USD
[DecimalPlaces] => 2
[Amount] => 0.03
)
[settlementAmount] => stdClass Object
(
[AmountText] => 000000000003
[CurrencyCode] => USD
[DecimalPlaces] => 2
[Amount] => 0.03
)
[customFieldList] =>
[clientIp] =>
[officeId] => 9104135843
[ddcId] =>
)
[paymentPage] =>
)
[Version] => 1.0
[ApiResponse] => stdClass Object
(
[ResponseMessageId] => 03dad34c-ae08-4636-9e0c-ff777504d864
[ResponseToRequestMessageId] => 866900bf-d915-3415-4844-039c43152970
[ResponseCode] => PC-B050001
[ResponseDescription] => Success
[ResponseDateTime] => 2024-04-05T09:03:42.9878657Z
[ResponseTime] => 3100
[AcquirerResponseCode] =>
[AcquirerResponseDescription] =>
[EciValue] =>
[MarketingDescription] => Payment success but not completed yet.
Please finish your payment via selected payment channel later.
)
)
[aud] => 4b0d276fcaf04fbd9469859949b1b83c
[iss] => PacoIssuer
[exp] => 1712311423
[iat] => 1712307823
[nbf] => 1712307823
)
You are receving the verification URL $result->response->Data->paymentIncompleteResult->aresACSChallenge->acsURL
To handle OTP verification, you need to redirect the user to the provided acsURL
<?php
if (isset($result->response->Data->paymentIncompleteResult->aresACSChallenge->acsURL)) {
$acsUrl = $result->response->Data->paymentIncompleteResult->aresACSChallenge->acsURL;
// Redirect the user to the ACS URL for OTP verification
header("Location: $acsUrl");
exit;
} else {
// Handle case where ACS URL is not provided
}
2C2P expects your application to handle the user interface part so that user can enter the OTP for verification. This script takes the OTP provided by the user, checks it with the 2C2P payment gateway to confirm it’s correct, and then either finalizes the transaction if the OTP is verified or cancels it if not.
require 'vendor/autoload.php';
use GuzzleHttpClient;
$endpoint = 'https://demo2.2c2p.com/2C2PFrontEnd/RedirectV3/payment'; // Change this to the actual API endpoint
$apiKey = 'YOUR_API_KEY'; // Your 2C2P API key
$merchantId = 'YOUR_MERCHANT_ID'; // Your 2C2P merchant ID
$transactionId = $_SESSION['transactionId'];
// User provided OTP from the form
$otp = filter_input(INPUT_POST, 'otp', FILTER_SANITIZE_STRING);
// Prepare the data for submission
$data = [
'merchant_id' => $merchantId,
'transaction_id' => $transactionId,
'otp' => $otp,
'api_key' => $apiKey,
];
// Initialize Guzzle HTTP client
$client = new Client();
try {
// Make the HTTP request to 2C2P API for OTP submission
$response = $client->request('POST', $endpoint, [
'form_params' => $data,
'verify' => false // Only use this in development, SSL verification should be enabled in production
]);
// Check the status of the response
if ($response->getStatusCode() == 200) {
$responseBody = json_decode($response->getBody(), true);
if ($responseBody['response_code'] == '0000') {
echo "OTP verified successfully, transaction completed.";
} else {
echo "Failed to verify OTP: " . $responseBody['response_description'];
}
} else {
echo "HTTP error occurred: " . $response->getStatusCode();
}
} catch (Exception $e) {
// Handle any errors that may have occurred
echo "An error occurred: " . $e->getMessage();
}