Skip to content

fix(formstack): record live-capture findings and add real delivery test vectors - #197

Merged
garethx merged 2 commits into
hookdeck:mainfrom
garethx:fix/formstack-live-capture
Sep 25, 2026
Merged

garethx merged 2 commits into
hookdeck:mainfrom
garethx:fix/formstack-live-capture

Conversation

@garethx

@garethx garethx commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Two real Formstack Forms WebHook deliveries were captured through a Hookdeck source on 2026-09-25, and their signatures were recomputed. This settles the facts the skill previously hedged on, because Formstack's public docs don't state them.

What the captures confirmed

  • Scheme. HMAC-SHA256 over the raw urlencoded body, lowercase hex, header value sha256=<hex>. The base64 form of the same MAC does not match.
  • Key. The first delivery was signed with HMAC Key test. The key was then changed to test1, and the second delivery verified only with test1.
  • Shared Secret. It arrives as a body field named HandshakeKey, after FormID and UniqueID, inside the signed content. It stayed test across the key change, so the HMAC Key itself is never sent.
  • Envelope. FormID and UniqueID arrive as strings. No timestamp, delivery-id or event-type field or header.
  • User-Agent. FormstackWebhook/1.0 (Form <FormID>). The skill records it as observed and still routes on FormID.

Wire body of the second capture:

FormID=6606394&UniqueID=1500878955&HandshakeKey=test
x-fs-signature: sha256=30dff7f180b6d69eab397a5d51719474df490b730514c253e8b5832d3b51b970

Changes

  • The skill page, the three reference docs and the example READMEs replace the single-upstream hedging with the observed facts.
  • The "if hex never matches, try base64" troubleshooting step is removed.
  • The Documents (WebMerge) scope note now names that product's actual keys, merge_id, handshake, file_name and file_contents, and says it sends no signature header.
  • Both captured deliveries are test vectors in the express, nextjs and fastapi suites. The suites now check the verifier against signatures Formstack produced, not only ones the tests computed.
  • The TODO items for digest format and live verification are closed. JSON-content-type capture is added as an open item.
  • The providers.yaml brief is updated so a regeneration doesn't reintroduce the old hedges.

Not asserted

  • Retry policy, timeouts and a delivery-id header are still not documented. None was observed either.
  • The HandshakeKey name and the user-agent format are marked observed, not documented.
  • Only urlencoded deliveries were captured. JSON is untested against a real signature.
  • Both captures had a Shared Secret set, so the skill doesn't say whether HandshakeKey is omitted or sent empty without one.

Testing

  • validate-provider.sh formstack-webhooks passes.
  • express: 37 passed.
  • nextjs: 38 passed.
  • fastapi: 38 passed.

Related PRs:

🤖 Generated with Claude Code

…st vectors

Two real Formstack Forms WebHook deliveries were captured on 2026-09-25 and
their signatures recomputed. They settle what the public docs leave out:

- HMAC-SHA256 over the raw urlencoded body, lowercase hex, sent as
  sha256=<hex>. The base64 form does not match. A key change verified only
  with the new key.
- The Shared Secret arrives as a body field named HandshakeKey, inside the
  signed content. The HMAC Key is never sent.
- FormID and UniqueID arrive as strings, first on the wire.
- User-Agent is FormstackWebhook/1.0 (Form <FormID>). No delivery-id header.

Removes the 'if hex never matches, try base64' fallback and the
single-upstream hedging, closes the matching TODO items, updates the brief,
and adds both captured deliveries as test vectors in the express, nextjs and
fastapi suites.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Secret

Both captures had a Shared Secret set, so whether the field is omitted or
sent empty without one was never observed. Say so, and track it in TODO.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@garethx
garethx marked this pull request as ready for review September 25, 2026 13:56
@garethx
garethx merged commit 4cc57d7 into hookdeck:main Sep 25, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant