Analyse de l'IPN (URL de notification)
I. Prérequis : restrictions serveur marchand
- Vous devez autoriser la plage d'adresses IP 194.50.38.0/24, port par défaut 443 (HTTPS) sur votre serveur.
- Lien pour le paramètrage de l'IPN.
II. Les données transmises
Paramètre | Description | Valeur |
---|---|---|
kr-hash | Hash de l'objet JSON stocké dans kr-answer. Il permet de vérifier l'authenticité de la réponse. | Ex: c3c0323c748fdb7c2d24bd39ada99663526236828efa795193bebfdea022fe58 |
kr-hash-algorithm | Algorithme utilisé pour calculer le hash. | Sa valeur est sha256_hmac |
kr-hash-key | Clé HMAC-SHA-256 (2 ème clé du tableau des clés API REST ). Clé utilisée pour signer kr-answer. | password (cas IPN). |
kr-answer-type | Type de l'objet JSON contenu dans kr-answer. | Ex : V4/Payment |
kr-answer | Objet contenant le résultat du paiement, encodé en JSON. | Ex : {"shopId":"42229744","orderCycle":"CLOSED","orderStatus":"PAID", (...) |
III. Vérifier l'authenticité de l'IPN
Vous devez vérifier l'authenticité des données reçues.
Chiffrez le kr-answer reçu en utilisant la fonction
hash_hmac
- Algorithme de chiffrement : sha256
- Clé secrète : le mot de passe qui commence par testpassword** ou prodpassword** (2ème clé du tableau des clés API REST ).
- Base d'encodage : héxadécimale (base 16).
Vérifiez l'authenticité du message reçu
- si le kr-hash est égal au chiffrement du kr-answer alors le message est authentique.
Exemple de code du fichier d'exemple : ipn.php
// STEP 1 : check the signature with the password
if (!checkHash($_POST, PASSWORD)) {
echo 'Invalid signature. <br/>';
echo '<pre>' . print_r($_POST, true) . '</pre>';
die();
}
$answer = array();
$answer['kr-hash'] = $_POST['kr-hash'];
$answer['kr-hash-algorithm'] = $_POST['kr-hash-algorithm'];
$answer['kr-answer-type'] = $_POST['kr-answer-type'];
$answer['kr-answer'] = json_decode($_POST['kr-answer'], true);
// STEP 2 : function to check the signature
function checkHash($data, $key){
$supported_sign_algos = array('sha256_hmac');
if (!in_array($data['kr-hash-algorithm'], $supported_sign_algos)) {
return false;
}
$kr_answer = str_replace('\/', '/', $data['kr-answer']);
$hash = hash_hmac('sha256', $kr_answer, $key);
return ($hash == $data['kr-hash']);
}
IV. Vérifier le statut de la transaction
Vérifiez le paramètre orderStatus contenu dans kr-answer.
La valeur PAID du champ orderStatus signifie que la transaction a été acceptée.
Plus d'infos : Cycle de vie d'une transaction
Exemple de kr-answer
:
{ "shopId": "42229744", "orderCycle": "CLOSED", "orderStatus": "PAID", "serverDate": "2022-01-21T09:28:17+00:00", "orderDetails": { "orderTotalAmount": 990, "orderEffectiveAmount": 990, "orderCurrency": "EUR", "mode": "TEST", "orderId": "myOrderId-475882", "metadata": null, "_type": "V4/OrderDetails" }, "customer": { "billingDetails": { "address": null, "category": null, "cellPhoneNumber": null, "city": null, "country": null, "district": null, "firstName": null, "identityCode": null, "language": "FR", "lastName": null, "phoneNumber": null, "state": null, "streetNumber": null, "title": null, "zipCode": null, "legalName": null, "_type": "V4/Customer/BillingDetails" }, "email": "sample@example.com", "reference": null, "shippingDetails": { "address": null, "address2": null, "category": null, "city": null, "country": null, "deliveryCompanyName": null, "district": null, "firstName": null, "identityCode": null, "lastName": null, "legalName": null, "phoneNumber": null, "shippingMethod": null, "shippingSpeed": null, "state": null, "streetNumber": null, "zipCode": null, "_type": "V4/Customer/ShippingDetails" }, "extraDetails": { "browserAccept": null, "fingerPrintId": null, "ipAddress": "185.244.73.2", "browserUserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36", "_type": "V4/Customer/ExtraDetails" }, "shoppingCart": { "insuranceAmount": null, "shippingAmount": null, "taxAmount": null, "cartItemInfo": null, "_type": "V4/Customer/ShoppingCart" }, "_type": "V4/Customer/Customer" }, "transactions": [ { "shopId": "42229744", "uuid": "1c8356b0e24442b2acc579cf1ae4d814", "amount": 990, "currency": "EUR", "paymentMethodType": "CARD", "paymentMethodToken": null, "status": "PAID", "detailedStatus": "AUTHORISED", "operationType": "DEBIT", "effectiveStrongAuthentication": "ENABLED", "creationDate": "2022-01-21T09:28:16+00:00", "errorCode": null, "errorMessage": null, "detailedErrorCode": null, "detailedErrorMessage": null, "metadata": null, "transactionDetails": { "liabilityShift": "YES", "effectiveAmount": 990, "effectiveCurrency": "EUR", "creationContext": "CHARGE", "cardDetails": { "paymentSource": "EC", "manualValidation": "NO", "expectedCaptureDate": "2022-01-27T09:38:10+00:00", "effectiveBrand": "VISA", "pan": "497011XXXXXX1003", "expiryMonth": 12, "expiryYear": 2025, "country": "FR", "issuerCode": 17807, "issuerName": "Banque Populaire Occitane", "effectiveProductCode": null, "legacyTransId": "929936", "legacyTransDate": "2022-01-21T09:28:16+00:00", "paymentMethodSource": "NEW", "authorizationResponse": { "amount": 990, "currency": "EUR", "authorizationDate": "2022-01-21T09:28:16+00:00", "authorizationNumber": "3fe205", "authorizationResult": "0", "authorizationMode": "FULL", "_type": "V4/PaymentMethod/Details/Cards/CardAuthorizationResponse" }, "captureResponse": { "refundAmount": null, "refundCurrency": null, "captureDate": null, "captureFileNumber": null, "effectiveRefundAmount": null, "effectiveRefundCurrency": null, "_type": "V4/PaymentMethod/Details/Cards/CardCaptureResponse" }, "threeDSResponse": { "authenticationResultData": { "transactionCondition": null, "enrolled": null, "status": null, "eci": null, "xid": null, "cavvAlgorithm": null, "cavv": null, "signValid": null, "brand": null, "_type": "V4/PaymentMethod/Details/Cards/CardAuthenticationResponse" }, "_type": "V4/PaymentMethod/Details/Cards/ThreeDSResponse" }, "authenticationResponse": { "id": "30eaa40d-dd76-4617-b527-4bed6240b81c", "operationSessionId": "ae6f2ad3ffea41bb8faf1aefabad87b9", "protocol": { "name": "THREEDS", "version": "2.1.0", "network": "VISA", "challengePreference": "NO_PREFERENCE", "simulation": true, "_type": "V4/Charge/Authenticate/Protocol" }, "value": { "authenticationType": "CHALLENGE", "authenticationId": { "authenticationIdType": "dsTransId", "value": "bafdb21f-e3d6-4d1c-b4f6-d1668b7f7f21", "_type": "V4/Charge/Authenticate/AuthenticationId" }, "authenticationValue": { "authenticationValueType": "CAVV", "value": "BqLgDBHYRaCBpip3Fn3+erKT9vg=", "_type": "V4/Charge/Authenticate/AuthenticationValue" }, "status": "SUCCESS", "commerceIndicator": "05", "extension": { "authenticationType": "THREEDS_V2", "threeDSServerTransID": "30eaa40d-dd76-4617-b527-4bed6240b81c", "dsTransID": "bafdb21f-e3d6-4d1c-b4f6-d1668b7f7f21", "acsTransID": "bd6e58b4-6f37-4993-b428-9096766d83a6", "_type": "V4/Charge/Authenticate/AuthenticationResultExtensionThreedsV2" }, "reason": { "_type": "V4/Charge/Authenticate/AuthenticationResultReason" }, "_type": "V4/Charge/Authenticate/AuthenticationResult" }, "_type": "V4/AuthenticationResponseData" }, "installmentNumber": null, "installmentCode": null, "markAuthorizationResponse": { "amount": null, "currency": null, "authorizationDate": null, "authorizationNumber": null, "authorizationResult": null, "_type": "V4/PaymentMethod/Details/Cards/MarkAuthorizationResponse" }, "cardHolderName": null, "identityDocumentNumber": null, "identityDocumentType": null, "_type": "V4/PaymentMethod/Details/CardDetails" }, "fraudManagement": { "_type": "V4/PaymentMethod/Details/FraudManagement" }, "subscriptionDetails": { "subscriptionId": null, "_type": "V4/PaymentMethod/Details/SubscriptionDetails" }, "parentTransactionUuid": null, "mid": "9999999", "sequenceNumber": 1, "taxAmount": null, "preTaxAmount": null, "taxRate": null, "externalTransactionId": null, "nsu": null, "tid": "001", "acquirerNetwork": "CB", "taxRefundAmount": null, "userInfo": "JS Client", "paymentMethodTokenPreviouslyRegistered": null, "occurrenceType": "UNITAIRE", "_type": "V4/TransactionDetails" }, "_type": "V4/PaymentTransaction" } ], "subMerchantDetails": null, "_type": "V4/Payment" }
V. Rejeu de l'IPN
En cas d'échec, un mécanisme de rejeu automatique se configure lors du paramétrage de l'IPN : lien.
Si vous activez le rejeu, la plateforme renvoie automatiquement l'IPN en cas d'échec, tous les 15 minutes, et ce, jusqu'à 4 fois.
Si vous ne souhaitez pas attendre ce délai, utilisez le Web Service Order/Get pour retrouver la liste des transactions associées à une référence commande (orderId). Il est recommandé :
- Limiter un appel par minute.
- Attendre une réponse avant le prochain appel.