Appearance
vela-webhook
The webhook event verifier package for VelaPay. Published as @velapay/webhook (v0.1.0). Despite the name, this repo ships a library — not a standalone Worker. The actual fan-out runtime lives inside vela-dashboard/worker/ and consumes @velapay/webhook to verify signatures and reify event types.
Purpose and Role
- Provide an isomorphic (Node + edge) HMAC-SHA256 verifier for Vela's webhook delivery format (Stripe-compatible wire format).
- Expose Zod-typed discriminated union over every Vela event so consumers get exhaustive switch coverage in TypeScript.
- Wrap raw Helius Enhanced webhook payloads into typed Vela events — consumers parse Vela domain events, not raw Helius bytes.
- Centralize retry, dedup, and idempotency primitives so the dashboard fan-out and any future delivery surface use the same logic.
- Ship test fixtures so consumers can build dispatch tests without re-deriving valid signed payloads.
- Parse v1.9 Payment Intent and refund events produced by the dashboard transactional outbox.
Tech Stack
| Technology | Version | Purpose |
|---|---|---|
| TypeScript | ^5.8.x | Language |
| Bun | 1.3.x | Runtime + package manager + test runner |
| Zod | ^3.x | Event schema validation (consumes @velapay/sdk/events) |
| Web Crypto API | — | HMAC-SHA256 verification (works in Workers, Node, Bun) |
| Biome | latest | Lint + format |
Built into dual CommonJS + ESM with build.ts (Bun bundler).
Package Surface
| Export | Purpose |
|---|---|
verify(payload, signature, secret) | HMAC-SHA256 signature verification (constant-time compare) |
parseEvent(rawBody) | Parse a verified body into a typed Vela event (Zod-discriminated) |
EventType enum | All supported event types (mandate.created, mandate.cancelled, pull.executed, stream.settled, plan.changed, …) |
RetryPolicy | Svix-style retry schedule (exponential backoff with jitter, max attempts) |
IdempotencyKey helpers | Dedup key generation + collision detection |
DLQEvent | Wrapper for events that exhausted retries |
| Test fixtures | Pre-signed payloads under test-fixtures/ for downstream tests |
Directory Structure
vela-webhook/
├── src/
│ ├── verify.ts # HMAC verification (Web Crypto)
│ ├── parse.ts # Raw body → typed Vela event
│ ├── retry.ts # Retry schedule + jitter
│ ├── idempotency.ts # Dedup key derivation
│ └── index.ts
├── schemas/ # Zod schemas (re-exported from @velapay/sdk/events)
├── test-fixtures/ # Signed sample payloads for downstream tests
├── tests/ # bun:test unit tests
├── build.ts # Bun bundler (CJS + ESM dual output)
├── package.json
└── tsconfig.jsonConsumers
| Consumer | How |
|---|---|
vela-dashboard (worker) | Verifies inbound Helius webhook signatures, parses payloads into typed events, queues dispatch. Replaces inline Helius parsing that v1.0–v1.7 carried. |
| External merchants | Install @velapay/webhook to verify deliveries in their own backends. |
Deployment Target
- npm (when published) — currently versioned but unpublished.
- Workspace consumption — linked into
vela-dashboardvia the@vela/webhookalias for local development.
Notable Design Decisions
Library, not Worker
The fan-out runtime lives where the data does — in the dashboard's Worker, alongside D1 (for delivery state) and Queues (for retries). Splitting it into a separate Worker would have introduced a service-binding hop without a clear win. The package shape lets external merchants verify deliveries in their own infrastructure too.
Wrap Helius, Don't Replace It
This repo deliberately does not introduce a new event feed. Helius Enhanced webhooks are still the source of truth for on-chain events. @velapay/webhook only types and re-shapes them — so on-chain truth and merchant-facing webhooks never drift.
Commerce OS is the exception to the ingest origin, not the schema boundary: the dashboard produces commerce events from verified business transitions and routes them directly by merchant_id. The package still supplies the canonical schemas and verifier. Commerce consumers deduplicate by UUID event ID, never by transaction signature.
Stripe Wire Format
Signatures use the Stripe-compatible t=...,v1=... header format. Merchants migrating from Stripe can reuse existing signature-verification utilities or move to @velapay/webhook with no payload-shape surprises.
Schema-Diff CI Gate
Event schemas are co-versioned with @velapay/sdk/events. CI enforces additive-only schema evolution — a removal or rename fails the build. This protects every downstream consumer from silent breaking changes.
Related
- Helius webhook configuration: Helius Infrastructure →
- Webhook troubleshooting runbook: Webhook Troubleshooting →
- Dashboard worker's dispatch path: vela-dashboard →