@setup-automatizado/sicredi-sdk 1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Guilherme Jansen - Setup Automatizado LTDA
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,663 @@
1
+ # @setup-automatizado/sicredi-sdk
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@setup-automatizado/sicredi-sdk.svg)](https://www.npmjs.com/package/@setup-automatizado/sicredi-sdk)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.6+-3178c6.svg)](https://www.typescriptlang.org/)
6
+ [![Node.js](https://img.shields.io/badge/Node.js-18%2B-339933.svg)](https://nodejs.org/)
7
+
8
+ Production-grade TypeScript SDK for the Sicredi PIX and Boleto Hibrido APIs. Built for reliability and developer experience.
9
+
10
+ ## Features
11
+
12
+ - **Zero dependencies** -- no external runtime dependencies, only dev tooling
13
+ - **mTLS authentication** -- native mutual TLS support for Sicredi's certificate-based API
14
+ - **Auto-refresh tokens** -- OAuth2 tokens are cached and refreshed automatically before expiry
15
+ - **Automatic retries** -- configurable retry logic with exponential backoff for transient failures
16
+ - **Bun + Node.js** -- first-class support for both runtimes (auto-detected)
17
+ - **Full TypeScript** -- strict types for every request, response, and error
18
+ - **QR Code generation** -- built-in SVG QR code generator for PIX "copia e cola" strings
19
+ - **Boleto Hibrido** -- complete support for PIX charges with due dates, penalties, interest, and discounts
20
+ - **Webhook handling** -- parse and validate Sicredi webhook callback payloads
21
+ - **Lazy initialization** -- certificates and connections are set up on first use, not at construction
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ # Bun (recommended)
27
+ bun add @setup-automatizado/sicredi-sdk
28
+
29
+ # npm
30
+ npm install @setup-automatizado/sicredi-sdk
31
+
32
+ # pnpm
33
+ pnpm add @setup-automatizado/sicredi-sdk
34
+
35
+ # yarn
36
+ yarn add @setup-automatizado/sicredi-sdk
37
+ ```
38
+
39
+ ## Quick Start
40
+
41
+ ```typescript
42
+ import { Sicredi, generateTxId } from '@setup-automatizado/sicredi-sdk';
43
+
44
+ const sicredi = new Sicredi({
45
+ clientId: process.env.SICREDI_CLIENT_ID!,
46
+ clientSecret: process.env.SICREDI_CLIENT_SECRET!,
47
+ certificate: {
48
+ cert: './certs/certificado.pem',
49
+ key: './certs/aplicacao.key',
50
+ ca: './certs/CadeiaCompletaSicredi.pem',
51
+ },
52
+ environment: 'sandbox',
53
+ });
54
+
55
+ // Create a PIX charge
56
+ const txid = generateTxId();
57
+ const charge = await sicredi.cob.create(txid, {
58
+ calendario: { expiracao: 3600 },
59
+ devedor: { cpf: '12345678909', nome: 'Fulano de Tal' },
60
+ valor: { original: '100.00' },
61
+ chave: 'your-pix-key',
62
+ solicitacaoPagador: 'Payment for order #123',
63
+ });
64
+
65
+ console.log(charge.pixCopiaECola); // PIX copy-and-paste string
66
+ console.log(charge.location); // Payment URL
67
+ ```
68
+
69
+ ## API Reference
70
+
71
+ ### Configuration
72
+
73
+ ```typescript
74
+ import { Sicredi } from '@setup-automatizado/sicredi-sdk';
75
+
76
+ const sicredi = new Sicredi({
77
+ // Required
78
+ clientId: 'your-client-id',
79
+ clientSecret: 'your-client-secret',
80
+ certificate: {
81
+ cert: './path/to/cert.pem', // or PEM string
82
+ key: './path/to/key.pem', // or PEM string
83
+ ca: './path/to/ca.pem', // optional, CA chain
84
+ passphrase: 'optional', // private key passphrase
85
+ },
86
+
87
+ // Optional
88
+ environment: 'production', // 'production' | 'sandbox' (default: 'production')
89
+ baseUrl: 'https://custom.url', // overrides environment URL
90
+ timeout: 30000, // request timeout in ms (default: 30000)
91
+ maxRetries: 3, // retry attempts (default: 3)
92
+ debug: false, // enable debug logging (default: false)
93
+ });
94
+ ```
95
+
96
+ The `certificate` fields accept either a file path or a PEM-encoded string directly. File paths are resolved relative to the current working directory.
97
+
98
+ ### PIX Imediato (`sicredi.cob`)
99
+
100
+ Immediate PIX charges without a due date.
101
+
102
+ #### Create a charge
103
+
104
+ ```typescript
105
+ const charge = await sicredi.cob.create(txid, {
106
+ calendario: { expiracao: 3600 }, // expiration in seconds
107
+ devedor: {
108
+ cpf: '12345678909', // or cnpj: '12345678000195'
109
+ nome: 'Fulano de Tal',
110
+ },
111
+ valor: { original: '100.00' },
112
+ chave: 'your-pix-key',
113
+ solicitacaoPagador: 'Optional description',
114
+ infoAdicionais: [
115
+ { nome: 'Order', valor: '#12345' },
116
+ ],
117
+ });
118
+ ```
119
+
120
+ #### Create with auto-generated txid
121
+
122
+ ```typescript
123
+ const charge = await sicredi.cob.createAuto({
124
+ calendario: { expiracao: 3600 },
125
+ valor: { original: '50.00' },
126
+ chave: 'your-pix-key',
127
+ });
128
+ // charge.txid is generated by Sicredi
129
+ ```
130
+
131
+ #### Get a charge
132
+
133
+ ```typescript
134
+ const charge = await sicredi.cob.get(txid);
135
+ // Optional: pass a revision number
136
+ const charge = await sicredi.cob.get(txid, 2);
137
+ ```
138
+
139
+ #### Update a charge
140
+
141
+ ```typescript
142
+ const updated = await sicredi.cob.update(txid, {
143
+ valor: { original: '150.00' },
144
+ solicitacaoPagador: 'Updated description',
145
+ });
146
+ ```
147
+
148
+ #### Cancel a charge
149
+
150
+ ```typescript
151
+ const cancelled = await sicredi.cob.cancel(txid);
152
+ // Sets status to REMOVIDA_PELO_USUARIO_RECEBEDOR
153
+ ```
154
+
155
+ #### List charges
156
+
157
+ ```typescript
158
+ const list = await sicredi.cob.list({
159
+ inicio: '2026-01-01T00:00:00Z',
160
+ fim: '2026-01-31T23:59:59Z',
161
+ cpf: '12345678909', // optional filter
162
+ status: 'ATIVA', // optional: ATIVA | CONCLUIDA | REMOVIDA_PELO_USUARIO_RECEBEDOR | REMOVIDA_PELO_PSP
163
+ paginacao: {
164
+ paginaAtual: 0,
165
+ itensPorPagina: 10,
166
+ },
167
+ });
168
+
169
+ console.log(list.parametros.paginacao.quantidadeTotalDeItens);
170
+ for (const cob of list.cobs) {
171
+ console.log(cob.txid, cob.status, cob.valor.original);
172
+ }
173
+ ```
174
+
175
+ ### Boleto Hibrido (`sicredi.cobv`)
176
+
177
+ PIX charges with a due date, supporting penalties, interest, and discounts.
178
+
179
+ #### Create a Boleto Hibrido
180
+
181
+ ```typescript
182
+ const cobv = await sicredi.cobv.create(txid, {
183
+ calendario: {
184
+ dataDeVencimento: '2026-03-15', // due date (YYYY-MM-DD)
185
+ validadeAposVencimento: 30, // days valid after due date
186
+ },
187
+ devedor: {
188
+ cnpj: '12345678000195',
189
+ nome: 'Empresa Exemplo LTDA',
190
+ },
191
+ valor: {
192
+ original: '1500.00',
193
+ multa: {
194
+ modalidade: 2, // 1 = fixed value, 2 = percentage
195
+ valorPerc: '2.00', // 2% penalty
196
+ },
197
+ juros: {
198
+ modalidade: 2, // 2 = percentage per month
199
+ valorPerc: '1.00', // 1% per month
200
+ },
201
+ desconto: {
202
+ modalidade: 1, // 1 = fixed value by date
203
+ descontoDataFixa: [
204
+ { data: '2026-03-10', valorPerc: '50.00' },
205
+ ],
206
+ },
207
+ },
208
+ chave: 'your-pix-key',
209
+ solicitacaoPagador: 'Monthly invoice',
210
+ });
211
+ ```
212
+
213
+ #### Get, update, cancel, and list
214
+
215
+ ```typescript
216
+ // Get
217
+ const cobv = await sicredi.cobv.get(txid);
218
+
219
+ // Update
220
+ const updated = await sicredi.cobv.update(txid, {
221
+ valor: { original: '1600.00' },
222
+ });
223
+
224
+ // Cancel
225
+ const cancelled = await sicredi.cobv.cancel(txid);
226
+
227
+ // List
228
+ const list = await sicredi.cobv.list({
229
+ inicio: '2026-01-01T00:00:00Z',
230
+ fim: '2026-01-31T23:59:59Z',
231
+ });
232
+ ```
233
+
234
+ ### Webhooks (`sicredi.webhook`)
235
+
236
+ Configure webhook URLs to receive PIX payment notifications.
237
+
238
+ #### Configure a webhook
239
+
240
+ ```typescript
241
+ await sicredi.webhook.configure('your-pix-key', 'https://your-domain.com/webhook/pix');
242
+ ```
243
+
244
+ #### Get webhook configuration
245
+
246
+ ```typescript
247
+ const webhook = await sicredi.webhook.get('your-pix-key');
248
+ console.log(webhook.webhookUrl);
249
+ console.log(webhook.chave);
250
+ console.log(webhook.criacao);
251
+ ```
252
+
253
+ #### List webhooks
254
+
255
+ ```typescript
256
+ const list = await sicredi.webhook.list({
257
+ inicio: '2026-01-01T00:00:00Z',
258
+ fim: '2026-01-31T23:59:59Z',
259
+ });
260
+
261
+ for (const wh of list.webhooks) {
262
+ console.log(wh.chave, wh.webhookUrl);
263
+ }
264
+ ```
265
+
266
+ #### Delete a webhook
267
+
268
+ ```typescript
269
+ await sicredi.webhook.delete('your-pix-key');
270
+ ```
271
+
272
+ ### PIX Recebidos (`sicredi.pix`)
273
+
274
+ Query received PIX payments and request refunds/returns.
275
+
276
+ #### Get a received PIX payment
277
+
278
+ ```typescript
279
+ const pix = await sicredi.pix.get('E01181521202301011234abcdef12345');
280
+ console.log(pix.endToEndId);
281
+ console.log(pix.valor);
282
+ console.log(pix.chave);
283
+ console.log(pix.horario.solicitacao);
284
+ ```
285
+
286
+ #### List received PIX payments
287
+
288
+ ```typescript
289
+ const list = await sicredi.pix.list({
290
+ inicio: '2026-01-01T00:00:00Z',
291
+ fim: '2026-01-31T23:59:59Z',
292
+ txIdPresente: true, // optional: filter by txid presence
293
+ devolucaoPresente: false, // optional: filter by refund presence
294
+ paginacao: { paginaAtual: 0, itensPorPagina: 50 },
295
+ });
296
+
297
+ for (const pix of list.pix) {
298
+ console.log(pix.endToEndId, pix.valor, pix.horario.solicitacao);
299
+ }
300
+ ```
301
+
302
+ #### Request a refund (devolucao)
303
+
304
+ ```typescript
305
+ const refund = await sicredi.pix.requestReturn(
306
+ 'E01181521202301011234abcdef12345', // endToEndId
307
+ 'refund-001', // devolucao ID
308
+ {
309
+ valor: '50.00',
310
+ natureza: 'ORIGINAL', // optional: 'ORIGINAL' | 'RETIRADA'
311
+ descricao: 'Refund for order #123',
312
+ },
313
+ );
314
+
315
+ console.log(refund.rtrId); // Return Transaction Reference ID
316
+ console.log(refund.status); // 'EM_PROCESSAMENTO' | 'DEVOLVIDO' | 'NAO_REALIZADO'
317
+ ```
318
+
319
+ #### Get refund status
320
+
321
+ ```typescript
322
+ const refund = await sicredi.pix.getReturn(
323
+ 'E01181521202301011234abcdef12345',
324
+ 'refund-001',
325
+ );
326
+ console.log(refund.status);
327
+ ```
328
+
329
+ ### Lote CobV (`sicredi.lotecobv`)
330
+
331
+ Create and manage batches of Boleto Hibrido charges.
332
+
333
+ #### Create a batch
334
+
335
+ ```typescript
336
+ await sicredi.lotecobv.create(1, {
337
+ descricao: 'January invoices',
338
+ cobsv: [
339
+ {
340
+ txid: generateTxId(),
341
+ calendario: { dataDeVencimento: '2026-02-15' },
342
+ devedor: { cpf: '12345678909', nome: 'Cliente A' },
343
+ valor: { original: '200.00' },
344
+ chave: 'your-pix-key',
345
+ },
346
+ {
347
+ txid: generateTxId(),
348
+ calendario: { dataDeVencimento: '2026-02-15' },
349
+ devedor: { cnpj: '12345678000195', nome: 'Empresa B' },
350
+ valor: { original: '500.00' },
351
+ chave: 'your-pix-key',
352
+ },
353
+ ],
354
+ });
355
+ ```
356
+
357
+ #### Update specific charges in a batch
358
+
359
+ ```typescript
360
+ await sicredi.lotecobv.update(1, {
361
+ cobsv: [
362
+ { txid: 'existing-txid-here-12345678', valor: { original: '250.00' } },
363
+ ],
364
+ });
365
+ ```
366
+
367
+ #### Get batch status
368
+
369
+ ```typescript
370
+ const batch = await sicredi.lotecobv.get(1);
371
+ for (const item of batch.cobsv) {
372
+ console.log(item.txid, item.status); // 'EM_PROCESSAMENTO' | 'CRIADA'
373
+ if (item.problema) {
374
+ console.error(item.problema.title, item.problema.detail);
375
+ }
376
+ }
377
+ ```
378
+
379
+ #### List batches
380
+
381
+ ```typescript
382
+ const list = await sicredi.lotecobv.list({
383
+ inicio: '2026-01-01T00:00:00Z',
384
+ fim: '2026-01-31T23:59:59Z',
385
+ });
386
+ ```
387
+
388
+ ### Payload Locations (`sicredi.loc`)
389
+
390
+ Manage payload locations for QR codes.
391
+
392
+ #### Create a location
393
+
394
+ ```typescript
395
+ const loc = await sicredi.loc.create({ tipoCob: 'cob' }); // or 'cobv'
396
+ console.log(loc.id);
397
+ console.log(loc.location);
398
+ ```
399
+
400
+ #### Get a location
401
+
402
+ ```typescript
403
+ const loc = await sicredi.loc.get(42);
404
+ ```
405
+
406
+ #### List locations
407
+
408
+ ```typescript
409
+ const list = await sicredi.loc.list({
410
+ inicio: '2026-01-01T00:00:00Z',
411
+ fim: '2026-01-31T23:59:59Z',
412
+ tipoCob: 'cobv', // optional filter
413
+ });
414
+ ```
415
+
416
+ #### Unlink a txid from a location
417
+
418
+ ```typescript
419
+ await sicredi.loc.unlink(42);
420
+ ```
421
+
422
+ #### Handle webhook callbacks
423
+
424
+ ```typescript
425
+ import { parseWebhookPayload } from '@setup-automatizado/sicredi-sdk';
426
+
427
+ // Works with Express, Koa, Bun, or any framework
428
+ const result = parseWebhookPayload(requestBody);
429
+
430
+ if (result.valid) {
431
+ for (const pix of result.payload!.pix) {
432
+ console.log(pix.endToEndId);
433
+ console.log(pix.txid);
434
+ console.log(pix.valor);
435
+ console.log(pix.chave);
436
+ console.log(pix.horario);
437
+ }
438
+ }
439
+ ```
440
+
441
+ ### Utilities
442
+
443
+ #### Transaction ID
444
+
445
+ ```typescript
446
+ import { generateTxId, isValidTxId } from '@setup-automatizado/sicredi-sdk';
447
+
448
+ const txid = generateTxId(); // 35-char alphanumeric string
449
+ const txid = generateTxId(26); // custom length (26-35)
450
+ isValidTxId('abc123...'); // true/false
451
+ ```
452
+
453
+ #### Validators
454
+
455
+ ```typescript
456
+ import {
457
+ isValidCpf,
458
+ isValidCnpj,
459
+ isValidPixKey,
460
+ detectPixKeyType,
461
+ isValidMonetaryValue,
462
+ } from '@setup-automatizado/sicredi-sdk';
463
+
464
+ isValidCpf('12345678909'); // true/false (with check digits)
465
+ isValidCnpj('12345678000195'); // true/false (with check digits)
466
+ isValidPixKey('+5511999999999'); // true/false
467
+ detectPixKeyType('user@example.com'); // 'email'
468
+ detectPixKeyType('12345678909'); // 'cpf'
469
+ detectPixKeyType('a1b2c3d4-e5f6-7890-abcd-ef1234567890'); // 'evp'
470
+ isValidMonetaryValue('100.00'); // true
471
+ isValidMonetaryValue('100.0'); // false (must be 2 decimal places)
472
+ ```
473
+
474
+ #### QR Code
475
+
476
+ ```typescript
477
+ import { generateQrCodeSvg, generateQrCodeDataUrl } from '@setup-automatizado/sicredi-sdk';
478
+
479
+ // Generate SVG string from PIX "copia e cola"
480
+ const svg = generateQrCodeSvg(charge.pixCopiaECola!, {
481
+ size: 256,
482
+ margin: 4,
483
+ darkColor: '#000000',
484
+ lightColor: '#FFFFFF',
485
+ });
486
+
487
+ // Generate data URL for embedding in HTML <img> tags
488
+ const dataUrl = generateQrCodeDataUrl(charge.pixCopiaECola!);
489
+ // <img src={dataUrl} alt="PIX QR Code" />
490
+ ```
491
+
492
+ #### Date helpers
493
+
494
+ ```typescript
495
+ import {
496
+ toISOString,
497
+ createDateRange,
498
+ parseDate,
499
+ formatDateOnly,
500
+ } from '@setup-automatizado/sicredi-sdk';
501
+
502
+ const { inicio, fim } = createDateRange(30); // last 30 days as ISO strings
503
+ const dateStr = formatDateOnly(new Date()); // '2026-02-08'
504
+ const date = parseDate('2026-02-08T00:00:00Z'); // Date object
505
+ ```
506
+
507
+ #### Constants
508
+
509
+ ```typescript
510
+ import { SICREDI_URLS, SICREDI_ISPB } from '@setup-automatizado/sicredi-sdk';
511
+
512
+ SICREDI_URLS.production; // 'https://api-pix.sicredi.com.br'
513
+ SICREDI_URLS.sandbox; // 'https://api-pix-h.sicredi.com.br'
514
+ SICREDI_ISPB; // '01181521'
515
+ ```
516
+
517
+ ## Error Handling
518
+
519
+ The SDK provides typed error classes for different failure scenarios:
520
+
521
+ ```typescript
522
+ import {
523
+ SicrediApiError,
524
+ SicrediAuthError,
525
+ SicrediValidationError,
526
+ SicrediConnectionError,
527
+ SicrediCertificateError,
528
+ } from '@setup-automatizado/sicredi-sdk';
529
+
530
+ try {
531
+ const charge = await sicredi.cob.create(txid, data);
532
+ } catch (error) {
533
+ if (error instanceof SicrediApiError) {
534
+ // API returned an error response (4xx/5xx)
535
+ console.error('API Error:', error.statusCode);
536
+ console.error('Title:', error.title);
537
+ console.error('Detail:', error.detail);
538
+ console.error('Violations:', error.violacoes);
539
+ } else if (error instanceof SicrediAuthError) {
540
+ // Authentication failed (invalid credentials, expired token)
541
+ console.error('Auth Error:', error.message);
542
+ } else if (error instanceof SicrediValidationError) {
543
+ // Local validation failed (invalid txid, etc.)
544
+ console.error('Validation Error:', error.message);
545
+ } else if (error instanceof SicrediConnectionError) {
546
+ // Network error (timeout, DNS, etc.)
547
+ console.error('Connection Error:', error.message);
548
+ } else if (error instanceof SicrediCertificateError) {
549
+ // Certificate loading/validation failed
550
+ console.error('Certificate Error:', error.message);
551
+ }
552
+ }
553
+ ```
554
+
555
+ All errors extend the base `SicrediError` class, which includes:
556
+ - `message` -- human-readable error description
557
+ - `code` -- machine-readable error code (e.g., `'API_ERROR'`, `'AUTH_ERROR'`)
558
+ - `hint` -- optional suggestion for fixing the issue
559
+
560
+ ## Environments
561
+
562
+ | Environment | Base URL | Description |
563
+ |---|---|---|
564
+ | `production` | `https://api-pix.sicredi.com.br` | Live Sicredi PIX API |
565
+ | `sandbox` | `https://api-pix-h.sicredi.com.br` | Homologation/testing environment |
566
+
567
+ ```typescript
568
+ // Production (default)
569
+ const sicredi = new Sicredi({ environment: 'production', ... });
570
+
571
+ // Sandbox
572
+ const sicredi = new Sicredi({ environment: 'sandbox', ... });
573
+
574
+ // Custom URL (overrides environment)
575
+ const sicredi = new Sicredi({ baseUrl: 'https://custom-proxy.example.com', ... });
576
+ ```
577
+
578
+ ## Certificate Setup
579
+
580
+ Sicredi requires mTLS (mutual TLS) for API authentication. You will need:
581
+
582
+ 1. **Client certificate** (`cert`) -- your application's certificate in PEM format
583
+ 2. **Private key** (`key`) -- the private key corresponding to the certificate in PEM format
584
+ 3. **CA chain** (`ca`) -- Sicredi's complete certificate chain in PEM format (optional but recommended)
585
+
586
+ These are typically provided by Sicredi during the API onboarding process. If your certificates are in PKCS#12 (`.p12` / `.pfx`) format, convert them to PEM:
587
+
588
+ ```bash
589
+ # Extract certificate
590
+ openssl pkcs12 -in certificado.p12 -clcerts -nokeys -out certificado.pem
591
+
592
+ # Extract private key
593
+ openssl pkcs12 -in certificado.p12 -nocerts -nodes -out aplicacao.key
594
+ ```
595
+
596
+ You can provide the certificate as file paths or directly as PEM strings:
597
+
598
+ ```typescript
599
+ // File paths (resolved from cwd)
600
+ certificate: {
601
+ cert: './certs/certificado.pem',
602
+ key: './certs/aplicacao.key',
603
+ ca: './certs/CadeiaCompletaSicredi.pem',
604
+ }
605
+
606
+ // PEM strings (e.g., from environment variables)
607
+ certificate: {
608
+ cert: process.env.SICREDI_CERT!,
609
+ key: process.env.SICREDI_KEY!,
610
+ ca: process.env.SICREDI_CA!,
611
+ }
612
+ ```
613
+
614
+ ## Examples
615
+
616
+ See the [`examples/`](./examples) directory for complete working examples:
617
+
618
+ - **[basic-pix-charge.ts](./examples/basic-pix-charge.ts)** -- Create, query, and list PIX immediate charges
619
+ - **[boleto-hibrido.ts](./examples/boleto-hibrido.ts)** -- Create Boleto Hibrido with penalties, interest, and discounts
620
+ - **[webhook-setup.ts](./examples/webhook-setup.ts)** -- Configure, list, and delete webhooks
621
+ - **[express-webhook-handler.ts](./examples/express-webhook-handler.ts)** -- Handle PIX webhook callbacks with Express
622
+
623
+ ## Contributing
624
+
625
+ Contributions are welcome! Please follow these steps:
626
+
627
+ 1. Fork the repository
628
+ 2. Create a feature branch (`git checkout -b feat/my-feature`)
629
+ 3. Make your changes
630
+ 4. Run checks:
631
+ ```bash
632
+ bun run typecheck
633
+ bun run lint
634
+ bun run test
635
+ ```
636
+ 5. Commit using [Conventional Commits](https://www.conventionalcommits.org/) format
637
+ 6. Open a Pull Request
638
+
639
+ ### Development
640
+
641
+ ```bash
642
+ # Install dependencies
643
+ bun install
644
+
645
+ # Type checking
646
+ bun run typecheck
647
+
648
+ # Linting
649
+ bun run lint
650
+
651
+ # Run tests
652
+ bun run test
653
+
654
+ # Run tests with coverage
655
+ bun run test:coverage
656
+
657
+ # Build
658
+ bun run build
659
+ ```
660
+
661
+ ## License
662
+
663
+ [MIT](./LICENSE) -- Copyright (c) 2026 Guilherme Jansen - Setup Automatizado LTDA