@distyra/sdk 0.6.0 → 0.7.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 CHANGED
@@ -77,6 +77,43 @@ Note: `resolution.retryable` is a different signal. It is `true` only for a tran
77
77
  backend error (`timed_out` / `transient_error`), which you retry within seconds. See the
78
78
  full resolution-and-retries guide at <https://api.distyra.com/docs>.
79
79
 
80
+ ## Verifying webhooks
81
+
82
+ Distyra signs every webhook delivery with a Stripe-shape header:
83
+
84
+ ```
85
+ X-Distyra-Signature: t=<unix>,v1=<hmac_sha256_hex>
86
+ ```
87
+
88
+ `verifyWebhook` checks it (HMAC-SHA256 over `"<t>.<rawBody>"`, keyed by the
89
+ endpoint's signing secret, with replay protection). Always verify against the
90
+ **raw request body**, before JSON parsing — re-serializing changes the bytes and
91
+ breaks the signature.
92
+
93
+ ```ts
94
+ import { verifyWebhook } from '@distyra/sdk';
95
+
96
+ // Express — capture the raw body, e.g. app.use(express.raw({ type: 'application/json' }))
97
+ app.post('/webhooks/distyra', (req, res) => {
98
+ const raw = req.body.toString('utf8');
99
+ const result = verifyWebhook(
100
+ process.env.DISTYRA_WEBHOOK_SECRET!,
101
+ raw,
102
+ req.header('X-Distyra-Signature'),
103
+ );
104
+ if (!result.ok) return res.status(400).send(result.reason);
105
+
106
+ const event = JSON.parse(raw);
107
+ // ... handle event ...
108
+ res.sendStatus(200);
109
+ });
110
+ ```
111
+
112
+ It returns `{ ok: true, timestamp }` or `{ ok: false, reason }` where `reason` is
113
+ `'malformed'`, `'stale'`, or `'no_match'`. The default replay window is 5 minutes
114
+ (`DEFAULT_TOLERANCE_SECONDS`); override it with `{ toleranceSeconds }`. Uses
115
+ `node:crypto`, so it runs server-side (Node 18+).
116
+
80
117
  ## Lower-level access
81
118
 
82
119
  The generated `paths` and `operations` types are re-exported if you want to build your own `openapi-fetch` client or reference response shapes directly: