CommerceHook

Changelog

v2026.09.17

Everything that shipped, newest first. Versions are dated rather than numbered: CommerceHook deploys continuously, so the only thing a version can honestly tell you is when. Subscribe to the Atom feed .

2026.09.17

17 September 2026
Fixed MCP

Connecting an MCP client works now

Connecting CommerceHook to Claude, Cursor or any other MCP client failed at the point where you approve access. You were sent to sign in, signed in fine, and landed back on a page asking you to sign in again. Try a few times and the emails stopped arriving too, because sign-in links are capped at five in fifteen minutes.

The cause was our session cookie. It was set to SameSite=Strict, which tells your browser never to send it when you arrive from another site. Approving an app means arriving from another site, every single time, so the consent page never saw that you were already signed in. Nothing else in the product asks you to come back from somewhere else, which is why this sat unnoticed.

The cookie is now SameSite=Lax. That changes exactly one thing: your browser sends it when you follow a link to us. It still refuses to send it on anything that changes your data from another site, which is the part that was ever doing the work.

We would rather that protection did not rest on a cookie setting at all, so now it does not. A request that changes something and relies on your session is checked against where it came from and refused if that is not us. API keys are unaffected, because a key is only ever sent on purpose.

If you hit the sign-in limit while trying, it clears after fifteen minutes. A passkey skips the wait.

Fixed Sign-in

Sign-in links survive corporate email scanners

If your email goes through Microsoft Defender, Mimecast, Proofpoint or anything like them, your sign-in link was probably dead before you clicked it. Those systems open every link in a message to check it is safe. Ours signed you in the moment it was opened, so the scanner used your link and you arrived to be told it had expired, seconds after asking for it.

It was worse than it sounds. Even the lightest possible check, one that asks for a page’s headers without loading it, was enough to spend the link.

Sign-in links now open a page with a button on it. Opening the page does nothing; pressing the button signs you in. A scanner will follow a link, but it will not press a button, so the link is still yours when you get to it. Team invites work the same way, and for the same reason: a scanner was able to accept an invitation on someone’s behalf.

That is one extra click, and we would rather not have added it. The alternatives do not survive contact with how these scanners actually work. Letting a link work a few times does not help when the scan happens at delivery and you read the email an hour later. Hiding the token from the server does not help either, because the scan runs a real browser and will run the page’s code. A person pressing a button is the part no scanner imitates.

Passkeys skip all of this, since nothing is emailed. Settings, then Passkeys, once you are in.

Fixed Dashboard

The dashboard fits on a phone again

Every page in the dashboard scrolled sideways on a phone. The header was the cause. Brand, four nav links, the theme toggle, your plan badge and your email address were all held on one row that was never allowed to wrap, which came to 506 pixels of content in a 375 pixel screen. Help ran off the right edge, the account controls were off-screen entirely, and the whole page drifted sideways as you scrolled it.

The header now wraps on narrow screens. Brand and account controls stay on the top row, the nav sits on its own row underneath. Wide screens are unchanged.

Signing out was impossible on a phone, which is the part worth apologising for. Sign out lives in the menu behind your email address, and that whole menu was hidden on small screens, so there was no way to end a session without finding a laptop. The menu is there now, behind your initial rather than the full address.

Registering webhooks was in the same state, and worse: that panel’s header came to 741 pixels, so the close control sat off the edge of the screen. You could open the panel and then not shut it. It wraps now, the platform tabs scroll sideways on their own, and the close button sits next to the title where you can always reach it.

Content also stopped hiding in the middle of the screen. Cards were inset by the page margin and drew a rounded border inside that, so text began 33 pixels in from each edge and roughly a fifth of a phone screen went on framing. On narrow screens cards now run edge to edge and keep only the horizontal rules between sections.

Two smaller things while we were in there. Opening an event gave you a payload panel and a metadata panel that each scrolled inside a page that also scrolled, so a thumb swipe often moved the wrong one; those separate scrolling areas are now confined to wide screens, where the two sit side by side. And the seam between Headers and Metadata was drawing two one-pixel rules on top of each other, which looked like a double line because it was one.

2026.08.28

28 August 2026
Improved MCP

Your agent now knows which tools can destroy something

