@scell/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 +21 -0
- package/README.md +464 -0
- package/dist/index.d.mts +2292 -0
- package/dist/index.d.ts +2292 -0
- package/dist/index.js +1755 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1748 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +71 -0
- package/src/client.ts +297 -0
- package/src/errors.ts +256 -0
- package/src/index.ts +195 -0
- package/src/resources/api-keys.ts +141 -0
- package/src/resources/auth.ts +286 -0
- package/src/resources/balance.ts +157 -0
- package/src/resources/companies.ts +224 -0
- package/src/resources/invoices.ts +246 -0
- package/src/resources/signatures.ts +245 -0
- package/src/resources/webhooks.ts +258 -0
- package/src/types/api-keys.ts +35 -0
- package/src/types/auth.ts +58 -0
- package/src/types/balance.ts +87 -0
- package/src/types/common.ts +114 -0
- package/src/types/companies.ts +86 -0
- package/src/types/index.ts +115 -0
- package/src/types/invoices.ts +191 -0
- package/src/types/signatures.ts +153 -0
- package/src/types/webhooks.ts +146 -0
- package/src/utils/retry.ts +167 -0
- package/src/utils/webhook-verify.ts +290 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Scell.io
|
|
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,464 @@
|
|
|
1
|
+
# @scell/sdk
|
|
2
|
+
|
|
3
|
+
Official TypeScript SDK for [Scell.io](https://scell.io) - Electronic invoicing (Factur-X/UBL/CII) and eIDAS-compliant electronic signatures API.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Full TypeScript support with strict types
|
|
8
|
+
- Two authentication modes: Bearer token (dashboard) and API key (external API)
|
|
9
|
+
- Automatic retries with exponential backoff and jitter
|
|
10
|
+
- Webhook signature verification
|
|
11
|
+
- Zero external dependencies (uses native fetch)
|
|
12
|
+
- ESM and CommonJS support
|
|
13
|
+
- Node.js 18+ and browser compatible
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @scell/sdk
|
|
19
|
+
# or
|
|
20
|
+
yarn add @scell/sdk
|
|
21
|
+
# or
|
|
22
|
+
pnpm add @scell/sdk
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
### Authentication
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { ScellClient, ScellApiClient, ScellAuth } from '@scell/sdk';
|
|
31
|
+
|
|
32
|
+
// 1. Login to get a token
|
|
33
|
+
const auth = await ScellAuth.login({
|
|
34
|
+
email: 'user@example.com',
|
|
35
|
+
password: 'your-password',
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// 2. Dashboard operations (Bearer token)
|
|
39
|
+
const client = new ScellClient(auth.token);
|
|
40
|
+
|
|
41
|
+
// 3. API operations (X-API-Key)
|
|
42
|
+
const apiClient = new ScellApiClient('your-api-key');
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Create an Invoice
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
const { data: invoice } = await apiClient.invoices.create({
|
|
49
|
+
invoice_number: 'FACT-2024-001',
|
|
50
|
+
direction: 'outgoing',
|
|
51
|
+
output_format: 'facturx',
|
|
52
|
+
issue_date: '2024-01-15',
|
|
53
|
+
due_date: '2024-02-15',
|
|
54
|
+
currency: 'EUR',
|
|
55
|
+
total_ht: 1000.0,
|
|
56
|
+
total_tax: 200.0,
|
|
57
|
+
total_ttc: 1200.0,
|
|
58
|
+
seller_siret: '12345678901234',
|
|
59
|
+
seller_name: 'My Company SAS',
|
|
60
|
+
seller_address: {
|
|
61
|
+
line1: '1 Rue de la Paix',
|
|
62
|
+
postal_code: '75001',
|
|
63
|
+
city: 'Paris',
|
|
64
|
+
country: 'FR',
|
|
65
|
+
},
|
|
66
|
+
buyer_siret: '98765432109876',
|
|
67
|
+
buyer_name: 'Client Company',
|
|
68
|
+
buyer_address: {
|
|
69
|
+
line1: '2 Avenue des Champs',
|
|
70
|
+
postal_code: '75008',
|
|
71
|
+
city: 'Paris',
|
|
72
|
+
country: 'FR',
|
|
73
|
+
},
|
|
74
|
+
lines: [
|
|
75
|
+
{
|
|
76
|
+
description: 'Consulting services - January 2024',
|
|
77
|
+
quantity: 10,
|
|
78
|
+
unit_price: 100.0,
|
|
79
|
+
tax_rate: 20.0,
|
|
80
|
+
total_ht: 1000.0,
|
|
81
|
+
total_tax: 200.0,
|
|
82
|
+
total_ttc: 1200.0,
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
console.log('Invoice created:', invoice.id);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Create a Signature Request
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { readFileSync } from 'fs';
|
|
94
|
+
|
|
95
|
+
const pdfContent = readFileSync('contract.pdf');
|
|
96
|
+
|
|
97
|
+
const { data: signature } = await apiClient.signatures.create({
|
|
98
|
+
title: 'Service Agreement 2024',
|
|
99
|
+
description: 'Annual service contract',
|
|
100
|
+
document: pdfContent.toString('base64'),
|
|
101
|
+
document_name: 'contract.pdf',
|
|
102
|
+
signers: [
|
|
103
|
+
{
|
|
104
|
+
first_name: 'John',
|
|
105
|
+
last_name: 'Doe',
|
|
106
|
+
email: 'john.doe@example.com',
|
|
107
|
+
auth_method: 'email',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
first_name: 'Jane',
|
|
111
|
+
last_name: 'Smith',
|
|
112
|
+
phone: '+33612345678',
|
|
113
|
+
auth_method: 'sms',
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
ui_config: {
|
|
117
|
+
logo_url: 'https://mycompany.com/logo.png',
|
|
118
|
+
primary_color: '#3b82f6',
|
|
119
|
+
company_name: 'My Company',
|
|
120
|
+
},
|
|
121
|
+
redirect_complete_url: 'https://myapp.com/signed',
|
|
122
|
+
redirect_cancel_url: 'https://myapp.com/cancelled',
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Send signing URLs to signers
|
|
126
|
+
signature.signers?.forEach((signer) => {
|
|
127
|
+
console.log(`${signer.email}: ${signer.signing_url}`);
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Webhook Verification
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
import { ScellWebhooks } from '@scell/sdk';
|
|
135
|
+
|
|
136
|
+
// Express.js example
|
|
137
|
+
app.post('/webhooks/scell', async (req, res) => {
|
|
138
|
+
const signature = req.headers['x-scell-signature'] as string;
|
|
139
|
+
const payload = JSON.stringify(req.body);
|
|
140
|
+
|
|
141
|
+
// Verify the webhook signature
|
|
142
|
+
const isValid = await ScellWebhooks.verifySignature(
|
|
143
|
+
payload,
|
|
144
|
+
signature,
|
|
145
|
+
process.env.WEBHOOK_SECRET!
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
if (!isValid) {
|
|
149
|
+
return res.status(401).send('Invalid signature');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Parse and handle the event
|
|
153
|
+
const event = ScellWebhooks.parsePayload(payload);
|
|
154
|
+
|
|
155
|
+
switch (event.event) {
|
|
156
|
+
case 'invoice.validated':
|
|
157
|
+
console.log('Invoice validated:', event.data);
|
|
158
|
+
break;
|
|
159
|
+
case 'signature.completed':
|
|
160
|
+
console.log('Signature completed:', event.data);
|
|
161
|
+
break;
|
|
162
|
+
case 'balance.low':
|
|
163
|
+
console.log('Low balance alert!');
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
res.status(200).send('OK');
|
|
168
|
+
});
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## API Reference
|
|
172
|
+
|
|
173
|
+
### ScellClient (Dashboard)
|
|
174
|
+
|
|
175
|
+
For user/dashboard operations with Bearer token authentication.
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
const client = new ScellClient(token, {
|
|
179
|
+
baseUrl: 'https://api.scell.io/api/v1', // optional
|
|
180
|
+
timeout: 30000, // optional, in ms
|
|
181
|
+
retry: { maxRetries: 3 }, // optional
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// Resources
|
|
185
|
+
client.auth // User authentication
|
|
186
|
+
client.companies // Company management
|
|
187
|
+
client.apiKeys // API key management
|
|
188
|
+
client.balance // Balance and transactions
|
|
189
|
+
client.webhooks // Webhook management
|
|
190
|
+
client.invoices // Invoice listing (read-only)
|
|
191
|
+
client.signatures // Signature listing (read-only)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### ScellApiClient (External API)
|
|
195
|
+
|
|
196
|
+
For creating invoices and signatures with X-API-Key authentication.
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
const apiClient = new ScellApiClient(apiKey, {
|
|
200
|
+
baseUrl: 'https://api.scell.io/api/v1', // optional
|
|
201
|
+
timeout: 30000, // optional
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// Resources
|
|
205
|
+
apiClient.invoices // Create, download, convert invoices
|
|
206
|
+
apiClient.signatures // Create, download, remind, cancel signatures
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Companies
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
// List companies
|
|
213
|
+
const { data: companies } = await client.companies.list();
|
|
214
|
+
|
|
215
|
+
// Create company
|
|
216
|
+
const { data: company } = await client.companies.create({
|
|
217
|
+
name: 'My Company',
|
|
218
|
+
siret: '12345678901234',
|
|
219
|
+
address_line1: '1 Rue Example',
|
|
220
|
+
postal_code: '75001',
|
|
221
|
+
city: 'Paris',
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// Update company
|
|
225
|
+
await client.companies.update(companyId, { email: 'new@example.com' });
|
|
226
|
+
|
|
227
|
+
// Delete company
|
|
228
|
+
await client.companies.delete(companyId);
|
|
229
|
+
|
|
230
|
+
// KYC
|
|
231
|
+
const kyc = await client.companies.initiateKyc(companyId);
|
|
232
|
+
const status = await client.companies.kycStatus(companyId);
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Invoices
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
// List invoices (dashboard)
|
|
239
|
+
const { data, meta } = await client.invoices.list({
|
|
240
|
+
direction: 'outgoing',
|
|
241
|
+
status: 'validated',
|
|
242
|
+
from: '2024-01-01',
|
|
243
|
+
per_page: 50,
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// Get invoice
|
|
247
|
+
const { data: invoice } = await client.invoices.get(invoiceId);
|
|
248
|
+
|
|
249
|
+
// Create invoice (API key required)
|
|
250
|
+
const { data: newInvoice } = await apiClient.invoices.create({...});
|
|
251
|
+
|
|
252
|
+
// Download
|
|
253
|
+
const { url, expires_at } = await apiClient.invoices.download(invoiceId, 'pdf');
|
|
254
|
+
|
|
255
|
+
// Audit trail
|
|
256
|
+
const { data: trail, integrity_valid } = await apiClient.invoices.auditTrail(invoiceId);
|
|
257
|
+
|
|
258
|
+
// Convert format
|
|
259
|
+
await apiClient.invoices.convert({ invoice_id: invoiceId, target_format: 'ubl' });
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Signatures
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
// List signatures (dashboard)
|
|
266
|
+
const { data, meta } = await client.signatures.list({
|
|
267
|
+
status: 'pending',
|
|
268
|
+
per_page: 25,
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// Get signature
|
|
272
|
+
const { data: signature } = await client.signatures.get(signatureId);
|
|
273
|
+
|
|
274
|
+
// Create signature (API key required)
|
|
275
|
+
const { data: newSignature } = await apiClient.signatures.create({...});
|
|
276
|
+
|
|
277
|
+
// Download files
|
|
278
|
+
const { url: signedUrl } = await apiClient.signatures.download(signatureId, 'signed');
|
|
279
|
+
const { url: auditUrl } = await apiClient.signatures.download(signatureId, 'audit_trail');
|
|
280
|
+
|
|
281
|
+
// Send reminder
|
|
282
|
+
const { signers_reminded } = await apiClient.signatures.remind(signatureId);
|
|
283
|
+
|
|
284
|
+
// Cancel
|
|
285
|
+
await apiClient.signatures.cancel(signatureId);
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Balance
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
// Get balance
|
|
292
|
+
const { data: balance } = await client.balance.get();
|
|
293
|
+
console.log(`${balance.amount} ${balance.currency}`);
|
|
294
|
+
|
|
295
|
+
// Reload balance
|
|
296
|
+
const { transaction } = await client.balance.reload({ amount: 100 });
|
|
297
|
+
|
|
298
|
+
// Update settings
|
|
299
|
+
await client.balance.updateSettings({
|
|
300
|
+
auto_reload_enabled: true,
|
|
301
|
+
auto_reload_threshold: 50,
|
|
302
|
+
auto_reload_amount: 200,
|
|
303
|
+
low_balance_alert_threshold: 100,
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
// List transactions
|
|
307
|
+
const { data: transactions } = await client.balance.transactions({
|
|
308
|
+
type: 'debit',
|
|
309
|
+
service: 'invoice',
|
|
310
|
+
from: '2024-01-01',
|
|
311
|
+
});
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### Webhooks
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
// List webhooks
|
|
318
|
+
const { data: webhooks } = await client.webhooks.list();
|
|
319
|
+
|
|
320
|
+
// Create webhook
|
|
321
|
+
const { data: webhook } = await client.webhooks.create({
|
|
322
|
+
url: 'https://myapp.com/webhooks/scell',
|
|
323
|
+
events: ['invoice.validated', 'signature.completed', 'balance.low'],
|
|
324
|
+
environment: 'production',
|
|
325
|
+
});
|
|
326
|
+
// IMPORTANT: Store webhook.secret securely!
|
|
327
|
+
|
|
328
|
+
// Update webhook
|
|
329
|
+
await client.webhooks.update(webhookId, { is_active: false });
|
|
330
|
+
|
|
331
|
+
// Test webhook
|
|
332
|
+
const result = await client.webhooks.test(webhookId);
|
|
333
|
+
console.log('Test successful:', result.success);
|
|
334
|
+
|
|
335
|
+
// Regenerate secret
|
|
336
|
+
const { data: updated } = await client.webhooks.regenerateSecret(webhookId);
|
|
337
|
+
// Update your stored secret!
|
|
338
|
+
|
|
339
|
+
// View logs
|
|
340
|
+
const { data: logs } = await client.webhooks.logs(webhookId);
|
|
341
|
+
|
|
342
|
+
// Delete webhook
|
|
343
|
+
await client.webhooks.delete(webhookId);
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
## Error Handling
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
import {
|
|
350
|
+
ScellError,
|
|
351
|
+
ScellAuthenticationError,
|
|
352
|
+
ScellValidationError,
|
|
353
|
+
ScellRateLimitError,
|
|
354
|
+
ScellNotFoundError,
|
|
355
|
+
ScellInsufficientBalanceError,
|
|
356
|
+
} from '@scell/sdk';
|
|
357
|
+
|
|
358
|
+
try {
|
|
359
|
+
await apiClient.invoices.create(data);
|
|
360
|
+
} catch (error) {
|
|
361
|
+
if (error instanceof ScellValidationError) {
|
|
362
|
+
console.log('Validation errors:', error.errors);
|
|
363
|
+
error.getAllMessages().forEach(msg => console.log(msg));
|
|
364
|
+
} else if (error instanceof ScellAuthenticationError) {
|
|
365
|
+
console.log('Invalid credentials');
|
|
366
|
+
} else if (error instanceof ScellRateLimitError) {
|
|
367
|
+
console.log(`Rate limited. Retry after ${error.retryAfter}s`);
|
|
368
|
+
} else if (error instanceof ScellInsufficientBalanceError) {
|
|
369
|
+
console.log('Insufficient balance, please reload');
|
|
370
|
+
} else if (error instanceof ScellNotFoundError) {
|
|
371
|
+
console.log('Resource not found');
|
|
372
|
+
} else if (error instanceof ScellError) {
|
|
373
|
+
console.log(`API error: ${error.message} (${error.status})`);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
## Retry Configuration
|
|
379
|
+
|
|
380
|
+
The SDK automatically retries failed requests for rate limits (429) and server errors (5xx).
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
import { withRetry, createRetryWrapper } from '@scell/sdk';
|
|
384
|
+
|
|
385
|
+
// Custom retry options
|
|
386
|
+
const client = new ScellClient(token, {
|
|
387
|
+
retry: {
|
|
388
|
+
maxRetries: 5,
|
|
389
|
+
baseDelay: 1000,
|
|
390
|
+
maxDelay: 30000,
|
|
391
|
+
jitterFactor: 0.1,
|
|
392
|
+
},
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
// Disable retry for specific request
|
|
396
|
+
const result = await client.companies.list({ skipRetry: true });
|
|
397
|
+
|
|
398
|
+
// Manual retry wrapper
|
|
399
|
+
const result = await withRetry(
|
|
400
|
+
() => apiClient.invoices.create(data),
|
|
401
|
+
{ maxRetries: 5 }
|
|
402
|
+
);
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## Webhook Events
|
|
406
|
+
|
|
407
|
+
| Event | Description |
|
|
408
|
+
|-------|-------------|
|
|
409
|
+
| `invoice.created` | Invoice created |
|
|
410
|
+
| `invoice.validated` | Invoice validated |
|
|
411
|
+
| `invoice.transmitted` | Invoice transmitted to recipient |
|
|
412
|
+
| `invoice.accepted` | Invoice accepted |
|
|
413
|
+
| `invoice.rejected` | Invoice rejected |
|
|
414
|
+
| `invoice.error` | Invoice processing error |
|
|
415
|
+
| `signature.created` | Signature request created |
|
|
416
|
+
| `signature.waiting` | Waiting for signers |
|
|
417
|
+
| `signature.signed` | A signer has signed |
|
|
418
|
+
| `signature.completed` | All signers have signed |
|
|
419
|
+
| `signature.refused` | Signature refused |
|
|
420
|
+
| `signature.expired` | Signature expired |
|
|
421
|
+
| `signature.error` | Signature processing error |
|
|
422
|
+
| `balance.low` | Balance below low threshold |
|
|
423
|
+
| `balance.critical` | Balance below critical threshold |
|
|
424
|
+
|
|
425
|
+
## TypeScript Types
|
|
426
|
+
|
|
427
|
+
All types are exported and can be imported:
|
|
428
|
+
|
|
429
|
+
```typescript
|
|
430
|
+
import type {
|
|
431
|
+
Invoice,
|
|
432
|
+
InvoiceStatus,
|
|
433
|
+
InvoiceDirection,
|
|
434
|
+
CreateInvoiceInput,
|
|
435
|
+
Signature,
|
|
436
|
+
SignatureStatus,
|
|
437
|
+
CreateSignatureInput,
|
|
438
|
+
Signer,
|
|
439
|
+
Company,
|
|
440
|
+
Balance,
|
|
441
|
+
Transaction,
|
|
442
|
+
Webhook,
|
|
443
|
+
WebhookEvent,
|
|
444
|
+
WebhookPayload,
|
|
445
|
+
} from '@scell/sdk';
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
## Environment Variables
|
|
449
|
+
|
|
450
|
+
```bash
|
|
451
|
+
# API Configuration
|
|
452
|
+
SCELL_API_URL=https://api.scell.io/api/v1
|
|
453
|
+
SCELL_API_KEY=your-api-key
|
|
454
|
+
SCELL_WEBHOOK_SECRET=whsec_your-webhook-secret
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
## Requirements
|
|
458
|
+
|
|
459
|
+
- Node.js 18.0.0 or higher (for native fetch)
|
|
460
|
+
- TypeScript 5.0 or higher (for development)
|
|
461
|
+
|
|
462
|
+
## License
|
|
463
|
+
|
|
464
|
+
MIT
|