@better-webhook/cli 0.3.1 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +489 -180
- package/dist/index.cjs +1831 -661
- package/dist/index.d.cts +1 -2
- package/dist/index.d.ts +1 -2
- package/dist/index.js +1853 -661
- package/package.json +19 -6
package/README.md
CHANGED
|
@@ -5,287 +5,594 @@
|
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
[](https://nodejs.org/)
|
|
7
7
|
|
|
8
|
-
A
|
|
8
|
+
A modern CLI tool for webhook development, testing, and debugging. Capture incoming webhooks, replay them against your local server, manage reusable templates, and generate provider-specific signatures automatically.
|
|
9
9
|
|
|
10
10
|
## Features
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
🎯 **
|
|
12
|
+
- 🎣 **Capture** — Start a local server to capture incoming webhooks from any provider
|
|
13
|
+
- 🔄 **Replay** — Replay captured webhooks to any endpoint with full header preservation
|
|
14
|
+
- 📋 **Templates** — Download and run curated webhook templates from the community
|
|
15
|
+
- 🔐 **Signatures** — Automatic signature generation for Stripe, GitHub, Shopify, Slack, and more
|
|
16
|
+
- 🌐 **WebSocket** — Real-time capture notifications via WebSocket for dashboard integration
|
|
17
|
+
- 🎯 **Provider Detection** — Automatically identifies webhook providers from headers
|
|
18
|
+
|
|
19
|
+
## Supported Providers
|
|
20
|
+
|
|
21
|
+
| Provider | Signature Algorithm | Auto-Detection |
|
|
22
|
+
| ------------ | ------------------------------- | -------------- |
|
|
23
|
+
| Stripe | HMAC-SHA256 (`t={ts},v1={sig}`) | ✅ |
|
|
24
|
+
| GitHub | HMAC-SHA256 (`sha256={sig}`) | ✅ |
|
|
25
|
+
| Shopify | HMAC-SHA256 (Base64) | ✅ |
|
|
26
|
+
| Slack | HMAC-SHA256 (`v0={sig}`) | ✅ |
|
|
27
|
+
| Twilio | HMAC-SHA1 (Base64) | ✅ |
|
|
28
|
+
| SendGrid | HMAC-SHA256 (Base64) | ✅ |
|
|
29
|
+
| Linear | HMAC-SHA256 (Hex) | ✅ |
|
|
30
|
+
| Clerk (Svix) | HMAC-SHA256 (`v1,{sig}`) | ✅ |
|
|
31
|
+
| Discord | Ed25519 | ✅ |
|
|
32
|
+
| Custom | — | — |
|
|
18
33
|
|
|
19
34
|
## Installation
|
|
20
35
|
|
|
21
|
-
### NPM/YARN/PNPM
|
|
22
|
-
|
|
23
36
|
```bash
|
|
24
|
-
#
|
|
37
|
+
# NPM
|
|
25
38
|
npm install -g @better-webhook/cli
|
|
26
|
-
# or use with npx
|
|
27
|
-
npx @better-webhook/cli --help
|
|
28
39
|
|
|
29
|
-
#
|
|
40
|
+
# Yarn
|
|
30
41
|
yarn global add @better-webhook/cli
|
|
31
42
|
|
|
32
|
-
#
|
|
43
|
+
# PNPM
|
|
33
44
|
pnpm add -g @better-webhook/cli
|
|
45
|
+
|
|
46
|
+
# Or use with npx (no installation required)
|
|
47
|
+
npx @better-webhook/cli --help
|
|
34
48
|
```
|
|
35
49
|
|
|
36
50
|
### Verify Installation
|
|
37
51
|
|
|
38
52
|
```bash
|
|
39
|
-
better-webhook --
|
|
53
|
+
better-webhook --version
|
|
54
|
+
# 2.0.0
|
|
40
55
|
```
|
|
41
56
|
|
|
42
57
|
## Quick Start
|
|
43
58
|
|
|
44
|
-
### 1.
|
|
59
|
+
### 1. Capture Webhooks
|
|
45
60
|
|
|
46
|
-
|
|
47
|
-
# List available webhook definitions
|
|
48
|
-
better-webhook webhooks list
|
|
61
|
+
Start a local server to capture incoming webhooks:
|
|
49
62
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
better-webhook
|
|
63
|
+
```bash
|
|
64
|
+
# Start capture server on default port 3001
|
|
65
|
+
better-webhook capture
|
|
53
66
|
|
|
54
|
-
#
|
|
55
|
-
better-webhook
|
|
56
|
-
better-webhook webhooks run mywebhook --url https://example.com/hook --method POST
|
|
67
|
+
# Use a custom port
|
|
68
|
+
better-webhook capture --port 4000
|
|
57
69
|
```
|
|
58
70
|
|
|
59
|
-
|
|
71
|
+
Point your webhook provider (Stripe, GitHub, etc.) to `http://localhost:3001` or use a tunneling service like ngrok.
|
|
60
72
|
|
|
61
|
-
|
|
62
|
-
# Start capture server (default port 3001)
|
|
63
|
-
better-webhook capture
|
|
64
|
-
better-webhook capture --port 3000
|
|
73
|
+
### 2. View & Manage Captures
|
|
65
74
|
|
|
75
|
+
```bash
|
|
66
76
|
# List captured webhooks
|
|
67
|
-
better-webhook
|
|
68
|
-
better-webhook capture list --limit 20
|
|
77
|
+
better-webhook captures list
|
|
69
78
|
|
|
70
|
-
#
|
|
71
|
-
better-webhook
|
|
79
|
+
# Show detailed information about a capture
|
|
80
|
+
better-webhook captures show abc123
|
|
81
|
+
|
|
82
|
+
# Search captures
|
|
83
|
+
better-webhook captures search "github"
|
|
84
|
+
|
|
85
|
+
# Delete a capture
|
|
86
|
+
better-webhook captures delete abc123
|
|
72
87
|
```
|
|
73
88
|
|
|
74
89
|
### 3. Replay Webhooks
|
|
75
90
|
|
|
91
|
+
Replay a captured webhook to your local development server:
|
|
92
|
+
|
|
76
93
|
```bash
|
|
77
|
-
#
|
|
78
|
-
better-webhook replay
|
|
79
|
-
|
|
94
|
+
# Interactive mode (select capture and enter URL)
|
|
95
|
+
better-webhook replay
|
|
96
|
+
|
|
97
|
+
# Direct replay
|
|
98
|
+
better-webhook replay abc123 http://localhost:3000/api/webhooks/github
|
|
80
99
|
```
|
|
81
100
|
|
|
82
|
-
|
|
101
|
+
### 4. Use Templates
|
|
102
|
+
|
|
103
|
+
Download and run curated webhook templates:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# List available templates
|
|
107
|
+
better-webhook templates list
|
|
83
108
|
|
|
84
|
-
|
|
109
|
+
# Download a template
|
|
110
|
+
better-webhook templates download github-push
|
|
85
111
|
|
|
86
|
-
|
|
112
|
+
# Run a template against your endpoint
|
|
113
|
+
better-webhook run github-push --url http://localhost:3000/webhooks/github
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
87
117
|
|
|
88
|
-
|
|
89
|
-
| -------------------------- | ---------------------------------- | ------------------- |
|
|
90
|
-
| `webhooks list` | List available webhook definitions | - |
|
|
91
|
-
| `webhooks run <name>` | Execute a webhook definition | `--url`, `--method` |
|
|
92
|
-
| `webhooks download [name]` | Download community templates | `--all`, `--force` |
|
|
118
|
+
## Commands Reference
|
|
93
119
|
|
|
94
120
|
### `better-webhook capture`
|
|
95
121
|
|
|
96
|
-
|
|
122
|
+
Start a server to capture incoming webhooks. All captured webhooks are saved to `~/.better-webhook/captures/`.
|
|
97
123
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
| `capture list` | List captured webhook requests | `--limit` |
|
|
102
|
-
| `capture template <id> [name]` | Generate template from capture | `--url`, `--output-dir` |
|
|
124
|
+
```bash
|
|
125
|
+
better-webhook capture [options]
|
|
126
|
+
```
|
|
103
127
|
|
|
104
|
-
|
|
128
|
+
| Option | Description | Default |
|
|
129
|
+
| ------------------- | ----------------- | --------- |
|
|
130
|
+
| `-p, --port <port>` | Port to listen on | `3001` |
|
|
131
|
+
| `-h, --host <host>` | Host to bind to | `0.0.0.0` |
|
|
105
132
|
|
|
106
|
-
|
|
133
|
+
**Features:**
|
|
107
134
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
135
|
+
- Automatically detects webhook provider from headers
|
|
136
|
+
- Saves full request including headers, body, query params
|
|
137
|
+
- WebSocket server for real-time notifications
|
|
138
|
+
- Returns capture ID in response for easy reference
|
|
111
139
|
|
|
112
|
-
|
|
140
|
+
**Example:**
|
|
113
141
|
|
|
114
|
-
|
|
142
|
+
```bash
|
|
143
|
+
better-webhook capture --port 4000 --host localhost
|
|
144
|
+
```
|
|
115
145
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
"email": "user@example.com"
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
### `better-webhook captures` (alias: `c`)
|
|
149
|
+
|
|
150
|
+
Manage captured webhooks.
|
|
151
|
+
|
|
152
|
+
#### `captures list` (alias: `ls`)
|
|
153
|
+
|
|
154
|
+
List captured webhooks, sorted by most recent first.
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
better-webhook captures list [options]
|
|
132
158
|
```
|
|
133
159
|
|
|
134
|
-
|
|
160
|
+
| Option | Description | Default |
|
|
161
|
+
| --------------------------- | ----------------------------------------- | ------- |
|
|
162
|
+
| `-l, --limit <limit>` | Maximum captures to show | `20` |
|
|
163
|
+
| `-p, --provider <provider>` | Filter by provider (stripe, github, etc.) | — |
|
|
135
164
|
|
|
136
|
-
|
|
137
|
-
| --------- | ------ | -------- | --------------------------- |
|
|
138
|
-
| `url` | string | ✅ | Target webhook URL |
|
|
139
|
-
| `method` | string | ❌ | HTTP method (default: POST) |
|
|
140
|
-
| `headers` | array | ❌ | Array of header objects |
|
|
141
|
-
| `body` | any | ❌ | Request payload |
|
|
165
|
+
#### `captures show <captureId>`
|
|
142
166
|
|
|
143
|
-
|
|
167
|
+
Show detailed information about a specific capture.
|
|
144
168
|
|
|
169
|
+
```bash
|
|
170
|
+
better-webhook captures show <captureId> [options]
|
|
145
171
|
```
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
172
|
+
|
|
173
|
+
| Option | Description |
|
|
174
|
+
| ------------ | ---------------------- |
|
|
175
|
+
| `-b, --body` | Show full body content |
|
|
176
|
+
|
|
177
|
+
**Arguments:**
|
|
178
|
+
|
|
179
|
+
- `<captureId>` — Full or partial capture ID
|
|
180
|
+
|
|
181
|
+
#### `captures search <query>`
|
|
182
|
+
|
|
183
|
+
Search captures by ID, path, method, provider, or filename.
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
better-webhook captures search <query>
|
|
154
187
|
```
|
|
155
188
|
|
|
156
|
-
|
|
189
|
+
#### `captures delete` (alias: `rm`)
|
|
157
190
|
|
|
158
|
-
|
|
191
|
+
Delete a specific captured webhook.
|
|
159
192
|
|
|
160
193
|
```bash
|
|
161
|
-
|
|
162
|
-
|
|
194
|
+
better-webhook captures delete <captureId> [options]
|
|
195
|
+
```
|
|
163
196
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
197
|
+
| Option | Description |
|
|
198
|
+
| ------------- | ------------------------ |
|
|
199
|
+
| `-f, --force` | Skip confirmation prompt |
|
|
200
|
+
|
|
201
|
+
#### `captures clean` (alias: `remove-all`)
|
|
202
|
+
|
|
203
|
+
Remove all captured webhooks.
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
better-webhook captures clean [options]
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
| Option | Description |
|
|
210
|
+
| ------------- | ------------------------ |
|
|
211
|
+
| `-f, --force` | Skip confirmation prompt |
|
|
212
|
+
|
|
213
|
+
---
|
|
167
214
|
|
|
168
|
-
|
|
169
|
-
|
|
215
|
+
### `better-webhook templates` (alias: `t`)
|
|
216
|
+
|
|
217
|
+
Manage webhook templates. Templates are fetched from the [better-webhook repository](https://github.com/endalk200/better-webhook/tree/main/templates).
|
|
218
|
+
|
|
219
|
+
#### `templates list` (alias: `ls`)
|
|
220
|
+
|
|
221
|
+
List available remote templates from the repository.
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
better-webhook templates list [options]
|
|
170
225
|
```
|
|
171
226
|
|
|
172
|
-
|
|
227
|
+
| Option | Description |
|
|
228
|
+
| --------------------------- | -------------------------------------- |
|
|
229
|
+
| `-p, --provider <provider>` | Filter by provider |
|
|
230
|
+
| `-r, --refresh` | Force refresh the template index cache |
|
|
231
|
+
|
|
232
|
+
#### `templates download` (alias: `get`)
|
|
233
|
+
|
|
234
|
+
Download a template to local storage (`~/.better-webhook/templates/`).
|
|
173
235
|
|
|
174
236
|
```bash
|
|
175
|
-
|
|
176
|
-
|
|
237
|
+
better-webhook templates download [templateId] [options]
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
| Option | Description |
|
|
241
|
+
| ----------- | -------------------------------- |
|
|
242
|
+
| `-a, --all` | Download all available templates |
|
|
243
|
+
|
|
244
|
+
If no `templateId` is provided, shows an interactive selection menu.
|
|
245
|
+
|
|
246
|
+
#### `templates local`
|
|
247
|
+
|
|
248
|
+
List downloaded local templates.
|
|
177
249
|
|
|
178
|
-
|
|
179
|
-
better-webhook
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
250
|
+
```bash
|
|
251
|
+
better-webhook templates local [options]
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
| Option | Description |
|
|
255
|
+
| --------------------------- | ------------------ |
|
|
256
|
+
| `-p, --provider <provider>` | Filter by provider |
|
|
257
|
+
|
|
258
|
+
#### `templates search <query>`
|
|
259
|
+
|
|
260
|
+
Search templates by name, provider, or event type.
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
better-webhook templates search <query>
|
|
183
264
|
```
|
|
184
265
|
|
|
185
|
-
|
|
266
|
+
#### `templates cache`
|
|
267
|
+
|
|
268
|
+
Manage the template index cache.
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
better-webhook templates cache [options]
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
| Option | Description |
|
|
275
|
+
| ------------- | ------------------------ |
|
|
276
|
+
| `-c, --clear` | Clear the template cache |
|
|
277
|
+
|
|
278
|
+
#### `templates clean` (alias: `remove-all`)
|
|
279
|
+
|
|
280
|
+
Remove all downloaded templates.
|
|
186
281
|
|
|
187
282
|
```bash
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
283
|
+
better-webhook templates clean [options]
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
| Option | Description |
|
|
287
|
+
| ------------- | ------------------------ |
|
|
288
|
+
| `-f, --force` | Skip confirmation prompt |
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
### `better-webhook run`
|
|
293
|
+
|
|
294
|
+
Run a webhook template against a target URL. Automatically generates provider-specific signatures when a secret is provided.
|
|
191
295
|
|
|
192
|
-
|
|
193
|
-
better-webhook
|
|
296
|
+
```bash
|
|
297
|
+
better-webhook run [templateId] [options]
|
|
194
298
|
```
|
|
195
299
|
|
|
196
|
-
|
|
300
|
+
| Option | Description | Required |
|
|
301
|
+
| ----------------------- | ------------------------------------------ | -------- |
|
|
302
|
+
| `-u, --url <url>` | Target URL to send the webhook to | ✅ |
|
|
303
|
+
| `-s, --secret <secret>` | Secret for signature generation | — |
|
|
304
|
+
| `-H, --header <header>` | Add custom header (format: `key:value`) | — |
|
|
305
|
+
| `-v, --verbose` | Show detailed request/response information | — |
|
|
306
|
+
|
|
307
|
+
**Arguments:**
|
|
308
|
+
|
|
309
|
+
- `[templateId]` — Template ID to run (interactive selection if omitted)
|
|
197
310
|
|
|
198
|
-
|
|
311
|
+
**Signature Generation:**
|
|
312
|
+
|
|
313
|
+
When you provide a secret (`--secret`), the CLI automatically generates the correct signature header based on the template's provider. You can also use environment variables (see [Environment Variables](#environment-variables)).
|
|
314
|
+
|
|
315
|
+
**Example:**
|
|
316
|
+
|
|
317
|
+
```bash
|
|
318
|
+
# Run with inline secret
|
|
319
|
+
better-webhook run github-push \
|
|
320
|
+
--url http://localhost:3000/api/webhooks/github \
|
|
321
|
+
--secret "your-webhook-secret"
|
|
322
|
+
|
|
323
|
+
# Run with custom headers
|
|
324
|
+
better-webhook run github-push \
|
|
325
|
+
--url http://localhost:3000/api/webhooks/github \
|
|
326
|
+
--secret "$GITHUB_WEBHOOK_SECRET" \
|
|
327
|
+
--header "X-Custom-Header:value" \
|
|
328
|
+
--verbose
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
### `better-webhook replay`
|
|
334
|
+
|
|
335
|
+
Replay a captured webhook to a target URL. Preserves original headers (except connection-related ones) and allows overrides.
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
better-webhook replay [captureId] [targetUrl] [options]
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
| Option | Description |
|
|
342
|
+
| ----------------------- | -------------------------------------------- |
|
|
343
|
+
| `-m, --method <method>` | Override HTTP method |
|
|
344
|
+
| `-H, --header <header>` | Add or override header (format: `key:value`) |
|
|
345
|
+
| `-v, --verbose` | Show detailed request/response information |
|
|
346
|
+
|
|
347
|
+
**Arguments:**
|
|
348
|
+
|
|
349
|
+
- `[captureId]` — Capture ID to replay (interactive selection if omitted)
|
|
350
|
+
- `[targetUrl]` — Target URL (prompts if omitted, defaults to original path on localhost:3000)
|
|
351
|
+
|
|
352
|
+
**Example:**
|
|
353
|
+
|
|
354
|
+
```bash
|
|
355
|
+
# Interactive mode
|
|
356
|
+
better-webhook replay
|
|
357
|
+
|
|
358
|
+
# Direct replay with options
|
|
359
|
+
better-webhook replay abc123 http://localhost:3000/webhooks \
|
|
360
|
+
--method POST \
|
|
361
|
+
--header "X-Debug:true" \
|
|
362
|
+
--verbose
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## Environment Variables
|
|
368
|
+
|
|
369
|
+
The CLI automatically reads webhook secrets from environment variables based on the provider:
|
|
370
|
+
|
|
371
|
+
| Provider | Environment Variable |
|
|
372
|
+
| -------- | ------------------------- |
|
|
373
|
+
| Stripe | `STRIPE_WEBHOOK_SECRET` |
|
|
374
|
+
| GitHub | `GITHUB_WEBHOOK_SECRET` |
|
|
375
|
+
| Shopify | `SHOPIFY_WEBHOOK_SECRET` |
|
|
376
|
+
| Twilio | `TWILIO_WEBHOOK_SECRET` |
|
|
377
|
+
| Slack | `SLACK_WEBHOOK_SECRET` |
|
|
378
|
+
| Linear | `LINEAR_WEBHOOK_SECRET` |
|
|
379
|
+
| Clerk | `CLERK_WEBHOOK_SECRET` |
|
|
380
|
+
| SendGrid | `SENDGRID_WEBHOOK_SECRET` |
|
|
381
|
+
| Discord | `DISCORD_WEBHOOK_SECRET` |
|
|
382
|
+
| Custom | `WEBHOOK_SECRET` |
|
|
383
|
+
|
|
384
|
+
**Usage:**
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
export GITHUB_WEBHOOK_SECRET="your-secret-here"
|
|
388
|
+
better-webhook run github-push --url http://localhost:3000/webhooks/github
|
|
389
|
+
# Secret is automatically used for signature generation
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
## Storage Locations
|
|
395
|
+
|
|
396
|
+
All CLI data is stored in `~/.better-webhook/`:
|
|
397
|
+
|
|
398
|
+
```
|
|
399
|
+
~/.better-webhook/
|
|
400
|
+
├── captures/ # Captured webhook requests
|
|
401
|
+
│ ├── 2024-01-15_10-30-00_abc12345.json
|
|
402
|
+
│ └── 2024-01-15_11-00-00_def67890.json
|
|
403
|
+
├── templates/ # Downloaded templates
|
|
404
|
+
│ ├── github/
|
|
405
|
+
│ │ ├── github-push.json
|
|
406
|
+
│ │ └── github-pull_request.json
|
|
407
|
+
│ └── stripe/
|
|
408
|
+
│ └── stripe-invoice.json
|
|
409
|
+
└── templates-cache.json # Template index cache (1 hour TTL)
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## Webhook Template Format
|
|
415
|
+
|
|
416
|
+
Templates follow this JSON schema:
|
|
199
417
|
|
|
200
418
|
```json
|
|
201
419
|
{
|
|
202
|
-
"url": "https://api.
|
|
420
|
+
"url": "https://api.example.com/webhook",
|
|
203
421
|
"method": "POST",
|
|
204
422
|
"headers": [
|
|
205
|
-
{ "key": "
|
|
423
|
+
{ "key": "Content-Type", "value": "application/json" },
|
|
424
|
+
{ "key": "X-Custom-Header", "value": "custom-value" }
|
|
206
425
|
],
|
|
207
426
|
"body": {
|
|
208
|
-
"
|
|
209
|
-
"object": "event",
|
|
210
|
-
"type": "payment_intent.succeeded",
|
|
427
|
+
"event": "user.created",
|
|
211
428
|
"data": {
|
|
212
|
-
"
|
|
213
|
-
|
|
214
|
-
"amount": 2000,
|
|
215
|
-
"currency": "usd",
|
|
216
|
-
"status": "succeeded"
|
|
217
|
-
}
|
|
429
|
+
"id": "12345",
|
|
430
|
+
"email": "user@example.com"
|
|
218
431
|
}
|
|
219
|
-
}
|
|
432
|
+
},
|
|
433
|
+
"provider": "custom",
|
|
434
|
+
"event": "user.created",
|
|
435
|
+
"description": "Triggered when a new user is created"
|
|
220
436
|
}
|
|
221
437
|
```
|
|
222
438
|
|
|
223
|
-
|
|
439
|
+
| Field | Type | Required | Description |
|
|
440
|
+
| ------------- | ------ | -------- | --------------------------------------------------- |
|
|
441
|
+
| `url` | string | — | Default target URL (can be overridden with `--url`) |
|
|
442
|
+
| `method` | string | — | HTTP method (default: `POST`) |
|
|
443
|
+
| `headers` | array | — | Array of `{ key, value }` header objects |
|
|
444
|
+
| `body` | any | — | Request payload (object or string) |
|
|
445
|
+
| `provider` | string | — | Provider name for signature generation |
|
|
446
|
+
| `event` | string | — | Event type identifier |
|
|
447
|
+
| `description` | string | — | Human-readable description |
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
## Captured Webhook Format
|
|
452
|
+
|
|
453
|
+
Captured webhooks are stored with full request details:
|
|
224
454
|
|
|
225
455
|
```json
|
|
226
456
|
{
|
|
227
|
-
"
|
|
457
|
+
"id": "550e8400-e29b-41d4-a716-446655440000",
|
|
458
|
+
"timestamp": "2024-01-15T10:30:00.000Z",
|
|
228
459
|
"method": "POST",
|
|
229
|
-
"
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
"
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
]
|
|
245
|
-
}
|
|
460
|
+
"url": "/webhooks/github?action=opened",
|
|
461
|
+
"path": "/webhooks/github",
|
|
462
|
+
"headers": {
|
|
463
|
+
"content-type": "application/json",
|
|
464
|
+
"x-github-event": "push",
|
|
465
|
+
"x-hub-signature-256": "sha256=..."
|
|
466
|
+
},
|
|
467
|
+
"body": { "...parsed JSON..." },
|
|
468
|
+
"rawBody": "{...original string...}",
|
|
469
|
+
"query": { "action": "opened" },
|
|
470
|
+
"provider": "github",
|
|
471
|
+
"contentType": "application/json",
|
|
472
|
+
"contentLength": 1234
|
|
246
473
|
}
|
|
247
474
|
```
|
|
248
475
|
|
|
249
|
-
|
|
476
|
+
---
|
|
250
477
|
|
|
251
|
-
|
|
478
|
+
## Use Cases
|
|
479
|
+
|
|
480
|
+
### Local Development
|
|
252
481
|
|
|
253
|
-
|
|
254
|
-
- **1**: General error (network, validation, file not found)
|
|
482
|
+
Test your webhook endpoints during development:
|
|
255
483
|
|
|
256
484
|
```bash
|
|
257
|
-
#
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
#
|
|
261
|
-
|
|
485
|
+
# Terminal 1: Start your app
|
|
486
|
+
npm run dev
|
|
487
|
+
|
|
488
|
+
# Terminal 2: Capture webhooks
|
|
489
|
+
better-webhook capture --port 4000
|
|
262
490
|
|
|
263
|
-
#
|
|
264
|
-
|
|
265
|
-
|
|
491
|
+
# Configure your webhook provider to send to http://localhost:4000
|
|
492
|
+
# (use ngrok for external providers: ngrok http 4000)
|
|
493
|
+
|
|
494
|
+
# Terminal 3: Replay captured webhooks to your app
|
|
495
|
+
better-webhook replay abc123 http://localhost:3000/api/webhooks
|
|
266
496
|
```
|
|
267
497
|
|
|
268
|
-
|
|
498
|
+
### Debugging Webhook Issues
|
|
269
499
|
|
|
270
|
-
|
|
500
|
+
```bash
|
|
501
|
+
# Capture the problematic webhook
|
|
502
|
+
better-webhook capture
|
|
271
503
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
| `WEBHOOKS_DIR` | Directory for webhook definitions | `.webhooks` |
|
|
275
|
-
| `CAPTURES_DIR` | Directory for captured webhooks | `.webhook-captures` |
|
|
504
|
+
# Inspect the full request
|
|
505
|
+
better-webhook captures show abc123 --body
|
|
276
506
|
|
|
277
|
-
|
|
507
|
+
# Replay to your local server with verbose output
|
|
508
|
+
better-webhook replay abc123 http://localhost:3000/webhooks --verbose
|
|
509
|
+
```
|
|
278
510
|
|
|
279
|
-
|
|
280
|
-
| ----------- | ------------------------ |
|
|
281
|
-
| `--help` | Show help information |
|
|
282
|
-
| `--version` | Show version information |
|
|
511
|
+
### Testing Signature Verification
|
|
283
512
|
|
|
284
|
-
|
|
513
|
+
```bash
|
|
514
|
+
# Run a template with your production secret
|
|
515
|
+
better-webhook run stripe-invoice.payment_succeeded \
|
|
516
|
+
--url http://localhost:3000/api/webhooks/stripe \
|
|
517
|
+
--secret "whsec_your_stripe_secret" \
|
|
518
|
+
--verbose
|
|
519
|
+
```
|
|
285
520
|
|
|
286
|
-
|
|
521
|
+
### CI/CD Integration
|
|
522
|
+
|
|
523
|
+
```bash
|
|
524
|
+
# Test webhook endpoints in your pipeline
|
|
525
|
+
better-webhook templates download github-push
|
|
526
|
+
better-webhook run github-push \
|
|
527
|
+
--url "$TEST_ENDPOINT" \
|
|
528
|
+
--secret "$GITHUB_WEBHOOK_SECRET"
|
|
529
|
+
|
|
530
|
+
# Check exit code
|
|
531
|
+
if [ $? -eq 0 ]; then
|
|
532
|
+
echo "Webhook test passed"
|
|
533
|
+
fi
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
---
|
|
537
|
+
|
|
538
|
+
## WebSocket API
|
|
539
|
+
|
|
540
|
+
The capture server exposes a WebSocket endpoint on the same port for real-time notifications:
|
|
541
|
+
|
|
542
|
+
```javascript
|
|
543
|
+
const ws = new WebSocket("ws://localhost:3001");
|
|
544
|
+
|
|
545
|
+
ws.onmessage = (event) => {
|
|
546
|
+
const message = JSON.parse(event.data);
|
|
547
|
+
|
|
548
|
+
switch (message.type) {
|
|
549
|
+
case "capture":
|
|
550
|
+
console.log("New capture:", message.payload.capture);
|
|
551
|
+
break;
|
|
552
|
+
case "captures_updated":
|
|
553
|
+
console.log("Captures list:", message.payload.captures);
|
|
554
|
+
break;
|
|
555
|
+
}
|
|
556
|
+
};
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
**Message Types:**
|
|
287
560
|
|
|
288
|
-
|
|
561
|
+
| Type | Description | Payload |
|
|
562
|
+
| ------------------ | --------------------------- | --------------------- |
|
|
563
|
+
| `capture` | New webhook captured | `{ file, capture }` |
|
|
564
|
+
| `captures_updated` | Initial state on connection | `{ captures, count }` |
|
|
565
|
+
|
|
566
|
+
---
|
|
567
|
+
|
|
568
|
+
## Error Handling
|
|
569
|
+
|
|
570
|
+
The CLI uses standard exit codes:
|
|
571
|
+
|
|
572
|
+
| Code | Description |
|
|
573
|
+
| ---- | ------------------------------------------------- |
|
|
574
|
+
| `0` | Success |
|
|
575
|
+
| `1` | Error (validation, network, file not found, etc.) |
|
|
576
|
+
|
|
577
|
+
Detailed error messages are displayed in the terminal:
|
|
578
|
+
|
|
579
|
+
```bash
|
|
580
|
+
better-webhook run nonexistent-template --url http://localhost:3000
|
|
581
|
+
# ❌ Template not found: nonexistent-template
|
|
582
|
+
# Download it with: better-webhook templates download nonexistent-template
|
|
583
|
+
|
|
584
|
+
better-webhook capture --port 99999
|
|
585
|
+
# Invalid port number
|
|
586
|
+
|
|
587
|
+
better-webhook replay abc123 invalid-url
|
|
588
|
+
# Please enter a valid URL
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
---
|
|
592
|
+
|
|
593
|
+
## Development
|
|
594
|
+
|
|
595
|
+
### Building from Source
|
|
289
596
|
|
|
290
597
|
```bash
|
|
291
598
|
git clone https://github.com/endalk200/better-webhook.git
|
|
@@ -294,15 +601,22 @@ pnpm install
|
|
|
294
601
|
pnpm --filter @better-webhook/cli build
|
|
295
602
|
```
|
|
296
603
|
|
|
297
|
-
### Running
|
|
604
|
+
### Running Locally
|
|
298
605
|
|
|
299
606
|
```bash
|
|
300
|
-
|
|
607
|
+
cd apps/webhook-cli
|
|
608
|
+
pnpm start -- capture --port 3001
|
|
301
609
|
```
|
|
302
610
|
|
|
611
|
+
---
|
|
612
|
+
|
|
613
|
+
## Contributing
|
|
614
|
+
|
|
615
|
+
We welcome contributions! Please see our [Contributing Guide](https://github.com/endalk200/better-webhook/blob/main/CONTRIBUTING.md) for details.
|
|
616
|
+
|
|
303
617
|
## Changelog
|
|
304
618
|
|
|
305
|
-
See [CHANGELOG.md](
|
|
619
|
+
See [CHANGELOG.md](./CHANGELOG.md) for version history.
|
|
306
620
|
|
|
307
621
|
## License
|
|
308
622
|
|
|
@@ -313,8 +627,3 @@ MIT © [Endalk](https://github.com/endalk200)
|
|
|
313
627
|
- 🐛 [Report bugs](https://github.com/endalk200/better-webhook/issues)
|
|
314
628
|
- 💡 [Request features](https://github.com/endalk200/better-webhook/issues)
|
|
315
629
|
- 📖 [Documentation](https://github.com/endalk200/better-webhook#readme)
|
|
316
|
-
|
|
317
|
-
---
|
|
318
|
-
|
|
319
|
-
Made with ❤️ by [Endalk](https://github.com/endalk200)
|
|
320
|
-
|