The MCP server’s tools now say what they do before they do it, using the standard hints an MCP client can read: whether a tool only reads, whether it can destroy something, and whether it reaches outside CommerceHook.

Two matter in practice. delete_endpoint is marked destructive, so clients that pause before destructive calls will now pause before that one, rather than relying on the description asking nicely. And replay_event is marked open-world, because it fires a request at a URL you supply and whatever your handler does next is outside our reach.

Every tool also carries a proper title now, so they read as names rather than function calls in whichever client you use.

2026.08.27

27 August 2026
New Dashboard

Stripe webhooks, next to the order they paid for

Stripe is now a first-class platform alongside BigCommerce, WooCommerce, Square and Shopify. Paste a Stripe API key in the register panel, tick events across payments, checkout, subscriptions, invoices, refunds and disputes, and we create the webhook endpoint for you. Stripe hands back the signing secret at creation, so every delivery shows a verified tick or a clear cross from the very first one, secret rolls included.

Stripe’s own tooling is the best of any platform we support, so this sits alongside it rather than against it. What it adds is the part Workbench cannot see: your storefront’s orders/create and Stripe’s payment_intent.succeeded for the same basket, interleaved in one timeline, kept for 90 days on Pro where the Dashboard’s resend reaches 15 days and the CLI’s 30.

Two smaller things worth knowing. Stripe is the first platform where a key can be cut down to exactly this job, so the panel steers you to a restricted key with write access to Webhook Endpoints rather than quietly taking your secret key. And every delivery says whether it is test or live money, so deep links land in the matching Dashboard instead of a live page insisting the payment does not exist.

Already registered in the Stripe Dashboard by hand? Paste that endpoint’s signing secret and verification works identically.

Fixed Dashboard

The Stripe restricted-key instructions were wrong

If you set up Stripe today and followed our instructions to the letter, registration refused your key. Sorry. We told you to create a restricted key with Webhook Endpoints: write and Account: read, and there is no “Account” row on Stripe’s key-creation page to tick.

The permission you need is real, it is just filed somewhere unexpected: Connect → Accounts: read. That name reads as though it concerns other people’s accounts under a platform, which is why we missed it, but it is what lets a key read the account it belongs to, and it is the only row on that page that grants it. Tick it even if you have never touched Connect.

So the minimum key is those two rows and nothing else. The docs now say so, the register panel says so, and the error you get when the key is missing that permission now names the row you are looking for instead of sending you hunting for one that does not exist.

2026.08.26

26 August 2026
New Dashboard

Adobe I/O deliveries badge as Magento

Deliveries arriving through Adobe I/O Events, the delivery route for Adobe Commerce and Magento, are now recognised: the timeline badges them as Magento and shows the event code (com.adobe.commerce.observer.sales_order_save_after and friends) as the event type, the way BigCommerce scopes and Shopify topics already appear.

Detection keys on the signature headers Adobe documents, so it works whichever event provider fires. Full Magento registration support is still on the way; this covers anyone already pointing Adobe I/O at an endpoint.

New Ingestion

Adobe I/O's webhook check now passes

Adobe I/O Events validates a webhook URL before it will register one: a GET carrying a challenge parameter that expects the value echoed straight back. Endpoints now answer that probe, so registering a CommerceHook URL with Adobe I/O (the delivery route for Adobe Commerce) passes validation first time instead of falling back to Adobe’s manual dance.

The probe is answered, not stored: it is Adobe checking the URL, not a delivery, so it never shows up in your timeline. Every other GET captures exactly as before.

Improved CLI

CLI 0.4.0: listen goes live

commercehook listen and events --tail now ride the same live stream the dashboard uses, so a delivery forwards to your handler the moment it arrives rather than on the next poll. The old polling loop stays underneath as the safety net: if the socket drops, the CLI says so on stderr and polls every few seconds until the stream returns, and the at-least-once forwarding contract is unchanged either way.

Needs a Node with a built-in WebSocket (22 or newer); older Nodes keep polling exactly as before. Update with commercehook upgrade, whichever way you installed.

New Dashboard

Compare two deliveries side by side

Open an event and the inspector now offers a compare view: pick any other delivery on the endpoint and read a line-by-line diff of the headers and the payload, older on the left. The usual question, “what changed since the previous delivery of this type”, has a one-click shortcut; every other row in the timeline grows a ⇄ for the rest.

