@postman/postman-plugin 0.3.0 → 0.4.1-rc.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 +46 -9
- package/dist/hosts/antigravity.js +47 -0
- package/dist/hosts/codex-hooks.js +68 -0
- package/dist/hosts/codex.js +87 -8
- package/dist/hosts/copilot.js +60 -0
- package/dist/hosts/index.js +3 -1
- package/dist/json-rpc.js +113 -0
- package/dist/system.js +40 -3
- package/mcp.pi.json +2 -2
- package/package.json +1 -1
- package/skills/ai-readiness/SKILL.md +40 -44
- package/skills/api-discovery/SKILL.md +64 -145
- package/skills/api-discovery/reference/orbit.md +17 -5
- package/skills/api-documentation/SKILL.md +41 -46
- package/skills/api-engineer/SKILL.md +78 -23
- package/skills/api-mocking/SKILL.md +117 -163
- package/skills/api-monitoring/SKILL.md +52 -129
- package/skills/api-simulation/SKILL.md +130 -178
- package/skills/api-simulation/reference/sim_yaml_schema.md +41 -103
- package/skills/api-testing/SKILL.md +48 -95
- package/skills/bootstrap/SKILL.md +123 -224
- package/skills/ci-integration/SKILL.md +53 -113
- package/skills/collection-schema-v3/SKILL.md +43 -204
- package/skills/collection-schema-v3/reference/http.md +150 -0
- package/skills/datasets/SKILL.md +89 -315
- package/skills/datasets/reference/spreadsheets.md +25 -0
- package/skills/flows/SKILL.md +57 -206
- package/skills/flows/reference/flow_cli_flags.md +3 -2
- package/skills/performance-testing/SKILL.md +46 -62
- package/skills/performance-testing/references/jmeter-import/README.md +82 -0
- package/skills/performance-testing/references/jmeter-import/import-report.md +52 -0
- package/skills/performance-testing/references/jmeter-import/mapping-table.md +95 -0
- package/skills/performance-testing/references/jmeter-import/postman-perf-capabilities.md +56 -0
- package/skills/performance-testing/references/jmeter-import/script-translation.md +97 -0
- package/skills/postman-mcp-server/SKILL.md +53 -59
- package/skills/postman-mcp-server/references/docs.md +0 -1
- package/skills/postman-mcp-server/references/learn.md +10 -9
- package/skills/postman-mcp-server/references/mock.md +0 -1
- package/skills/postman-mcp-server/references/search.md +0 -1
- package/skills/postman-mcp-server/references/security.md +0 -1
- package/skills/postman-mcp-server/references/setup.md +0 -1
- package/skills/postman-mcp-server/references/sync.md +0 -1
- package/skills/postman-mcp-server/references/test.md +0 -1
- package/skills/variables/SKILL.md +44 -87
- package/skills/webhook-testing/SKILL.md +103 -0
- package/skills/webhook-testing/reference/forwarding.md +10 -0
- package/skills/webhook-testing/reference/outbound_webhooks.md +25 -0
- package/skills/webhook-testing/reference/webhook_scripts.md +163 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: webhook-testing
|
|
3
|
+
description: Capture, forward to localhost, replay, and validate webhook deliveries using a reusable public URL. Keep sender configuration across debugging sessions and record arrivals even while local forwarding is stopped, helping distinguish delivery failures from local connectivity issues. Use for implementing or debugging incoming handlers and testing webhooks an API sends, whether or not Postman is mentioned. Example requests include "get payment events to localhost," "inspect a webhook delivery," and "replay an event after a fix"; these illustrate intent, not an exhaustive list or exact phrases to match.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Webhook Testing
|
|
7
|
+
|
|
8
|
+
`postman webhook` gives a sender a hosted URL,
|
|
9
|
+
`https://<webhookId>.webhook.pstmn.io`, that records every request it gets,
|
|
10
|
+
with the raw headers and body as they were sent, and forwards each one to a
|
|
11
|
+
port on this machine. You don't need a separate tunnel. Two properties shape
|
|
12
|
+
how to use it:
|
|
13
|
+
|
|
14
|
+
- **Reuse the URL across debugging sessions.** It survives new sessions, pause
|
|
15
|
+
and start, so the sender is registered once. Reuse a webhook when the user
|
|
16
|
+
names one or says the sender already posts to one. Use `list` to resolve that
|
|
17
|
+
reference; ask only if the available context still leaves multiple plausible choices.
|
|
18
|
+
Create a new one when a new endpoint is needed. Each new webhook is another
|
|
19
|
+
URL to register and a second event history.
|
|
20
|
+
- **Every request is recorded,** including requests that arrive while nothing
|
|
21
|
+
is forwarding. `requests describe` shows a delivery exactly as it was sent.
|
|
22
|
+
After a fix, `requests replay` sends it again, so you don't need the sender
|
|
23
|
+
to fire it again.
|
|
24
|
+
|
|
25
|
+
The command is singular, and every subcommand needs a signed-in session. Run what you need,
|
|
26
|
+
and read `bootstrap` only if a command fails with a setup error such as `Authentication required`.
|
|
27
|
+
When all you have is the URL, its subdomain is the webhook id.
|
|
28
|
+
|
|
29
|
+
For capture or inspection alone, create or reuse a webhook and inspect its
|
|
30
|
+
recorded requests; no local service or forwarding to a local port is needed.
|
|
31
|
+
|
|
32
|
+
Use replays and [scripts](reference/webhook_scripts.md) to validate incoming events.
|
|
33
|
+
|
|
34
|
+
## Get a sender reaching localhost
|
|
35
|
+
|
|
36
|
+
When the task is to reach a local handler, check the path from the public URL
|
|
37
|
+
meant to be forwarded to the local service:
|
|
38
|
+
|
|
39
|
+
1. **Make sure the route exists.** A URL that forwards to a local service with no
|
|
40
|
+
matching route only ever returns 404. Check the local service for a handler for
|
|
41
|
+
this event. Add a missing handler when implementing the receiver is part
|
|
42
|
+
of the task. Senders retry, and replay re-sends an identical request, so
|
|
43
|
+
deduplicate using the sender's stable event identifier where available.
|
|
44
|
+
Acknowledge valid, authenticated events that the handler intentionally
|
|
45
|
+
ignores with a 2xx to avoid unnecessary retries; malformed or
|
|
46
|
+
unauthenticated requests still need rejection.
|
|
47
|
+
2. **Reuse the existing webhook or create a new endpoint.** To create one,
|
|
48
|
+
use `postman webhook create --title <name>`. When a new endpoint is clearly
|
|
49
|
+
needed, creating it directly avoids an unnecessary discovery step.
|
|
50
|
+
3. **Start the local service, then forward to its port** with
|
|
51
|
+
`postman webhook forward <webhookId> <port>`. `forward` runs until it's
|
|
52
|
+
stopped, so run it in the background. For stopping the forwarding process,
|
|
53
|
+
see [Forwarding lifecycle](reference/forwarding.md).
|
|
54
|
+
4. **Send one request to the URL, at the route's path.** Check that a 2xx came
|
|
55
|
+
back and that the handler logged the request. `requests list` shows whether
|
|
56
|
+
the request reached the webhook at all, which separates a wrong URL from a
|
|
57
|
+
forwarding or routing problem.
|
|
58
|
+
|
|
59
|
+
For a connectivity task, one successful probe demonstrates that the tested
|
|
60
|
+
path reaches the handler. Sender compatibility and handler correctness need
|
|
61
|
+
evidence from actual sender deliveries and relevant scenarios.
|
|
62
|
+
|
|
63
|
+
## Gotchas / Notes
|
|
64
|
+
|
|
65
|
+
- **Build the webhook script's test event from the sender's contract, not from your handler.**
|
|
66
|
+
A payload written to match the handler you just wrote only proves the two
|
|
67
|
+
agree with each other. Take it from the sender's documented event schema.
|
|
68
|
+
Better, use a real delivery: send one from the sender's test mode (such as
|
|
69
|
+
`stripe trigger <event>` or a GitHub redelivery), then replay that recorded
|
|
70
|
+
request as you iterate.
|
|
71
|
+
- **A permission error needs workspace context.** Check the selected workspace
|
|
72
|
+
and the account's access. A cloned repository may point to a workspace this
|
|
73
|
+
account cannot use. If the intended accessible workspace is known, pass
|
|
74
|
+
`-w`; otherwise ask which workspace to use. Creating another workspace does
|
|
75
|
+
not grant access to the existing one.
|
|
76
|
+
- **Some old signed events fail verification on replay, by design.** Stripe
|
|
77
|
+
(`t=` in `Stripe-Signature`) and Slack (`X-Slack-Request-Timestamp`) sign a
|
|
78
|
+
timestamp, and their SDKs reject one older than about five minutes.
|
|
79
|
+
Send a fresh event instead of loosening verification. GitHub's signature has no
|
|
80
|
+
timestamp, so its replays still verify.
|
|
81
|
+
- **Confirm before `delete`.** It's permanent, and a sender still registered
|
|
82
|
+
to the URL starts failing. Replay also reaches application code, so account
|
|
83
|
+
for the handler's side effects when choosing which delivery to resend.
|
|
84
|
+
|
|
85
|
+
## Handing over
|
|
86
|
+
|
|
87
|
+
For endpoint setup, leave the webhook active so the user can point a sender
|
|
88
|
+
at it. For a completed investigation, choose the final state based on whether
|
|
89
|
+
the sender still needs the endpoint. Forwarding stops when the `forward`
|
|
90
|
+
process does; while the webhook remains active, arrivals are recorded and
|
|
91
|
+
can be replayed. Give the user:
|
|
92
|
+
|
|
93
|
+
- the URL with the route's path;
|
|
94
|
+
- for local forwarding, the two commands that start the loop again: start
|
|
95
|
+
the local service, then `postman webhook forward <webhookId> <port>`;
|
|
96
|
+
- any changes made to the local service;
|
|
97
|
+
- what was verified: the captured delivery or the response and handler receipt
|
|
98
|
+
for a forwarding test.
|
|
99
|
+
|
|
100
|
+
To validate deliveries automatically with a `pm.test` script, see
|
|
101
|
+
[reference/webhook_scripts.md](reference/webhook_scripts.md). To test the
|
|
102
|
+
webhooks your own API sends, with a Postman webhook as the subscriber, see
|
|
103
|
+
[reference/outbound_webhooks.md](reference/outbound_webhooks.md).
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Forwarding lifecycle
|
|
2
|
+
|
|
3
|
+
`postman webhook forward <webhookId> <port>` runs until stopped. To stop a
|
|
4
|
+
background forwarding process, use
|
|
5
|
+
`pkill -INT -f "webhook forward <webhookId>"`. `kill $!` may reach only the
|
|
6
|
+
`postman` launcher and leave forwarding running.
|
|
7
|
+
|
|
8
|
+
Stopping forwarding leaves the webhook available to record deliveries. Start
|
|
9
|
+
forwarding again when the local service is ready, then replay a captured
|
|
10
|
+
request when the task needs it.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Testing the webhooks your API sends
|
|
2
|
+
|
|
3
|
+
Here the Postman webhook stands in for a subscriber. Create one with
|
|
4
|
+
`postman webhook create`, then register its URL as the subscriber endpoint in
|
|
5
|
+
your app, through its config or your subscription API. Trigger the action that
|
|
6
|
+
emits the event, with `postman request` or a collection that already covers it
|
|
7
|
+
(see the `api-testing` skill). Find the delivery with `requests list` and read
|
|
8
|
+
it with `requests describe`.
|
|
9
|
+
|
|
10
|
+
Check the delivery against the event contract you publish:
|
|
11
|
+
|
|
12
|
+
- the event type and the body's shape;
|
|
13
|
+
- the signature header, recomputed from the raw body with the secret your
|
|
14
|
+
subscriber holds;
|
|
15
|
+
- the delivery or idempotency id, which should be unique per event and stay
|
|
16
|
+
the same across retries.
|
|
17
|
+
|
|
18
|
+
Put those checks in an `onEvent` script so each delivery gets a test report;
|
|
19
|
+
see [webhook_scripts.md](webhook_scripts.md). Its last section covers checking
|
|
20
|
+
your own signature scheme.
|
|
21
|
+
|
|
22
|
+
To test retries, the subscriber has to fail. Either set the webhook's routing to
|
|
23
|
+
respond with a 5xx in the Postman app (routing isn't a CLI command), or forward
|
|
24
|
+
to a local endpoint that returns one. Check that `requests list` records the
|
|
25
|
+
failing response status before you read the repeated deliveries as retries.
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Webhook scripts
|
|
2
|
+
|
|
3
|
+
Recipes for the `onEvent` script that `postman webhook scripts set` uploads.
|
|
4
|
+
Each delivery runs the script in a fresh Postman sandbox, with the incoming
|
|
5
|
+
request in `pm.request`. `pm.test` results appear in
|
|
6
|
+
`postman webhook requests describe <webhookId> <requestId>`, and the
|
|
7
|
+
`console.log` output appears with `--verbose`.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
postman webhook scripts set <webhookId> ./webhooks/github-on-event.js --event onEvent
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Contents
|
|
14
|
+
|
|
15
|
+
- [How webhook scripts behave](#how-webhook-scripts-behave)
|
|
16
|
+
- [What a script can use](#what-a-script-can-use)
|
|
17
|
+
- [Asserting on the payload](#asserting-on-the-payload)
|
|
18
|
+
- [Signature checks](#signature-checks): GitHub, Stripe, Slack, any HMAC
|
|
19
|
+
|
|
20
|
+
## How webhook scripts behave
|
|
21
|
+
|
|
22
|
+
- **`onEvent`** runs when a request arrives, before Postman forwards or
|
|
23
|
+
responds. Use it to validate the payload, verify the signature, or modify
|
|
24
|
+
the request. **`onResponse`** runs after Postman has responded to the
|
|
25
|
+
sender. Use it for logging and follow-up work from your local responder
|
|
26
|
+
or the configured forwarding endpoint.
|
|
27
|
+
- **The file in the repo is the only copy you can read.** The CLI has
|
|
28
|
+
`scripts set` but no command that reads a script back, and a second `set`
|
|
29
|
+
replaces the first. Commit the script beside the handler it guards, and set
|
|
30
|
+
it again after you edit it. The file can be JavaScript or TypeScript.
|
|
31
|
+
- **No state carries over between deliveries.** A script can't remember which
|
|
32
|
+
event ids it has already seen, so test duplicate handling in the handler, by
|
|
33
|
+
replaying a request twice.
|
|
34
|
+
- **Secrets come from the linked environment.** Read a signing secret with
|
|
35
|
+
`pm.environment.get` and never write it into the file. An environment is
|
|
36
|
+
linked to a webhook in its settings in the Postman app. See the `variables`
|
|
37
|
+
skill for where a secret belongs.
|
|
38
|
+
- **Results are per delivery.** The console output that `--verbose` shows is
|
|
39
|
+
capped at 25 KB per event.
|
|
40
|
+
- **A script is a test, not your handler's guard.** Postman doesn't document
|
|
41
|
+
that a failing `pm.test` stops the request from being routed. Your handler
|
|
42
|
+
verifies signatures itself, whatever the script reports.
|
|
43
|
+
|
|
44
|
+
## What a script can use
|
|
45
|
+
|
|
46
|
+
| Available | Not available |
|
|
47
|
+
| --- | --- |
|
|
48
|
+
| `pm.request.headers.get(name)`, `pm.request.body.raw` | `pm.globals`, `pm.collectionVariables`, `pm.iterationData` |
|
|
49
|
+
| `pm.test`, `pm.expect` | `pm.execution.setNextRequest`, `pm.visualizer` |
|
|
50
|
+
| `pm.environment.get`, from the environment linked to the webhook | State that lasts beyond one delivery |
|
|
51
|
+
| `require("crypto-js")` and other packages, from the Package Library, npm or JSR | |
|
|
52
|
+
| `pm.execution.runRequest`, to run a saved collection request | |
|
|
53
|
+
|
|
54
|
+
Parse and hash `pm.request.body.raw`. Postman keeps the body exactly as the
|
|
55
|
+
sender sent it, and every signature scheme below is computed over those exact
|
|
56
|
+
bytes. A body that was parsed and serialized again fails the check even when
|
|
57
|
+
the JSON is the same.
|
|
58
|
+
|
|
59
|
+
## Asserting on the payload
|
|
60
|
+
|
|
61
|
+
Write down the contract the handler depends on. A test fails on the first
|
|
62
|
+
delivery that breaks it, instead of when the handler happens to crash.
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
// Just a reference based on expected payload, it can be of a different data type as well.
|
|
66
|
+
const event = JSON.parse(pm.request.body.raw);
|
|
67
|
+
|
|
68
|
+
pm.test("is a JSON event with an id and a type", function () {
|
|
69
|
+
pm.expect(event).to.have.property("id").that.is.a("string");
|
|
70
|
+
pm.expect(event).to.have.property("type").that.is.a("string");
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
pm.test("is an event this handler subscribes to", function () {
|
|
74
|
+
pm.expect(["payment_intent.succeeded", "payment_intent.payment_failed"])
|
|
75
|
+
.to.include(event.type);
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Signature checks
|
|
80
|
+
|
|
81
|
+
Postman also has signature-verification presets for Stripe, GitHub and Slack
|
|
82
|
+
in the Postman app. Use a script when you want the check in a file that can be
|
|
83
|
+
reviewed, or when the provider has no preset. Read the secret from the linked
|
|
84
|
+
environment. A secret pasted into the script ends up in the repo and in the
|
|
85
|
+
webhook's configuration.
|
|
86
|
+
|
|
87
|
+
### GitHub
|
|
88
|
+
|
|
89
|
+
`X-Hub-Signature-256` is `sha256=` followed by the hex HMAC-SHA256 of the raw
|
|
90
|
+
body. There's no timestamp, so a replayed delivery still verifies.
|
|
91
|
+
|
|
92
|
+
```javascript
|
|
93
|
+
const CryptoJS = require("crypto-js");
|
|
94
|
+
|
|
95
|
+
const secret = pm.environment.get("github_webhook_secret");
|
|
96
|
+
const expected = "sha256=" +
|
|
97
|
+
CryptoJS.HmacSHA256(pm.request.body.raw, secret).toString(CryptoJS.enc.Hex);
|
|
98
|
+
|
|
99
|
+
pm.test("GitHub signature matches the body", function () {
|
|
100
|
+
pm.expect(pm.request.headers.get("X-Hub-Signature-256")).to.equal(expected);
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Stripe
|
|
105
|
+
|
|
106
|
+
`Stripe-Signature` is `t=<unix seconds>,v1=<hex>[,v1=<hex>…]`. Stripe signs
|
|
107
|
+
`<t>.<raw body>` with the endpoint's whole `whsec_…` secret, prefix included.
|
|
108
|
+
More than one `v1` appears while a secret is being rolled, and any one of them
|
|
109
|
+
can match.
|
|
110
|
+
|
|
111
|
+
```javascript
|
|
112
|
+
const CryptoJS = require("crypto-js");
|
|
113
|
+
|
|
114
|
+
const secret = pm.environment.get("stripe_webhook_secret");
|
|
115
|
+
const fields = pm.request.headers.get("Stripe-Signature").split(",");
|
|
116
|
+
const t = fields.find(f => f.startsWith("t=")).slice(2);
|
|
117
|
+
const signatures = fields.filter(f => f.startsWith("v1=")).map(f => f.slice(3));
|
|
118
|
+
const expected = CryptoJS.HmacSHA256(t + "." + pm.request.body.raw, secret)
|
|
119
|
+
.toString(CryptoJS.enc.Hex);
|
|
120
|
+
|
|
121
|
+
pm.test("Stripe signature matches the body", function () {
|
|
122
|
+
pm.expect(signatures).to.include(expected);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
pm.test("Stripe timestamp is within five minutes", function () {
|
|
126
|
+
pm.expect(Math.abs(Date.now() / 1000 - Number(t))).to.be.below(300);
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The timestamp test fails on a replay of anything older than five minutes. That
|
|
131
|
+
failure is expected and doesn't mean the replay is broken.
|
|
132
|
+
|
|
133
|
+
### Slack
|
|
134
|
+
|
|
135
|
+
Slack signs `v0:<X-Slack-Request-Timestamp>:<raw body>` with the app's signing
|
|
136
|
+
secret and sends `X-Slack-Signature: v0=<hex>`.
|
|
137
|
+
|
|
138
|
+
```javascript
|
|
139
|
+
const CryptoJS = require("crypto-js");
|
|
140
|
+
|
|
141
|
+
const secret = pm.environment.get("slack_signing_secret");
|
|
142
|
+
const ts = pm.request.headers.get("X-Slack-Request-Timestamp");
|
|
143
|
+
const expected = "v0=" +
|
|
144
|
+
CryptoJS.HmacSHA256("v0:" + ts + ":" + pm.request.body.raw, secret)
|
|
145
|
+
.toString(CryptoJS.enc.Hex);
|
|
146
|
+
|
|
147
|
+
pm.test("Slack signature matches the body", function () {
|
|
148
|
+
pm.expect(pm.request.headers.get("X-Slack-Signature")).to.equal(expected);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
pm.test("Slack timestamp is within five minutes", function () {
|
|
152
|
+
pm.expect(Math.abs(Date.now() / 1000 - Number(ts))).to.be.below(300);
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Any other HMAC scheme, including your own API's
|
|
157
|
+
|
|
158
|
+
Start from the provider's documentation, or your own if you're checking the
|
|
159
|
+
webhooks your API sends. Find out three things: which header carries the
|
|
160
|
+
signature and any prefix it uses, exactly which bytes are signed (the body
|
|
161
|
+
alone, or a timestamp or id joined to it), and whether the result is hex or
|
|
162
|
+
base64. A mismatch is nearly always one of those three. Use
|
|
163
|
+
`CryptoJS.enc.Base64` in place of `CryptoJS.enc.Hex` for a base64 signature.
|