# Guide to Walmart Webhooks: Features and Best Practices

Walmart Marketplace webhooks notify sellers about store activity: a purchase order is created, an item goes out of stock, the buy box changes, a return is created. If you're building on Walmart Marketplace, webhooks are how you react to seller events without polling.

This guide covers how Walmart's two notification systems work, how inbound verification actually works (it's not the public-key scheme you might expect), and the best practices for production.

## What are Walmart webhooks?

Walmart Marketplace has two notification systems, and they verify differently:

1. General event notifications: you create a subscription with an `eventType`, `resourceName`, and `eventUrl`, and set an `authMethod` (`BASIC_AUTH`, `HMAC` with your client secret, or `OAUTH`). Walmart uses those credentials to authenticate itself to your endpoint; it does not sign the payload for you to verify with a public key.
2. Performance webhooks (`SELLER_PERFORMANCE_ALARMS`/`REPORT`): signed with an HMAC-SHA256 over a canonical string, delivered in `WM_SEC.*` headers.

Crucially, inbound verification is not the `SHA256WithRSA` public-key scheme (`WM_SEC.AUTH_SIGNATURE` / `WM_CONSUMER.*`). That scheme is how a seller signs outbound calls to Walmart, not how you verify inbound webhooks. Confirm which system your integration targets; this guide covers inbound verification.

## Walmart webhook features

| Feature | Details |
| --- | --- |
| Configuration | Webhooks Subscription API (`eventType` + `resourceName` + `eventUrl` + `authMethod`) |
| General-notification auth | `BASIC_AUTH`, `HMAC` (HMAC-SHA256 with client secret), or `OAUTH`, set by you |
| Performance-webhook signature | `WM_SEC.SIGNATURE` (base64 HMAC-SHA256), `WM_SEC.TIMESTAMP`, `WM_SEC.KEY_ID` |
| Canonical string | `METHOD\nPATH_AND_QUERY\nWM_SEC.TIMESTAMP\nSHA256_HEX(rawBody)` |
| Replay window | ~5 minutes (+2 min skew) |
| Deduplication | By delivery id, over 7 days |
| Acknowledgement | 2xx within 3 seconds |
| General retries | 5 min, then 15 min, then 45 min |
| SDK | None |

## Common events

Walmart event names are uppercase (verified from the Get Event Types API):

| Event | Fires when |
| --- | --- |
| `PO_CREATED` | A purchase order is created |
| `INVENTORY_OOS` | An item goes out of stock |
| `BUY_BOX_CHANGED` | The buy box changes for an item |
| `RETURN_CREATED` | A return is created |

Subscribe to the events you process, and consult Walmart's Get Event Types API for the full list.

## Setting up Walmart webhooks

Create a subscription via the Webhooks Subscription API with `eventType`, `resourceName`, `eventUrl`, and an `authMethod`. For general notifications, the `authMethod` is how Walmart proves itself to you, so choose one and configure your endpoint to check it. Respond 2xx within 3 seconds.

## Securing Walmart webhooks

### General event notifications: verify the credentials you set

For general notifications, Walmart authenticates using the `authMethod` you configured. If you set `BASIC_AUTH`, verify the `Authorization` credentials; if `HMAC`, verify the HMAC-SHA256 computed with your client secret; if `OAUTH`, validate the token. There's no separate payload signature to check.

### Performance webhooks: verify WM_SEC.SIGNATURE

Performance webhooks are signed. Build the canonical string `METHOD\nPATH_AND_QUERY\nWM_SEC.TIMESTAMP\nSHA256_HEX(rawBody)`, compute a base64 HMAC-SHA256 with your shared secret, and compare against the `WM_SEC.SIGNATURE` header. Verify against the raw body, enforce the ~5-minute replay window, and dedupe by delivery id.

```javascript
const crypto = require("crypto");

const SECRET = process.env.WALMART_WEBHOOK_SECRET;

function verifyPerformance(req, rawBody) {
  const timestamp = req.headers["wm_sec.timestamp"];
  // Reject stale deliveries (~5 min window, +2 min skew)
  if (Math.abs(Date.now() - Number(timestamp)) > 7 * 60 * 1000) return false;

  const bodyHash = crypto.createHash("sha256").update(rawBody).digest("hex");
  const canonical = [
    req.method,
    req.originalUrl, // path + query
    timestamp,
    bodyHash,
  ].join("\n");

  const expected = crypto
    .createHmac("sha256", SECRET)
    .update(canonical)
    .digest("base64");

  const a = Buffer.from(expected);
  const b = Buffer.from(req.headers["wm_sec.signature"] || "");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
  if (!verifyPerformance(req, req.body)) {
    return res.sendStatus(401);
  }

  res.sendStatus(200); // acknowledge within 3s
  processQueue.add(JSON.parse(req.body)); // process asynchronously
});

```

