Learn about the third step for setting up Square webhooks, which is to verify that you receive the event notification and validate that the notification originated from Square.
You can verify the creation and receipt of an event notification using either a test endpoint you create or a public site such as webhook.site. You can use API Explorer to generate events that webhooks can subscribe to.
To verify your event notification subscription using webhook.site:
Go to webhook.site in a browser, copy the provided unique URL to the clipboard, and leave the page open.
Create a webhook subscription by following the steps in Subscribe to Event Notifications. For testing purposes, choose Select All under Events.
Enter the unique URL you copied from webhook.site as your notification URL.
Trigger an event from API Explorer. For example, generate a customer.created event by calling the CreateCustomer endpoint in the Customers API and providing a first or last name, company name, email address, or phone number.
Return to the webhook.site page to view the event notification.
After you verify that your webhook subscription is working, you need to add code to your notification URL so that your application can process the event.
Link to section
Validate that the notification is from Square
Your notification URL is public and can be called by anyone, so you must validate each event notification to confirm that it originated from Square. A non-Square post can potentially compromise your application. Requests that fail validation cannot be trusted and should be discarded.
All webhook notifications from Square include an x-square-hmacsha256-signature header. The value of this header is an HMAC-SHA-256 signature generated using:
The signature key for your webhook subscription.
The notification URL for your webhook subscription.
The raw body of the request.
To validate the webhook notification, generate the HMAC-SHA-256 signature in your own code and compare it to the x-square-hmacsha256-signature of the event notification you received. If needed, you can find your signature key and notification URL for your application's webhook subscription under Webhooks in the Developer Console.
Important
A malicious agent can compromise your notification endpoint by using a timing analysis attack to determine the key you're 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.
Link to section
Validation examples
The following examples show how to use the WebhooksHelper utility in the Square SDKs to generate an HMAC-SHA256 signature from a signature key, notification URL, and raw event notification body. The generated signature is then compared with the event notification's x-square-hmacsha256-signature sent in the test cURL request.
Important
When testing your webhook event notifications, make sure to use the raw request body without any whitespace. For example, {"hello":"world"}.
// server.mjsimport * as http from'http';
import { WebhooksHelper } from"square";
// The URL where event notifications are sent.constNOTIFICATION_URL = 'https://example.com/webhook';
// The signature key defined for the subscription.constSIGNATURE_KEY = 'asdf1234';
// Generate a signature from the notification url, signature key,// and request body and compare it to the Square signature header.asyncfunctionisFromSquare(signature, body) {
returnawaitWebhooksHelper.verifySignature({
requestBody: body,
signatureHeader: signature,
signatureKey: SIGNATURE_KEY,
notificationUrl: NOTIFICATION_URL
});
}
asyncfunctionrequestHandler(request, response) {
let body = '';
request.setEncoding('utf8');
request.on('data', function(chunk) {
body += chunk;
});
request.on('end', asyncfunction() {
const signature = request.headers['x-square-hmacsha256-signature'];
if (awaitisFromSquare(signature, body)) {
// Signature is valid. Return 200 OK.console.info("Request body: " + body);
response.writeHead(200);
} else {
// Signature is invalid. Return 403 Forbidden.console.info("Invalid signature");
response.writeHead(403);
}
response.end();
});
}
// Start a simple server for local testing.// Different frameworks may provide the raw request body in other ways.// INSTRUCTIONS// After installing the SDK:// 1. Run the server:// node server.mjs// 2. Send the following request from a separate terminal:// curl -vX POST localhost:8000 -d '{"hello":"world"}' -H "X-Square-HmacSha256-Signature: 2kRE5qRU2tR+tBGlDwMEw2avJ7QM4ikPYD/PJ3bd9Og="const server = http.createServer(requestHandler);
server.listen(8000);
# server.py
from http.server import BaseHTTPRequestHandler, HTTPServer
from square.utilities.webhooks_helper import is_valid_webhook_event_signature
# The URL where event notifications are sent.
NOTIFICATION_URL = 'https://example.com/webhook'# The signature key defined for the subscription.
SIGNATURE_KEY = 'asdf1234'
class MainHandler(BaseHTTPRequestHandler):
def do_POST(self):
length = int(self.headers.get('content-length', 0))
body = self.rfile.read(length).decode('utf-8')
square_signature = self.headers.get('x-square-hmacsha256-signature')
# Generate a signature from the notification url, signature key,# and request body and compare it to the Square signature header.
is_from_square = is_valid_webhook_event_signature(body,
square_signature,
SIGNATURE_KEY,
NOTIFICATION_URL)
if is_from_square:
# Signature is valid. Return 200 OK.
self.send_response(200)
print("Request body: {}".format(body))
else:
# Signature is invalid. Return 403 Forbidden.
self.send_response(403)
self.end_headers()
# Start a simple server for local testing.# Different frameworks may provide the raw request body in other ways.# INSTRUCTIONS# After installing the SDK:# 1. Run the server:# python server.py# 2. Send the following request from a separate terminal:# curl -vX POST localhost:8000 -d '{"hello":"world"}' -H "X-Square-HmacSha256-Signature: 2kRE5qRU2tR+tBGlDwMEw2avJ7QM4ikPYD/PJ3bd9Og="
server = HTTPServer(("0.0.0.0", 8000), MainHandler)
server.serve_forever()
using Square.Utilities;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
public class Server
{
/// <summary>The URL where event notifications are sent.</summary>
private const string NOTIFICATION_URL = "https://example.com/webhook";
/// <summary>The signature key defined for the subscription.</summary>
private const string SIGNATURE_KEY = "asdf1234";
/// <summary>
/// Generate a signature from the notification url, signature key,
/// and request body and compare it to the Square signature header.
/// </summary>
private static async Task<bool> IsFromSquare(HttpListenerRequest request)
{
using (var reader = new StreamReader(request.InputStream, Encoding.UTF8))
{
var signature = request.Headers.Get("x-square-hmacsha256-signature") ?? "";
var requestBody = await reader.ReadToEndAsync();
return WebhooksHelper.IsValidWebhookEventSignature(requestBody, signature, SIGNATURE_KEY, NOTIFICATION_URL);
}
}
/// <summary>
/// Start a simple server forlocal testing. Different frameworks may provide the raw request body in other ways.
/// </summary>
/// <remarks>
/// INSTRUCTIONS
/// After installing the SDK:
/// 1. Run the server:
/// (You will first need to include your own csharp.csproj file.)
/// <code>dotnet run</code>
/// 2. Send the following request from a separate terminal:
/// <code>curl -vX POST localhost:8000 -d '{"hello":"world"}' -H "X-Square-HmacSha256-Signature: 2kRE5qRU2tR+tBGlDwMEw2avJ7QM4ikPYD/PJ3bd9Og="</code>
/// </remarks>
public static void Main(string[] args)
{
HttpListener server = new HttpListener();
server.Prefixes.Add("http://localhost:8000/");
server.Start();
while (true)
{
HttpListenerContext context = server.GetContext();
var task = IsFromSquare(context.Request);
task.Wait();
bool isFromSquare = task.Result;
using (HttpListenerResponse response = context.Response)
{
if (isFromSquare)
{
// Signature is valid. Return 200 OK.
response.StatusCode = 200;
}
else
{
// Signature is invalid. Return 403 Forbidden.
response.StatusCode = 403;
}
}
}
}
}
}
Link to section
Go
The following example uses the Go SDK. For installation instructions, see Square Go SDK Quickstart.
Copy
Expand
// server.go
package main
import (
"context""fmt""io/ioutil""net/http""os""github.com/square/square-go-sdk"
squareclient "github.com/square/square-go-sdk/client"
)
// The URL where event notifications are sent.
// The signature key defined for the subscription.
const (
NOTIFICATION_URL = "https://example.com/webhook"
SIGNATURE_KEY = "asdf1234"
)
// Generate a signature from the notification url, signature key,
// and request body and compare it to the Square signature header.
func isFromSquare(signature string, body []byte) bool {
client := squareclient.NewClient()
err := client.Webhooks.VerifySignature(
context.TODO(),
&square.VerifySignatureRequest{
RequestBody: string(body),
SignatureHeader: signature,
SignatureKey: SIGNATURE_KEY,
NotificationURL: NOTIFICATION_URL,
},
);
return err == nil
}
func requestHandler(w http.ResponseWriter, r *http.Request) {
signature := r.Header.Get("X-Square-HmacSha256-Signature")
body, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, "Failed to read request body", http.StatusInternalServerError)
return
}
if isFromSquare(signature, body) {
// Signature is valid. Return 200 OK.
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "Request body: %s\n", body)
} else {
// Signature is invalid. Return 403 Forbidden.
w.WriteHeader(http.StatusForbidden)
fmt.Fprintln(w, "Invalid signature")
}
}
// Start a simple server forlocal testing.
// Different frameworks may provide the raw request body in other ways.
// INSTRUCTIONS
// After initializing a new Go module and installing the SDK:
// 1. Run the server:
// go run server.go
// 2. Send the following request from a separate terminal:
// curl -vX POST localhost:8000 -d '{"hello":"world"}' -H "X-Square-HmacSha256-Signature: 2kRE5qRU2tR+tBGlDwMEw2avJ7QM4ikPYD/PJ3bd9Og="
func main() {
http.HandleFunc("/", requestHandler)
port := "8000"
fmt.Printf("Server is listening on port %s\n", port)
if err := http.ListenAndServe(":"+port, nil); err != nil {
fmt.Fprintf(os.Stderr, "Failed to start server: %v\n", err)
os.Exit(1)
}
}
// Server.javapackage com.square.examples;
import com.squareup.square.utilities.WebhooksHelper;
import com.sun.net.httpserver.HttpServer;
import java.net.InetSocketAddress;
import java.util.logging.Level;
import java.util.logging.Logger;
publicclassServer {
// The URL where event notifications are sent.privatestaticfinalStringNOTIFICATION_URL="https://example.com/webhook";
// The signature key defined for the subscription.privatestaticfinalStringSIGNATURE_KEY="asdf1234";
// Start a simple server for local testing.// Different frameworks may provide the raw request body in other ways.// INSTRUCTIONS// After installing the SDK:// 1. Run the server:// See the setup steps below.// 2. Send the following request from a separate terminal:// curl -vX POST localhost:8000 -d '{"hello":"world"}' -H "X-Square-HmacSha256-Signature: 2kRE5qRU2tR+tBGlDwMEw2avJ7QM4ikPYD/PJ3bd9Og="publicstaticvoidmain(String[] args) {
try {
HttpServerserver= HttpServer.create(newInetSocketAddress(8000), 0);
server.createContext("/", httpExchange -> {
varsigHeaders= httpExchange.getRequestHeaders().get("x-square-hmacsha256-signature");
varrequestBody=newString(httpExchange.getRequestBody().readAllBytes());
booleanisFromSquare=false;
if (sigHeaders.size() == 1) {
Stringsignature= sigHeaders.get(0);
// Generate a signature from the notification url, signature key,// and request body and compare it to the Square signature header.
isFromSquare = WebhooksHelper.verifySignature(requestBody, signature, SIGNATURE_KEY, NOTIFICATION_URL);
}
if (isFromSquare) {
// Signature is valid. Return 200 OK.
httpExchange.sendResponseHeaders(200, 0);
Logger.getLogger(Server.class.getName()).log(Level.INFO, "Request body: " + requestBody);
} else {
// Signature is invalid. Return 403 Forbidden.
httpExchange.sendResponseHeaders(403, 0);
Logger.getLogger(Server.class.getName()).log(Level.INFO, "Invalid signature");
}
httpExchange.getResponseBody().close();
});
server.start();
} catch (Throwable tr) {
tr.printStackTrace();
}
}
}
After the server starts, send the test cURL command from a separate terminal.
Copy
curl -vX POST localhost:8000 -d '{"hello":"world"}' -H "X-Square-HmacSha256-Signature: 2kRE5qRU2tR+tBGlDwMEw2avJ7QM4ikPYD/PJ3bd9Og="
Link to section
PHP
The following examples use the PHP SDK. For installation instructions, see Square PHP SDK Quickstart.
Copy
Expand
<?php// server.phprequire'vendor/autoload.php';
useSquare\Utils\WebhooksHelper;
// The URL where event notifications are sent.define("NOTIFICATION_URL", "https://example.com/webhook");
// The signature key defined for the subscription.define("SIGNATURE_KEY", "asdf1234");
// Start a simple server for local testing.// Different frameworks may provide the raw request body in other ways.// INSTRUCTIONS// After installing the SDK:// 1. Run the server:// php -S localhost:8000 server.php// 2. Send the following request from a separate terminal:// curl -vX POST localhost:8000 -d '{"hello":"world"}' -H "X-Square-HmacSha256-Signature: 2kRE5qRU2tR+tBGlDwMEw2avJ7QM4ikPYD/PJ3bd9Og="$headers = apache_request_headers();
$signature = $headers["X-Square-HmacSha256-Signature"];
$body = '';
$handle = fopen('php://input', 'r');
while(!feof($handle)) {
$body .= fread($handle, 1024);
}
// Generate a signature from the notification url, signature key,// and request body and compare it to the Square signature header.if (WebhooksHelper::verifySignature($body, $signature, SIGNATURE_KEY, NOTIFICATION_URL)) {
// Signature is valid. Return 200 OK.http_response_code(200);
echo"Request body: $body\n";
} else {
// Signature is invalid. Return 403 Forbidden.http_response_code(403);
echo"Invalid signature\n";
}
returnhttp_response_code();
?>
# server.rb
require 'base64'
require 'openssl'
require 'sinatra'
require 'square'# The URL where event notifications are sent.
NOTIFICATION_URL = "https://example.com/webhook"# The signature key defined for the subscription.
SIGNATURE_KEY = "asdf1234"# Generate a signature from the notification url, signature key,# and request body and compare it to the Square signature header.
def is_from_square(signature, body)
return Square::WebhooksHelper.is_valid_webhook_event_signature(body, signature, SIGNATURE_KEY, NOTIFICATION_URL)
end
# Start a simple server for local testing.# Different frameworks may provide the raw request body in other ways.# INSTRUCTIONS# After installing the SDK:# 1. Run the server:# (You may need to `gem install sinatra` first.)# ruby server.rb# 2. Send the following request from a separate terminal:# curl -vX POST localhost:8000 -d '{"hello":"world"}' -H "X-Square-HmacSha256-Signature: 2kRE5qRU2tR+tBGlDwMEw2avJ7QM4ikPYD/PJ3bd9Og="set :port, 8000
post '/'do
signature = request.env['HTTP_X_SQUARE_HMACSHA256_SIGNATURE']
body = request.body.read
if is_from_square(signature, body)
# Signature is valid. Return 200 OK.
status 200
puts "Request body: %s" % body
else# Signature invalid valid. Return 403 Forbidden.
status 403
end
end
When you interact with our mobile applications or online services, we obtain certain information by using automated technologies, such as cookies, web beacons, and other technologies described in our Cookie Policy. This information might be about you, your preferences, or your device. You may opt out of certain categories of cookies, other than those that are strictly necessary to provide you with our Services. Expand the different categories for more information and to make your choices.
To effectuate your right to opt-out of the sharing of your personal information for purposes of targeted advertising, please toggle off "retargeting or advertising technology" cookies below.
More informationPrivacy Notice
Manage cookie preferences
Strictly necessary technology
Always Active
These technologies are necessary for us to provide you with the Services.
Performance and analytical technology
Always Active
This information is used to make sure our Services can cope with the volume of users, to help us correct errors in the Services and to measure use across our Services. These technologies help us understand if you have used our Services before so we can identify the number of unique users we receive. They also help us understand how long you spend using our Services and from where you have accessed the Services, so that we can improve the Services and learn about the most popular aspects of the Services.
Functionality technology
Always Active
These technologies enable us to remember you have used our Services before, preferences you may have indicated, and information you have provided to us to give you a customized experience. For example, this would include ensuring the continuity of your registration process.
Retargeting or advertising technology
Always Active
We use third parties, for example, Google Analytics, to analyze statistical information from users of the Site. We might be able to associate such information with other information which we collect from you once we receive it from a third party. For example, these technologies may collect information about whether you clicked an ad to download our application.