{"id":422,"date":"2017-04-18T00:00:54","date_gmt":"2017-04-18T04:00:54","guid":{"rendered":"http:\/\/www.johnconde.net\/blog\/?p=422"},"modified":"2023-01-08T12:05:20","modified_gmt":"2023-01-08T16:05:20","slug":"handling-authorize-net-webhooks-with-php","status":"publish","type":"post","link":"https:\/\/website-0f9bf4a4.hpx.ppi.temporary.site\/blog\/handling-authorize-net-webhooks-with-php\/","title":{"rendered":"Handling Authorize.Net&#8217;s Webhooks with PHP"},"content":{"rendered":"<p>On December 1st, 2016, <a href=\"https:\/\/community.developer.authorize.net\/t5\/The-Authorize-Net-Developer-Blog\/New-Webhooks-Support-for-Authorize-Net\/ba-p\/55539\" rel=\"external\">Authorize.Net announced support for Webhooks<\/a>. What is a Webhook?<\/p>\n<blockquote cite=\"https:\/\/webhooks.pbworks.com\/\"><p>A WebHook is an HTTP callback: an HTTP POST that occurs when something happens; a simple event-notification via HTTP POST. A web application implementing WebHooks will POST a message to a URL when certain things happen.&nbsp;&nbsp;<\/p><\/blockquote>\n<p>When working with Authorize.Net to process payments, you may want to be notified when some or all of the following events occur:<\/p>\n<ul>\n<li>A customer profile is created, updated, or deleted<\/li>\n<li>A payment profile is created, updated, or deleted<\/li>\n<li>A subscription is created, cancelled, expiring soon, updated, suspended, or terminated<\/li>\n<li>A payment is made, an authorization is made, a prior authorization is captured<\/li>\n<li>A payment suspected of fraud is held, later approved, or declined<\/li>\n<li>A refund is made<\/li>\n<li>A void is made<\/li>\n<\/ul>\n<p>Your business requirements will determine which events are required to receive a Webhook notification. You can see a list of the Webhooks defined by Authorize.Net in the <a href=\"http:\/\/developer.authorize.net\/api\/reference\/features\/webhooks.html\" rel=\"external\">Webhooks documentation<\/a>.<\/p>\n<p>If you have a current implementation of Authorize.Net you may already be using <a href=\"http:\/\/www.johnconde.net\/blog\/all-about-authorize-nets-silent-post\/\">Silent Post<\/a> to receive information about payments. <a href=\"https:\/\/support.authorize.net\/authkb\/index?page=content&amp;id=A609\" rel=\"external\">Authorize.Net sees Webhooks as ultimately replacing Silent Post<\/a> so they recommend developers begin transitioning to it immediately. However, it&#8217;s not a simple transition as there are big differences between Silent Post and Webhooks. Points of note include:<\/p>\n<ul>\n<li><b>More Event Types<\/b>: Silent Post will send a copy of transaction responses only. Webhooks will notifiy you of all events you are interested including payment transactions as well as subscription information and profile changes.<\/li>\n<li><b>Less Information<\/b>: Although Webhooks offer many more event types than Silent Post, it provides far less information. You will get just enough information to know what event occured and an identifier for the event. Used in conjunction with Transaction Details API you can get the relevant transaction information that is normally provided by Silent Post. You can see a list of the categories of events and their associated identifiers in the Webhooks documentation.<\/li>\n<\/ul>\n<h2>Creating and Reacting to a Webhook<\/h2>\n<p>Just as with any Authorize.Net API interaction, you must retrieve your API login and transaction key from your Merchant Control Panel. While you are there be sure to configure a Signature Key as you cannot work with Webhooks without it. We will use this to verify the notification came from Authorize.Net.<\/p>\n<p>Once you configured your Signature Key and have your API credentials, you can use the AuthnetJSON PHP library to create your webhook. You can have one or more event defined in a Webhook allowing you to choose how you want to organize your Webhooks. In the example below we will have all of the events we want to be notified for created in one Webhook which is what will be what most business requirements define.<\/p>\n<div class=\"note yellownote\">The code samples below use the <a href=\"https:\/\/github.com\/stymiee\/authnetjson\" rel=\"external\">AuthnetJSON PHP library<\/a>. Be sure to read the <a href=\"\/\/www.johnconde.net\/blog\/tutorial-integrate-all-authorize-net-json-apis-with-one-universal-php-class-aim-arb-cim-transaction-details\/\">tutorial for installation instructions and making API calls<\/a>.<\/div>\n<h3>Example: Webhooks for Payment Notification<\/h3>\n<p>As Authorize.Net encourages developers to transition to Webhooks as Silent Post will eventually be deprecated and retired, we will create and handle a Webhook for payments allowing us to duplicate Silent Post functionality.<\/p>\n<h4>Step 1: Create your Webhook<\/h4>\n<p>To create your webhook you will call <code>AuthnetWebhooksRequest::createWebhooks()<\/code>. It accepts a comma separated list of events you wish to receive notifications for. We will create notifications for all of the event types associated with payments. In the example below we set the Webhook notification URL to <code>http:\/\/example.com\/webhooks<\/code> which is a fictitious URL. Change this to be the URL of your actual Webhook handler.<\/p>\n<pre lang=\"php\">$request = AuthnetApiFactory::getWebhooksHandler(AUTHNET_LOGIN, AUTHNET_TRANSKEY, \r\n                            AuthnetApiFactory::USE_DEVELOPMENT_SERVER);\r\n$response = $request->createWebhooks([\r\n  'net.authorize.payment.authorization.created',\r\n  'net.authorize.payment.capture.created',\r\n  'net.authorize.payment.authcapture.created',\r\n  'net.authorize.payment.priorAuthCapture.created',\r\n  'net.authorize.payment.refund.created',\r\n  'net.authorize.payment.void.created'\r\n], 'http:\/\/example.com\/webhooks', 'active');<\/pre>\n<h4>Step 2: Validate the Webhook Notification<\/h4>\n<p>Now that you have created your Webhook with notifications for all payment related events, you need to be ready to receive notifications for all payment related events. Your first step when receiving a Webhook notification is to verify that a hashed copy of the webhook notification, using your signature key, is correct. If the hash provided does not match the hashed request body then the webhook is not valid. (You may want to log this information somewhere for future analysis). (Be sure to replace <code>*your_authnet_signature_key*<\/code> with your actual Signature Key).<\/p>\n<pre lang=\"php\">$headers = getallheaders();\r\n$payload = file_get_contents(\"php:\/\/input\");\r\n$webhook = new AuthnetWebhook(AUTHNET_SIGNATURE, $payload, $headers);\r\nif ($webhook->isValid()) {\r\n    \/\/ Access notification values\r\n}\r\n<\/pre>\n<h4>Step 3: Receive and Parse The Webhook Notification<\/h4>\n<p>Once you have validated the webhook you can access its properties just using object notation just like the rest of the AuthnetJson package allows.<\/p>\n<pre lang=\"php\">$headers = getallheaders();\r\n$payload = file_get_contents(\"php:\/\/input\");\r\n$webhook = new AuthnetWebhook(AUTHNET_SIGNATURE, $payload, $headers);\r\nif ($webhook->isValid()) {\r\n    \/\/ Get the transaction ID\r\n    $transactionId = $webhook->payload->id;\r\n}\r\n<\/pre>\n<p>There is more information contained within the notification. You can see a full example of all of the possible notifications and their content in the Webhooks documentation.<\/p>\n<h4>Step 4: Retrieve Transaction Data via the Transaction Details API<\/h4>\n<p>Once you have parsed the Webhook notification and extracted the transaction ID you would make an API call to the Transaction Details API <code>getTransactionDetailsRequest<\/code> endpoint using that transaction ID to get all of the relevant response information about that transaction:<\/p>\n<pre lang=\"php\">$headers = getallheaders();\r\n$payload = file_get_contents(\"php:\/\/input\");\r\n$webhook = new AuthnetWebhook(AUTHNET_SIGNATURE, $payload, $headers);\r\nif ($webhook->isValid()) {\r\n    \/\/ Get the transaction ID\r\n    $transactionId = $webhook->payload->id;\r\n\r\n    \/\/ Here you can get more information about the transaction\r\n    $request  = AuthnetApiFactory::getJsonApiHandler(AUTHNET_LOGIN, AUTHNET_TRANSKEY);\r\n    $response = $request->getTransactionDetailsRequest(array(\r\n        'transId' => $transactionId\r\n    ));\r\n\r\n    \/* You can put these response values in the database or whatever your business logic dictates.\r\n    $response->transaction->transactionType\r\n    $response->transaction->transactionStatus\r\n    $response->transaction->authCode\r\n    $response->transaction->AVSResponse\r\n    *\/\r\n}\r\n<\/pre>\n<p>You can view the Transaction Details documentation or view the <a href=\"https:\/\/github.com\/stymiee\/authnetjson\/blob\/master\/examples\/reporting\/getTransactionDetailsRequest.php\" rel=\"external\">AuthnetJSON PHP library example in Github<\/a> to see all of the available response fields.<\/p>\n<h3>Summary<\/h3>\n<p>Although Webhooks do not provide as much information as a Silent Post, they do offer the possibility of being notified of any event of which you may want to be aware of, including expiring subscriptions, which are not supported by Silent Post. Combined with the Transaction Details API your system can be flexible enough to handle any event giving you full visibility into your payment activity.<\/p>\n<h2>References<\/h2>\n<ul>\n<li><a href=\"http:\/\/developer.authorize.net\/api\/reference\/features\/webhooks.html\" rel=\"external\">Webhooks Documentation<\/a><\/li>\n<li><a href=\"http:\/\/developer.authorize.net\/api\/reference\/features\/transaction_reporting.html\" rel=\"external\">Transaction Details API<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/stymiee\/authnetjson\" rel=\"external\">AuthnetJson PHP Package<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>On December 1st, 2016, Authorize.Net announced support for Webhooks. What is a Webhook? A WebHook is an HTTP callback: an HTTP POST that occurs when something happens; a simple event-notification via HTTP POST. <a href=\"https:\/\/website-0f9bf4a4.hpx.ppi.temporary.site\/blog\/handling-authorize-net-webhooks-with-php\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[16],"tags":[82,60,50,88],"class_list":["post-422","post","type-post","status-publish","format-standard","hentry","category-programming","tag-api","tag-authorizenet","tag-php","tag-webhooks"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/pwpo4-6O","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/website-0f9bf4a4.hpx.ppi.temporary.site\/blog\/wp-json\/wp\/v2\/posts\/422","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/website-0f9bf4a4.hpx.ppi.temporary.site\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/website-0f9bf4a4.hpx.ppi.temporary.site\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/website-0f9bf4a4.hpx.ppi.temporary.site\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/website-0f9bf4a4.hpx.ppi.temporary.site\/blog\/wp-json\/wp\/v2\/comments?post=422"}],"version-history":[{"count":29,"href":"https:\/\/website-0f9bf4a4.hpx.ppi.temporary.site\/blog\/wp-json\/wp\/v2\/posts\/422\/revisions"}],"predecessor-version":[{"id":761,"href":"https:\/\/website-0f9bf4a4.hpx.ppi.temporary.site\/blog\/wp-json\/wp\/v2\/posts\/422\/revisions\/761"}],"wp:attachment":[{"href":"https:\/\/website-0f9bf4a4.hpx.ppi.temporary.site\/blog\/wp-json\/wp\/v2\/media?parent=422"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/website-0f9bf4a4.hpx.ppi.temporary.site\/blog\/wp-json\/wp\/v2\/categories?post=422"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/website-0f9bf4a4.hpx.ppi.temporary.site\/blog\/wp-json\/wp\/v2\/tags?post=422"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}