Handling Authorize.Net’s Webhooks with PHP

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 web application implementing WebHooks will POST a message to a URL when certain things happen.  

When working with Authorize.Net to process payments, you may want to be notified when some or all of the following events occur:

  • A customer profile is created, updated, or deleted
  • A payment profile is created, updated, or deleted
  • A subscription is created, cancelled, expiring soon, updated, suspended, or terminated
  • A payment is made, an authorization is made, a prior authorization is captured
  • A payment suspected of fraud is held, later approved, or declined
  • A refund is made
  • A void is made

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 Webhooks documentation.

If you have a current implementation of Authorize.Net you may already be using Silent Post to receive information about payments. Authorize.Net sees Webhooks as ultimately replacing Silent Post so they recommend developers begin transitioning to it immediately. However, it’s not a simple transition as there are big differences between Silent Post and Webhooks. Points of note include:

  • More Event Types: 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.
  • Less Information: 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.

Creating and Reacting to a Webhook

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.

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.

Example: Webhooks for Payment Notification

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.

Step 1: Create your Webhook

To create your webhook you will call AuthnetWebhooksRequest::createWebhooks(). 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 http://example.com/webhooks which is a fictitious URL. Change this to be the URL of your actual Webhook handler.

$request = AuthnetApiFactory::getWebhooksHandler(AUTHNET_LOGIN, AUTHNET_TRANSKEY, 
                            AuthnetApiFactory::USE_DEVELOPMENT_SERVER);
$response = $request->createWebhooks([
  'net.authorize.payment.authorization.created',
  'net.authorize.payment.capture.created',
  'net.authorize.payment.authcapture.created',
  'net.authorize.payment.priorAuthCapture.created',
  'net.authorize.payment.refund.created',
  'net.authorize.payment.void.created'
], 'http://example.com/webhooks', 'active');

Step 2: Validate the Webhook Notification

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 *your_authnet_signature_key* with your actual Signature Key).

$headers = getallheaders();
$payload = file_get_contents("php://input");
$webhook = new AuthnetWebhook(AUTHNET_SIGNATURE, $payload, $headers);
if ($webhook->isValid()) {
    // Access notification values
}

Step 3: Receive and Parse The Webhook Notification

Once you have validated the webhook you can access its properties just using object notation just like the rest of the AuthnetJson package allows.

$headers = getallheaders();
$payload = file_get_contents("php://input");
$webhook = new AuthnetWebhook(AUTHNET_SIGNATURE, $payload, $headers);
if ($webhook->isValid()) {
    // Get the transaction ID
    $transactionId = $webhook->payload->id;
}

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.

Step 4: Retrieve Transaction Data via the Transaction Details API

Once you have parsed the Webhook notification and extracted the transaction ID you would make an API call to the Transaction Details API getTransactionDetailsRequest endpoint using that transaction ID to get all of the relevant response information about that transaction:

$headers = getallheaders();
$payload = file_get_contents("php://input");
$webhook = new AuthnetWebhook(AUTHNET_SIGNATURE, $payload, $headers);
if ($webhook->isValid()) {
    // Get the transaction ID
    $transactionId = $webhook->payload->id;
 
    // Here you can get more information about the transaction
    $request  = AuthnetApiFactory::getJsonApiHandler(AUTHNET_LOGIN, AUTHNET_TRANSKEY);
    $response = $request->getTransactionDetailsRequest(array(
        'transId' => $transactionId
    ));
 
    /* You can put these response values in the database or whatever your business logic dictates.
    $response->transaction->transactionType
    $response->transaction->transactionStatus
    $response->transaction->authCode
    $response->transaction->AVSResponse
    */
}

You can view the Transaction Details documentation or view the AuthnetJSON PHP library example in Github to see all of the available response fields.

Summary

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.

References

9 thoughts on “Handling Authorize.Net’s Webhooks with PHP

  1. Hello John.
    Thanks for your informative post. I’m using sandbox account and activated the following notifications:
    “net.authorize.payment.authorization.created”,
    “net.authorize.payment.authcapture.created”,
    “net.authorize.payment.capture.created”,
    “net.authorize.payment.refund.created”,
    “net.authorize.payment.priorAuthCapture.created”,
    “net.authorize.payment.void.created”,
    “net.authorize.customer.created”,
    “net.authorize.customer.paymentProfile.created”,
    “net.authorize.customer.subscription.expiring”,
    “net.authorize.customer.subscription.updated”
    I receive notification for one time payments but for some reason I didn’t get any notification for ARB(recurring subscription). Have you ever tested the webhooks for ARB transactions? Do you know which event should be activated to receive the status of ARB transactions?
    Thank you

  2. I would expect the net.authorize.payment.authcapture.created event to cover subscription payments. If you’re not seeing them it might be that the sandbox is not sending them by design or that the subscription payment is not actually happening. I would recommend contacting Authorize.Net and verify that this is correct.

  3. The AUTHNET_SIGNATURE should be the “Signature Key” from Authorize.net, right? No matter what I try the webhook will not validate when I do test posts. The $webhook->isValid call fails every time. This should work on sandbox mode, right?

  4. @Drew Michael i also met this same issue in sandbox account. Is this working in sandbox mode?

  5. The code for validating webhooks was modified to account for a case sensitivity issue and the example in the README does work. Give it a try and you should have better luck.

Leave a Reply

Your email address will not be published. Required fields are marked *