Payloads are compared as JSON, so a platform reordering its keys reads as no change, while a retry that re-signs the delivery shows precisely which headers moved. Long unchanged stretches fold away behind a count, and the comparison lives in the URL, so a diff worth staring at is one you can send to a colleague. If the older delivery has already left its retention window, the view says so plainly rather than showing half a diff.

New Dashboard

Copy a delivery as code, export an endpoint as a file

Every event in the inspector now has a Copy as code section: curl, fetch, and Python snippets that reproduce the delivery against your own handler. Method, platform headers, and the body byte for byte, which matters because a signature only verifies against the exact bytes. Replay sends the delivery for you; these hand it to you, for a test suite or a bug report.

Endpoints export too. Under the event list you can download the whole timeline, or just what the current search matches, as JSON or as a HAR capture that opens straight in your browser’s devtools. The same export is on the REST API at GET /api/endpoints/{id}/export (streamed, so a full 90 days of Pro retention downloads without a timeout) and as the export_events MCP tool, so an agent can pull an endpoint’s history in one call.

New Dashboard

Events appear the moment they arrive

The timeline used to check for new events every five seconds. It now holds a live connection, and a delivery shows up the instant it lands, whether the tab is focused or not. The dot in the header tells you which is happening: solid means live, softer means the connection is re-establishing and the five-second check is covering the gap, so nothing is ever missed either way.

Under the hood each endpoint gets its own switchboard that sleeps between deliveries, and a connection re-proves its access every hour. Nothing about your endpoints or webhook URLs changes.

New Dashboard

Register Shopify webhooks from the dashboard

Shopify joins BigCommerce, WooCommerce and Square as a first-class platform. Hand over your custom app’s details, tick the topics you care about, and CommerceHook creates one subscription per topic over the GraphQL Admin API. Save the app’s API secret key with the store and every delivery is checked against Shopify’s signature, so a payload that does not match shows a clear cross instead of slipping through.

The timing matters more on Shopify than anywhere else: a failed delivery is retried eight times over four hours and then the subscription is silently deleted. An endpoint that always answers in milliseconds never gives it the reason, and everything that arrives is kept, linked straight to the order, product or customer in your admin.

2026.08.12

12 August 2026
New CLI

CLI 0.3.0: the signature verdict reaches your terminal

commercehook event <id> now prints the same signature verdict the dashboard shows: a tick when the delivery’s body verifies against the secret registered through CommerceHook, MISMATCH when it does not, and nothing when there is nothing to check. Update with commercehook upgrade, whichever way you installed.

Fixed Dashboard

Connected apps stop hiding between refreshes

The Connected apps section in settings only believed an app was connected while it held an unexpired access token. An idle connector, one whose token had lapsed and had not refreshed yet, disappeared from the list, so settings could claim “nothing is connected” about a Claude connector you had used that same day. Connections are now recognised by the grant itself, so the list matches reality: connected until you revoke it.

New Dashboard

Register Square webhooks from the dashboard

Square is now a first-class platform next to BigCommerce and WooCommerce. Save a Square access token, pick the events you care about and whether you are on sandbox or production, and CommerceHook creates the subscription for you and holds on to its signing key. Every delivery that lands is labelled by event type and checked against that key, so a payload whose signature does not match shows a clear cross instead of slipping through unnoticed.

Square is a little different from the others: it sends events from all of your connected sellers to a single URL, and keeps sandbox and production apart. The timeline tells you which merchant each delivery came from and which environment it was, and where Square has a page for the record behind an event, the inspector links you straight to it.

New Dashboard

The dashboard follows your colour scheme too

Light mode reached the dashboard, a day behind the site. It follows your browser’s preference, and the sun-and-moon button in the header overrides it; the choice is remembered per device, separately from the site’s. Everything the inspector shows, from the JSON tree’s syntax tints to the platform badges, holds the same contrast bar in both schemes. If you never leave dark mode, nothing has changed.

New Site

The site follows your colour scheme

commercehook.app now has a light mode. It follows your browser’s preference by default, and the sun-and-moon button in the header overrides it whenever you disagree; the choice is remembered on your device. The dashboard is still dark only, and gets the same treatment next.

