Skip to content

fix(pay): actionable webhook.verify errors for the raw-body mistake - #36

Merged
PancheI merged 1 commit into
mainfrom
fix/pay-webhook-verify-hints
Aug 18, 2026
Merged

fix(pay): actionable webhook.verify errors for the raw-body mistake#36
PancheI merged 1 commit into
mainfrom
fix/pay-webhook-verify-hints

Conversation

@PancheI

@PancheI PancheI commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Problem

The most common "I can't verify AgentaOS webhooks" report is not a signing bug — it's integrators passing a parsed body instead of the raw request bytes (e.g. req.body after a global express.json()). The SDK stringified that object to "[object Object]" and surfaced a generic "Signature does not match payload", giving no clue what was wrong.

Verified against a real production webhook: signing is correct, webhooks.verify() is correct, and the docs already show express.raw(). The gap was purely the error message — so people file tickets instead of self-diagnosing.

Change (messages only — algorithm unchanged)

  1. Reject a non-string/Buffer payload up front with an actionable message that names the received type and shows the fix:

    Webhook payload must be the raw request body (a string or Buffer), but received object. You are likely passing an already-parsed JSON body … Read the raw body instead, e.g. in Express: app.post('/webhooks', express.raw({ type: 'application/json' }), handler).

  2. Add a raw-body hint to the signature-mismatch error, mirroring Stripe's "Are you passing the raw request body you received?".

Tests

+3 cases in webhooks.test.ts (parsed object → helpful error incl. express.raw, null → helpful error, genuine mismatch → hints at raw body). 15/15 pass, tsc --noEmit + biome clean. Changeset included (@agentaos/pay patch).

🤖 Generated with Claude Code

The #1 reason merchants "can't verify webhooks" is passing a parsed/re-serialized
body instead of the raw request bytes (e.g. `req.body` after `express.json()`),
which the SDK stringified to `[object Object]` and surfaced as a generic
"signature does not match payload". They had no way to know what was wrong.

- Reject a non-string/Buffer payload up front with a message that names the
  received type and shows the fix (`express.raw({ type: 'application/json' })`).
- Add a raw-body hint to the signature-mismatch error, mirroring Stripe's
  "Are you passing the raw request body you received?".

No change to the verification algorithm. Adds 3 tests (parsed object → helpful
error, null → helpful error, mismatch → hints at raw body); 15/15 pass, tsc +
biome clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@PancheI
PancheI merged commit 0d4ab68 into main Aug 18, 2026
1 check passed
@PancheI
PancheI deleted the fix/pay-webhook-verify-hints branch August 18, 2026 19:38
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