* Just uncomment the below line to read the data from actual request. */ /** @var Array $headers */ //$headers = getallheaders(); /** * In Documentions https://developer.paypal.com/docs/api/webhooks/#verify-webhook-signature_post * All header keys as UPPERCASE, but I recive the header key as the example array, First letter as UPPERCASE */ $headers = array_change_key_case($headers, CASE_UPPER); $signatureVerification = new VerifyWebhookSignature(); $signatureVerification->setAuthAlgo($headers['PAYPAL-AUTH-ALGO']); $signatureVerification->setTransmissionId($headers['PAYPAL-TRANSMISSION-ID']); $signatureVerification->setCertUrl($headers['PAYPAL-CERT-URL']); $signatureVerification->setWebhookId("9XL90610J3647323C"); // Note that the Webhook ID must be a currently valid Webhook that you created with your client ID/secret. $signatureVerification->setTransmissionSig($headers['PAYPAL-TRANSMISSION-SIG']); $signatureVerification->setTransmissionTime($headers['PAYPAL-TRANSMISSION-TIME']); $webhookEvent = new WebhookEvent(); $webhookEvent->fromJson($requestBody); $signatureVerification->setWebhookEvent($webhookEvent); $request = clone $signatureVerification; try { /** @var \PayPal\Api\VerifyWebhookSignatureResponse $output */ $output = $signatureVerification->post($apiContext); } catch (Exception $ex) { // NOTE: PLEASE DO NOT USE RESULTPRINTER CLASS IN YOUR ORIGINAL CODE. FOR SAMPLE ONLY ResultPrinter::printError("Validate Received Webhook Event", "WebhookEvent", null, $request->toJSON(), $ex); exit(1); } // NOTE: PLEASE DO NOT USE RESULTPRINTER CLASS IN YOUR ORIGINAL CODE. FOR SAMPLE ONLY ResultPrinter::printResult("Validate Received Webhook Event", "WebhookEvent", $output->getVerificationStatus(), $request->toJSON(), $output);
/** * Retrieves the Webhooks event resource identified by event_id. Can be used to retrieve the payload for an event. * * @param string $eventId * @param ApiContext $apiContext is the APIContext for this call. It can be used to pass dynamic configuration and credentials. * @param PayPalRestCall $restCall is the Rest Call Service that is used to make rest calls * @return WebhookEvent */ public static function get($eventId, $apiContext = null, $restCall = null) { ArgumentValidator::validate($eventId, 'eventId'); $payLoad = ""; $json = self::executeCall("/v1/notifications/webhooks-events/{$eventId}", "GET", $payLoad, null, $apiContext, $restCall); $ret = new WebhookEvent(); $ret->fromJson($json); return $ret; }
/** * @dataProvider mockProvider * @param WebhookEvent $obj */ public function testList($obj, $mockApiContext) { $mockPayPalRestCall = $this->getMockBuilder('\\PayPal\\Transport\\PayPalRestCall')->disableOriginalConstructor()->getMock(); $mockPayPalRestCall->expects($this->any())->method('execute')->will($this->returnValue(WebhookEventListTest::getJson())); $params = array(); $result = $obj->all($params, $mockApiContext, $mockPayPalRestCall); $this->assertNotNull($result); }
public function testEventSearch() { $result = WebhookEvent::all(array(), $this->apiContext, $this->mockPayPalRestCall); $this->assertNotNull($result); return $result; }
/** * Load and validate order, instantiate proper configuration * * @return Mage_Sales_Model_Order * @throws Exception */ protected function getOrder(\PayPal\Api\WebhookEvent $webhookEvent) { if (empty($this->_order)) { // get proper order $resource = $webhookEvent->getResource(); if (!$resource) { throw new Exception('Event resource not found.'); } if (isset($resource->parent_payment)) { $transactionId = $resource->parent_payment; } else { $transactionId = $resource->id; } $transaction = Mage::getModel('sales/order_payment_transaction')->load($transactionId, 'txn_id'); $this->_order = Mage::getModel('sales/order')->load($transaction->getOrderId()); if (!$this->_order->getId()) { $this->_debugData['exception'] = sprintf('Wrong order ID: "%s".', $id); Mage::app()->getResponse()->setHeader('HTTP/1.1', '503 Service Unavailable')->sendResponse(); exit; } } return $this->_order; }
<?php $apiContext = (require __DIR__ . '/../bootstrap.php'); // # Validate Webhook // PHP Currently does not support certificate chain validation, that is necessary to validate webhook directly, from received data // To resolve that, we need to use alternative, which includes making a GET call to obtain the data directly from PayPal. // // ## Received Body from Webhook // Body received from webhook. This would be the data that you receive in the post request that comes from PayPal, to your webhook set URL. // This is a sample data, that represents the webhook event data. $bodyReceived = '{"id":"WH-36G56432PK518391U-9HW18392D95289106","create_time":"2015-06-01T20:21:13Z","resource_type":"sale","event_type":"PAYMENT.SALE.COMPLETED","summary":"Payment completed for $ 20.0 USD","resource":{"id":"2FY57107YS3937627","create_time":"2015-06-01T20:20:28Z","update_time":"2015-06-01T20:20:46Z","amount":{"total":"20.00","currency":"USD"},"payment_mode":"INSTANT_TRANSFER","state":"completed","protection_eligibility":"ELIGIBLE","protection_eligibility_type":"ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE","parent_payment":"PAY-2SV945219E505370PKVWL5DA","transaction_fee":{"value":"0.88","currency":"USD"},"links":[{"href":"https://api.sandbox.paypal.com/v1/payments/sale/2FY57107YS3937627","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/payments/sale/2FY57107YS3937627/refund","rel":"refund","method":"POST"},{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-2SV945219E505370PKVWL5DA","rel":"parent_payment","method":"GET"}]},"links":[{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-36G56432PK518391U-9HW18392D95289106","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-36G56432PK518391U-9HW18392D95289106/resend","rel":"resend","method":"POST"}]}'; /** * This is one way to receive the entire body that you received from PayPal webhook. This is one of the way to retrieve that information. * Just uncomment the below line to read the data from actual request. */ /** @var String $bodyReceived */ // $bodyReceived = file_get_contents('php://input'); // ### Validate Received Event Method // Call the validateReceivedEvent() method with provided body, and apiContext object to validate try { /** @var \PayPal\Api\WebhookEvent $output */ $output = \PayPal\Api\WebhookEvent::validateAndGetReceivedEvent($bodyReceived, $apiContext); } catch (Exception $ex) { // NOTE: PLEASE DO NOT USE RESULTPRINTER CLASS IN YOUR ORIGINAL CODE. FOR SAMPLE ONLY ResultPrinter::printError("Validate Received Webhook Event", "WebhookEvent", null, $bodyReceived, $ex); exit(1); } // NOTE: PLEASE DO NOT USE RESULTPRINTER CLASS IN YOUR ORIGINAL CODE. FOR SAMPLE ONLY ResultPrinter::printResult("Validate Received Webhook Event", "WebhookEvent", $output->getId(), $bodyReceived, $output);
/** * @dataProvider mockProvider * @param $mockApiContext ApiContext * @expectedException \InvalidArgumentException * @expectedExceptionMessage Id attribute not found in JSON. Possible reason could be invalid JSON Object */ public function testValidateWebhookValidJSONWithoutId($obj, $mockApiContext) { WebhookEvent::validateAndGetReceivedEvent('{"summary":"json"}', $mockApiContext); }
<?php // # Search Webhook Events Sample // // This sample code demonstrate how to use this call to search for all webhook events., as documented here at: // https://developer.paypal.com/docs/api/#search-webhook-events // API used: GET /v1/notifications/webhooks-events // ## Get Webhook Instance // ## PLEASE NOTE: // Creating webhook is sample purposes only. In real scenario, you dont need to create a new webhook everytime you want to search // for a webhook events. This is made in a sample just to make sure there is minimum of one webhook to listen to. /** @var \PayPal\Api\Webhook $webhook */ $webhook = (require __DIR__ . '/../bootstrap.php'); $params = array(); // ### Search Webhook events try { $output = \PayPal\Api\WebhookEvent::all($params, $apiContext); } catch (Exception $ex) { // NOTE: PLEASE DO NOT USE RESULTPRINTER CLASS IN YOUR ORIGINAL CODE. FOR SAMPLE ONLY ResultPrinter::printError("Search Webhook events", "WebhookEventList", null, null, $ex); exit(1); } // NOTE: PLEASE DO NOT USE RESULTPRINTER CLASS IN YOUR ORIGINAL CODE. FOR SAMPLE ONLY ResultPrinter::printResult("Search Webhook events", "WebhookEventList", null, $params, $output); return $output;
/** * Load and validate order, instantiate proper configuration * * @return Mage_Sales_Model_Order * @throws Exception */ protected function getOrder(\PayPal\Api\WebhookEvent $webhookEvent) { if (empty($this->_order)) { // get proper order $resource = $webhookEvent->getResource(); if (!$resource) { throw new Exception('Event resource not found.'); } $transactionId = $resource->id; $transaction = Mage::getModel('sales/order_payment_transaction')->load($transactionId, 'txn_id'); $this->_order = Mage::getModel('sales/order')->load($transaction->getOrderId()); if (!$this->_order->getId()) { Mage::throwException('Order not found.'); } } return $this->_order; }