Both schemes are held to the same accessibility bar: our CI audits every page in each one, so neither can silently regress.

2026.08.11

11 August 2026
New CLI

A CLI, on npm

CommerceHook now has a command line: npx commercehook (or install it globally) gives you commercehook version today, with sign-in, tail, inspect and replay on the way. It is 7 kB with zero dependencies, every command takes --json for scripting, and it checks once a day whether a newer release exists and says so without getting in your way.

The CLI has its own version numbers (0.1.0 as of this entry), because installed software and a deployed service age differently.

New Site

A way to reach us that is not a mailto link

There is a form at /contact for bugs, questions and “why does it not do X”. Signed-in users get the same thing on a Help page in the dashboard, which attaches your plan, endpoint count and the version you are running, so a reply does not have to start by asking.

Messages are written down before they are emailed, so nothing is lost if our mail provider is having a bad afternoon, and the address you give is used to reply and nothing else. No marketing, ever.

New CLI

commercehook listen, webhooks on your laptop

commercehook listen <endpoint> --forward-to http://localhost:3000/webhooks streams every delivery into the handler on your machine: original method, platform headers and raw body, with the event id in x-commercehook-replay and x-commercehook-forwarded: 1 so a handler can tell live traffic from a manual replay. Register the CommerceHook URL with your platform once and develop locally ever after. It fills the ngrok role in the webhook loop, except every delivery is also captured and inspectable afterwards, which a tunnel never gave anybody.

A non-2xx from your handler is reported and the stream continues, because your handler erroring mid-edit is the loop doing its job. --since 15m and --replay-last 5 start with history; Ctrl-C prints what was forwarded and where to resume. Delivery is at-least-once with a lag of a few seconds (it polls, as the dashboard does), so deduplicate by event id if your handler cares.

Fixed Sign-in

Deleting your account disconnects your apps

Connected apps (a Claude connector, for instance) kept working until their tokens expired after an account was deleted. Deletion now revokes every grant in the same request, so a connected app stops on its next call, and an hourly sweep clears anything orphaned. Deleted means deleted, including the credentials you had forgotten about.

Improved REST API

Events carry their query string

GET /api/events/:id now returns query (the raw string, encoding and ordering intact) and params (the same thing as [name, value] pairs). Pairs rather than an object, because a name may legally repeat and an object would silently drop half of it. The MCP get_event tool inherits both.

Improved Dashboard

Fold away the parts of an event you are not reading

Every section of the inspector (payload, query params, headers, metadata, replay) collapses when you click its heading, and stays that way as you click through the timeline. Comparing headers across ten deliveries no longer means scrolling past ten payloads.

Improved Dashboard

Headers and query params, readable and copyable

Headers used to sit at the bottom of the narrow right-hand column, which on a laptop-height window meant scrolling past the metadata, the BigCommerce panel and replay to reach a squeezed box where application/json wrapped in the middle. They have moved under the payload, in the wide column, where they belong: they are what the platform sent, the same as the body.

Every value is now one click to select and one click to copy, with a copy-the-lot button per section that gives you JSON. Query params get the same treatment.

Improved CLI

Install the CLI without Node

Prefer not to have Node in the loop? Each CLI release now ships standalone binaries for macOS, Linux and Windows, and brew install commercehook/tap/commercehook works. Run commercehook upgrade to see how to update whichever way you installed.

New REST API

OAuth tokens now work on the whole REST API

An OAuth access token used to work only on the MCP endpoint; the rest of the API wanted an API key or a browser session. Now any endpoint that takes Authorization: Bearer chk_... takes an OAuth token too, with the same 120-requests-a-minute budget, counted per grant.

This makes a connected app and an API key the same kind of thing: both can drive the full API, both are visible in your settings, and disconnecting an app under Connected apps cuts off its API access on the next call. API keys and their behaviour are completely unchanged.

New Dashboard

Query params in the inspector

Some platforms put meaning in the URL rather than the body: a shop domain, a topic, a channel id, occasionally a signature. The inspector showed every header and threw the query away, so a delivery could arrive with half its information invisible.

