Beta Release
This is pre-release documentation for an API in public beta and is subject to change.
Square Webhooks

Validate Notifications

Validate Square Webhooks (beta) event notifications.

Node.js (SDK)

Once you are sure your webhooks are working, you will need to add code to your notification URL so that your application does something with the events it receives.

Your webhook endpoints are public and can be called by anyone. For this reason, you must validate webhook notifications to confirm they came from Square. A non-Square caller can potentially compromising your Square account.

All Webhooks (beta) notifications from Square include an X-Square-Signature header. The value of this header is an HMAC-SHA1 signature generated using your webhook notification URL and the body of the request excluding all whitespace.

You can validate the webhook notification by generating the HMAC-SHA1 in your own code and comparing it to the signature of the notification you received. You will need the Signature Key assigned by the Square Application Dashboard in the Webhooks settings page for your application.

Important

A malicious agent can compromise your notification endpoint by using a timing analysis attack to determine the key you are using to decrypt and compare webhook signatures. You should use a constant-time crypto library to prevent such attacks by masking the actual time taken to decrypt and compare signatures.

Information you will need
Permalink Get a link to this section

  • The webhook signature key assigned by the Square Developer Portal in the Webhooks settings page for your application. You will compare the webhook signature key to the key provided in the notification.

In the Webhooks page for your application, click on the Square API Webhook endpoint that you are verifying. The Webhook Details dialog opens and shows the signature key of the subscription:

v2WebhookEndpoint

Step 1: Get the notification signature and body
Permalink Get a link to this section

// This example uses Express to handle HTTP requests
const express = require('express');
const app = express();

// Parse HTTP bodies as JSON
app.use(express.json());

app.post('/webhooks', function(req, resp) {
  // Notification signature: 'gf6sy...wOFw9Gw='
  // Note: Signature is truncated for illustration
  const signature = req.header('X-Square-Signature');

  /*
  webhook notification body
  {
    "merchant_id": "6VEKB6...",
    "type": "webhooks.test_notification",
    "event_id": "44db71b7-c20a-416e-428a-fd8e1837e4f5",
    "created_at": "2019-07-31T17:10:55.49604564Z",
    "data": {
      "type": "webhooks",
      "id": "8e4600d9-7e6c-44d5-8942-31fb7e45ef0e"
    }
  }
  */
  const body = req.body;

  // Send a 200 response to indicate success
  resp.sendStatus(200);
});

app.listen(3000, () => console.log('listening for webhooks on port 3000'));

Did you know?

You can get the timestamp of the initial event notification delivery, the number of notification retries, and the Square environment that generated the notification by reading the Event metadata headers on the event message.

Square makes every attempt to insure that notifications arrive at your notification endpoint in the order they were created. However, chronological order is not guaranteed. When processing notifications for unrelated operations, this may not be a problem.

Every notification carries an HTTP header - Square-Initial-Delivery-Timestamp that has the time that the notification was created. If your business process requires notifications to be processed in the order events are triggered, this header allows notifications to be queued for processing in chronological order.

Step 2: Validate the signature
Permalink Get a link to this section

The example function below generates an HMAC-SHA1 signature from your notification URL and the notification body, then compares it with the provided signature.

// The crypto module provides cryptographic functionality
const crypto = require('crypto');

function isValidSignature(body, url, signature) {
  // Concatenate your notification URL and
  // the JSON body of the webhook notification
  const combined = url + body;

  // Webhook subscription signature key defined in dev portal for app 
  // webhook listener endpoint: https://webhook.site/my-listener-endpoint
  // Note: Signature key is truncated for illustration
  const signatureKey = 'uTYf8X...0HGvYg';

  // Generate the HMAC-SHA1 signature of the string
  // signed with your webhook signature key
  const hmac = crypto.createHmac('sha1', signatureKey);
  hmac.write(combined)
  hmac.end()
  const checkHash = hmac.read().toString('base64');
    
  // Compare HMAC-SHA1 signatures.
  if (checkHash === signature) {
    console.log('Validation success!');
  } else {
    console.log('Validation error.');
  }
}