@pague-dev/sdk-node 0.1.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.
@@ -0,0 +1,437 @@
1
+ //#region src/charges/interfaces/charge.interface.d.ts
2
+ type ChargeStatus = 'active' | 'expired' | 'disabled' | 'paid';
3
+ type PaymentMethod = 'pix' | 'credit_card' | 'boleto';
4
+ type NotificationType = 'email';
5
+ interface Charge {
6
+ id: string;
7
+ projectId: string;
8
+ customerId?: string;
9
+ name: string;
10
+ description?: string;
11
+ amount: number;
12
+ currency: string;
13
+ status: ChargeStatus;
14
+ slug: string;
15
+ url: string;
16
+ paymentMethods: PaymentMethod[];
17
+ maxInstallments?: number;
18
+ notifications: NotificationType[];
19
+ allowCoupons: boolean;
20
+ expiresAt?: string;
21
+ paymentsCount: number;
22
+ totalCollected: number;
23
+ createdAt: string;
24
+ updatedAt?: string;
25
+ }
26
+ //#endregion
27
+ //#region src/interfaces.d.ts
28
+ type Response<T> = {
29
+ data: T;
30
+ error: null;
31
+ } | {
32
+ data: null;
33
+ error: ErrorResponse;
34
+ };
35
+ interface ErrorResponse {
36
+ statusCode: number | null;
37
+ error: string;
38
+ message: string;
39
+ details?: Record<string, unknown>;
40
+ timestamp?: string;
41
+ traceId?: string;
42
+ }
43
+ interface PaginatedResponse<T> {
44
+ items: T[];
45
+ total: number;
46
+ page: number;
47
+ limit: number;
48
+ totalPages: number;
49
+ }
50
+ interface PaginationOptions {
51
+ page?: number;
52
+ limit?: number;
53
+ }
54
+ interface GetOptions {
55
+ query?: Record<string, unknown>;
56
+ }
57
+ interface PostOptions {
58
+ query?: Record<string, unknown>;
59
+ }
60
+ //#endregion
61
+ //#region src/charges/interfaces/create-charge.interface.d.ts
62
+ interface CreateChargeOptions {
63
+ projectId: string;
64
+ name: string;
65
+ description?: string;
66
+ amount: number;
67
+ paymentMethods: PaymentMethod[];
68
+ expiresAt?: string;
69
+ customerId?: string;
70
+ }
71
+ type CreateChargeResponse = Response<Charge>;
72
+ //#endregion
73
+ //#region src/charges/interfaces/get-charge.interface.d.ts
74
+ type GetChargeResponse = Response<Charge>;
75
+ //#endregion
76
+ //#region src/charges/interfaces/list-charges.interface.d.ts
77
+ interface ListChargesOptions extends PaginationOptions {
78
+ search?: string;
79
+ status?: ChargeStatus;
80
+ projectId?: string;
81
+ }
82
+ type ListChargesResponse = Response<PaginatedResponse<Charge>>;
83
+ //#endregion
84
+ //#region src/customers/interfaces/customer.interface.d.ts
85
+ type DocumentType = 'cpf' | 'cnpj';
86
+ interface Customer {
87
+ id: string;
88
+ name: string;
89
+ email?: string;
90
+ phone?: string;
91
+ documentType: DocumentType;
92
+ document: string;
93
+ createdAt: string;
94
+ }
95
+ //#endregion
96
+ //#region src/customers/interfaces/create-customer.interface.d.ts
97
+ interface CreateCustomerOptions {
98
+ name: string;
99
+ document: string;
100
+ email?: string;
101
+ phone?: string;
102
+ }
103
+ type CreateCustomerResponse = Response<Customer>;
104
+ //#endregion
105
+ //#region src/customers/interfaces/list-customers.interface.d.ts
106
+ interface ListCustomersOptions extends PaginationOptions {
107
+ search?: string;
108
+ }
109
+ type ListCustomersResponse = Response<PaginatedResponse<Customer>>;
110
+ //#endregion
111
+ //#region src/common/base-resource.d.ts
112
+ /**
113
+ * Base class for API resources that follow CRUD patterns.
114
+ * Provides common create, list, and get operations.
115
+ */
116
+ declare abstract class BaseResource<TEntity, TCreateOptions = never, TListOptions extends object = object> {
117
+ protected readonly pdev: Pdev;
118
+ protected abstract readonly endpoint: string;
119
+ constructor(pdev: Pdev);
120
+ /**
121
+ * Create a new entity
122
+ */
123
+ create(options: TCreateOptions): Promise<Response<TEntity>>;
124
+ /**
125
+ * List entities with pagination
126
+ */
127
+ list(options?: TListOptions): Promise<Response<PaginatedResponse<TEntity>>>;
128
+ /**
129
+ * Get a single entity by ID
130
+ */
131
+ get(id: string): Promise<Response<TEntity>>;
132
+ }
133
+ /**
134
+ * Base class for resources that only support create operations
135
+ */
136
+ declare abstract class CreateOnlyResource<TEntity, TCreateOptions> {
137
+ protected readonly pdev: Pdev;
138
+ protected abstract readonly endpoint: string;
139
+ constructor(pdev: Pdev);
140
+ create(options: TCreateOptions): Promise<Response<TEntity>>;
141
+ }
142
+ /**
143
+ * Base class for resources that only support get operations
144
+ */
145
+ declare abstract class GetOnlyResource<TEntity> {
146
+ protected readonly pdev: Pdev;
147
+ protected abstract readonly endpoint: string;
148
+ constructor(pdev: Pdev);
149
+ get(id: string): Promise<Response<TEntity>>;
150
+ }
151
+ //#endregion
152
+ //#region src/charges/charges.d.ts
153
+ declare class Charges extends BaseResource<Charge, CreateChargeOptions, ListChargesOptions> {
154
+ protected readonly endpoint = "/charges";
155
+ }
156
+ //#endregion
157
+ //#region src/customers/customers.d.ts
158
+ declare class Customers extends BaseResource<Customer, CreateCustomerOptions, ListCustomersOptions> {
159
+ protected readonly endpoint = "/customers";
160
+ }
161
+ //#endregion
162
+ //#region src/pix/interfaces/pix.interface.d.ts
163
+ type PixStatus = 'pending' | 'completed' | 'failed' | 'cancelled';
164
+ interface PixCharge {
165
+ id: string;
166
+ status: PixStatus;
167
+ amount: number;
168
+ currency: string;
169
+ pixCopyPaste: string;
170
+ expiresAt: string;
171
+ externalReference?: string;
172
+ customerId?: string;
173
+ createdAt: string;
174
+ }
175
+ //#endregion
176
+ //#region src/pix/interfaces/create-pix.interface.d.ts
177
+ interface CreatePixCustomer {
178
+ name: string;
179
+ document: string;
180
+ email?: string;
181
+ phone?: string;
182
+ }
183
+ interface CreatePixOptions {
184
+ amount: number;
185
+ description?: string;
186
+ customerId?: string;
187
+ customer?: CreatePixCustomer;
188
+ projectId?: string;
189
+ expiresIn?: number;
190
+ externalReference?: string;
191
+ metadata?: Record<string, unknown>;
192
+ }
193
+ type CreatePixResponse = Response<PixCharge>;
194
+ //#endregion
195
+ //#region src/pix/pix.d.ts
196
+ declare class Pix extends CreateOnlyResource<PixCharge, CreatePixOptions> {
197
+ protected readonly endpoint = "/pix";
198
+ }
199
+ //#endregion
200
+ //#region src/projects/interfaces/project.interface.d.ts
201
+ interface Project {
202
+ id: string;
203
+ name: string;
204
+ description?: string;
205
+ color: string;
206
+ logoUrl?: string;
207
+ createdAt: string;
208
+ }
209
+ //#endregion
210
+ //#region src/projects/interfaces/create-project.interface.d.ts
211
+ interface CreateProjectOptions {
212
+ name: string;
213
+ description?: string;
214
+ color: string;
215
+ logoUrl?: string;
216
+ }
217
+ type CreateProjectResponse = Response<Project>;
218
+ //#endregion
219
+ //#region src/projects/interfaces/list-projects.interface.d.ts
220
+ type SortBy = 'createdAt' | 'updatedAt' | 'name';
221
+ type SortOrder = 'asc' | 'desc';
222
+ interface ListProjectsOptions extends PaginationOptions {
223
+ sortBy?: SortBy;
224
+ sortOrder?: SortOrder;
225
+ }
226
+ type ListProjectsResponse = Response<PaginatedResponse<Project>>;
227
+ //#endregion
228
+ //#region src/projects/projects.d.ts
229
+ declare class Projects extends BaseResource<Project, CreateProjectOptions, ListProjectsOptions> {
230
+ protected readonly endpoint = "/projects";
231
+ }
232
+ //#endregion
233
+ //#region src/transactions/interfaces/transaction.interface.d.ts
234
+ type TransactionStatus = 'pending' | 'completed' | 'failed' | 'cancelled';
235
+ type TransactionType = 'payment' | 'fee' | 'refund' | 'chargeback' | 'withdrawal';
236
+ type TransactionPaymentMethod = 'pix' | 'credit_card' | 'boleto';
237
+ interface Transaction {
238
+ id: string;
239
+ status: TransactionStatus;
240
+ type: TransactionType;
241
+ paymentMethod: TransactionPaymentMethod;
242
+ amount: number;
243
+ currency: string;
244
+ description?: string;
245
+ externalReference?: string;
246
+ customerId?: string;
247
+ projectId?: string;
248
+ metadata?: Record<string, unknown>;
249
+ pixCopyPaste?: string;
250
+ expiresAt?: string;
251
+ paidAt?: string;
252
+ createdAt: string;
253
+ updatedAt?: string;
254
+ }
255
+ //#endregion
256
+ //#region src/transactions/interfaces/get-transaction.interface.d.ts
257
+ type GetTransactionResponse = Response<Transaction>;
258
+ //#endregion
259
+ //#region src/transactions/transactions.d.ts
260
+ declare class Transactions extends GetOnlyResource<Transaction> {
261
+ protected readonly endpoint = "/transactions";
262
+ }
263
+ //#endregion
264
+ //#region src/pdev.d.ts
265
+ declare class Pdev {
266
+ readonly key: string;
267
+ private readonly baseUrl;
268
+ private readonly headers;
269
+ readonly pix: Pix;
270
+ readonly customers: Customers;
271
+ readonly projects: Projects;
272
+ readonly charges: Charges;
273
+ readonly transactions: Transactions;
274
+ constructor(key?: string);
275
+ post<T>(path: string, body?: unknown, options?: PostOptions): Promise<Response<T>>;
276
+ get<T>(path: string, options?: GetOptions): Promise<Response<T>>;
277
+ private buildUrl;
278
+ private fetchRequest;
279
+ }
280
+ //#endregion
281
+ //#region src/webhooks/interfaces.d.ts
282
+ /**
283
+ * Available webhook event types
284
+ */
285
+ type WebhookEventType = 'payment_completed' | 'payment_failed' | 'refund_completed';
286
+ /**
287
+ * Base webhook payload structure
288
+ */
289
+ interface WebhookPayload<T extends WebhookEventType, D> {
290
+ /** Type of event that triggered the webhook */
291
+ event: T;
292
+ /** Unique event identifier (typically the transaction ID) */
293
+ eventId: string;
294
+ /** ISO 8601 formatted timestamp of when the event occurred */
295
+ timestamp: string;
296
+ /** Event-specific data */
297
+ data: D;
298
+ }
299
+ /**
300
+ * Data payload for payment_completed event
301
+ */
302
+ interface PaymentCompletedData {
303
+ /** Transaction identifier */
304
+ transactionId: string;
305
+ /** Payment amount */
306
+ amount: number;
307
+ /** Platform fees charged */
308
+ feeAmount: number;
309
+ /** Amount received after fees (amount - feeAmount) */
310
+ netAmount: number;
311
+ /** Currency code (e.g., "BRL") */
312
+ currency: string;
313
+ /** Payment method used (e.g., "pix") */
314
+ paymentMethod: string;
315
+ /** Payment status */
316
+ status: 'completed';
317
+ /** ISO 8601 timestamp of when payment was completed */
318
+ completedAt: string;
319
+ }
320
+ /**
321
+ * Data payload for payment_failed event
322
+ */
323
+ interface PaymentFailedData {
324
+ /** Transaction identifier */
325
+ transactionId: string;
326
+ /** Payment amount */
327
+ amount: number;
328
+ /** Currency code (e.g., "BRL") */
329
+ currency: string;
330
+ /** Payment method used (e.g., "pix") */
331
+ paymentMethod: string;
332
+ /** Payment status */
333
+ status: 'failed';
334
+ /** ISO 8601 timestamp of when payment failed */
335
+ failedAt: string;
336
+ /** Reason for failure (e.g., "expired", "insufficient_funds") */
337
+ failureReason: string;
338
+ }
339
+ /**
340
+ * Data payload for refund_completed event
341
+ */
342
+ interface RefundCompletedData {
343
+ /** Refund transaction identifier */
344
+ refundTransactionId: string;
345
+ /** Original payment transaction ID that was refunded */
346
+ originalTransactionId: string;
347
+ /** Refunded amount */
348
+ amount: number;
349
+ /** Fees (typically 0 for refunds) */
350
+ feeAmount: number;
351
+ /** Currency code (e.g., "BRL") */
352
+ currency: string;
353
+ /** Refund status */
354
+ status: 'completed';
355
+ /** ISO 8601 timestamp of when refund was completed */
356
+ refundedAt: string;
357
+ }
358
+ /**
359
+ * Payment completed webhook event
360
+ */
361
+ type PaymentCompletedEvent = WebhookPayload<'payment_completed', PaymentCompletedData>;
362
+ /**
363
+ * Payment failed webhook event
364
+ */
365
+ type PaymentFailedEvent = WebhookPayload<'payment_failed', PaymentFailedData>;
366
+ /**
367
+ * Refund completed webhook event
368
+ */
369
+ type RefundCompletedEvent = WebhookPayload<'refund_completed', RefundCompletedData>;
370
+ /**
371
+ * Union type of all possible webhook events
372
+ */
373
+ type WebhookEvent = PaymentCompletedEvent | PaymentFailedEvent | RefundCompletedEvent;
374
+ /**
375
+ * Webhook headers sent with each request
376
+ */
377
+ interface WebhookHeaders {
378
+ /** HMAC-SHA256 signature of the payload */
379
+ 'x-webhook-signature': string;
380
+ /** Unix timestamp in milliseconds when webhook was sent */
381
+ 'x-webhook-timestamp': string;
382
+ /** Content type (always application/json) */
383
+ 'content-type': string;
384
+ }
385
+ //#endregion
386
+ //#region src/webhooks/verify.d.ts
387
+ /**
388
+ * Parses a webhook payload and returns a type-safe WebhookEvent.
389
+ * Returns null if the payload is invalid.
390
+ *
391
+ * @param payload - The raw request body as a string
392
+ * @returns Parsed WebhookEvent or null if invalid
393
+ *
394
+ * @example
395
+ * ```typescript
396
+ * import { parseWebhook } from 'pague-dev';
397
+ *
398
+ * app.post('/webhook', (req, res) => {
399
+ * // 1. Verify signature first (implement using your framework)
400
+ * // const isValid = verifySignature(req.body, req.headers['x-webhook-signature'], secret);
401
+ *
402
+ * // 2. Parse the webhook payload
403
+ * const event = parseWebhook(req.body);
404
+ *
405
+ * if (!event) {
406
+ * return res.status(400).send('Invalid webhook payload');
407
+ * }
408
+ *
409
+ * // 3. Handle the event with full type safety
410
+ * switch (event.event) {
411
+ * case 'payment_completed':
412
+ * // event.data is PaymentCompletedData
413
+ * console.log('Payment completed:', event.data.transactionId);
414
+ * console.log('Amount:', event.data.amount);
415
+ * console.log('Net amount:', event.data.netAmount);
416
+ * break;
417
+ *
418
+ * case 'payment_failed':
419
+ * // event.data is PaymentFailedData
420
+ * console.log('Payment failed:', event.data.transactionId);
421
+ * console.log('Reason:', event.data.failureReason);
422
+ * break;
423
+ *
424
+ * case 'refund_completed':
425
+ * // event.data is RefundCompletedData
426
+ * console.log('Refund completed:', event.data.refundTransactionId);
427
+ * console.log('Original transaction:', event.data.originalTransactionId);
428
+ * break;
429
+ * }
430
+ *
431
+ * res.status(200).send('OK');
432
+ * });
433
+ * ```
434
+ */
435
+ declare function parseWebhook(payload: string): WebhookEvent | null;
436
+ //#endregion
437
+ export { Charge, ChargeStatus, CreateChargeOptions, CreateChargeResponse, CreateCustomerOptions, CreateCustomerResponse, CreatePixCustomer, CreatePixOptions, CreatePixResponse, CreateProjectOptions, CreateProjectResponse, Customer, DocumentType, type ErrorResponse, GetChargeResponse, GetTransactionResponse, ListChargesOptions, ListChargesResponse, ListCustomersOptions, ListCustomersResponse, ListProjectsOptions, ListProjectsResponse, NotificationType, type PaginatedResponse, type PaginationOptions, PaymentCompletedData, PaymentCompletedEvent, PaymentFailedData, PaymentFailedEvent, PaymentMethod, Pdev, PixCharge, PixStatus, Project, RefundCompletedData, RefundCompletedEvent, type Response, SortBy, SortOrder, Transaction, TransactionPaymentMethod, TransactionStatus, TransactionType, WebhookEvent, WebhookEventType, WebhookHeaders, WebhookPayload, parseWebhook };
package/dist/index.mjs ADDED
@@ -0,0 +1,263 @@
1
+ //#region src/common/utils/build-pagination-query.ts
2
+ function buildPaginationQuery(options) {
3
+ const searchParams = new URLSearchParams();
4
+ for (const [key, value] of Object.entries(options)) if (value !== void 0 && value !== null) searchParams.set(key, String(value));
5
+ return searchParams.toString();
6
+ }
7
+
8
+ //#endregion
9
+ //#region src/common/base-resource.ts
10
+ /**
11
+ * Base class for API resources that follow CRUD patterns.
12
+ * Provides common create, list, and get operations.
13
+ */
14
+ var BaseResource = class {
15
+ constructor(pdev) {
16
+ this.pdev = pdev;
17
+ }
18
+ /**
19
+ * Create a new entity
20
+ */
21
+ async create(options) {
22
+ return this.pdev.post(this.endpoint, options);
23
+ }
24
+ /**
25
+ * List entities with pagination
26
+ */
27
+ async list(options = {}) {
28
+ const queryString = buildPaginationQuery(options);
29
+ const path = queryString ? `${this.endpoint}?${queryString}` : this.endpoint;
30
+ return this.pdev.get(path);
31
+ }
32
+ /**
33
+ * Get a single entity by ID
34
+ */
35
+ async get(id) {
36
+ return this.pdev.get(`${this.endpoint}/${id}`);
37
+ }
38
+ };
39
+ /**
40
+ * Base class for resources that only support create operations
41
+ */
42
+ var CreateOnlyResource = class {
43
+ constructor(pdev) {
44
+ this.pdev = pdev;
45
+ }
46
+ async create(options) {
47
+ return this.pdev.post(this.endpoint, options);
48
+ }
49
+ };
50
+ /**
51
+ * Base class for resources that only support get operations
52
+ */
53
+ var GetOnlyResource = class {
54
+ constructor(pdev) {
55
+ this.pdev = pdev;
56
+ }
57
+ async get(id) {
58
+ return this.pdev.get(`${this.endpoint}/${id}`);
59
+ }
60
+ };
61
+
62
+ //#endregion
63
+ //#region src/charges/charges.ts
64
+ var Charges = class extends BaseResource {
65
+ endpoint = "/charges";
66
+ };
67
+
68
+ //#endregion
69
+ //#region src/config.ts
70
+ const config = { baseUrl: "https://api.pague.dev/v1" };
71
+
72
+ //#endregion
73
+ //#region src/customers/customers.ts
74
+ var Customers = class extends BaseResource {
75
+ endpoint = "/customers";
76
+ };
77
+
78
+ //#endregion
79
+ //#region src/pix/pix.ts
80
+ var Pix = class extends CreateOnlyResource {
81
+ endpoint = "/pix";
82
+ };
83
+
84
+ //#endregion
85
+ //#region src/projects/projects.ts
86
+ var Projects = class extends BaseResource {
87
+ endpoint = "/projects";
88
+ };
89
+
90
+ //#endregion
91
+ //#region src/transactions/transactions.ts
92
+ var Transactions = class extends GetOnlyResource {
93
+ endpoint = "/transactions";
94
+ };
95
+
96
+ //#endregion
97
+ //#region src/pdev.ts
98
+ var Pdev = class {
99
+ key;
100
+ baseUrl;
101
+ headers;
102
+ pix;
103
+ customers;
104
+ projects;
105
+ charges;
106
+ transactions;
107
+ constructor(key) {
108
+ if (!key) {
109
+ if (typeof process !== "undefined" && process.env) this.key = process.env.PDEV_API_KEY || "";
110
+ else this.key = "";
111
+ if (!this.key) throw new Error("Missing API key. Pass it to the constructor `new Pdev(\"pd_live_xxx\")` or set the PDEV_API_KEY environment variable.");
112
+ } else this.key = key;
113
+ this.baseUrl = config.baseUrl;
114
+ this.headers = new Headers({
115
+ "X-API-Key": this.key,
116
+ "Content-Type": "application/json"
117
+ });
118
+ this.pix = new Pix(this);
119
+ this.customers = new Customers(this);
120
+ this.projects = new Projects(this);
121
+ this.charges = new Charges(this);
122
+ this.transactions = new Transactions(this);
123
+ }
124
+ async post(path, body, options = {}) {
125
+ const url = this.buildUrl(path, options.query);
126
+ return this.fetchRequest(url, {
127
+ method: "POST",
128
+ headers: this.headers,
129
+ body: body ? JSON.stringify(body) : void 0
130
+ });
131
+ }
132
+ async get(path, options = {}) {
133
+ const url = this.buildUrl(path, options.query);
134
+ return this.fetchRequest(url, {
135
+ method: "GET",
136
+ headers: this.headers
137
+ });
138
+ }
139
+ buildUrl(path, query) {
140
+ let url = `${this.baseUrl}${path}`;
141
+ if (query) {
142
+ const searchParams = new URLSearchParams();
143
+ for (const [key, value] of Object.entries(query)) if (value !== void 0 && value !== null) searchParams.set(key, String(value));
144
+ const queryString = searchParams.toString();
145
+ if (queryString) url += `?${queryString}`;
146
+ }
147
+ return url;
148
+ }
149
+ async fetchRequest(url, options) {
150
+ try {
151
+ const response = await fetch(url, options);
152
+ if (!response.ok) try {
153
+ const rawError = await response.text();
154
+ return {
155
+ data: null,
156
+ error: JSON.parse(rawError)
157
+ };
158
+ } catch {
159
+ return {
160
+ data: null,
161
+ error: {
162
+ statusCode: response.status,
163
+ error: "UnknownError",
164
+ message: "An unexpected error occurred"
165
+ }
166
+ };
167
+ }
168
+ return {
169
+ data: await response.json(),
170
+ error: null
171
+ };
172
+ } catch {
173
+ return {
174
+ data: null,
175
+ error: {
176
+ statusCode: null,
177
+ error: "NetworkError",
178
+ message: "Unable to fetch data. The request could not be resolved."
179
+ }
180
+ };
181
+ }
182
+ }
183
+ };
184
+
185
+ //#endregion
186
+ //#region src/webhooks/verify.ts
187
+ /**
188
+ * Type guard to check if an event is a valid WebhookEvent
189
+ */
190
+ function isValidWebhookEvent(event) {
191
+ if (typeof event !== "object" || event === null) return false;
192
+ const obj = event;
193
+ if (typeof obj.event !== "string") return false;
194
+ if (typeof obj.eventId !== "string") return false;
195
+ if (typeof obj.timestamp !== "string") return false;
196
+ if (typeof obj.data !== "object" || obj.data === null) return false;
197
+ return [
198
+ "payment_completed",
199
+ "payment_failed",
200
+ "refund_completed"
201
+ ].includes(obj.event);
202
+ }
203
+ /**
204
+ * Parses a webhook payload and returns a type-safe WebhookEvent.
205
+ * Returns null if the payload is invalid.
206
+ *
207
+ * @param payload - The raw request body as a string
208
+ * @returns Parsed WebhookEvent or null if invalid
209
+ *
210
+ * @example
211
+ * ```typescript
212
+ * import { parseWebhook } from 'pague-dev';
213
+ *
214
+ * app.post('/webhook', (req, res) => {
215
+ * // 1. Verify signature first (implement using your framework)
216
+ * // const isValid = verifySignature(req.body, req.headers['x-webhook-signature'], secret);
217
+ *
218
+ * // 2. Parse the webhook payload
219
+ * const event = parseWebhook(req.body);
220
+ *
221
+ * if (!event) {
222
+ * return res.status(400).send('Invalid webhook payload');
223
+ * }
224
+ *
225
+ * // 3. Handle the event with full type safety
226
+ * switch (event.event) {
227
+ * case 'payment_completed':
228
+ * // event.data is PaymentCompletedData
229
+ * console.log('Payment completed:', event.data.transactionId);
230
+ * console.log('Amount:', event.data.amount);
231
+ * console.log('Net amount:', event.data.netAmount);
232
+ * break;
233
+ *
234
+ * case 'payment_failed':
235
+ * // event.data is PaymentFailedData
236
+ * console.log('Payment failed:', event.data.transactionId);
237
+ * console.log('Reason:', event.data.failureReason);
238
+ * break;
239
+ *
240
+ * case 'refund_completed':
241
+ * // event.data is RefundCompletedData
242
+ * console.log('Refund completed:', event.data.refundTransactionId);
243
+ * console.log('Original transaction:', event.data.originalTransactionId);
244
+ * break;
245
+ * }
246
+ *
247
+ * res.status(200).send('OK');
248
+ * });
249
+ * ```
250
+ */
251
+ function parseWebhook(payload) {
252
+ let parsed;
253
+ try {
254
+ parsed = JSON.parse(payload);
255
+ } catch {
256
+ return null;
257
+ }
258
+ if (!isValidWebhookEvent(parsed)) return null;
259
+ return parsed;
260
+ }
261
+
262
+ //#endregion
263
+ export { Pdev, parseWebhook };