Deliveries now record the query string exactly as sent, and the inspector lists it above Headers. A repeated key such as ?id=1&id=2 shows both values, because that is what arrived. Events captured before this show no params: we cannot invent what was never stored.

New Dashboard

Register WooCommerce webhooks from the dashboard

The register panel’s platform picker now has a second real choice. Pick WooCommerce, choose from the twelve core topics (or add any action.* WordPress hook), and either copy a ready-made command or hand us the store URL and API key pair to create the webhooks for you. Key pairs can be saved for next time, encrypted, with the secret never shown again; each save is checked against the live store first, so a typo fails now rather than later.

Two WooCommerce quirks are handled where they would otherwise confuse: the panel warns about the ping delivery WooCommerce sends the moment a webhook is created, and there is a field for the signing secret WooCommerce uses to HMAC every delivery, so the handler you replay to can verify signatures. Deliveries themselves have been detected and inspectable all along; this closes the register-and-verify loop.

New Dashboard

Replay and registration history, with names attached

Replaying an event and registering webhooks both did their job and then forgot it happened. On a team that forgetting has a cost: nobody could say whether the staging handler was already retried, or which scopes a colleague pointed at an endpoint last Tuesday.

Both actions are now remembered. The replay panel lists past attempts under the form: destination, status (or “unreachable” when the handler never answered), how long it took, when, and who ran it. The register panel does the same for previous “do it for me” runs, per scope, with the hook id BigCommerce assigned or the error it answered with. Commands you copy and run in your own terminal never touch us, so they do not appear.

Attribution survives account changes the way team activity already does: an email address follows its owner, and a deleted account shows as “a former member” rather than pretending nobody did it. Replay history also rides on GET /api/events/{id}, so the REST API and the MCP get_event tool return it too.

History lives with what it describes: replay attempts are kept as long as the event they replayed, registration records as long as the endpoint.

New CLI

Sign in to the CLI with your browser

commercehook login (CLI 0.2.0) opens your browser on the same consent screen any connected app gets; approve it and the terminal is signed in. No password typed into a prompt, no token pasted from a settings page. The CLI then appears under Connected apps in settings, where it can be disconnected like anything else. commercehook logout revokes that grant properly rather than just forgetting it locally, and commercehook whoami answers the question you ask right before doing anything important.

Sign-ins refresh themselves silently for 30 days of use; after that the CLI says plainly to log in again. For CI and machines with no browser, login --with-api-key stores an API key instead, or set CH_API_KEY and store nothing.

New Site

The CLI has a home: /cli and /docs/cli

The CLI now has a product page at /cli and a full reference at /docs/cli: install, browser sign-in, every command with an example, and a plainly-stated section on listen semantics (at-least-once, poll-bounded lag, dedupe by event id). The docs page is the canonical reference: commercehook --help points at it, so what you read there is current even when the binary on your machine is not. llms.txt and the authentication guide now describe the CLI too.

New CLI

The CLI learns endpoints, events, tail, inspect and replay

The CLI now does the actual work: endpoints lists (and creates, renames, deletes, with a confirmation that names what it is about to remove), events <endpoint> shows deliveries with search and pagination, event <id> is the inspector in your terminal, and replay <id> --to <url> re-sends a delivery at your handler.

The one to try is events <endpoint> --tail: one line per delivery as it arrives, updating live while you work on the handler next to it. With --json, every command emits the API response as-is, and tail becomes a stream of JSON lines, ready for jq.

Endpoints are referenced by name prefix as well as id, and an ambiguous prefix is an error listing the candidates, never a guess.

Improved REST API

The health check says which version is deployed

GET /api/health now includes a version field carrying the deployed release, so a monitor, a script or the forthcoming CLI can tell what it is talking to without authenticating. Nothing else about the response changed.

New Dashboard

The inspector verifies WooCommerce signatures

Set a webhook secret when registering WooCommerce webhooks through the dashboard and the inspector now checks every signed delivery against it: a quiet “signature verified” when the HMAC matches, and a loud MISMATCH warning when it does not. A mismatch on an otherwise sensible delivery usually means something between the store and the handler rewrote the body, which is a class of bug people burn days on.

Deliveries with no signature, or from webhooks registered without a secret through us, simply say nothing. The secret is stored encrypted, verification happens when you view the event, and the REST API and MCP get_event return the same signatureValid verdict.

