IntegrationsIntegrations

How to Test Square Webhooks Locally

What Webhooks Does Square Send?

Square's webhook system notifies your application about events across their commerce platform. Key event types include payment.completed, payment.updated, order.created, order.updated, order.fulfillment.updated, inventory.count.updated, customer.created, customer.updated, catalog.version.updated, and refund.created.

Each webhook payload includes the event type, a merchant_id, event_id for deduplication, and a data object containing the relevant resource. Square also includes created_at timestamps and the object ID so you can fetch the full resource from the API if needed.

Square signs webhooks with an HMAC-SHA256 signature in the x-square-hmacsha256-signature header, computed using your webhook signature key and the notification URL plus the request body. This is important for verifying that requests genuinely come from Square.

Setting Up Square Webhooks

In the Square Developer Dashboard, go to your application and navigate to Webhooks. Click "Add" and enter your ReqPour URL as the notification URL, e.g., https://abc123.reqpour.com/square. Select the event types you want to receive.

Square provides a sandbox environment with test API credentials. Configure your webhook subscription to point to your ReqPour endpoint, then use the Square sandbox to create test payments and orders. Each event flows through ReqPour where you can inspect it.

Note the webhook signature key that Square provides — you will need this to verify webhook signatures. Store it in an environment variable. During development, you can use the ReqPour dashboard to see the signature header value and compare it with your computed hash.

Handling Square Webhooks

Here is a handler for Square webhook events:

javascript
const crypto = require('crypto');

const SQUARE_WEBHOOK_SIGNATURE_KEY = process.env.SQUARE_WEBHOOK_KEY; const NOTIFICATION_URL = 'https://abc123.reqpour.com/square';

app.post('/square', express.json(), (req, res) => { // Verify signature const signature = req.headers['x-square-hmacsha256-signature']; const body = JSON.stringify(req.body); const hmac = crypto .createHmac('sha256', SQUARE_WEBHOOK_SIGNATURE_KEY) .update(NOTIFICATION_URL + body) .digest('base64');

if (signature !== hmac) { return res.status(403).send('Invalid signature'); }

const { type, data } = req.body;

switch (type) { case 'payment.completed': console.log('Payment completed:', data.id); break; case 'order.updated': console.log('Order updated:', data.id); break; case 'inventory.count.updated': console.log('Inventory changed:', data.object.inventory_counts); break; }

res.status(200).send('OK'); }); ```

Note that Square's signature includes the notification URL concatenated with the body. During development, use your ReqPour URL as the notification URL in the HMAC computation.

Testing Square Payment Flows

Square's sandbox provides test card numbers for simulating different payment outcomes. Use these with the Square Web Payments SDK or Terminal API to trigger payment.completed and payment.updated events. The full payment object appears in the ReqPour dashboard where you can examine amounts, card details, and processing fees.

For order management, create orders via the Orders API in sandbox mode. Watch order.created events arrive, then update fulfillment status to trigger order.fulfillment.updated events. The ReqPour request inspector shows the nested order structure with line items, taxes, discounts, and fulfillment details.

Use ReqPour's relay to forward all these events to your local development server:

bash
npx reqpour relay --to http://localhost:4000/webhooks/square

The relay preserves the full request including headers, so signature verification works correctly on your local server.

Square Webhook Best Practices

Square has a 10-second timeout for webhook responses. Return a 200 status immediately and process events asynchronously. After 14 consecutive failures, Square disables the webhook subscription and you will need to re-enable it manually.

Use the event_id field for idempotency. Square guarantees at-least-once delivery, meaning you may receive the same event more than once. Store processed event IDs and skip duplicates. ReqPour's replay feature is perfect for testing this — replay the same event twice and verify your handler handles the duplicate gracefully.

Square webhooks include only the object ID, not always the full object. For events like catalog.version.updated, you may need to call the Square API to fetch the full catalog data. During development, compare the webhook payload (visible in ReqPour) with the API response to understand what data is and is not included in the webhook.

Get started with ReqPour

Catch, inspect, and relay webhooks to localhost. Free to start, $3/mo for Pro.