# Guide to eBay Webhooks: Features and Best Practices

eBay notifications (eBay's webhooks) notify your application about account and authorization events: a user requests marketplace account deletion, an authorization is revoked. If you sell or build on eBay, handling these correctly, especially Marketplace Account Deletion, is a compliance requirement, not just a nice-to-have.

This guide covers how eBay notifications work, the mandatory endpoint challenge, how to verify the ECDSA message signature, and the best practices for production.

## What are eBay webhooks?

eBay's Notification API delivers HTTP POSTs to a destination endpoint you register, each signed with an ECDSA message signature. Before eBay sends any notifications, it validates your endpoint with a challenge it expects you to answer with a specific hash. Then every notification carries an `x-ebay-signature` you verify using a public key fetched from eBay by key ID.

## eBay webhook features

| Feature | Details |
| --- | --- |
| Configuration | Developer portal (Application Keys > Alerts and Notifications) or the Notification API |
| Endpoint challenge | GET with `challenge_code`; return SHA-256 of `challengeCode + verificationToken + endpoint` |
| Signature header | `x-ebay-signature` (base64 JSON: `alg`, `kid`, `signature`, `digest`) |
| Signature scheme | ECDSA over the raw body; public key via `getPublicKey` by `kid` |
| Public key | `GET /commerce/notification/v1/public_key/{public_key_id}` (cache ~1 hour) |
| Acknowledgement | 2xx within 24h or the app keyset can be disabled |
| SDK | `event-notification-nodejs-sdk` (official Node listener) |

## Common topics

eBay notification topics use uppercase IDs. The two you're most likely to handle:

| Topic | Fires when |
| --- | --- |
| `MARKETPLACE_ACCOUNT_DELETION` | A user requests account/data deletion (compliance-mandated to handle) |
| `AUTHORIZATION_REVOCATION` | A user revokes your app's authorization |

eBay has additional topics; validate exact uppercase `topicId` strings against a live `getTopics` call before building a larger event table, since names beyond these two vary.

## Setting up eBay webhooks

Configure notifications in the developer portal under Application Keys > Alerts and Notifications (for Marketplace Account Deletion), and for other topics via the Notification API (topics + destinations + subscriptions). Creating a destination triggers the endpoint challenge below.

## Securing eBay webhooks

### The endpoint-creation challenge

When you create a destination, eBay sends a `GET https://<endpoint>?challenge_code=...`. You must return HTTP 200 with JSON `{"challengeResponse":"<hex>"}`, where the hex is the SHA-256 hash of exactly `challengeCode + verificationToken + endpoint`, in that order. The `verificationToken` is a 32-80 character string you choose (`[A-Za-z0-9_-]`). The concatenation order is mandatory; get it wrong and the endpoint won't validate.

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

const VERIFICATION_TOKEN = process.env.EBAY_VERIFICATION_TOKEN; // 32-80 chars
const ENDPOINT = "https://your-app.example.com/webhook"; // exactly as registered

app.get("/webhook", (req, res) => {
  const challengeCode = req.query.challenge_code;
  const hash = crypto.createHash("sha256");
  hash.update(challengeCode);        // 1. challengeCode
  hash.update(VERIFICATION_TOKEN);   // 2. verificationToken
  hash.update(ENDPOINT);             // 3. endpoint  (order is mandatory)
  res.status(200).json({ challengeResponse: hash.digest("hex") });
});

```

### Verifying the ECDSA message signature

Each notification carries an `x-ebay-signature` header: a base64-encoded JSON object with `alg`, `kid`, `signature`, and `digest`. Use the `kid` to fetch the matching public key via the Notification API's `getPublicKey` (`GET /commerce/notification/v1/public_key/{public_key_id}`), then verify the signature over the raw request body. Cache the public key (~1 hour). Because this is fiddly ECDSA, prefer eBay's official Node listener SDK, `event-notification-nodejs-sdk`, which handles the signature verification and public-key caching (keyed by `kid`) for you:

```javascript
// Using event-notification-nodejs-sdk (recommended)
const { validateSignature } = require("ebay-event-notification-sdk"); // per SDK docs

app.post("/webhook", express.raw({ type: "application/json" }), async (req, res) => {
  const isValid = await validateSignature(
    req.body,                       // raw body
    req.headers["x-ebay-signature"],
    { /* app credentials / config per the SDK */ }
  );
  if (!isValid) return res.sendStatus(412); // eBay expects rejection on bad signature

  res.sendStatus(200); // 2xx acknowledges
  processQueue.add(JSON.parse(req.body)); // process asynchronously
});

```

If you verify manually, base64-decode `x-ebay-signature` to read `alg`/`kid`/`signature`, fetch and cache the public key by `kid`, and verify the ECDSA signature over the raw body.

## eBay webhook limitations and pain points

### The challenge-hash order is strict

The Problem: The endpoint challenge hashes `challengeCode + verificationToken + endpoint` in exactly that order. Any other order (or a mismatched `endpoint` string) fails validation and the destination won't be created.

Why It Happens: eBay defines a precise concatenation to prove you hold the verification token and control the endpoint.

Workarounds:

* Hash the three values in the mandated order, and use the exact registered `endpoint` string.

How Hookdeck Can Help: Hookdeck can answer the eBay challenge and verify signatures at the edge, so your application receives pre-verified events without reproducing the hash contract.

### ECDSA with a fetched public key

The Problem: Signature verification is asymmetric: decode the header JSON, fetch a public key by `kid`, and verify ECDSA over the raw body. It's easy to get the encoding or caching wrong.

Why It Happens: eBay uses ECDSA message signatures with ID-referenced public keys.

Workarounds:

* Use the official `event-notification-nodejs-sdk`, which handles verification and caching.

How Hookdeck Can Help: Hookdeck verifies the ECDSA signature at the edge, so your app receives pre-verified events without embedding the crypto.

### Account deletion is compliance-critical

The Problem: `MARKETPLACE_ACCOUNT_DELETION` must be handled, and failing to acknowledge notifications (2xx within 24h) can get your app keyset disabled, breaking your entire integration.

Why It Happens: eBay mandates deletion handling and enforces it via keyset status.

Workarounds:

* Ensure the endpoint reliably returns 2xx and actually processes deletions.
* Monitor keyset health and alert on delivery failures.

How Hookdeck Can Help: Hookdeck reliably accepts and acknowledges eBay's notifications and durably queues them, so a downstream hiccup doesn't cascade into a disabled keyset. Its observability surfaces failures fast.

### Duplicates and topic naming

The Problem: The same notification can arrive more than once, and topic IDs beyond the core two vary, so a hardcoded topic list can miss events.

Why It Happens: At-least-once delivery plus an evolving topic catalog.

Workarounds:

* Dedupe on the notification ID, and validate topic strings against `getTopics`.

How Hookdeck Can Help: Hookdeck deduplicates deliveries at the edge, so retries don't double-process. See our [guide to webhook idempotency](/webhooks/guides/implement-webhook-idempotency).

## Best practices

### Answer the challenge in the exact order

Hash `challengeCode + verificationToken + endpoint` (that order), return `{"challengeResponse":"<hex>"}` with a 200, and use the exact registered endpoint string.

### Verify the ECDSA signature via the SDK

Use `event-notification-nodejs-sdk` to verify `x-ebay-signature` over the raw body and cache the public key by `kid`.

### Acknowledge within the window, process asynchronously

Return 2xx (well within 24h, ideally immediately) and defer work to a queue so keyset health is never at risk. See [why to process webhooks asynchronously](/webhooks/guides/why-implement-asynchronous-processing-webhooks).

### Handle account deletion reliably and dedupe

Treat `MARKETPLACE_ACCOUNT_DELETION` as compliance-critical, dedupe on the notification ID, and validate topics against `getTopics`.

## Conclusion

eBay notifications require two things most webhooks don't: a precise endpoint challenge (SHA-256 of `challengeCode + verificationToken + endpoint`, in that exact order) and ECDSA signature verification using a public key fetched by `kid`. On top of that, Marketplace Account Deletion is compliance-critical and failing to acknowledge can disable your keyset.

[Hookdeck](https://hookdeck.com) answers the challenge, verifies the ECDSA signature, deduplicates, and durably queues every notification at the edge, so your app reliably processes verified, unique events and never risks its keyset over a downstream hiccup.

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