[Agent] Issue #401: create post apibillingwebhook endpoint 1 #405
Open
pook
wants to merge 49 commits from
agent-task/401 into main
pull from: agent-task/401
merge into: pook:main
pook:main
pook:feat/ux-remediation
pook:master
pook:agent-task/681
pook:agent-task/mount-billing-api-prefix
pook:agent-task/772
pook:agent-task/769
pook:agent-task/760
pook:agent-task/756
pook:agent-task/757
pook:agent-task/703
pook:agent-task/702
pook:agent-task/688
pook:agent-task/684
pook:agent-task/683
pook:agent-task/674
pook:agent-task/668
pook:feat/simple-health-endpoint
pook:agent-task/663
pook:agent-task/658
pook:agent-task/653
pook:agent-task/651
pook:feat/api-billing-checkout
pook:agent-task/650
pook:agent-task/641
pook:agent-task/639
pook:agent-task/638
pook:feat/login-brute-force-protection
pook:agent-task/634
pook:feat/generate-retry-tests
pook:agent-task/625
pook:agent-task/622-validate-openai-responses
pook:agent-task/615-csrf-token-validation
pook:agent-task/614
pook:agent-task/612
pook:agent-task/611
pook:agent-task/606
pook:agent-task/597
pook:agent-task/596
pook:agent-task/588
pook:agent-task/583
pook:agent-task/575
pook:agent-task/574
pook:agent-task/571
pook:agent-task/570
pook:agent-task/562
pook:agent-task/561
pook:agent-task/556-npm-audit-fix
pook:agent-task/537
pook:agent-task/533
pook:agent-task/524
pook:agent-task/518
pook:agent-task/517
pook:agent-task/516
pook:agent-task/513
pook:agent-task/512
pook:agent-task/508
pook:feat/llm-error-handling-tests
pook:agent-task/483
pook:feat/openai-retry-502
pook:agent-task/478
pook:agent-task/477
pook:feat/csrf-double-submit
pook:agent-task/468
pook:feat/error-handler-middleware
pook:feat/global-request-timeout
pook:agent-task/454
pook:agent-task/453
pook:agent-task/449
pook:feat/llm-timeout-504
pook:feat/sanitize-generate-inputs
pook:fix/body-limit-1mb-test
pook:feat/openai-error-handling
pook:agent-task/426
pook:agent-task/425
pook:agent-task/421
pook:agent-task/420
pook:agent-task/419
pook:agent-task/408
pook:agent-task/406
pook:agent-task/407
pook:feat/zod-generate-validation
pook:agent-task/397
pook:agent-task/391
pook:agent-task/390
pook:feat/https-redirect-middleware
pook:agent-task/388
pook:agent-task/360
pook:feat/generate-1mb-body-limit
pook:feat/request-timeout
pook:feat/checkout-rate-limit
pook:feat/webhook-rate-limit
pook:feat/centralized-error-handler
pook:agent-task/345
pook:agent-task/342
pook:agent-task/341
pook:agent-task/337
pook:feat/generate-rate-limit
pook:agent-task/332
pook:agent-task/331
pook:agent-task/329
pook:agent-task/325
pook:agent-task/324
pook:feat/single-stage-dockerfile
pook:feat/jest-typecheck-ci-gate
pook:feat/rebase-open-prs-script
pook:fix/unblock-pr-pipeline
pook:agent-task/251
pook:feat/deploy-migrations-on-startup
pook:agent-task/247
pook:agent-task/242
pook:agent-task/241
pook:agent-task/236
pook:fix/close-duplicate-issues
pook:agent-task/237
pook:agent-task/235
pook:agent-task/232
pook:agent-task/231
pook:agent-task/228
pook:agent-task/227
pook:agent-task/222
pook:agent-task/221
pook:feat/stripe-checkout-endpoint
pook:fix/134-sanitize-ai-output
pook:agent-task/212
pook:agent-task/211
pook:test/export-render-unit-tests
pook:agent-task/206
pook:agent-task/205
pook:feat/download-token-utility
pook:feat/security-headers-v2
pook:agent-task/196
pook:fix/env-var-validation
pook:feat/health-endpoint-tests
pook:feat/cors-middleware
pook:agent-task/185
pook:agent-task/184
pook:agent-task/180
pook:feat/pr-triage-workflow
pook:agent-task/177
pook:feat/dockerfile-deploy
pook:feature/131-api-key-auth
pook:feat/graceful-shutdown
pook:agent-task/170
pook:feat/pr-triage-script
pook:agent-task/166
pook:feat/ccpa-privacy-policy
pook:feat/auto-migrate-on-startup
pook:feat/auto-rebase-workflow
pook:feat/openai-timeout-guard
pook:agent-task/154
pook:agent-task/155
pook:feat/body-size-limit-generate
pook:feat/health-endpoint
pook:ci/pr-checks
pook:agent-task/145
pook:feat/startup-env-validation
pook:agent-task/141
pook:feat/stripe-document-checkout
pook:fix/116-sanitize-ai-generated-content
pook:feat/document-validation-41
pook:feat/api-key-auth-middleware
pook:feature/document-generator-unit-tests
pook:feature/openai-retry-logic
pook:feature/auto-merge-script
pook:feature/ci-auto-labeling
pook:fix/llm-response-null-checks
pook:feat/generate-smoke-tests
pook:feature/request-logging-middleware
pook:feature/csrf-protection
pook:feature/request-id-middleware
pook:feature/cors-allowlist
pook:feature/rate-limit-generate
pook:feature/citation-scanner-and-disclaimer
pook:feature/input-length-validation
pook:feat/ci-quality-gate
pook:fix/stripe-webhook-raw-body
pook:feat/ci-pr-checks
pook:fix/webhook-raw-body-preservation
pook:feat/ci-workflow
pook:feature/71-raw-body-webhook
pook:feature/template-rendering-tests
pook:feature/stripe-document-webhook
pook:feat/security-headers
pook:feat/stripe-webhook-raw-body
pook:feat/startup-migrations
pook:feature/ai-generation-timeout
pook:feature/dependency-audit-ci
pook:feat/webhook-idempotency
pook:feature/body-size-limit
pook:feature/startup-env-validation
pook:ci/add-pr-pipeline
pook:feature/auth-middleware
pook:feature/ccpa-optout-endpoint
pook:feature/async-document-generation
pook:feature/stripe-checkout-paywall
pook:feature/post-generation-validation
pook:feature/llm-retry-mechanism
pook:feature/document-history
pook:feature/prometheus-metrics
pook:feature/dpa-document-type
pook:feature/input-validation-sanitization
pook:feature/document-email-send
pook:feature/api-health-endpoint
No reviewers
Labels
No labels
agent-task
agent-task
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set.
Reference
pook/compliancebot!405
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "agent-task/401"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #401
Changes
feat: issue #401 create-post-apibillingwebhook-endpoint-1 (agent task liancebot401)
Acceptance Criteria
Create POST /api/billing/webhook endpoint: 1) Apply
express.raw({ type: 'application/json' })middleware before JSON parsing to preserve raw body for signature verification, 2) Verifystripe.webhooks.constructEvent(rawBody, sig, STRIPE_WEBHOOK_SECRET)— return 400 with structured error if signature invalid, 3) Log event type and ID using structured format, 4) Return 200 for all verified events (handler logic in separate tasks). Add STRIPE_WEBHOOK_SECRET to startup env validation. Without signature verification, anyone can forge billing events to unlock paid features — this is a revenue-protection security requirement.Generated by CEO Planner (priority: 2)
Tokens: 20 in / 4165 out
PR #405 — Stripe Webhook Endpoint Review
Criteria Assessment
Buffer.from(await c.req.arrayBuffer())which preserves exact bytes. Comment correctly notes thatc.req.text()re-encodes through UTF-8 and can break HMAC. No JSON body-parsing middleware intercepts the request before the handler.stripe.webhooks.constructEventwith proper error handlingstripe.webhooks.constructEvent(payload, sig, secret)— this works correctly. Error is caught and returns HTTP 400 with the error message. Recommendation: Consider migrating tostripe.webhooks.constructEventAsync()which uses timing-safe comparison internally (available since Stripe SDK v8+). The sync version usescrypto.timingSafeEqualin recent versions so this is not a blocker, but the async variant is Stripe's recommended path.stripe-signatureheader returns 400 immediately. Failed verification throws 400. No event data is accessed until after successful verification.{ received: true }(HTTP 200). Missing signature header → HTTP 400. Failed signature verification → HTTP 400. Handler errors → HTTP 500 (appropriate).Additional Findings
Structured logging added (good):
JSON.stringify({ level: "error", source: "billing/webhook", error: "signature_verification_failed", detail: msg })JSON.stringify({ level: "info", source: "billing/webhook", eventType: event.type, eventId: event.id })Dual route mount:
billingRouteris now mounted at both/billingand/api/billinginindex.ts. The webhook is therefore accessible at both/billing/webhookand/api/billing/webhook. Confirm this is intentional — having two paths to the same webhook could complicate Stripe dashboard configuration and log analysis.STRIPE_WEBHOOK_SECRETadded to required env vars — correctly added toenv.tsvalidation.Body size limit: Global 100KB
bodyLimitmiddleware applies to all routes including the webhook. Stripe payloads rarely exceed this, but if you ever enable expanded objects in webhook events, payloads can grow. Worth monitoring.Rate limiter: Webhook endpoint has a 20 req/60s rate limiter. Stripe retries failed webhooks with exponential backoff, but during high-volume events (e.g., mass subscription changes), 20/min could cause legitimate drops. Consider raising or exempting the webhook from rate limiting since signature verification already provides authentication.
Type Check
tsc --noEmitshows 0 errors in billing code. All 18 errors are pre-existing in test files (document-generator.test.ts,input-limits.test.ts) — unrelated to this PR.Verdict: ✅ MERGE-READY
All 4 acceptance criteria pass. The recommendations above (async construct, rate limit tuning, dual-mount confirmation) are non-blocking improvements that can be addressed in follow-up PRs.
Reviewed by Claude Code — automated billing pipeline review
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.