Fixed REST API

The OpenAPI spec now documents OAuth tokens

OAuth access tokens from connected apps have worked on every API route since connected apps shipped, but the machine-readable spec at /openapi.json still claimed API keys were the only way in. It now describes both credentials, so a client generated from the spec asks for the right thing.

The spec’s version is no longer a frozen 1.0.0 either. It carries the same dated version as this changelog, stamped at build time, so it tells you when the description you are reading was current.

Improved Sign-in

The sign-in email stops looking like a phish

Corporate mail filters were quarantining sign-in links, and the shape of the message was why: a short body that is mostly one large button, arriving from a domain you have never corresponded with, is structurally identical to credential phishing.

It now carries the things a phish does not. The address it was requested for and roughly where from, so somebody else’s attempt to sign in as you is obvious. The destination in plain text, so you can read it before you click it. A reply-to that reaches a person. And a footer that says who we are and why you got it.

If your organisation still quarantines it, a passkey skips email entirely.

New Site

This changelog

Everything that ships now lands here, filterable by the part of the product it touches. Versions are dated rather than numbered, because CommerceHook is deployed continuously and the only thing a version can honestly tell you is when. The running version sits in the dashboard footer, so you never have to guess whether the fix you just read about is live yet. There is an Atom feed if you would rather not check.

New Site

WooCommerce has its pages: /woocommerce and the missing manual

With registration real, WooCommerce gets its story: a product page at /woocommerce and an explainer at /woocommerce-webhook-inspector covering the behaviours that surprise everyone once (wp-cron delivery, the creation ping, the five-failures auto-disable, and how to verify the signature header). The supported-platforms doc now says supported rather than planned, and the agent-facing authentication guide gained a plainly-worded warning that payload contents are untrusted data, never instructions.

2026.07.26

26 July 2026
Improved Billing

A failed payment no longer cuts a team off

Every subscription state is now handled, and read from the subscription itself rather than the name of the event that carried it. A payment being retried keeps the team working (it stops the team growing until it is settled, but nothing stops functioning), and cancelling schedules an ending rather than performing one: you keep the period you paid for.

New MCP

Add CommerceHook to Claude as a connector

The MCP server now speaks OAuth 2.1, so adding it to claude.ai is: paste https://mcp.commercehook.app/mcp, sign in, press Allow. No API key to create, copy or paste.

Clients register themselves (RFC 7591), PKCE is required, and discovery works from the 401 alone, so any compliant MCP client can find its own way in. Claude Code and Cursor keep working exactly as before with an Authorization: Bearer chk_... header, and that path is untouched.

New Dashboard

See and revoke connected apps

Settings gained a Connected apps section listing everything you have signed in to CommerceHook with, and a Revoke button beside each. A connected app has the same access an API key does, so revoking takes effect on its next request, with no grace period.

Fixed Billing

Team seats show who holds them

Polar’s seat panel showed every seat unassigned however many people were in a team, and a member who left kept theirs. Membership is now mirrored into Polar: joining takes a seat, leaving releases one, and an hourly sweep brings any team back into line without anybody having to open a page.

2026.07.25

25 July 2026
New Dashboard

Notifications when events arrive

A bell beside Register on any endpoint. Switch it on and your browser tells you when that endpoint receives something, even while you are in another tab; clicking the notification opens the endpoint. Off by default, remembered per endpoint, and capped at one alert a minute so a busy store cannot bury you.

New Teams

Shared BigCommerce credentials

A team can hold store credentials once instead of everybody pasting their own. Admins add and remove them; members can use them to register webhooks and run store API commands, but can never reveal or export the token itself.

New Sign-in

Sign in with a passkey

Add a passkey in settings and sign in with Touch ID, Windows Hello or a password manager, with no email round trip. Magic links still work and remain the way in on a new device.

New Teams

Teams

Endpoints, captured events and replay, shared with a whole team. Invite by email with a role (owner, admin or member), and every endpoint records who created it. Team endpoints keep their URL, so nothing has to be re-registered with the platform.

Seat pricing is graduated: $6 each up to five seats, $4 from six to fifteen, $3 beyond that, with a two-seat minimum. A seat includes Pro on that person’s own account.