@beinfi/pulse-sdk 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,1094 @@
1
+ declare class HttpClient {
2
+ private readonly apiKey;
3
+ private readonly baseUrl;
4
+ constructor(apiKey: string, baseUrl?: string);
5
+ request<T>(method: string, path: string, options?: {
6
+ body?: unknown;
7
+ query?: Record<string, string | number | undefined>;
8
+ }): Promise<T>;
9
+ private parseRateLimit;
10
+ private safeJson;
11
+ private handleError;
12
+ }
13
+
14
+ /**
15
+ * Configuration options for the Pulse SDK client.
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const pulse = new Pulse({
20
+ * apiKey: 'sk_live_...',
21
+ * baseUrl: 'https://api.beinfi.com'
22
+ * })
23
+ * ```
24
+ */
25
+ interface PulseConfig {
26
+ /** API key starting with `sk_live_`. Obtain from the Pulse dashboard under Developers > API Keys. */
27
+ apiKey: string;
28
+ /** Override the API base URL. Defaults to `https://api.beinfi.com`. */
29
+ baseUrl?: string;
30
+ }
31
+ /**
32
+ * Parameters for creating a new payment link.
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * const link = await pulse.paymentLinks.create({
37
+ * title: 'Web Development',
38
+ * amount: '150.00',
39
+ * currency: 'USD',
40
+ * description: 'Landing page development'
41
+ * })
42
+ * ```
43
+ */
44
+ interface CreatePaymentLinkParams {
45
+ /** Human-readable title shown to the payer (e.g. "Order #42"). */
46
+ title: string;
47
+ /** Payment amount as a decimal string (e.g. `"99.90"`). */
48
+ amount: string;
49
+ /** Optional description shown on the checkout page. */
50
+ description?: string;
51
+ /** Currency code. Defaults to `"USD"`. */
52
+ currency?: 'USD' | 'BRL';
53
+ }
54
+ /**
55
+ * A payment link object returned by the API.
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * const link = await pulse.paymentLinks.get('link-id')
60
+ * console.log(link.title, link.amount, link.status)
61
+ * ```
62
+ */
63
+ interface PaymentLink {
64
+ /** Unique identifier (UUID). */
65
+ id: string;
66
+ /** Human-readable title. */
67
+ title: string;
68
+ /** Optional description, or `null` if not set. */
69
+ description: string | null;
70
+ /** Payment amount as a decimal string (e.g. `"100.00"`). */
71
+ amount: string;
72
+ /** Currency code (e.g. `"USD"`, `"BRL"`). */
73
+ currency: string;
74
+ /** Current status of the link (e.g. `"active"`, `"inactive"`). */
75
+ status: string;
76
+ /** URL-friendly slug for the payment page. */
77
+ slug: string;
78
+ /** ID of the user who created this link. */
79
+ userId: string;
80
+ /** ISO 8601 timestamp of creation. */
81
+ createdAt: string;
82
+ /** ISO 8601 timestamp of last update. */
83
+ updatedAt: string;
84
+ }
85
+ /**
86
+ * Query parameters for listing payment links.
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * const links = await pulse.paymentLinks.list({ limit: 10, offset: 0 })
91
+ * ```
92
+ */
93
+ interface ListPaymentLinksParams {
94
+ /** Maximum number of results to return. Defaults to 20. */
95
+ limit?: number;
96
+ /** Number of results to skip (for pagination). Defaults to 0. */
97
+ offset?: number;
98
+ }
99
+ /**
100
+ * A payment intent represents a single payment attempt against a payment link.
101
+ *
102
+ * @example
103
+ * ```typescript
104
+ * const intents = await pulse.paymentLinks.listIntents('link-id')
105
+ * for (const intent of intents) {
106
+ * console.log(intent.status, intent.amount, intent.method)
107
+ * }
108
+ * ```
109
+ */
110
+ interface PaymentIntent {
111
+ /** Unique identifier (UUID). */
112
+ id: string;
113
+ /** ID of the parent payment link. */
114
+ paymentLinkId: string;
115
+ /** Payment amount as a decimal string, or `null` if not yet determined. */
116
+ amount: string;
117
+ /** Currency code (e.g. `"USD"`). */
118
+ currency: string;
119
+ /** Intent status: `"pending"` | `"observed"` | `"confirmed"` | `"failed"` | `"expired"`. */
120
+ status: string;
121
+ /** Payment method used (e.g. `"crypto"`, `"pix"`), or `null` if not yet selected. */
122
+ method: string | null;
123
+ /** Blockchain transaction hash, or `null` if not a crypto payment. */
124
+ txHash: string | null;
125
+ /** ISO 8601 timestamp when the payment was confirmed, or `null`. */
126
+ confirmedAt: string | null;
127
+ /** ISO 8601 timestamp of creation. */
128
+ createdAt: string;
129
+ /** ISO 8601 timestamp of last update. */
130
+ updatedAt: string;
131
+ }
132
+ /**
133
+ * A confirmed payment that has been received and credited.
134
+ *
135
+ * @example
136
+ * ```typescript
137
+ * // Received payments are delivered via webhook payloads
138
+ * // or can be queried from the dashboard
139
+ * ```
140
+ */
141
+ interface ReceivedPayment {
142
+ /** Unique identifier (UUID). */
143
+ id: string;
144
+ /** Payment amount as a decimal string. */
145
+ amount: string;
146
+ /** Currency code. */
147
+ currency: string;
148
+ /** Payment method (e.g. `"crypto"`, `"pix"`). */
149
+ method: string;
150
+ /** Blockchain transaction hash, or `null` for non-crypto payments. */
151
+ txHash: string | null;
152
+ /** ISO 8601 timestamp when the payment was confirmed. */
153
+ confirmedAt: string;
154
+ /** ID of the payment link this payment belongs to. */
155
+ paymentLinkId: string;
156
+ /** ISO 8601 timestamp of creation. */
157
+ createdAt: string;
158
+ }
159
+ /**
160
+ * Query parameters for listing received payments.
161
+ */
162
+ interface ListReceivedPaymentsParams {
163
+ /** Maximum number of results to return. */
164
+ limit?: number;
165
+ /** Number of results to skip (for pagination). */
166
+ offset?: number;
167
+ }
168
+ /**
169
+ * Parameters for creating a new webhook subscription.
170
+ *
171
+ * @example
172
+ * ```typescript
173
+ * const wh = await pulse.webhooks.create({
174
+ * url: 'https://example.com/webhook',
175
+ * events: ['payment.confirmed']
176
+ * })
177
+ * // Save wh.secret — it's only returned once at creation time
178
+ * ```
179
+ */
180
+ interface CreateWebhookParams {
181
+ /** The HTTPS URL that will receive webhook POST requests. */
182
+ url: string;
183
+ /** Array of event types to subscribe to (e.g. `["payment.confirmed"]`). */
184
+ events: string[];
185
+ }
186
+ /**
187
+ * A webhook subscription object.
188
+ *
189
+ * @example
190
+ * ```typescript
191
+ * const webhooks = await pulse.webhooks.list()
192
+ * for (const wh of webhooks) {
193
+ * console.log(wh.url, wh.events, wh.isActive)
194
+ * }
195
+ * ```
196
+ */
197
+ interface Webhook {
198
+ /** Unique identifier (UUID). */
199
+ id: string;
200
+ /** The URL receiving webhook deliveries. */
201
+ url: string;
202
+ /** Event types this webhook is subscribed to. */
203
+ events: string[];
204
+ /** Whether the webhook is currently active. */
205
+ isActive: boolean;
206
+ /** ISO 8601 timestamp of creation. */
207
+ createdAt: string;
208
+ }
209
+ /**
210
+ * Webhook object returned after creation, includes the signing secret.
211
+ * The `secret` is only returned once — store it securely.
212
+ *
213
+ * @example
214
+ * ```typescript
215
+ * const wh = await pulse.webhooks.create({
216
+ * url: 'https://example.com/webhook',
217
+ * events: ['payment.confirmed']
218
+ * })
219
+ * console.log(wh.secret) // "a1b2c3..." (64-char hex) — save this!
220
+ * ```
221
+ */
222
+ interface WebhookCreated extends Webhook {
223
+ /** HMAC signing secret (64-character hex string). Only returned at creation time. */
224
+ secret: string;
225
+ }
226
+ /**
227
+ * The payload delivered to your webhook endpoint when a `payment.confirmed` event fires.
228
+ * Sent as a JSON POST with `X-Pulse-Signature` and `X-Pulse-Event` headers.
229
+ *
230
+ * @example
231
+ * ```typescript
232
+ * // In your webhook handler:
233
+ * app.post('/webhook', (req) => {
234
+ * const isValid = Pulse.webhooks.verifySignature(
235
+ * req.rawBody,
236
+ * req.headers['x-pulse-signature'],
237
+ * process.env.WEBHOOK_SECRET
238
+ * )
239
+ * if (!isValid) return res.status(401).send('Invalid signature')
240
+ *
241
+ * const payload: WebhookPayload = req.body
242
+ * console.log('Payment confirmed:', payload.paymentIntentId, payload.amount)
243
+ * })
244
+ * ```
245
+ */
246
+ interface WebhookPayload {
247
+ /** ID of the confirmed payment intent. */
248
+ paymentIntentId: string;
249
+ /** Payment amount as a decimal string. */
250
+ amount: string;
251
+ /** Currency code. */
252
+ currency: string;
253
+ /** Payment method used (e.g. `"crypto"`, `"pix"`). */
254
+ method: string;
255
+ /** ISO 8601 timestamp when the payment was confirmed. */
256
+ confirmedAt: string;
257
+ /** Blockchain transaction hash (present for crypto payments). */
258
+ txHash?: string;
259
+ }
260
+ /**
261
+ * Parameters for tracking a usage event.
262
+ *
263
+ * @example
264
+ * ```typescript
265
+ * await pulse.metering.track({
266
+ * meterId: 'tokens',
267
+ * customerId: 'user_123',
268
+ * value: 1500,
269
+ * metadata: { model: 'gpt-4' }
270
+ * })
271
+ * ```
272
+ */
273
+ interface TrackEventParams {
274
+ /** Idempotency key. Auto-generated if not provided. */
275
+ eventId?: string;
276
+ /** Meter ID or slug to track against. */
277
+ meterId: string;
278
+ /** Your customer's identifier (externalId). */
279
+ customerId: string;
280
+ /** Quantity consumed (e.g. number of tokens). */
281
+ value: number | string;
282
+ /** When the event occurred. Defaults to now. */
283
+ timestamp?: Date;
284
+ /** Additional metadata attached to the event. */
285
+ metadata?: Record<string, unknown>;
286
+ }
287
+ /** A tracked event as returned by the API. */
288
+ interface TrackEventResponse {
289
+ id: string;
290
+ eventId: string;
291
+ meterId: string;
292
+ customerId: string;
293
+ value: string;
294
+ timestamp: string;
295
+ createdAt: string;
296
+ }
297
+ /** Result of a batch track operation. */
298
+ interface BatchTrackResponse {
299
+ accepted: number;
300
+ failed: number;
301
+ results: TrackEventResponse[];
302
+ errors?: Array<{
303
+ eventId?: string;
304
+ error: string;
305
+ }>;
306
+ }
307
+ /** Query parameters for aggregated usage. */
308
+ interface UsageQuery {
309
+ customerId?: string;
310
+ startDate?: string;
311
+ endDate?: string;
312
+ }
313
+ /** A single meter's aggregated usage. */
314
+ interface UsageItem {
315
+ meterId: string;
316
+ meterName: string;
317
+ unit: string;
318
+ unitPrice: string;
319
+ totalValue: string;
320
+ totalAmount: string;
321
+ eventCount: number;
322
+ }
323
+ /** Aggregated usage response. */
324
+ interface UsageResponse {
325
+ data: UsageItem[];
326
+ }
327
+ /** Parameters for creating a customer on a product. */
328
+ interface CreateCustomerParams {
329
+ externalId: string;
330
+ name?: string;
331
+ email?: string;
332
+ metadata?: Record<string, unknown>;
333
+ }
334
+ /** Parameters for creating a product. */
335
+ interface CreateProductParams {
336
+ name: string;
337
+ description?: string;
338
+ }
339
+ /** Parameters for creating a meter on a product. */
340
+ interface CreateMeterParams {
341
+ name: string;
342
+ displayName: string;
343
+ unit: string;
344
+ unitPrice: string;
345
+ }
346
+ /** A meter object returned by the API. */
347
+ interface Meter {
348
+ id: string;
349
+ name: string;
350
+ displayName: string;
351
+ unit: string;
352
+ unitPrice: string;
353
+ status: string;
354
+ }
355
+ /** A product with meters. */
356
+ interface MeteringProduct {
357
+ id: string;
358
+ name: string;
359
+ description?: string;
360
+ status: string;
361
+ meters: Array<{
362
+ id: string;
363
+ name: string;
364
+ displayName: string;
365
+ unit: string;
366
+ unitPrice: string;
367
+ }>;
368
+ }
369
+ /** A customer linked to a product. */
370
+ interface ProductCustomer {
371
+ id: string;
372
+ externalId: string;
373
+ name?: string | null;
374
+ email?: string | null;
375
+ createdAt: string;
376
+ }
377
+ /**
378
+ * Rate limit information returned in API response headers.
379
+ * Available on every response as `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`.
380
+ */
381
+ interface RateLimitInfo {
382
+ /** Maximum requests allowed per minute for your tier (free=100, pro=1000, enterprise=5000). */
383
+ limit: number;
384
+ /** Remaining requests in the current window. */
385
+ remaining: number;
386
+ /** Unix timestamp (seconds) when the rate limit window resets. */
387
+ reset: number;
388
+ }
389
+ /**
390
+ * Shape of error responses returned by the Pulse API.
391
+ *
392
+ * @example
393
+ * ```json
394
+ * { "error": "unauthorized", "message": "Invalid API key" }
395
+ * ```
396
+ */
397
+ interface ApiErrorResponse {
398
+ /** Machine-readable error code (e.g. `"unauthorized"`, `"rate_limit_exceeded"`). */
399
+ error: string;
400
+ /** Human-readable error description. */
401
+ message: string;
402
+ }
403
+
404
+ /**
405
+ * Resource for managing payment links.
406
+ * Access via `pulse.paymentLinks`.
407
+ *
408
+ * @example
409
+ * ```typescript
410
+ * const pulse = new Pulse('sk_live_...')
411
+ *
412
+ * // Create a payment link
413
+ * const link = await pulse.paymentLinks.create({
414
+ * title: 'Order #42',
415
+ * amount: '100.00',
416
+ * })
417
+ *
418
+ * // List all links
419
+ * const links = await pulse.paymentLinks.list({ limit: 10 })
420
+ * ```
421
+ */
422
+ declare class PaymentLinksResource {
423
+ private readonly client;
424
+ constructor(client: HttpClient);
425
+ /**
426
+ * Create a new payment link.
427
+ *
428
+ * @param params - Payment link parameters (title, amount, optional currency and description).
429
+ * @returns The created payment link object.
430
+ * @throws {PulseAuthenticationError} If the API key is invalid.
431
+ * @throws {PulseApiError} If validation fails (e.g. invalid currency).
432
+ *
433
+ * @example
434
+ * ```typescript
435
+ * const link = await pulse.paymentLinks.create({
436
+ * title: 'Web Development',
437
+ * amount: '150.00',
438
+ * currency: 'USD',
439
+ * description: 'Landing page development',
440
+ * })
441
+ * console.log(link.id, link.slug)
442
+ * ```
443
+ */
444
+ create(params: CreatePaymentLinkParams): Promise<PaymentLink>;
445
+ /**
446
+ * List payment links for the authenticated user.
447
+ *
448
+ * @param params - Optional pagination parameters (limit, offset).
449
+ * @returns Array of payment link objects.
450
+ * @throws {PulseAuthenticationError} If the API key is invalid.
451
+ *
452
+ * @example
453
+ * ```typescript
454
+ * const links = await pulse.paymentLinks.list({ limit: 10, offset: 0 })
455
+ * for (const link of links) {
456
+ * console.log(link.title, link.amount, link.status)
457
+ * }
458
+ * ```
459
+ */
460
+ list(params?: ListPaymentLinksParams): Promise<PaymentLink[]>;
461
+ /**
462
+ * Get a single payment link by ID.
463
+ *
464
+ * @param linkId - The payment link UUID.
465
+ * @returns The payment link object.
466
+ * @throws {PulseAuthenticationError} If the API key is invalid.
467
+ * @throws {PulseApiError} With status 404 if the link doesn't exist.
468
+ *
469
+ * @example
470
+ * ```typescript
471
+ * const link = await pulse.paymentLinks.get('abc-123-def')
472
+ * console.log(link.title, link.amount)
473
+ * ```
474
+ */
475
+ get(linkId: string): Promise<PaymentLink>;
476
+ /**
477
+ * List payment intents (payment attempts) for a specific payment link.
478
+ *
479
+ * @param linkId - The payment link UUID.
480
+ * @returns Array of payment intent objects.
481
+ * @throws {PulseAuthenticationError} If the API key is invalid.
482
+ *
483
+ * @example
484
+ * ```typescript
485
+ * const intents = await pulse.paymentLinks.listIntents('abc-123-def')
486
+ * const confirmed = intents.filter(i => i.status === 'confirmed')
487
+ * console.log(`${confirmed.length} confirmed payments`)
488
+ * ```
489
+ */
490
+ listIntents(linkId: string): Promise<PaymentIntent[]>;
491
+ }
492
+
493
+ /**
494
+ * Resource for managing webhook subscriptions.
495
+ * Access via `pulse.webhooks`.
496
+ *
497
+ * @example
498
+ * ```typescript
499
+ * const pulse = new Pulse('sk_live_...')
500
+ *
501
+ * // Create a webhook
502
+ * const wh = await pulse.webhooks.create({
503
+ * url: 'https://example.com/webhook',
504
+ * events: ['payment.confirmed'],
505
+ * })
506
+ * console.log(wh.secret) // save this!
507
+ *
508
+ * // List webhooks
509
+ * const list = await pulse.webhooks.list()
510
+ * ```
511
+ */
512
+ declare class WebhooksResource {
513
+ private readonly client;
514
+ constructor(client: HttpClient);
515
+ /**
516
+ * Create a new webhook subscription.
517
+ * The response includes a `secret` field (64-char hex) used to verify signatures.
518
+ * **Store this secret securely** — it is only returned once at creation time.
519
+ *
520
+ * @param params - Webhook URL and event types to subscribe to.
521
+ * @returns The created webhook with its signing secret.
522
+ * @throws {PulseAuthenticationError} If the API key is invalid.
523
+ *
524
+ * @example
525
+ * ```typescript
526
+ * const wh = await pulse.webhooks.create({
527
+ * url: 'https://example.com/webhook',
528
+ * events: ['payment.confirmed'],
529
+ * })
530
+ * // Save wh.secret to your environment/secrets manager
531
+ * console.log('Webhook secret:', wh.secret)
532
+ * ```
533
+ */
534
+ create(params: CreateWebhookParams): Promise<WebhookCreated>;
535
+ /**
536
+ * List all webhook subscriptions for the authenticated user.
537
+ *
538
+ * @returns Array of webhook objects (without secrets).
539
+ * @throws {PulseAuthenticationError} If the API key is invalid.
540
+ *
541
+ * @example
542
+ * ```typescript
543
+ * const webhooks = await pulse.webhooks.list()
544
+ * for (const wh of webhooks) {
545
+ * console.log(wh.url, wh.events, wh.isActive)
546
+ * }
547
+ * ```
548
+ */
549
+ list(): Promise<Webhook[]>;
550
+ /**
551
+ * Delete a webhook subscription.
552
+ *
553
+ * @param id - The webhook UUID to delete.
554
+ * @throws {PulseAuthenticationError} If the API key is invalid.
555
+ *
556
+ * @example
557
+ * ```typescript
558
+ * await pulse.webhooks.delete('webhook-id')
559
+ * ```
560
+ */
561
+ delete(id: string): Promise<void>;
562
+ }
563
+
564
+ /**
565
+ * Resource for usage-based metering and billing.
566
+ * Access via `pulse.metering`.
567
+ *
568
+ * @example
569
+ * ```typescript
570
+ * const pulse = new Pulse('sk_live_...')
571
+ *
572
+ * // Track a usage event
573
+ * await pulse.metering.track({
574
+ * meterId: 'meter_id',
575
+ * customerId: 'user_123',
576
+ * value: 1500,
577
+ * })
578
+ *
579
+ * // Query aggregated usage
580
+ * const usage = await pulse.metering.getUsage({ customerId: 'user_123' })
581
+ * ```
582
+ */
583
+ declare class MeteringResource {
584
+ private readonly client;
585
+ constructor(client: HttpClient);
586
+ /**
587
+ * Track a single usage event.
588
+ *
589
+ * @param params - Event parameters (meterId, customerId, value).
590
+ * @returns The created event object.
591
+ *
592
+ * @example
593
+ * ```typescript
594
+ * await pulse.metering.track({
595
+ * meterId: 'tokens',
596
+ * customerId: 'user_123',
597
+ * value: 1500,
598
+ * metadata: { model: 'gpt-4' }
599
+ * })
600
+ * ```
601
+ */
602
+ track(params: TrackEventParams): Promise<TrackEventResponse>;
603
+ /**
604
+ * Track multiple usage events in a single request.
605
+ *
606
+ * @param events - Array of event parameters.
607
+ * @returns Batch result with accepted/failed counts.
608
+ *
609
+ * @example
610
+ * ```typescript
611
+ * await pulse.metering.trackBatch([
612
+ * { meterId: 'tokens', customerId: 'user_1', value: 500 },
613
+ * { meterId: 'tokens', customerId: 'user_2', value: 1200 },
614
+ * ])
615
+ * ```
616
+ */
617
+ trackBatch(events: TrackEventParams[]): Promise<BatchTrackResponse>;
618
+ /**
619
+ * Query aggregated usage data.
620
+ *
621
+ * @param query - Optional filters (customerId, date range).
622
+ * @returns Aggregated usage by meter.
623
+ *
624
+ * @example
625
+ * ```typescript
626
+ * const usage = await pulse.metering.getUsage({ customerId: 'user_123' })
627
+ * for (const item of usage.data) {
628
+ * console.log(item.meterName, item.totalValue, item.totalAmount)
629
+ * }
630
+ * ```
631
+ */
632
+ getUsage(query?: UsageQuery): Promise<UsageResponse>;
633
+ /**
634
+ * List all products.
635
+ *
636
+ * @returns Array of product objects with meters.
637
+ */
638
+ listProducts(): Promise<MeteringProduct[]>;
639
+ /**
640
+ * Create a new product.
641
+ *
642
+ * @param data - Product data (name, optional description).
643
+ * @returns The created product object.
644
+ *
645
+ * @example
646
+ * ```typescript
647
+ * const product = await pulse.metering.createProduct({
648
+ * name: 'AI Agent',
649
+ * description: 'Usage-based AI agent billing',
650
+ * })
651
+ * ```
652
+ */
653
+ createProduct(data: CreateProductParams): Promise<MeteringProduct>;
654
+ /**
655
+ * Create a new meter on a product.
656
+ *
657
+ * @param productId - The product UUID.
658
+ * @param data - Meter data (name, displayName, unit, unitPrice).
659
+ * @returns The created meter object.
660
+ *
661
+ * @example
662
+ * ```typescript
663
+ * const meter = await pulse.metering.createMeter('product-id', {
664
+ * name: 'tokens',
665
+ * displayName: 'AI Tokens',
666
+ * unit: 'token',
667
+ * unitPrice: '0.0001',
668
+ * })
669
+ * ```
670
+ */
671
+ createMeter(productId: string, data: CreateMeterParams): Promise<Meter>;
672
+ /**
673
+ * Create a customer for a product.
674
+ *
675
+ * @param productId - The product UUID.
676
+ * @param data - Customer data (externalId, name, email, metadata).
677
+ * @returns The created customer object.
678
+ *
679
+ * @example
680
+ * ```typescript
681
+ * const customer = await pulse.metering.createCustomer('product-id', {
682
+ * externalId: 'user_123',
683
+ * name: 'John Doe',
684
+ * email: 'john@example.com',
685
+ * })
686
+ * ```
687
+ */
688
+ createCustomer(productId: string, data: CreateCustomerParams): Promise<ProductCustomer>;
689
+ /**
690
+ * Get customer usage for a specific product.
691
+ *
692
+ * @param productId - The product UUID.
693
+ * @param customerId - The customer external ID.
694
+ * @param query - Optional date range filters.
695
+ * @returns Aggregated usage by meter for the customer.
696
+ */
697
+ getCustomerUsage(productId: string, customerId: string, query?: {
698
+ startDate?: string;
699
+ endDate?: string;
700
+ }): Promise<UsageResponse>;
701
+ /**
702
+ * Create a session for tracking multiple events for a customer.
703
+ * Events are accumulated and sent as a batch when `.end()` is called.
704
+ *
705
+ * @param customerId - The customer external ID.
706
+ * @returns A session instance.
707
+ *
708
+ * @example
709
+ * ```typescript
710
+ * const session = pulse.metering.session('user_123')
711
+ * session.track('tokens', 500)
712
+ * session.track('tokens', 300)
713
+ * session.track('requests', 1)
714
+ * await session.end() // sends batch: tokens=800, requests=1
715
+ * ```
716
+ */
717
+ session(customerId: string): MeteringSession;
718
+ }
719
+ /**
720
+ * A session accumulates track calls and sends them as a batch.
721
+ */
722
+ declare class MeteringSession {
723
+ private readonly metering;
724
+ private readonly customerId;
725
+ private events;
726
+ constructor(metering: MeteringResource, customerId: string);
727
+ /**
728
+ * Queue a tracking event in this session.
729
+ */
730
+ track(meterId: string, value: number | string, metadata?: Record<string, unknown>): this;
731
+ /**
732
+ * Send all accumulated events as a batch and clear the session.
733
+ */
734
+ end(): Promise<BatchTrackResponse>;
735
+ }
736
+
737
+ /**
738
+ * Verify the HMAC-SHA256 signature of an incoming webhook request.
739
+ * Use this to ensure the request came from Pulse and wasn't tampered with.
740
+ *
741
+ * The signature is sent in the `X-Pulse-Signature` header as `sha256={hex}`.
742
+ *
743
+ * @param rawBody - The raw request body as a string (not parsed JSON).
744
+ * @param signatureHeader - The `X-Pulse-Signature` header value (e.g. `"sha256=abc123..."`).
745
+ * @param secret - Your webhook signing secret (64-char hex, from webhook creation).
746
+ * @returns `true` if the signature is valid, `false` otherwise.
747
+ *
748
+ * @example
749
+ * ```typescript
750
+ * import { Pulse } from '@beinfi/pulse-sdk'
751
+ *
752
+ * // Express/Node.js example
753
+ * app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
754
+ * const isValid = Pulse.webhooks.verifySignature(
755
+ * req.body.toString(),
756
+ * req.headers['x-pulse-signature'] as string,
757
+ * process.env.PULSE_WEBHOOK_SECRET!
758
+ * )
759
+ *
760
+ * if (!isValid) {
761
+ * return res.status(401).send('Invalid signature')
762
+ * }
763
+ *
764
+ * const event = JSON.parse(req.body.toString())
765
+ * console.log('Payment confirmed:', event.paymentIntentId)
766
+ * res.sendStatus(200)
767
+ * })
768
+ * ```
769
+ *
770
+ * @example
771
+ * ```typescript
772
+ * // Standalone import
773
+ * import { verifyWebhookSignature } from '@beinfi/pulse-sdk'
774
+ *
775
+ * const valid = verifyWebhookSignature(rawBody, signatureHeader, secret)
776
+ * ```
777
+ */
778
+ declare function verifyWebhookSignature(rawBody: string, signatureHeader: string, secret: string): boolean;
779
+
780
+ /**
781
+ * Successful payment data returned by the checkout widget.
782
+ */
783
+ interface CheckoutPayment {
784
+ /** ID of the completed payment intent. */
785
+ paymentIntentId: string;
786
+ /** Payment amount as a decimal string. */
787
+ amount: string;
788
+ /** Currency code (e.g. `"USD"`). */
789
+ currency: string;
790
+ /** Payment method used (e.g. `"crypto"`, `"pix"`). */
791
+ method: string;
792
+ /** Blockchain transaction hash (present for crypto payments). */
793
+ txHash?: string;
794
+ }
795
+ /**
796
+ * Error object emitted by the checkout widget.
797
+ */
798
+ interface CheckoutError {
799
+ /** Human-readable error message. */
800
+ message: string;
801
+ /** Machine-readable error code. */
802
+ code?: string;
803
+ }
804
+ /**
805
+ * Theme customization for the checkout widget.
806
+ * All values are CSS color strings (hex, rgb, hsl, etc.).
807
+ *
808
+ * @example
809
+ * ```typescript
810
+ * const instance = Pulse.checkout.mount('#checkout', {
811
+ * linkId: 'link-id',
812
+ * theme: {
813
+ * background: '#1a1a2e',
814
+ * foreground: '#ffffff',
815
+ * accent: '#e94560',
816
+ * }
817
+ * })
818
+ * ```
819
+ */
820
+ interface CheckoutTheme {
821
+ /** Background color of the checkout widget. */
822
+ background?: string;
823
+ /** Primary text color. */
824
+ foreground?: string;
825
+ /** Card/surface background color. */
826
+ card?: string;
827
+ /** Accent color for buttons and interactive elements. */
828
+ accent?: string;
829
+ /** Text color on accent-colored elements. */
830
+ accentForeground?: string;
831
+ }
832
+ /**
833
+ * Options for mounting the Pulse checkout widget.
834
+ *
835
+ * @example
836
+ * ```typescript
837
+ * const instance = Pulse.checkout.mount('#checkout', {
838
+ * linkId: 'abc-123',
839
+ * onSuccess: (payment) => console.log('Paid!', payment),
840
+ * onError: (err) => console.error('Failed:', err.message),
841
+ * })
842
+ * ```
843
+ */
844
+ interface CheckoutMountOptions {
845
+ /** The payment link ID to load in the checkout widget. */
846
+ linkId: string;
847
+ /** Override the checkout base URL. Defaults to `https://pulse.beinfi.com`. */
848
+ baseUrl?: string;
849
+ /** Custom theme colors for the checkout widget. */
850
+ theme?: CheckoutTheme;
851
+ /** Called when the checkout iframe is ready and rendered. */
852
+ onReady?: () => void;
853
+ /** Called when the payment is successfully confirmed. */
854
+ onSuccess?: (payment: CheckoutPayment) => void;
855
+ /** Called when a payment error occurs. */
856
+ onError?: (error: CheckoutError) => void;
857
+ /** Called when the checkout widget is unmounted/closed. */
858
+ onClose?: () => void;
859
+ }
860
+ /**
861
+ * Handle returned by {@link mountCheckout}. Use it to control the checkout widget lifecycle.
862
+ *
863
+ * @example
864
+ * ```typescript
865
+ * const instance = Pulse.checkout.mount('#checkout', { linkId: 'abc-123' })
866
+ *
867
+ * // Listen for events
868
+ * instance.on('success', (payment) => console.log('Paid!', payment))
869
+ *
870
+ * // Clean up when done
871
+ * instance.unmount()
872
+ * ```
873
+ */
874
+ interface CheckoutInstance {
875
+ /** Remove the checkout iframe and clean up event listeners. */
876
+ unmount: () => void;
877
+ /** Subscribe to checkout events: `"ready"`, `"success"`, `"error"`, `"close"`. */
878
+ on: (event: 'ready' | 'success' | 'error' | 'close', handler: (...args: any[]) => void) => void;
879
+ }
880
+
881
+ /**
882
+ * Mount the Pulse checkout widget into a DOM element.
883
+ * Embeds an iframe-based checkout that handles payment flow (crypto, PIX)
884
+ * and communicates back via postMessage events.
885
+ *
886
+ * @param selector - A CSS selector string or an HTMLElement to mount the checkout into.
887
+ * @param options - Checkout configuration including the payment link ID and event callbacks.
888
+ * @returns A {@link CheckoutInstance} with `unmount()` and `on()` methods.
889
+ * @throws {Error} If the container element is not found.
890
+ *
891
+ * @example
892
+ * ```typescript
893
+ * import { Pulse } from '@beinfi/pulse-sdk'
894
+ *
895
+ * // Mount into a div
896
+ * const checkout = Pulse.checkout.mount('#checkout-container', {
897
+ * linkId: 'abc-123',
898
+ * theme: {
899
+ * background: '#0f0f23',
900
+ * accent: '#6366f1',
901
+ * },
902
+ * onReady: () => console.log('Checkout loaded'),
903
+ * onSuccess: (payment) => {
904
+ * console.log('Payment confirmed!', payment.paymentIntentId)
905
+ * checkout.unmount()
906
+ * },
907
+ * onError: (err) => console.error('Payment failed:', err.message),
908
+ * })
909
+ *
910
+ * // Alternative: use .on() event listeners
911
+ * checkout.on('success', (payment) => {
912
+ * window.location.href = '/thank-you'
913
+ * })
914
+ * ```
915
+ *
916
+ * @example
917
+ * ```typescript
918
+ * // Standalone import
919
+ * import { mountCheckout } from '@beinfi/pulse-sdk'
920
+ *
921
+ * const instance = mountCheckout('#checkout', { linkId: 'abc-123' })
922
+ * ```
923
+ */
924
+ declare function mountCheckout(selector: string | HTMLElement, options: CheckoutMountOptions): CheckoutInstance;
925
+
926
+ /**
927
+ * Base error class for all Pulse SDK errors.
928
+ * All errors thrown by the SDK extend this class.
929
+ *
930
+ * @example
931
+ * ```typescript
932
+ * try {
933
+ * await pulse.paymentLinks.create({ title: 'Test', amount: '10.00' })
934
+ * } catch (err) {
935
+ * if (err instanceof PulseError) {
936
+ * console.error('Pulse SDK error:', err.message)
937
+ * }
938
+ * }
939
+ * ```
940
+ */
941
+ declare class PulseError extends Error {
942
+ constructor(message: string);
943
+ }
944
+ /**
945
+ * Error thrown when the Pulse API returns a non-2xx response.
946
+ * Contains the HTTP status code, machine-readable error code, and optional rate limit info.
947
+ *
948
+ * @example
949
+ * ```typescript
950
+ * try {
951
+ * await pulse.paymentLinks.create({ title: 'Test', amount: '10.00' })
952
+ * } catch (err) {
953
+ * if (err instanceof PulseApiError) {
954
+ * console.error(`API error ${err.status}: [${err.errorCode}] ${err.message}`)
955
+ * }
956
+ * }
957
+ * ```
958
+ */
959
+ declare class PulseApiError extends PulseError {
960
+ /** HTTP status code (e.g. 400, 404, 500). */
961
+ readonly status: number;
962
+ /** Machine-readable error code (e.g. `"unauthorized"`, `"not_found"`). */
963
+ readonly errorCode: string;
964
+ /** Rate limit info from response headers, if available. */
965
+ readonly rateLimit?: RateLimitInfo;
966
+ constructor(status: number, errorCode: string, message: string, rateLimit?: RateLimitInfo);
967
+ }
968
+ /**
969
+ * Error thrown when the API key is invalid, expired, or revoked (HTTP 401).
970
+ *
971
+ * @example
972
+ * ```typescript
973
+ * try {
974
+ * await pulse.paymentLinks.list()
975
+ * } catch (err) {
976
+ * if (err instanceof PulseAuthenticationError) {
977
+ * console.error('Bad API key — check your sk_live_ key')
978
+ * }
979
+ * }
980
+ * ```
981
+ */
982
+ declare class PulseAuthenticationError extends PulseApiError {
983
+ constructor(message?: string);
984
+ }
985
+ /**
986
+ * Error thrown when the rate limit is exceeded (HTTP 429).
987
+ * Check `retryAfter` for the number of seconds to wait before retrying.
988
+ *
989
+ * @example
990
+ * ```typescript
991
+ * try {
992
+ * await pulse.paymentLinks.list()
993
+ * } catch (err) {
994
+ * if (err instanceof PulseRateLimitError) {
995
+ * console.log(`Rate limited. Retry in ${err.retryAfter}s`)
996
+ * await new Promise(r => setTimeout(r, err.retryAfter * 1000))
997
+ * }
998
+ * }
999
+ * ```
1000
+ */
1001
+ declare class PulseRateLimitError extends PulseApiError {
1002
+ /** Number of seconds to wait before retrying. */
1003
+ readonly retryAfter: number;
1004
+ constructor(retryAfter: number, rateLimit?: RateLimitInfo);
1005
+ }
1006
+
1007
+ /**
1008
+ * Main entry point for the Pulse SDK.
1009
+ * Create an instance with your API key to access payment links and webhooks.
1010
+ *
1011
+ * @example
1012
+ * ```typescript
1013
+ * import { Pulse } from '@beinfi/pulse-sdk'
1014
+ *
1015
+ * // Quick setup with just an API key
1016
+ * const pulse = new Pulse('sk_live_...')
1017
+ *
1018
+ * // Or with full config
1019
+ * const pulse = new Pulse({
1020
+ * apiKey: 'sk_live_...',
1021
+ * baseUrl: 'https://api.beinfi.com',
1022
+ * })
1023
+ *
1024
+ * // Create a payment link
1025
+ * const link = await pulse.paymentLinks.create({
1026
+ * title: 'Order #42',
1027
+ * amount: '100.00',
1028
+ * })
1029
+ *
1030
+ * // Verify webhook signatures (static method, no instance needed)
1031
+ * const isValid = Pulse.webhooks.verifySignature(rawBody, signature, secret)
1032
+ *
1033
+ * // Mount checkout widget (static method, browser only)
1034
+ * const checkout = Pulse.checkout.mount('#container', { linkId: link.id })
1035
+ * ```
1036
+ */
1037
+ declare class Pulse {
1038
+ /** Resource for creating, listing, and fetching payment links. */
1039
+ readonly paymentLinks: PaymentLinksResource;
1040
+ /** Resource for creating, listing, and deleting webhook subscriptions. */
1041
+ readonly webhooks: WebhooksResource;
1042
+ /** Resource for usage-based metering, tracking events, and querying usage. */
1043
+ readonly metering: MeteringResource;
1044
+ private readonly client;
1045
+ /**
1046
+ * Static utilities for verifying webhook signatures.
1047
+ * Does not require a Pulse instance — useful in webhook handler endpoints.
1048
+ *
1049
+ * @example
1050
+ * ```typescript
1051
+ * const isValid = Pulse.webhooks.verifySignature(
1052
+ * rawBody,
1053
+ * req.headers['x-pulse-signature'],
1054
+ * process.env.PULSE_WEBHOOK_SECRET
1055
+ * )
1056
+ * ```
1057
+ */
1058
+ static webhooks: {
1059
+ verifySignature: typeof verifyWebhookSignature;
1060
+ };
1061
+ /**
1062
+ * Static utilities for mounting the checkout widget.
1063
+ * Browser-only — embeds an iframe-based checkout for a payment link.
1064
+ *
1065
+ * @example
1066
+ * ```typescript
1067
+ * const instance = Pulse.checkout.mount('#checkout', {
1068
+ * linkId: 'abc-123',
1069
+ * onSuccess: (payment) => console.log('Paid!', payment),
1070
+ * })
1071
+ * ```
1072
+ */
1073
+ static checkout: {
1074
+ mount: typeof mountCheckout;
1075
+ };
1076
+ /**
1077
+ * Create a new Pulse SDK client.
1078
+ *
1079
+ * @param config - Either an API key string (`"sk_live_..."`) or a {@link PulseConfig} object.
1080
+ * @throws {PulseError} If the API key doesn't start with `"sk_live_"`.
1081
+ *
1082
+ * @example
1083
+ * ```typescript
1084
+ * // String shorthand
1085
+ * const pulse = new Pulse('sk_live_...')
1086
+ *
1087
+ * // Config object
1088
+ * const pulse = new Pulse({ apiKey: 'sk_live_...', baseUrl: 'https://api.beinfi.com' })
1089
+ * ```
1090
+ */
1091
+ constructor(config: string | PulseConfig);
1092
+ }
1093
+
1094
+ export { type ApiErrorResponse, type BatchTrackResponse, type CheckoutError, type CheckoutInstance, type CheckoutMountOptions, type CheckoutPayment, type CheckoutTheme, type CreateCustomerParams, type CreateMeterParams, type CreatePaymentLinkParams, type CreateProductParams, type CreateWebhookParams, type ListPaymentLinksParams, type ListReceivedPaymentsParams, type Meter, type MeteringProduct, type PaymentIntent, type PaymentLink, type ProductCustomer, Pulse, PulseApiError, PulseAuthenticationError, type PulseConfig, PulseError, PulseRateLimitError, type RateLimitInfo, type ReceivedPayment, type TrackEventParams, type TrackEventResponse, type UsageItem, type UsageQuery, type UsageResponse, type Webhook, type WebhookCreated, type WebhookPayload, mountCheckout, verifyWebhookSignature };