The same canonical-string HMAC in Python:

```python
import base64
import hashlib
import hmac
import os

SECRET = os.environ["WALMART_WEBHOOK_SECRET"].encode()

def verify_performance(method, path_and_query, timestamp, raw_body, signature):
    body_hash = hashlib.sha256(raw_body).hexdigest()
    canonical = "\n".join([method, path_and_query, timestamp, body_hash]).encode()
    expected = base64.b64encode(hmac.new(SECRET, canonical, hashlib.sha256).digest()).decode()
    return hmac.compare_digest(expected, signature or "")

```

## Walmart webhook limitations and pain points

### Two systems, and it's not the RSA scheme

The Problem: It's easy to reach for Walmart's `SHA256WithRSA` public-key signing, but that's for seller-to-Walmart outbound calls, not inbound verification. Inbound is either the credentials you set (general notifications) or the `WM_SEC.SIGNATURE` HMAC (performance webhooks).

Why It Happens: Walmart's docs cover both request-signing and webhook verification, and they're easy to conflate.

Workarounds:

* Confirm which system your integration targets, and verify with the credentials/HMAC path, not the RSA public-key path.

How Hookdeck Can Help: Hookdeck verifies the inbound scheme at the edge, so your application receives pre-verified events without you untangling Walmart's signing docs.

### The canonical string must be exact

The Problem: The performance-webhook signature is over `METHOD\nPATH_AND_QUERY\nTIMESTAMP\nSHA256_HEX(body)`. Any deviation (wrong path form, missing query, hashing a parsed body) fails verification.

Why It Happens: Walmart signs a canonical request representation, not just the body.

Workarounds:

* Reconstruct the canonical string exactly, hash the raw body, and compare in constant time.

How Hookdeck Can Help: Hookdeck handles the canonical-string verification at the edge, so your app doesn't reproduce it.

### Replay window and deduplication

The Problem: There's a ~5-minute replay window (+2 min skew), and Walmart expects you to dedupe by delivery id over 7 days. Skipping either leaves you open to replays or double-processing.

Why It Happens: Walmart binds a timestamp and expects idempotent handling.

Workarounds:

* Reject stale timestamps and dedupe on the delivery id for 7 days.

How Hookdeck Can Help: Hookdeck verifies freshness and deduplicates deliveries at the edge, so replays and retries don't reach your app. See our [guide to webhook idempotency](/webhooks/guides/implement-webhook-idempotency).

### The 3-second acknowledgement window

The Problem: You must return 2xx within 3 seconds, and general notifications retry only at 5/15/45 minutes. Slow processing risks the window and burns the small retry budget.

Why It Happens: Walmart caps the ack time and retries sparingly.

Workarounds:

* Verify, enqueue, and return 2xx immediately; process off a queue.

How Hookdeck Can Help: Hookdeck acknowledges Walmart within the window and durably queues events, decoupling the 3-second budget from your processing time.

## Best practices

### Verify the inbound scheme, not the RSA one

Check the `authMethod` credentials for general notifications, or the `WM_SEC.SIGNATURE` canonical-string HMAC for performance webhooks. Don't use the seller-outbound RSA scheme for inbound.

### Reconstruct the canonical string exactly and use the raw body

Build `METHOD\nPATH_AND_QUERY\nTIMESTAMP\nSHA256_HEX(rawBody)` precisely and compare in constant time.

### Enforce the replay window and dedupe

Reject stale timestamps and dedupe by delivery id over 7 days.

### Acknowledge within 3 seconds, process asynchronously

Return 2xx immediately and defer work to a queue. See [why to process webhooks asynchronously](/webhooks/guides/why-implement-asynchronous-processing-webhooks).

## Conclusion

Walmart Marketplace webhooks come in two systems: general notifications you authenticate with the credentials you set, and performance webhooks signed with a `WM_SEC.SIGNATURE` HMAC over a canonical `METHOD/PATH/TIMESTAMP/SHA256(body)` string. Neither is the RSA public-key scheme (that's seller-outbound). Verify the right one, reconstruct the canonical string exactly, enforce the replay window, dedupe, and acknowledge within 3 seconds.

[Hookdeck](https://hookdeck.com) verifies the inbound signature, deduplicates, and durably queues every event at the edge, so your app only ever processes verified, unique seller events.

[Get started with Hookdeck](https://dashboard.hookdeck.com/signup) for free and handle Walmart webhooks reliably in minutes.