@sanghosdk/js 0.1.2

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,2559 @@
1
+ /**
2
+ * Vérifie la signature HMAC-SHA256 d'un événement webhook Sangho.
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * // `constructEvent` est une méthode statique de `Sangho`, pas une méthode
7
+ * // d'instance sur `sangho.webhooks` — pas besoin d'avoir instancié le client.
8
+ * const event = await Sangho.constructEvent(
9
+ * rawBody,
10
+ * request.headers['sangho-signature'],
11
+ * 'whsec_xxxxx'
12
+ * )
13
+ * ```
14
+ */
15
+ declare function constructEvent<T = unknown>(payload: string | Uint8Array, signature: string, secret: string, tolerance?: number): Promise<{
16
+ id: string;
17
+ type: string;
18
+ created: number;
19
+ data: T;
20
+ }>;
21
+
22
+ interface ListParams {
23
+ /** Numéro de page (défaut : 1) */
24
+ page?: number;
25
+ /** Nombre d'éléments par page (défaut : 20, max : 100) */
26
+ page_size?: number;
27
+ /** Tri ex: "-created_at" (préfixe - pour DESC) */
28
+ ordering?: string;
29
+ /** Recherche full-text */
30
+ search?: string;
31
+ }
32
+ interface ListResponse<T> {
33
+ count: number;
34
+ next: string | null;
35
+ previous: string | null;
36
+ data: T[];
37
+ }
38
+ interface Timestamps {
39
+ created_at: string;
40
+ updated_at: string;
41
+ }
42
+ /** Montant monétaire exprimé en centimes (integer). Ex: 5000 = 50.00 XAF */
43
+ type AmountInCents = number;
44
+ /**
45
+ * Codes ISO 4217 actifs acceptés au niveau du *type* par le SDK.
46
+ *
47
+ * Important : cette liste ne représente que la validité ISO 4217 générale,
48
+ * PAS ce qu'un marchand donné a le droit d'utiliser. Sangho facture/entitle
49
+ * les devises par plan — un marchand ne peut utiliser à l'exécution que le
50
+ * sous-ensemble de devises inclus dans son plan (ou activé en backoffice).
51
+ * Utiliser une devise valide ISO 4217 mais hors plan est un problème
52
+ * *runtime*, tranché par le backend, qui répond avec une `SanghoError` dont
53
+ * `.code` vaut `CURRENCY_NOT_IN_PLAN` (ou `INVALID_CURRENCY` si le code
54
+ * n'est même pas un ISO 4217 reconnu) — voir `core/errors.ts`. Le SDK ne
55
+ * peut pas connaître statiquement le plan d'un marchand donné : il n'essaie
56
+ * donc pas d'imposer cette restriction au niveau des types, seulement la
57
+ * validité ISO 4217 elle-même.
58
+ */
59
+ declare const ISO_4217_CURRENCIES: readonly ["AED", "AFN", "ALL", "AMD", "ANG", "AOA", "ARS", "AUD", "AWG", "AZN", "BAM", "BBD", "BDT", "BGN", "BHD", "BIF", "BMD", "BND", "BOB", "BRL", "BSD", "BTN", "BWP", "BYN", "BZD", "CAD", "CDF", "CHF", "CLP", "CNY", "COP", "CRC", "CUP", "CVE", "CZK", "DJF", "DKK", "DOP", "DZD", "EGP", "ERN", "ETB", "EUR", "FJD", "FKP", "GBP", "GEL", "GHS", "GIP", "GMD", "GNF", "GTQ", "GYD", "HKD", "HNL", "HTG", "HUF", "IDR", "ILS", "INR", "IQD", "IRR", "ISK", "JMD", "JOD", "JPY", "KES", "KGS", "KHR", "KMF", "KPW", "KRW", "KWD", "KYD", "KZT", "LAK", "LBP", "LKR", "LRD", "LSL", "LYD", "MAD", "MDL", "MGA", "MKD", "MMK", "MNT", "MOP", "MRU", "MUR", "MVR", "MWK", "MXN", "MYR", "MZN", "NAD", "NGN", "NIO", "NOK", "NPR", "NZD", "OMR", "PAB", "PEN", "PGK", "PHP", "PKR", "PLN", "PYG", "QAR", "RON", "RSD", "RUB", "RWF", "SAR", "SBD", "SCR", "SDG", "SEK", "SGD", "SHP", "SLE", "SOS", "SRD", "SSP", "STN", "SYP", "SZL", "THB", "TJS", "TMT", "TND", "TOP", "TRY", "TTD", "TWD", "TZS", "UAH", "UGX", "USD", "UYU", "UZS", "VES", "VND", "VUV", "WST", "XAF", "XCD", "XOF", "XPF", "YER", "ZAR", "ZMW", "ZWL"];
60
+ /**
61
+ * Devise ISO 4217 valide (union dérivée de `ISO_4217_CURRENCIES` — source
62
+ * de vérité unique). Ne préjuge pas de ce qu'un marchand a le droit
63
+ * d'utiliser : voir la note sur `ISO_4217_CURRENCIES` ci-dessus.
64
+ */
65
+ type CurrencyCode = (typeof ISO_4217_CURRENCIES)[number];
66
+ /** Dictionnaire clé/valeur libre, max 50 clés, valeurs string. */
67
+ type Metadata = Record<string, string>;
68
+ interface Address {
69
+ line1: string;
70
+ line2?: string;
71
+ city: string;
72
+ state?: string;
73
+ postal_code?: string;
74
+ country: string;
75
+ }
76
+ interface SanghoOptions {
77
+ /** Override URL de base (utile pour tests/staging) */
78
+ baseURL?: string;
79
+ /** Timeout en ms (défaut : 30 000) */
80
+ timeout?: number;
81
+ /** Nombre de retries auto (défaut : 3) */
82
+ maxRetries?: number;
83
+ }
84
+ /**
85
+ * A utility type for creating class property interfaces that don't overwrite
86
+ * actual implementation values when used as type definitions
87
+ */
88
+ type InterfaceOnly<T> = {
89
+ [P in keyof T]?: T[P];
90
+ };
91
+ interface DRFOptions {
92
+ name: string;
93
+ description: string;
94
+ renders: string[];
95
+ parses: string[];
96
+ actions?: Record<string, unknown>;
97
+ }
98
+ type ForeignKey = string | number | null;
99
+
100
+ type AppMode = "test" | "prod";
101
+ type AppEnvironment = "sandbox" | "live";
102
+ interface AppCriteria {
103
+ is_active?: boolean;
104
+ name?: string;
105
+ environment?: AppEnvironment;
106
+ mode?: AppMode;
107
+ [key: string]: string | number | boolean;
108
+ }
109
+ interface AppKey {
110
+ id: string;
111
+ value: string;
112
+ name: string;
113
+ is_active: boolean;
114
+ created_at: string;
115
+ }
116
+ interface AppKeys {
117
+ pk: AppKey;
118
+ sk: AppKey;
119
+ }
120
+ interface App extends Timestamps {
121
+ id: string;
122
+ object: "app";
123
+ name: string;
124
+ description?: string | null;
125
+ logo?: string | null;
126
+ mode: AppMode;
127
+ environment: AppEnvironment;
128
+ currency: string;
129
+ is_active: boolean;
130
+ is_verified: boolean;
131
+ allowed_hosts: string[];
132
+ allowed_ips: string[];
133
+ company?: ForeignKey;
134
+ }
135
+ interface Payloads$9 {
136
+ name?: string;
137
+ description?: string;
138
+ logo?: File | string;
139
+ allowed_hosts?: string[];
140
+ allowed_ips?: string[];
141
+ is_active?: boolean;
142
+ }
143
+
144
+ type AccountProperties = {
145
+ /**
146
+ * Retourne l'application liée à la clé secrète courante.
147
+ * Nécessite une clé secrète (`sk_prod_*` ou `sk_test_*`).
148
+ *
149
+ * @example
150
+ * const app = await sangho.account.retrieve()
151
+ * console.log(app.id, app.mode)
152
+ */
153
+ retrieve(): Promise<App>;
154
+ };
155
+
156
+ type AppsProperties = {
157
+ /**
158
+ * Liste toutes les applications de l'owner authentifié.
159
+ * Si `criteria` est fourni, filtre les apps par les champs indiqués
160
+ * (transmis en query params). Sans critères, retourne tout.
161
+ *
162
+ * @param criteria - Filtres optionnels ex: `{ is_active: true, mode: "prod" }`
163
+ * @returns Tableau des apps correspondant aux critères
164
+ *
165
+ * @example
166
+ * const all = await sangho.apps.list()
167
+ * const prod = await sangho.apps.list({ mode: "prod", is_active: true })
168
+ */
169
+ list(criteria?: AppCriteria): Promise<App[]>;
170
+ /**
171
+ * Récupère une application par son identifiant.
172
+ *
173
+ * @param id - Identifiant de l'application (ex: `"app_xxx"`)
174
+ * @returns Les données de l'application
175
+ *
176
+ * @example
177
+ * const app = await sangho.apps.retrieve("app_xxx")
178
+ * console.log(app.mode) // "test" | "prod"
179
+ */
180
+ retrieve(id: string): Promise<App>;
181
+ /**
182
+ * Crée une nouvelle application.
183
+ * Si une app portant le même `name` existe déjà pour cet owner,
184
+ * le backend la retourne telle quelle (idempotent, HTTP 200).
185
+ *
186
+ * @param payloads - Champs de création (`name` recommandé)
187
+ * @returns L'application créée (HTTP 201) ou existante (HTTP 200)
188
+ *
189
+ * @example
190
+ * const app = await sangho.apps.create({ name: "Mon App" })
191
+ */
192
+ create(payloads: Payloads$9): Promise<App>;
193
+ /**
194
+ * Met à jour les paramètres de l'application (mise à jour partielle).
195
+ * La modification est propagée en sandbox et en live automatiquement.
196
+ *
197
+ * @param id - Identifiant de l'application
198
+ * @param payloads - Champs à modifier (tous optionnels)
199
+ * @returns L'application mise à jour
200
+ *
201
+ * @example
202
+ * const app = await sangho.apps.update("app_xxx", {
203
+ * name: "Mon App v2",
204
+ * allowed_hosts: ["mon-site.com"],
205
+ * })
206
+ */
207
+ update(id: string, payloads: Payloads$9): Promise<App>;
208
+ /**
209
+ * Suppression douce (soft-delete) de l'application.
210
+ * L'app est marquée `is_ready_to_delete` et purgée définitivement
211
+ * après un délai configuré côté backend.
212
+ *
213
+ * @param id - Identifiant de l'application
214
+ *
215
+ * @example
216
+ * await sangho.apps.delete("app_xxx")
217
+ */
218
+ delete(id: string): Promise<void>;
219
+ /**
220
+ * Récupère les clés publique et secrète de l'application.
221
+ * Les valeurs retournées sont partiellement obfusquées
222
+ * (13 caractères visibles, reste masqué).
223
+ *
224
+ * @param id - Identifiant de l'application
225
+ * @returns `{ pk: AppKey, sk: AppKey }`
226
+ *
227
+ * @example
228
+ * const { pk, sk } = await sangho.apps.keys("app_xxx")
229
+ * console.log(pk.value) // "apk_live_xxxxx..."
230
+ */
231
+ keys(id: string): Promise<AppKeys>;
232
+ /**
233
+ * Retourne les métadonnées DRF du endpoint `/apps/` :
234
+ * actions autorisées, schéma de champs, formats acceptés.
235
+ * N'exige pas d'authentification (découverte de schéma).
236
+ */
237
+ options(): Promise<DRFOptions>;
238
+ };
239
+
240
+ type AddressType = "main" | "branch" | "billing" | "shipping";
241
+ interface CompanyAddress extends Timestamps {
242
+ id: string;
243
+ object: "address";
244
+ company: string;
245
+ type: AddressType;
246
+ line1: string;
247
+ line2?: string | null;
248
+ neighborhood?: string | null;
249
+ city: string;
250
+ state?: string | null;
251
+ province?: string | null;
252
+ postal_code: string;
253
+ country: string;
254
+ is_active: boolean;
255
+ full_address: string;
256
+ }
257
+ /** Champs requis à la création — alignés sur CreateAddressSerializer */
258
+ interface CreatePayloads$9 {
259
+ type?: AddressType;
260
+ line1: string;
261
+ line2?: string;
262
+ neighborhood?: string;
263
+ city: string;
264
+ state?: string;
265
+ province?: string;
266
+ postal_code: string;
267
+ country: string;
268
+ }
269
+ /** Champs PATCH — tous optionnels, alignés sur AddressSerializer */
270
+ interface Payloads$8 {
271
+ type?: AddressType;
272
+ line1?: string;
273
+ line2?: string;
274
+ neighborhood?: string;
275
+ city?: string;
276
+ state?: string;
277
+ province?: string;
278
+ postal_code?: string;
279
+ country?: string;
280
+ is_active?: boolean;
281
+ }
282
+ /** Filtres GET /addresses/ — alignés sur get_queryset() */
283
+ interface AddressCriteria {
284
+ type?: AddressType;
285
+ is_active?: boolean;
286
+ }
287
+
288
+ type AddressesProperties = {
289
+ /**
290
+ * Liste toutes les adresses de l'entreprise liée à l'app.
291
+ * Filtre par `type` et/ou `is_active` si `criteria` est fourni,
292
+ * sinon retourne toutes les adresses.
293
+ *
294
+ * @param criteria - Filtres optionnels (type, is_active)
295
+ * @returns Tableau des adresses correspondantes
296
+ *
297
+ * @example
298
+ * const all = await sangho.addresses.list()
299
+ * const billing = await sangho.addresses.list({ type: "billing" })
300
+ * const active = await sangho.addresses.list({ is_active: true })
301
+ */
302
+ list(criteria?: AddressCriteria): Promise<CompanyAddress[]>;
303
+ /**
304
+ * Récupère une adresse par son identifiant.
305
+ *
306
+ * @param id - Identifiant de l'adresse
307
+ * @returns L'adresse correspondante
308
+ *
309
+ * @example
310
+ * const addr = await sangho.addresses.retrieve("123")
311
+ */
312
+ retrieve(id: string): Promise<CompanyAddress>;
313
+ /**
314
+ * Crée une nouvelle adresse pour l'entreprise liée à l'app.
315
+ * Si `type` vaut `"main"`, les autres adresses principales
316
+ * sont automatiquement reclassées en `"branch"` (backend).
317
+ *
318
+ * @param payloads - `line1`, `city`, `postal_code`, `country` requis
319
+ * @returns L'adresse créée
320
+ *
321
+ * @example
322
+ * const addr = await sangho.addresses.create({
323
+ * type: "billing",
324
+ * line1: "123 Avenue Léon MBA",
325
+ * city: "Libreville",
326
+ * postal_code: "00000",
327
+ * country: "GA",
328
+ * })
329
+ */
330
+ create(payloads: CreatePayloads$9): Promise<CompanyAddress>;
331
+ /**
332
+ * Met à jour partiellement une adresse (PATCH).
333
+ * L'adresse principale (`type: "main"`) ne peut pas être désactivée
334
+ * via `delete` — mais ses autres champs restent modifiables ici.
335
+ *
336
+ * @param id - Identifiant de l'adresse
337
+ * @param payloads - Champs à modifier (tous optionnels)
338
+ * @returns L'adresse mise à jour
339
+ *
340
+ * @example
341
+ * await sangho.addresses.update("123", { city: "Port-Gentil" })
342
+ */
343
+ update(id: string, payloads: Payloads$8): Promise<CompanyAddress>;
344
+ /**
345
+ * Désactive une adresse (soft delete — `is_active: false`).
346
+ * Le backend retourne HTTP 204 sans corps.
347
+ * L'adresse principale (`type: "main"`) ne peut pas être supprimée.
348
+ *
349
+ * @param id - Identifiant de l'adresse
350
+ *
351
+ * @example
352
+ * await sangho.addresses.delete("123")
353
+ */
354
+ delete(id: string): Promise<void>;
355
+ /**
356
+ * Retourne les métadonnées DRF du endpoint `/addresses/` :
357
+ * actions autorisées, schéma de champs, formats acceptés.
358
+ * N'exige pas d'authentification (découverte de schéma).
359
+ */
360
+ options(): Promise<DRFOptions>;
361
+ };
362
+
363
+ type PaymentIntentStatus = "requires_payment_method" | "requires_confirmation" | "requires_action" | "pending" | "processing" | "requires_capture" | "canceled" | "succeeded";
364
+ type CancellationReason = "duplicate" | "fraudulent" | "requested_by_customer" | "abandoned";
365
+ /**
366
+ * Représente un PaymentIntent Sangho.
367
+ * Préfixe d'identifiant : `pi_xxx`
368
+ * Expand disponibles : `?expand=customer`, `?expand=payment_link`
369
+ */
370
+ interface PaymentIntent extends Timestamps {
371
+ id: string;
372
+ object: "payment_intent";
373
+ reference: string;
374
+ customer_email?: string | null;
375
+ customer?: object | null;
376
+ currency: CurrencyCode;
377
+ amount: number;
378
+ status: PaymentIntentStatus;
379
+ description?: string | null;
380
+ payment_method?: string | null;
381
+ payment_method_types: string[];
382
+ category?: string | null;
383
+ url?: string | null;
384
+ payment_link?: string | null;
385
+ cancellation_reason?: string | null;
386
+ receipt_email?: string | null;
387
+ expires_at?: string | null;
388
+ metadata: Metadata;
389
+ }
390
+ /** Champs POST — alignés sur PaymentIntentSerializer + perform_create() */
391
+ interface CreatePayloads$8 {
392
+ amount: AmountInCents;
393
+ currency: CurrencyCode;
394
+ customer?: string;
395
+ description?: string;
396
+ payment_method?: string;
397
+ payment_method_types?: string[];
398
+ category?: string;
399
+ receipt_email?: string;
400
+ metadata?: Metadata;
401
+ /**
402
+ * Si `true`, le PaymentIntent passe immédiatement en `"processing"`
403
+ * après création (géré via `metadata._confirm_on_create` backend).
404
+ */
405
+ confirm?: boolean;
406
+ }
407
+ /** Champs PATCH — tous optionnels */
408
+ interface Payloads$7 {
409
+ amount?: AmountInCents;
410
+ currency?: CurrencyCode;
411
+ customer?: string;
412
+ description?: string;
413
+ payment_method?: string;
414
+ payment_method_types?: string[];
415
+ receipt_email?: string;
416
+ metadata?: Metadata;
417
+ }
418
+ /** Paramètres POST /payment-intents/:id/confirm/ */
419
+ interface ConfirmPayloads {
420
+ payment_method?: string;
421
+ }
422
+ /** Paramètres POST /payment-intents/:id/capture/ */
423
+ interface CapturePayloads {
424
+ /** Montant à capturer en centimes (≤ montant original) */
425
+ amount_to_capture?: AmountInCents;
426
+ }
427
+ /** Paramètres POST /payment-intents/:id/cancel/ */
428
+ interface CancelPayloads {
429
+ cancellation_reason?: CancellationReason;
430
+ }
431
+ /** Filtres GET /payment-intents/ — alignés sur get_queryset() */
432
+ interface PaymentIntentCriteria extends ListParams {
433
+ status?: PaymentIntentStatus;
434
+ currency?: CurrencyCode;
435
+ customer?: string;
436
+ created_after?: string;
437
+ created_before?: string;
438
+ }
439
+
440
+ type PaymentIntentsProperties = {
441
+ /**
442
+ * Liste les PaymentIntents avec filtres et pagination.
443
+ *
444
+ * @param criteria - Filtres optionnels (status, currency, customer, dates, pagination)
445
+ * @returns Liste paginée de PaymentIntents
446
+ *
447
+ * @example
448
+ * const all = await sangho.paymentIntents.list()
449
+ * const succeeded = await sangho.paymentIntents.list({ status: "succeeded" })
450
+ * const byEmail = await sangho.paymentIntents.list({ customer: "jean@example.com" })
451
+ */
452
+ list(criteria?: PaymentIntentCriteria): Promise<ListResponse<PaymentIntent>>;
453
+ /**
454
+ * Récupère un PaymentIntent par son identifiant.
455
+ * Ajouter `?expand=customer` ou `?expand=payment_link` pour les objets complets.
456
+ *
457
+ * @param id - Identifiant du PaymentIntent (format `pi_xxx`)
458
+ * @returns Le PaymentIntent correspondant
459
+ *
460
+ * @example
461
+ * const intent = await sangho.paymentIntents.retrieve("pi_xxx")
462
+ */
463
+ retrieve(id: string): Promise<PaymentIntent>;
464
+ /**
465
+ * Crée un nouveau PaymentIntent.
466
+ * Statut initial : `"requires_payment_method"`.
467
+ * Si `confirm: true`, passe immédiatement en `"processing"`.
468
+ *
469
+ * @param payloads - `amount` et `currency` requis
470
+ * @returns Le PaymentIntent créé
471
+ *
472
+ * @example
473
+ * const intent = await sangho.paymentIntents.create({
474
+ * amount: 5000,
475
+ * currency: "XAF",
476
+ * description: "Commande #42",
477
+ * })
478
+ */
479
+ create(payloads: CreatePayloads$8): Promise<PaymentIntent>;
480
+ /**
481
+ * Met à jour un PaymentIntent avant sa confirmation (PATCH).
482
+ *
483
+ * @param id - Identifiant du PaymentIntent (format `pi_xxx`)
484
+ * @param payloads - Champs à modifier (tous optionnels)
485
+ * @returns Le PaymentIntent mis à jour
486
+ *
487
+ * @example
488
+ * await sangho.paymentIntents.update("pi_xxx", {
489
+ * description: "Nouvelle description",
490
+ * metadata: { order_id: "42" },
491
+ * })
492
+ */
493
+ update(id: string, payloads: Payloads$7): Promise<PaymentIntent>;
494
+ /**
495
+ * Annule un PaymentIntent via DELETE (alias de `cancel()`).
496
+ * Retourne le PaymentIntent avec `status: "canceled"` (HTTP 200).
497
+ * Ne fonctionne pas sur les statuts `"canceled"` ou `"succeeded"`.
498
+ *
499
+ * @param id - Identifiant du PaymentIntent (format `pi_xxx`)
500
+ * @returns Le PaymentIntent annulé
501
+ *
502
+ * @example
503
+ * const canceled = await sangho.paymentIntents.delete("pi_xxx")
504
+ */
505
+ delete(id: string): Promise<PaymentIntent>;
506
+ /**
507
+ * Confirme un PaymentIntent pour déclencher le paiement.
508
+ * Statuts acceptés : `"requires_payment_method"`, `"requires_confirmation"`.
509
+ * Passe en `"processing"` après confirmation.
510
+ *
511
+ * @param id - Identifiant du PaymentIntent (format `pi_xxx`)
512
+ * @param payloads - Mode de paiement optionnel
513
+ * @returns Le PaymentIntent confirmé
514
+ *
515
+ * @example
516
+ * const intent = await sangho.paymentIntents.confirm("pi_xxx", {
517
+ * payment_method: "meth_xxx",
518
+ * })
519
+ */
520
+ confirm(id: string, payloads?: ConfirmPayloads): Promise<PaymentIntent>;
521
+ /**
522
+ * Capture un PaymentIntent en mode de capture manuelle.
523
+ * Nécessite `status: "requires_capture"`.
524
+ * Passe en `"succeeded"` après capture.
525
+ *
526
+ * @param id - Identifiant du PaymentIntent (format `pi_xxx`)
527
+ * @param payloads - Montant à capturer (≤ montant original, optionnel)
528
+ * @returns Le PaymentIntent capturé
529
+ *
530
+ * @example
531
+ * await sangho.paymentIntents.capture("pi_xxx", { amount_to_capture: 3000 })
532
+ */
533
+ capture(id: string, payloads?: CapturePayloads): Promise<PaymentIntent>;
534
+ /**
535
+ * Annule explicitement un PaymentIntent.
536
+ * Impossible si `status` vaut `"canceled"` ou `"succeeded"`.
537
+ *
538
+ * @param id - Identifiant du PaymentIntent (format `pi_xxx`)
539
+ * @param payloads - Raison d'annulation (défaut: `"requested_by_customer"`)
540
+ * @returns Le PaymentIntent annulé avec `status: "canceled"`
541
+ *
542
+ * @example
543
+ * await sangho.paymentIntents.cancel("pi_xxx", {
544
+ * cancellation_reason: "duplicate",
545
+ * })
546
+ */
547
+ cancel(id: string, payloads?: CancelPayloads): Promise<PaymentIntent>;
548
+ /**
549
+ * Retourne les métadonnées DRF du endpoint `/payment-intents/` :
550
+ * actions autorisées, schéma de champs, formats acceptés.
551
+ */
552
+ options(): Promise<DRFOptions>;
553
+ };
554
+
555
+ type CustomerStatus = "active" | "inactive" | "blocked";
556
+ interface Customer extends Timestamps {
557
+ id: string;
558
+ object: "customer";
559
+ app: string;
560
+ email: string;
561
+ name: string;
562
+ phone?: string | null;
563
+ address?: Address | null;
564
+ status: CustomerStatus;
565
+ is_blacklisted: boolean;
566
+ transactions_count: number;
567
+ total_spent: number;
568
+ metadata: Record<string, unknown>;
569
+ }
570
+ /** Champs requis à la création */
571
+ interface CreatePayloads$7 {
572
+ email: string;
573
+ name: string;
574
+ phone?: string;
575
+ metadata?: Record<string, unknown>;
576
+ }
577
+ /** Champs PATCH — tous optionnels */
578
+ interface Payloads$6 {
579
+ email?: string;
580
+ name?: string;
581
+ phone?: string;
582
+ status?: CustomerStatus;
583
+ metadata?: Record<string, unknown>;
584
+ }
585
+ /** Filtres GET /customers/ — alignés sur get_queryset() */
586
+ interface CustomerCriteria {
587
+ search?: string;
588
+ status?: CustomerStatus;
589
+ ordering?: string;
590
+ page?: number;
591
+ page_size?: number;
592
+ }
593
+ /** Filtres GET /customers/:id/transactions/ */
594
+ interface TransactionCriteria$1 {
595
+ page?: number;
596
+ page_size?: number;
597
+ ordering?: string;
598
+ }
599
+
600
+ type TransactionStatus = "approved" | "pending" | "completed" | "failed" | "refunded" | "disputed" | "canceled" | "cancelled";
601
+ type TransactionType = "deposit" | "refund" | "payout" | "withdraw" | "transfer";
602
+ /**
603
+ * Représente une transaction Sangho.
604
+ * Préfixe d'identifiant : `trans_xxx`
605
+ * Création impossible via API — résultat d'un PaymentIntent.
606
+ */
607
+ interface Transaction extends Timestamps {
608
+ id: string;
609
+ object: "transaction";
610
+ amount: number;
611
+ fee: number;
612
+ commission: number;
613
+ commission_rate: number;
614
+ currency: "XAF";
615
+ status: TransactionStatus;
616
+ type: TransactionType;
617
+ description?: string | null;
618
+ payment_intent: string;
619
+ expiration_date?: string | null;
620
+ processed_at?: string | null;
621
+ metadata: Metadata;
622
+ }
623
+ /** Champs PATCH — uniquement description + metadata */
624
+ interface Payloads$5 {
625
+ description?: string;
626
+ metadata?: Metadata;
627
+ }
628
+ /** Filtres GET /transactions/ — alignés sur get_queryset() */
629
+ interface TransactionCriteria extends ListParams {
630
+ status?: TransactionStatus;
631
+ type?: TransactionType;
632
+ created_after?: string;
633
+ created_before?: string;
634
+ min_amount?: number;
635
+ max_amount?: number;
636
+ }
637
+
638
+ type PaymentMethodType$1 = "mobile_money" | "bank_card" | "paypal";
639
+ type MobileMoneyProvider = "orange" | "mtn" | "wave" | "airtel" | "moovv";
640
+ type CardBrand = "visa" | "mastercard" | "amex" | "discover" | "jcb" | "unionpay" | "local" | "unknown";
641
+ interface MobileMoneyDetails {
642
+ provider: MobileMoneyProvider;
643
+ phone_masked: string;
644
+ country: string;
645
+ }
646
+ interface BankCardDetails {
647
+ brand: CardBrand;
648
+ last4: string;
649
+ exp_month: number;
650
+ exp_year: number;
651
+ cardholder_name?: string;
652
+ funding: "credit" | "debit" | "prepaid" | "unknown";
653
+ country?: string;
654
+ }
655
+ interface PayPalDetails {
656
+ payer_id?: string;
657
+ }
658
+ /** Représente un mode de paiement Sangho. Préfixe : `meth_xxx` */
659
+ interface PaymentMethod extends Timestamps {
660
+ id: string;
661
+ object: "payment_method";
662
+ app: string;
663
+ customer?: string | null;
664
+ type: PaymentMethodType$1;
665
+ is_default: boolean;
666
+ mobile_money?: MobileMoneyDetails | null;
667
+ bank_card?: BankCardDetails | null;
668
+ paypal?: PayPalDetails | null;
669
+ metadata: Metadata;
670
+ }
671
+ interface AttachPayloads {
672
+ customer: string;
673
+ }
674
+ /** Filtres GET /payment-methods/ */
675
+ interface PaymentMethodCriteria extends ListParams {
676
+ customer?: string;
677
+ type?: PaymentMethodType$1;
678
+ }
679
+
680
+ type CustomersProperties = {
681
+ /**
682
+ * Liste les clients de l'app avec filtres optionnels.
683
+ * Recherche sur email, prénom et nom via `search`.
684
+ *
685
+ * @param criteria - Filtres optionnels (search, status, ordering, pagination)
686
+ * @returns Liste paginée de clients
687
+ *
688
+ * @example
689
+ * const all = await sangho.customers.list()
690
+ * const active = await sangho.customers.list({ status: "active" })
691
+ * const search = await sangho.customers.list({ search: "jean" })
692
+ */
693
+ list(criteria?: CustomerCriteria): Promise<ListResponse<Customer>>;
694
+ /**
695
+ * Récupère un client par son identifiant.
696
+ *
697
+ * @param id - Identifiant du client (ex: `"cust_xxx"`)
698
+ * @returns Le client correspondant
699
+ *
700
+ * @example
701
+ * const customer = await sangho.customers.retrieve("cust_xxx")
702
+ */
703
+ retrieve(id: string): Promise<Customer>;
704
+ /**
705
+ * Crée un nouveau client lié à l'app.
706
+ * Le champ `name` est automatiquement éclaté en `firstname`
707
+ * et `lastname` côté backend.
708
+ *
709
+ * @param payloads - `email` et `name` requis
710
+ * @returns Le client créé
711
+ *
712
+ * @example
713
+ * const customer = await sangho.customers.create({
714
+ * email: "jean@example.com",
715
+ * name: "Jean Ondo",
716
+ * })
717
+ */
718
+ create(payloads: CreatePayloads$7): Promise<Customer>;
719
+ /**
720
+ * Met à jour partiellement un client (PATCH).
721
+ *
722
+ * @param id - Identifiant du client
723
+ * @param payloads - Champs à modifier (tous optionnels)
724
+ * @returns Le client mis à jour
725
+ *
726
+ * @example
727
+ * await sangho.customers.update("cust_xxx", { phone: "+24177000000" })
728
+ */
729
+ update(id: string, payloads: Payloads$6): Promise<Customer>;
730
+ /**
731
+ * Supprime définitivement un client (hard delete).
732
+ * Le backend retourne HTTP 204 sans corps.
733
+ *
734
+ * @param id - Identifiant du client
735
+ *
736
+ * @example
737
+ * await sangho.customers.delete("cust_xxx")
738
+ */
739
+ delete(id: string): Promise<void>;
740
+ /**
741
+ * Liste les transactions associées à un client.
742
+ *
743
+ * @param id - Identifiant du client
744
+ * @param criteria - Filtres de pagination optionnels
745
+ * @returns Liste paginée de transactions
746
+ *
747
+ * @example
748
+ * const txs = await sangho.customers.listTransactions("cust_xxx")
749
+ *
750
+ * @remarks Nécessite que l'action `GET /customers/:id/transactions/`
751
+ * soit déclarée côté backend (`@action` sur `CustomerViewSet`).
752
+ */
753
+ listTransactions(id: string, criteria?: TransactionCriteria$1): Promise<ListResponse<Transaction>>;
754
+ /**
755
+ * Liste les modes de paiement enregistrés d'un client.
756
+ *
757
+ * @param id - Identifiant du client
758
+ * @returns Liste des modes de paiement
759
+ *
760
+ * @example
761
+ * const methods = await sangho.customers.listPaymentMethods("cust_xxx")
762
+ *
763
+ * @remarks Nécessite que l'action `GET /customers/:id/payment-methods/`
764
+ * soit déclarée côté backend (`@action` sur `CustomerViewSet`).
765
+ */
766
+ listPaymentMethods(id: string): Promise<ListResponse<PaymentMethod>>;
767
+ /**
768
+ * Retourne les métadonnées DRF du endpoint `/customers/` :
769
+ * actions autorisées, schéma de champs, formats acceptés.
770
+ */
771
+ options(): Promise<DRFOptions>;
772
+ };
773
+
774
+ type ProductStatus = "active" | "inactive" | "draft" | "archived";
775
+ /**
776
+ * Mappe `product_format` Django → type SDK via `get_type()`.
777
+ * `"physical"` et `"service"` sont les seuls choices Django natifs.
778
+ * `"digital"` est supporté par le mapping mais absent des choices.
779
+ */
780
+ type ProductType = "physical" | "digital" | "service";
781
+ /**
782
+ * Image d'un produit — mappée depuis `ProductImageSerializer`.
783
+ * Pas de timestamps (absents des `Meta.fields`).
784
+ */
785
+ interface ProductImage {
786
+ id: string;
787
+ product: string;
788
+ url: string;
789
+ alt?: string;
790
+ position: number;
791
+ is_primary: boolean;
792
+ }
793
+ /**
794
+ * Représente un produit Sangho.
795
+ * Préfixe d'identifiant : `prod_xxx`
796
+ */
797
+ interface Product extends Timestamps {
798
+ id: string;
799
+ object: "product";
800
+ app: string;
801
+ name: string;
802
+ description?: string | null;
803
+ type: ProductType;
804
+ status: ProductStatus;
805
+ unit_amount: number;
806
+ currency: CurrencyCode;
807
+ stock?: number | null;
808
+ sku?: string | null;
809
+ is_shippable: boolean;
810
+ images: ProductImage[];
811
+ metadata: Metadata;
812
+ }
813
+ /** Champs POST — `name`, `unit_amount`, `currency` requis */
814
+ interface CreatePayloads$6 {
815
+ name: string;
816
+ description?: string;
817
+ type?: ProductType;
818
+ unit_amount: number;
819
+ currency: CurrencyCode;
820
+ stock?: number;
821
+ sku?: string;
822
+ is_shippable?: boolean;
823
+ metadata?: Metadata;
824
+ }
825
+ /** Champs PATCH — tous optionnels */
826
+ interface Payloads$4 {
827
+ name?: string;
828
+ description?: string;
829
+ type?: ProductType;
830
+ unit_amount?: number;
831
+ stock?: number;
832
+ sku?: string;
833
+ status?: ProductStatus;
834
+ is_shippable?: boolean;
835
+ metadata?: Metadata;
836
+ }
837
+ /** Filtres GET /products/ — alignés sur get_queryset() */
838
+ interface ProductCriteria extends ListParams {
839
+ status?: ProductStatus;
840
+ currency?: CurrencyCode;
841
+ }
842
+
843
+ type ProductsProperties = {
844
+ /**
845
+ * Liste les produits du catalogue avec filtres optionnels.
846
+ * Accessible avec clé publique ou secrète.
847
+ *
848
+ * @param criteria - Filtres (status, currency, search, ordering, pagination)
849
+ * @returns Liste paginée de produits
850
+ *
851
+ * @example
852
+ * const all = await sangho.products.list()
853
+ * const active = await sangho.products.list({ status: "active" })
854
+ * const search = await sangho.products.list({ search: "premium" })
855
+ */
856
+ list(criteria?: ProductCriteria): Promise<ListResponse<Product>>;
857
+ /**
858
+ * Récupère un produit par son identifiant.
859
+ * Accessible avec clé publique ou secrète.
860
+ *
861
+ * @param id - Identifiant du produit (format `prod_xxx`)
862
+ * @returns Le produit correspondant
863
+ *
864
+ * @example
865
+ * const product = await sangho.products.retrieve("prod_xxx")
866
+ */
867
+ retrieve(id: string): Promise<Product>;
868
+ /**
869
+ * Crée un nouveau produit dans le catalogue.
870
+ * Nécessite une clé secrète.
871
+ *
872
+ * @param payloads - `name`, `unit_amount` et `currency` requis
873
+ * @returns Le produit créé
874
+ *
875
+ * @example
876
+ * const product = await sangho.products.create({
877
+ * name: "Abonnement Premium",
878
+ * unit_amount: 9900,
879
+ * currency: "XAF",
880
+ * type: "service",
881
+ * })
882
+ */
883
+ create(payloads: CreatePayloads$6): Promise<Product>;
884
+ /**
885
+ * Met à jour partiellement un produit (PATCH).
886
+ * Nécessite une clé secrète.
887
+ *
888
+ * @param id - Identifiant du produit (format `prod_xxx`)
889
+ * @param payloads - Champs à modifier (tous optionnels)
890
+ * @returns Le produit mis à jour
891
+ *
892
+ * @example
893
+ * await sangho.products.update("prod_xxx", { stock: 50 })
894
+ */
895
+ update(id: string, payloads: Payloads$4): Promise<Product>;
896
+ /**
897
+ * Archive un produit (soft delete — `status: "archived"`).
898
+ * Le backend retourne HTTP 204 sans corps.
899
+ * Le produit reste accessible en lecture.
900
+ * Nécessite une clé secrète.
901
+ *
902
+ * @param id - Identifiant du produit (format `prod_xxx`)
903
+ *
904
+ * @example
905
+ * await sangho.products.delete("prod_xxx")
906
+ *
907
+ * @remarks
908
+ * Les actions dédiées `archive()` et `unarchive()` n'existent pas
909
+ * encore côté backend. Pour restaurer un produit archivé,
910
+ * utilisez `update(id, { status: "active" })`.
911
+ */
912
+ delete(id: string): Promise<void>;
913
+ /**
914
+ * Retourne les métadonnées DRF du endpoint `/products/` :
915
+ * actions autorisées, schéma de champs, formats acceptés.
916
+ */
917
+ options(): Promise<DRFOptions>;
918
+ };
919
+
920
+ type TransactionsProperties = {
921
+ /**
922
+ * Liste les transactions avec filtres optionnels.
923
+ * Les transactions sont créées automatiquement par les PaymentIntents —
924
+ * elles ne peuvent pas être créées via l'API.
925
+ *
926
+ * @param criteria - Filtres (status, type, montants, dates, pagination)
927
+ */
928
+ list(criteria?: TransactionCriteria): Promise<ListResponse<Transaction>>;
929
+ /**
930
+ * Récupère une transaction par son identifiant.
931
+ * Ajouter `?expand=payment_intent` pour l'objet complet.
932
+ *
933
+ * @param id - Identifiant de la transaction (format `trans_xxx`)
934
+ */
935
+ retrieve(id: string): Promise<Transaction>;
936
+ /**
937
+ * Met à jour la description ou les métadonnées d'une transaction (PATCH).
938
+ * Seuls `description` et `metadata` sont modifiables.
939
+ * Impossible sur les transactions dans un état final.
940
+ *
941
+ * @param id - Identifiant de la transaction
942
+ * @param payloads - `description` et/ou `metadata`
943
+ */
944
+ update(id: string, payloads: Payloads$5): Promise<Transaction>;
945
+ /**
946
+ * Annule une transaction en statut `pending` ou `processing`.
947
+ * Impossible sur les transactions `completed`, `failed`, ou `cancelled`.
948
+ *
949
+ * @param id - Identifiant de la transaction (format `trans_xxx`)
950
+ */
951
+ cancel(id: string): Promise<Transaction>;
952
+ /** Retourne les métadonnées DRF du endpoint `/transactions/`. */
953
+ options(): Promise<DRFOptions>;
954
+ };
955
+
956
+ type RefundStatus = "pending" | "processing" | "succeeded" | "failed" | "cancelled" | "expired";
957
+ type RefundReason = "duplicate" | "fraudulent" | "customer_request" | "product_issue" | "service_not_rendered";
958
+ /** Représente un remboursement Sangho. Préfixe : `refd_xxx` */
959
+ interface Refund extends Timestamps {
960
+ id: string;
961
+ object: "refund";
962
+ transaction: string;
963
+ amount: number;
964
+ currency: "XAF";
965
+ status: RefundStatus;
966
+ reason?: RefundReason | null;
967
+ description?: string | null;
968
+ failure_reason?: string | null;
969
+ metadata: Metadata;
970
+ }
971
+ /** Champs POST */
972
+ interface CreatePayloads$5 {
973
+ transaction: string;
974
+ amount?: number;
975
+ reason?: RefundReason;
976
+ description?: string;
977
+ metadata?: Metadata;
978
+ }
979
+ /** Filtres GET /refunds/ */
980
+ interface RefundCriteria extends ListParams {
981
+ transaction?: string;
982
+ status?: RefundStatus;
983
+ reason?: RefundReason;
984
+ }
985
+
986
+ type RefundsProperties = {
987
+ list(criteria?: RefundCriteria): Promise<ListResponse<Refund>>;
988
+ retrieve(id: string): Promise<Refund>;
989
+ /**
990
+ * Crée un remboursement sur une transaction réussie.
991
+ * Si `amount` est inférieur au montant original, le remboursement est partiel.
992
+ * @param payloads - `transaction` requis (ID `trans_xxx`)
993
+ */
994
+ create(payloads: CreatePayloads$5): Promise<Refund>;
995
+ /**
996
+ * Annule un remboursement en statut `pending`.
997
+ * Impossible sur les remboursements `succeeded`, `failed` ou `expired`.
998
+ */
999
+ cancel(id: string): Promise<Refund>;
1000
+ options(): Promise<DRFOptions>;
1001
+ };
1002
+
1003
+ type InvoiceStatus = "draft" | "open" | "paid" | "uncollectible" | "void";
1004
+ interface InvoiceLineItem {
1005
+ id?: string;
1006
+ description: string;
1007
+ quantity: number;
1008
+ unit_amount: number;
1009
+ amount: number;
1010
+ product?: string;
1011
+ metadata?: Metadata;
1012
+ }
1013
+ /** Ligne à fournir à la création */
1014
+ interface CreateLineItem {
1015
+ description: string;
1016
+ quantity: number;
1017
+ unit_amount: number;
1018
+ product?: string;
1019
+ metadata?: Metadata;
1020
+ }
1021
+ /**
1022
+ * Représente une facture Sangho.
1023
+ * Préfixe d'identifiant : `inv_xxx`
1024
+ * Devise fixe : XAF
1025
+ */
1026
+ interface Invoice extends Timestamps {
1027
+ id: string;
1028
+ object: "invoice";
1029
+ app: string;
1030
+ customer: string;
1031
+ number: string;
1032
+ status: InvoiceStatus;
1033
+ currency: "XAF";
1034
+ subtotal: number;
1035
+ tax: number;
1036
+ tax_rate?: number | null;
1037
+ total: number;
1038
+ amount_paid: number;
1039
+ amount_remaining: number;
1040
+ description?: string | null;
1041
+ footer?: string | null;
1042
+ line_items: InvoiceLineItem[];
1043
+ due_date?: string | null;
1044
+ paid_at?: string | null;
1045
+ voided_at?: string | null;
1046
+ hosted_url?: string | null;
1047
+ pdf_url?: string | null;
1048
+ metadata: Metadata;
1049
+ }
1050
+ /** Champs POST */
1051
+ interface CreatePayloads$4 {
1052
+ customer: string;
1053
+ line_items: CreateLineItem[];
1054
+ description?: string;
1055
+ footer?: string;
1056
+ due_date?: string;
1057
+ tax_rate?: number;
1058
+ metadata?: Metadata;
1059
+ /** Si true, passe immédiatement en `"open"` et envoie par email */
1060
+ send_immediately?: boolean;
1061
+ }
1062
+ /** Champs PATCH — uniquement sur factures `draft` */
1063
+ interface Payloads$3 {
1064
+ description?: string;
1065
+ footer?: string;
1066
+ due_date?: string;
1067
+ tax_rate?: number;
1068
+ metadata?: Metadata;
1069
+ }
1070
+ /** Filtres GET /invoices/ */
1071
+ interface InvoiceCriteria extends ListParams {
1072
+ customer?: string;
1073
+ status?: InvoiceStatus;
1074
+ currency?: string;
1075
+ due_date_before?: string;
1076
+ due_date_after?: string;
1077
+ }
1078
+
1079
+ type InvoicesProperties = {
1080
+ /**
1081
+ * Liste les factures avec filtres optionnels.
1082
+ *
1083
+ * @param criteria - Filtres (customer, status, currency, due_date, pagination)
1084
+ */
1085
+ list(criteria?: InvoiceCriteria): Promise<ListResponse<Invoice>>;
1086
+ /**
1087
+ * Récupère une facture par son identifiant.
1088
+ *
1089
+ * @param id - Identifiant de la facture (format `inv_xxx`)
1090
+ */
1091
+ retrieve(id: string): Promise<Invoice>;
1092
+ /**
1093
+ * Crée une nouvelle facture en statut `draft`.
1094
+ * Si `send_immediately: true`, passe directement en `open`.
1095
+ *
1096
+ * @param payloads - `customer` et `line_items` requis
1097
+ */
1098
+ create(payloads: CreatePayloads$4): Promise<Invoice>;
1099
+ /**
1100
+ * Met à jour une facture en statut `draft` (PATCH).
1101
+ * Impossible sur les factures `open`, `paid`, `void` ou `uncollectible`.
1102
+ *
1103
+ * @param id - Identifiant de la facture
1104
+ * @param payloads - Champs modifiables (description, footer, due_date, tax_rate)
1105
+ */
1106
+ update(id: string, payloads: Payloads$3): Promise<Invoice>;
1107
+ /**
1108
+ * Supprime définitivement une facture.
1109
+ * Uniquement possible si `status === "draft"`.
1110
+ * Retourne HTTP 204 sans corps.
1111
+ *
1112
+ * @param id - Identifiant de la facture
1113
+ */
1114
+ delete(id: string): Promise<void>;
1115
+ /**
1116
+ * Finalise et envoie une facture draft.
1117
+ * Passe en `status: "open"`.
1118
+ *
1119
+ * @param id - Identifiant de la facture
1120
+ */
1121
+ send(id: string): Promise<Invoice>;
1122
+ /**
1123
+ * Marque une facture ouverte comme payée manuellement.
1124
+ * Passe en `status: "paid"`, peuple `paid_at` et `amount_paid`.
1125
+ *
1126
+ * @param id - Identifiant de la facture
1127
+ */
1128
+ pay(id: string): Promise<Invoice>;
1129
+ /**
1130
+ * Annule une facture ouverte.
1131
+ * Passe en `status: "void"`, peuple `voided_at`.
1132
+ * Impossible sur les factures `paid` ou déjà `void`.
1133
+ *
1134
+ * @param id - Identifiant de la facture
1135
+ */
1136
+ void(id: string): Promise<Invoice>;
1137
+ /**
1138
+ * Marque une facture ouverte comme irrécupérable.
1139
+ * Passe en `status: "uncollectible"`.
1140
+ *
1141
+ * @param id - Identifiant de la facture
1142
+ */
1143
+ markUncollectible(id: string): Promise<Invoice>;
1144
+ /**
1145
+ * Retourne l'URL de téléchargement PDF d'une facture.
1146
+ * L'URL expire après 1 heure.
1147
+ *
1148
+ * @param id - Identifiant de la facture
1149
+ * @returns URL temporaire + date d'expiration ISO 8601
1150
+ */
1151
+ getPdfUrl(id: string): Promise<{
1152
+ url: string;
1153
+ expires_at: string;
1154
+ }>;
1155
+ /** Retourne les métadonnées DRF du endpoint `/invoices/`. */
1156
+ options(): Promise<DRFOptions>;
1157
+ };
1158
+
1159
+ type PaymentLinkStatus = "active" | "inactive" | "archived";
1160
+ type PaymentLinkType = "product" | "custom" | "donation";
1161
+ type PaymentLinkValidityType = "unlimited" | "limited" | "one_time";
1162
+ interface PaymentLinkRedirectUrl {
1163
+ success?: string;
1164
+ cancel?: string;
1165
+ }
1166
+ /**
1167
+ * Représente un PaymentLink Sangho.
1168
+ * `products` contient des IDs string par défaut,
1169
+ * ou des objets Product complets si `?expand=products`.
1170
+ */
1171
+ interface PaymentLink extends Timestamps {
1172
+ id: string;
1173
+ object: "payment_link";
1174
+ name?: string | null;
1175
+ description?: string | null;
1176
+ url: string;
1177
+ status: PaymentLinkStatus;
1178
+ currency: CurrencyCode;
1179
+ amount: number;
1180
+ full_amount: string;
1181
+ minimum_amount?: number | null;
1182
+ maximum_amount?: number | null;
1183
+ tax_amount?: number | null;
1184
+ discount_amount?: number | null;
1185
+ shipping_amount?: number | null;
1186
+ payment_link_type: PaymentLinkType;
1187
+ validity_type: PaymentLinkValidityType;
1188
+ expires_at?: string | null;
1189
+ max_usage?: number | null;
1190
+ redirect_url: PaymentLinkRedirectUrl;
1191
+ products: string[];
1192
+ product_quantity_settings: Record<string, number>;
1193
+ custom_fields: unknown[];
1194
+ advanced_options: Record<string, unknown>;
1195
+ metadata: Metadata;
1196
+ }
1197
+ /** Champs POST — alignés sur PaymentLinkSerializer + PaymentLinkValidator */
1198
+ interface CreatePayloads$3 {
1199
+ name?: string;
1200
+ description?: string;
1201
+ currency: CurrencyCode;
1202
+ payment_link_type?: PaymentLinkType;
1203
+ products?: string[];
1204
+ product_quantity_settings?: Record<string, number>;
1205
+ amount?: AmountInCents;
1206
+ minimum_amount?: AmountInCents;
1207
+ maximum_amount?: AmountInCents;
1208
+ redirect_url?: PaymentLinkRedirectUrl;
1209
+ max_usage?: number;
1210
+ validity_type?: PaymentLinkValidityType;
1211
+ expires_at?: string;
1212
+ custom_fields?: unknown[];
1213
+ advanced_options?: Record<string, unknown>;
1214
+ metadata?: Metadata;
1215
+ }
1216
+ /** Champs PATCH — tous optionnels */
1217
+ interface Payloads$2 {
1218
+ name?: string;
1219
+ description?: string;
1220
+ currency?: CurrencyCode;
1221
+ products?: string[];
1222
+ product_quantity_settings?: Record<string, number>;
1223
+ amount?: AmountInCents;
1224
+ minimum_amount?: AmountInCents;
1225
+ maximum_amount?: AmountInCents;
1226
+ redirect_url?: PaymentLinkRedirectUrl;
1227
+ max_usage?: number | null;
1228
+ validity_type?: PaymentLinkValidityType;
1229
+ expires_at?: string | null;
1230
+ custom_fields?: unknown[];
1231
+ advanced_options?: Record<string, unknown>;
1232
+ metadata?: Metadata;
1233
+ }
1234
+ /** Filtres GET /payment-links/ — alignés sur get_queryset() */
1235
+ interface PaymentLinkCriteria extends ListParams {
1236
+ status?: PaymentLinkStatus;
1237
+ currency?: CurrencyCode;
1238
+ }
1239
+
1240
+ type PaymentLinksProperties = {
1241
+ /**
1242
+ * Liste les liens de paiement avec filtres optionnels.
1243
+ *
1244
+ * @param criteria - Filtres (status, currency, search, ordering, pagination)
1245
+ * @returns Liste paginée de liens de paiement
1246
+ *
1247
+ * @example
1248
+ * const all = await sangho.paymentLinks.list()
1249
+ * const active = await sangho.paymentLinks.list({ status: "active" })
1250
+ * const search = await sangho.paymentLinks.list({ search: "promo" })
1251
+ */
1252
+ list(criteria?: PaymentLinkCriteria): Promise<ListResponse<PaymentLink>>;
1253
+ /**
1254
+ * Récupère un lien de paiement par son identifiant.
1255
+ * Ajouter `?expand=products` pour obtenir les objets Product complets.
1256
+ *
1257
+ * @param id - Identifiant du lien (ex: `"link_xxx"`)
1258
+ * @returns Le lien de paiement correspondant
1259
+ *
1260
+ * @example
1261
+ * const link = await sangho.paymentLinks.retrieve("link_xxx")
1262
+ */
1263
+ retrieve(id: string): Promise<PaymentLink>;
1264
+ /**
1265
+ * Crée un nouveau lien de paiement partageable.
1266
+ * Si `payment_link_type` vaut `"product"`, le champ `products` est requis.
1267
+ * Pour les autres types, `amount` et `currency` sont requis.
1268
+ *
1269
+ * @param payloads - Paramètres du lien (currency toujours requis)
1270
+ * @returns Le lien de paiement créé
1271
+ *
1272
+ * @example
1273
+ * const link = await sangho.paymentLinks.create({
1274
+ * currency: "XAF",
1275
+ * payment_link_type: "product",
1276
+ * products: ["prod_xxx"],
1277
+ * product_quantity_settings: { prod_xxx: 1 },
1278
+ * redirect_url: { success: "https://monsite.com/merci" },
1279
+ * })
1280
+ * console.log(link.url) // https://pay.sangho.ga/test/...
1281
+ */
1282
+ create(payloads: CreatePayloads$3): Promise<PaymentLink>;
1283
+ /**
1284
+ * Met à jour partiellement un lien de paiement (PATCH).
1285
+ * PUT n'est pas supporté côté backend.
1286
+ *
1287
+ * @param id - Identifiant du lien
1288
+ * @param payloads - Champs à modifier (tous optionnels)
1289
+ * @returns Le lien mis à jour
1290
+ *
1291
+ * @example
1292
+ * await sangho.paymentLinks.update("link_xxx", {
1293
+ * max_usage: 100,
1294
+ * redirect_url: { success: "https://monsite.com/merci" },
1295
+ * })
1296
+ */
1297
+ update(id: string, payloads: Payloads$2): Promise<PaymentLink>;
1298
+ /**
1299
+ * Archive un lien de paiement (soft delete).
1300
+ * Le backend ne supprime pas physiquement — l'historique est conservé.
1301
+ * Équivalent à `DELETE /payment-links/:id/` côté API.
1302
+ *
1303
+ * @param id - Identifiant du lien
1304
+ * @returns Le lien archivé (status: "archived")
1305
+ *
1306
+ * @example
1307
+ * const archived = await sangho.paymentLinks.delete("link_xxx")
1308
+ */
1309
+ delete(id: string): Promise<PaymentLink>;
1310
+ /**
1311
+ * Archive explicitement un lien via `POST /payment-links/:id/archive/`.
1312
+ * Retourne une erreur si le lien est déjà archivé.
1313
+ *
1314
+ * @param id - Identifiant du lien
1315
+ * @returns Le lien archivé
1316
+ *
1317
+ * @example
1318
+ * await sangho.paymentLinks.archive("link_xxx")
1319
+ */
1320
+ archive(id: string): Promise<PaymentLink>;
1321
+ /**
1322
+ * Restaure un lien archivé (`POST /payment-links/:id/restore/`).
1323
+ * Le lien repasse au statut `"active"`.
1324
+ * Retourne une erreur si le lien n'est pas archivé.
1325
+ *
1326
+ * @param id - Identifiant du lien
1327
+ * @returns Le lien restauré
1328
+ *
1329
+ * @example
1330
+ * await sangho.paymentLinks.restore("link_xxx")
1331
+ */
1332
+ restore(id: string): Promise<PaymentLink>;
1333
+ /**
1334
+ * Retourne les métadonnées DRF du endpoint `/payment-links/` :
1335
+ * actions autorisées, schéma de champs, formats acceptés.
1336
+ */
1337
+ options(): Promise<DRFOptions>;
1338
+ };
1339
+
1340
+ type CheckoutSessionStatus = "open" | "complete" | "expired" | "payment_failed" | "processing";
1341
+ type CheckoutMode = "payment" | "subscription" | "setup";
1342
+ /** Ligne de commande — type local, découplé de payment-links */
1343
+ interface LineItem {
1344
+ product: string;
1345
+ quantity: number;
1346
+ unit_amount?: number;
1347
+ name?: string;
1348
+ currency?: CurrencyCode;
1349
+ }
1350
+ /**
1351
+ * Représente une CheckoutSession Sangho.
1352
+ * Préfixe d'identifiant : `sess_xxx`
1353
+ */
1354
+ interface CheckoutSession extends Timestamps {
1355
+ id: string;
1356
+ object: "checkout_session";
1357
+ app: string;
1358
+ url: string;
1359
+ status: CheckoutSessionStatus;
1360
+ mode: CheckoutMode;
1361
+ customer?: string | null;
1362
+ customer_email?: string | null;
1363
+ currency: CurrencyCode;
1364
+ amount_total: AmountInCents;
1365
+ shipping_amount?: number | null;
1366
+ discount_amount?: number | null;
1367
+ line_items: LineItem[];
1368
+ success_url: string;
1369
+ cancel_url?: string | null;
1370
+ payment_intent?: string | null;
1371
+ subscription?: string | null;
1372
+ expires_at: string;
1373
+ metadata: Metadata;
1374
+ }
1375
+ /** Champs POST — `success_url`, `line_items`, `currency` requis */
1376
+ interface CreatePayloads$2 {
1377
+ success_url: string;
1378
+ line_items: LineItem[];
1379
+ currency: CurrencyCode;
1380
+ mode?: CheckoutMode;
1381
+ customer?: string;
1382
+ customer_email?: string;
1383
+ cancel_url?: string;
1384
+ shipping_amount?: AmountInCents;
1385
+ discount_amount?: AmountInCents;
1386
+ payment_method_types?: string[];
1387
+ /** Durée de validité en secondes (défaut: 1800, max: 86400) */
1388
+ expires_in?: number;
1389
+ metadata?: Metadata;
1390
+ }
1391
+ /** Filtres GET /checkout-sessions/ */
1392
+ interface CheckoutSessionCriteria extends ListParams {
1393
+ status?: CheckoutSessionStatus;
1394
+ mode?: CheckoutMode;
1395
+ customer?: string;
1396
+ created_after?: string;
1397
+ created_before?: string;
1398
+ }
1399
+
1400
+ type CheckoutSessionsProperties = {
1401
+ /**
1402
+ * Liste les sessions de checkout avec filtres optionnels.
1403
+ *
1404
+ * @param criteria - Filtres (status, mode, customer, dates, pagination)
1405
+ * @returns Liste paginée de sessions
1406
+ *
1407
+ * @example
1408
+ * const all = await sangho.checkoutSessions.list()
1409
+ * const open = await sangho.checkoutSessions.list({ status: "open" })
1410
+ * const subs = await sangho.checkoutSessions.list({ mode: "subscription" })
1411
+ */
1412
+ list(criteria?: CheckoutSessionCriteria): Promise<ListResponse<CheckoutSession>>;
1413
+ /**
1414
+ * Récupère une session de checkout par son identifiant.
1415
+ * Si la session est expirée mais encore marquée `"open"`,
1416
+ * le backend la bascule automatiquement en `"expired"`.
1417
+ * Accessible avec clé publique ou secrète.
1418
+ *
1419
+ * @param id - Identifiant de la session (format `sess_xxx`)
1420
+ */
1421
+ retrieve(id: string): Promise<CheckoutSession>;
1422
+ /**
1423
+ * Crée une session de checkout hébergée.
1424
+ * En mode `"payment"`, un PaymentIntent est automatiquement créé.
1425
+ * `success_url`, `line_items` et `currency` sont requis.
1426
+ *
1427
+ * @param payloads - Paramètres de la session
1428
+ * @returns La session avec son URL de redirection
1429
+ *
1430
+ * @example
1431
+ * const session = await sangho.checkoutSessions.create({
1432
+ * success_url: "https://monsite.com/merci",
1433
+ * cancel_url: "https://monsite.com/annulation",
1434
+ * currency: "XAF",
1435
+ * line_items: [{ product: "prod_xxx", quantity: 1 }],
1436
+ * })
1437
+ * window.location.href = session.url
1438
+ */
1439
+ create(payloads: CreatePayloads$2): Promise<CheckoutSession>;
1440
+ /**
1441
+ * Expire manuellement une session ouverte
1442
+ * (`POST /checkout-sessions/:id/expire/`).
1443
+ * Retourne une erreur si la session n'est pas en statut `"open"`.
1444
+ * Équivalent à `DELETE /checkout-sessions/:id/`.
1445
+ *
1446
+ * @param id - Identifiant de la session (format `sess_xxx`)
1447
+ * @returns La session expirée
1448
+ *
1449
+ * @example
1450
+ * await sangho.checkoutSessions.expire("sess_xxx")
1451
+ */
1452
+ expire(id: string): Promise<CheckoutSession>;
1453
+ /**
1454
+ * Alias de `expire()` — expire la session au lieu de la supprimer.
1455
+ * Le backend ne supprime pas physiquement les sessions.
1456
+ *
1457
+ * @param id - Identifiant de la session (format `sess_xxx`)
1458
+ */
1459
+ delete(id: string): Promise<CheckoutSession>;
1460
+ /**
1461
+ * Retourne les métadonnées DRF du endpoint `/checkout-sessions/`.
1462
+ */
1463
+ options(): Promise<DRFOptions>;
1464
+ };
1465
+
1466
+ type SubscriptionStatus = "trialing" | "active" | "past_due" | "paused" | "canceled" | "unpaid" | "expired";
1467
+ type BillingInterval = "day" | "week" | "month" | "year";
1468
+ type CollectionMethod = "charge_automatically" | "send_invoice";
1469
+ /**
1470
+ * Représente un abonnement Sangho.
1471
+ * Préfixe d'identifiant : `sub_xxx`
1472
+ */
1473
+ interface Subscription extends Timestamps {
1474
+ id: string;
1475
+ object: "subscription";
1476
+ app: string;
1477
+ customer: string;
1478
+ status: SubscriptionStatus;
1479
+ currency: "XAF";
1480
+ unit_amount: number;
1481
+ interval: BillingInterval;
1482
+ interval_count: number;
1483
+ collection_method: CollectionMethod;
1484
+ current_period_start: string;
1485
+ current_period_end: string;
1486
+ trial_start?: string | null;
1487
+ trial_end?: string | null;
1488
+ canceled_at?: string | null;
1489
+ cancel_at_period_end: boolean;
1490
+ product?: string | null;
1491
+ payment_method?: string | null;
1492
+ metadata: Metadata;
1493
+ }
1494
+ /** Champs POST */
1495
+ interface CreatePayloads$1 {
1496
+ customer: string;
1497
+ unit_amount: number;
1498
+ interval: BillingInterval;
1499
+ interval_count?: number;
1500
+ product?: string;
1501
+ payment_method?: string;
1502
+ collection_method?: CollectionMethod;
1503
+ trial_period_days?: number;
1504
+ cancel_at_period_end?: boolean;
1505
+ metadata?: Metadata;
1506
+ }
1507
+ /** Champs PATCH */
1508
+ interface Payloads$1 {
1509
+ unit_amount?: number;
1510
+ payment_method?: string;
1511
+ collection_method?: CollectionMethod;
1512
+ cancel_at_period_end?: boolean;
1513
+ metadata?: Metadata;
1514
+ }
1515
+ /** Filtres GET /subscriptions/ */
1516
+ interface SubscriptionCriteria extends ListParams {
1517
+ customer?: string;
1518
+ status?: SubscriptionStatus;
1519
+ currency?: string;
1520
+ }
1521
+
1522
+ type SubscriptionsProperties = {
1523
+ list(criteria?: SubscriptionCriteria): Promise<ListResponse<Subscription>>;
1524
+ retrieve(id: string): Promise<Subscription>;
1525
+ /**
1526
+ * Crée un abonnement récurrent.
1527
+ * Si `trial_period_days > 0`, démarre en statut `"trialing"`.
1528
+ * @param payloads - `customer`, `unit_amount` et `interval` requis
1529
+ */
1530
+ create(payloads: CreatePayloads$1): Promise<Subscription>;
1531
+ update(id: string, payloads: Payloads$1): Promise<Subscription>;
1532
+ /**
1533
+ * Annule un abonnement.
1534
+ * `cancel_at_period_end: true` (défaut) → annulation à la fin de la période.
1535
+ * `cancel_at_period_end: false` → annulation immédiate.
1536
+ */
1537
+ cancel(id: string, payloads?: {
1538
+ cancel_at_period_end?: boolean;
1539
+ }): Promise<Subscription>;
1540
+ /** Réactive un abonnement `canceled`, `past_due` ou `unpaid`. */
1541
+ reactivate(id: string): Promise<Subscription>;
1542
+ /** Suspend un abonnement actif (passe en `"paused"`). */
1543
+ pause(id: string): Promise<Subscription>;
1544
+ /** Reprend un abonnement `"paused"`. */
1545
+ resume(id: string): Promise<Subscription>;
1546
+ options(): Promise<DRFOptions>;
1547
+ };
1548
+
1549
+ type PaymentMethodsProperties = {
1550
+ list(criteria?: PaymentMethodCriteria): Promise<ListResponse<PaymentMethod>>;
1551
+ retrieve(id: string): Promise<PaymentMethod>;
1552
+ /**
1553
+ * Attache un mode de paiement à un client.
1554
+ * @param id - Identifiant du mode de paiement (`meth_xxx`)
1555
+ * @param payloads - `customer` requis
1556
+ */
1557
+ attach(id: string, payloads: AttachPayloads): Promise<PaymentMethod>;
1558
+ /** Détache un mode de paiement de son client. */
1559
+ detach(id: string): Promise<PaymentMethod>;
1560
+ /** Définit un mode de paiement comme défaut pour son client. */
1561
+ setDefault(id: string): Promise<PaymentMethod>;
1562
+ options(): Promise<DRFOptions>;
1563
+ };
1564
+
1565
+ type ReceiptStatus = "draft" | "issued" | "voided" | "archived";
1566
+ type PaymentMethodType = "card" | "mobile_money" | "bank_transfer" | "e_wallet";
1567
+ interface ReceiptItem {
1568
+ id: string;
1569
+ description: string;
1570
+ quantity: number;
1571
+ unit_amount: number;
1572
+ amount: number;
1573
+ currency: "XAF";
1574
+ }
1575
+ /**
1576
+ * Représente un reçu Sangho.
1577
+ * Préfixe d'identifiant : `rec_xxx`
1578
+ * Devise fixe : XAF — en lecture seule.
1579
+ */
1580
+ interface Receipt extends Timestamps {
1581
+ id: string;
1582
+ object: "receipt";
1583
+ app: string;
1584
+ number: string;
1585
+ customer: string;
1586
+ transaction?: string | null;
1587
+ status: ReceiptStatus;
1588
+ payment_method: PaymentMethodType;
1589
+ currency: "XAF";
1590
+ subtotal: number;
1591
+ tax: number;
1592
+ total: number;
1593
+ shipping_amount: number;
1594
+ discount_amount: number;
1595
+ items: ReceiptItem[];
1596
+ pdf_url?: string | null;
1597
+ issue_date: string;
1598
+ metadata: Metadata;
1599
+ }
1600
+ /** Filtres GET /receipts/ */
1601
+ interface ReceiptCriteria extends ListParams {
1602
+ customer?: string;
1603
+ transaction?: string;
1604
+ status?: ReceiptStatus;
1605
+ }
1606
+
1607
+ type ReceiptsProperties = {
1608
+ /**
1609
+ * Liste les reçus de l'app avec filtres optionnels.
1610
+ *
1611
+ * @param criteria - Filtres (customer, transaction, status, pagination)
1612
+ *
1613
+ * @example
1614
+ * const all = await sangho.receipts.list()
1615
+ * const paid = await sangho.receipts.list({ status: "issued" })
1616
+ */
1617
+ list(criteria?: ReceiptCriteria): Promise<ListResponse<Receipt>>;
1618
+ /**
1619
+ * Récupère un reçu par son identifiant.
1620
+ *
1621
+ * @param id - Identifiant du reçu (format `rec_xxx`)
1622
+ */
1623
+ retrieve(id: string): Promise<Receipt>;
1624
+ /**
1625
+ * Retourne l'URL de téléchargement PDF du reçu.
1626
+ * L'URL expire après 1 heure.
1627
+ *
1628
+ * @param id - Identifiant du reçu
1629
+ * @returns URL temporaire + date d'expiration ISO 8601
1630
+ *
1631
+ * @example
1632
+ * const { url } = await sangho.receipts.getPdfUrl("rec_xxx")
1633
+ * window.open(url)
1634
+ */
1635
+ getPdfUrl(id: string): Promise<{
1636
+ url: string;
1637
+ expires_at: string;
1638
+ }>;
1639
+ /** Retourne les métadonnées DRF du endpoint `/receipts/`. */
1640
+ options(): Promise<DRFOptions>;
1641
+ };
1642
+
1643
+ type WebhookEventType = "payment_intent.created" | "payment_intent.succeeded" | "payment_intent.payment_failed" | "payment_intent.canceled" | "payment_intent.requires_action" | "transaction.created" | "transaction.succeeded" | "transaction.failed" | "transaction.refunded" | "customer.created" | "customer.updated" | "customer.deleted" | "invoice.created" | "invoice.paid" | "invoice.payment_failed" | "invoice.voided" | "subscription.created" | "subscription.updated" | "subscription.canceled" | "subscription.trial_ending" | "refund.created" | "refund.updated" | "refund.failed" | "checkout.session.completed" | "checkout.session.expired" | "payout.created" | "payout.paid" | "payout.failed";
1644
+ type WebhookStatus = "ACTIVE" | "INACTIVE" | "DISABLED";
1645
+ type WebhookSecurityProfile = "HMAC_SHA256" | "JWT" | "BASIC";
1646
+ type DeliveryStatus = "pending" | "delivered" | "failed" | "retrying";
1647
+ interface WebhookRetryPolicy {
1648
+ max_attempts: number;
1649
+ backoff_type: "linear" | "exponential";
1650
+ initial_delay_seconds: number;
1651
+ }
1652
+ /** Représente un webhook Sangho. Préfixe : `wh_xxx` */
1653
+ interface Webhook extends Timestamps {
1654
+ id: string;
1655
+ object: "webhook";
1656
+ app: string;
1657
+ name: string;
1658
+ url: string;
1659
+ status: WebhookStatus;
1660
+ events: WebhookEventType[];
1661
+ security_profile: WebhookSecurityProfile;
1662
+ secret_preview: string;
1663
+ ssl_verification: boolean;
1664
+ retry_policy: WebhookRetryPolicy;
1665
+ rate_limit: number;
1666
+ timeout: number;
1667
+ failure_count: number;
1668
+ last_delivery_at?: string | null;
1669
+ metadata: Metadata;
1670
+ }
1671
+ interface WebhookDelivery extends Timestamps {
1672
+ id: string;
1673
+ object: "webhook_delivery";
1674
+ webhook: string;
1675
+ event_type: WebhookEventType | "webhook.test";
1676
+ url: string;
1677
+ status: DeliveryStatus;
1678
+ http_status?: number | null;
1679
+ is_successful: boolean;
1680
+ attempts: number;
1681
+ next_retry_at?: string | null;
1682
+ response_body?: string | null;
1683
+ response_time_ms?: number | null;
1684
+ delivered_at?: string | null;
1685
+ metadata: Metadata;
1686
+ }
1687
+ /** Champs POST */
1688
+ interface CreatePayloads {
1689
+ name: string;
1690
+ url: string;
1691
+ events: WebhookEventType[];
1692
+ security_profile?: WebhookSecurityProfile;
1693
+ ssl_verification?: boolean;
1694
+ retry_policy?: Partial<WebhookRetryPolicy>;
1695
+ rate_limit?: number;
1696
+ timeout?: number;
1697
+ metadata?: Metadata;
1698
+ }
1699
+ /** Champs PATCH */
1700
+ interface Payloads {
1701
+ name?: string;
1702
+ url?: string;
1703
+ events?: WebhookEventType[];
1704
+ status?: WebhookStatus;
1705
+ security_profile?: WebhookSecurityProfile;
1706
+ ssl_verification?: boolean;
1707
+ retry_policy?: Partial<WebhookRetryPolicy>;
1708
+ rate_limit?: number;
1709
+ timeout?: number;
1710
+ metadata?: Metadata;
1711
+ }
1712
+ /** Filtres GET /webhooks/ */
1713
+ interface WebhookCriteria extends ListParams {
1714
+ status?: WebhookStatus;
1715
+ }
1716
+ /** Filtres GET /webhooks/:id/deliveries/ */
1717
+ interface DeliveryCriteria extends ListParams {
1718
+ event_type?: WebhookEventType;
1719
+ status?: DeliveryStatus;
1720
+ }
1721
+
1722
+ type WebhooksProperties = {
1723
+ list(criteria?: WebhookCriteria): Promise<ListResponse<Webhook>>;
1724
+ retrieve(id: string): Promise<Webhook>;
1725
+ /**
1726
+ * Crée un endpoint webhook.
1727
+ * Le secret de signature est retourné en clair une seule fois dans la réponse.
1728
+ * Stockez-le immédiatement — il ne sera plus accessible ensuite.
1729
+ */
1730
+ create(payloads: CreatePayloads): Promise<Webhook & {
1731
+ secret: string;
1732
+ }>;
1733
+ update(id: string, payloads: Payloads): Promise<Webhook>;
1734
+ /** Supprime un webhook (HTTP 204). */
1735
+ delete(id: string): Promise<void>;
1736
+ /** Désactive un webhook sans le supprimer (passe en `"INACTIVE"`). */
1737
+ disable(id: string): Promise<Webhook>;
1738
+ /** Réactive un webhook désactivé (passe en `"ACTIVE"`). */
1739
+ enable(id: string): Promise<Webhook>;
1740
+ /**
1741
+ * Régénère le secret HMAC du webhook.
1742
+ * L'ancien secret est invalidé immédiatement.
1743
+ * @returns Le nouveau secret en clair (une seule fois)
1744
+ */
1745
+ rollSecret(id: string): Promise<{
1746
+ secret: string;
1747
+ }>;
1748
+ /** Envoie un événement test au webhook pour vérifier la connectivité. */
1749
+ sendTestEvent(id: string): Promise<WebhookDelivery>;
1750
+ listDeliveries(id: string, criteria?: DeliveryCriteria): Promise<ListResponse<WebhookDelivery>>;
1751
+ retrieveDelivery(webhookId: string, deliveryId: string): Promise<WebhookDelivery>;
1752
+ /** Rejoue une livraison échouée. */
1753
+ retryDelivery(webhookId: string, deliveryId: string): Promise<WebhookDelivery>;
1754
+ options(): Promise<DRFOptions>;
1755
+ };
1756
+
1757
+ interface SecurityProfile extends Timestamps {
1758
+ id: string;
1759
+ app: string;
1760
+ /** IPs autorisées — liste vide = toutes autorisées */
1761
+ allowed_ips: string[];
1762
+ /** Montant max par transaction en centimes */
1763
+ max_transaction_amount?: AmountInCents;
1764
+ /** Montant max par jour en centimes */
1765
+ max_daily_amount?: AmountInCents;
1766
+ /** Nombre max de transactions par heure */
1767
+ max_hourly_transactions?: number;
1768
+ require_cvv: boolean;
1769
+ require_3ds: boolean;
1770
+ block_vpn: boolean;
1771
+ block_tor: boolean;
1772
+ allowed_countries: string[];
1773
+ }
1774
+ interface UpdateSecurityProfileParams {
1775
+ allowed_ips?: string[];
1776
+ max_transaction_amount?: AmountInCents;
1777
+ max_daily_amount?: AmountInCents;
1778
+ max_hourly_transactions?: number;
1779
+ require_cvv?: boolean;
1780
+ require_3ds?: boolean;
1781
+ block_vpn?: boolean;
1782
+ block_tor?: boolean;
1783
+ allowed_countries?: string[];
1784
+ }
1785
+
1786
+ type SecurityProperties = {
1787
+ /**
1788
+ * Récupère le profil de sécurité de l'application.
1789
+ *
1790
+ * @example
1791
+ * ```typescript
1792
+ * const profile = await sangho.security.retrieve()
1793
+ * console.log(profile.allowed_ips)
1794
+ * ```
1795
+ */
1796
+ retrieve(): Promise<SecurityProfile>;
1797
+ /** Met à jour les paramètres de sécurité. */
1798
+ update(params: UpdateSecurityProfileParams): Promise<SecurityProfile>;
1799
+ /**
1800
+ * Ajoute des adresses IP à la liste blanche.
1801
+ *
1802
+ * @param ips - Liste d'IPs au format CIDR (ex: `["192.168.1.0/24"]`)
1803
+ */
1804
+ addAllowedIps(ips: string[]): Promise<SecurityProfile>;
1805
+ /** Retire des adresses IP de la liste blanche. */
1806
+ removeAllowedIps(ips: string[]): Promise<SecurityProfile>;
1807
+ };
1808
+
1809
+ type PartnerStatus = "active" | "inactive";
1810
+ type PartnerService = "PAYMENT" | "FRAUD" | "KYC" | "SETTLEMENT";
1811
+ /** Représente un partenaire Sangho. Lecture seule. */
1812
+ interface Partner extends Timestamps {
1813
+ id: string;
1814
+ object: "partner";
1815
+ name: string;
1816
+ webhook_url: string;
1817
+ services: PartnerService[];
1818
+ status: PartnerStatus;
1819
+ last_used?: string | null;
1820
+ }
1821
+ /** Filtres GET /partners/ */
1822
+ interface PartnerCriteria extends ListParams {
1823
+ status?: PartnerStatus;
1824
+ }
1825
+
1826
+ type PartnersProperties = {
1827
+ /**
1828
+ * Liste les partenaires actifs de la plateforme.
1829
+ * Lecture seule — les partenaires ne peuvent pas être créés via l'API.
1830
+ */
1831
+ list(criteria?: PartnerCriteria): Promise<ListResponse<Partner>>;
1832
+ /**
1833
+ * Récupère un partenaire par son identifiant.
1834
+ * @param id - Identifiant du partenaire
1835
+ */
1836
+ retrieve(id: string): Promise<Partner>;
1837
+ options(): Promise<DRFOptions>;
1838
+ };
1839
+
1840
+ type ReaderType = "android" | "firmware" | "virtual";
1841
+ type ReaderStatus = "online" | "offline" | "disabled";
1842
+ type TerminalSessionStatus = "pending" | "payment_method_presented" | "processing" | "succeeded" | "failed" | "canceled" | "timed_out";
1843
+ type TerminalPaymentMethodType = "card" | "mobile_money" | "qr_code";
1844
+ type OfflineSyncStatus = "pending" | "syncing" | "synced" | "conflict" | "failed";
1845
+ interface TerminalReader extends Timestamps {
1846
+ id: string;
1847
+ object: "terminal_reader";
1848
+ app: string;
1849
+ label: string;
1850
+ serial_number: string;
1851
+ reader_type: ReaderType;
1852
+ location?: string | null;
1853
+ status: ReaderStatus;
1854
+ reader_token: string;
1855
+ reader_token_expires: string;
1856
+ last_seen_at?: string | null;
1857
+ metadata: Metadata;
1858
+ }
1859
+ interface CreateReaderPayloads {
1860
+ label: string;
1861
+ serial_number: string;
1862
+ reader_type?: ReaderType;
1863
+ location?: string;
1864
+ metadata?: Metadata;
1865
+ }
1866
+ interface ReaderCriteria extends ListParams {
1867
+ status?: ReaderStatus;
1868
+ reader_type?: ReaderType;
1869
+ }
1870
+ interface TerminalSession extends Timestamps {
1871
+ id: string;
1872
+ object: "terminal_session";
1873
+ app: string;
1874
+ reader_id: string;
1875
+ payment_intent_id: string | null;
1876
+ amount: number;
1877
+ currency: "XAF";
1878
+ status: TerminalSessionStatus;
1879
+ payment_method_type?: TerminalPaymentMethodType | null;
1880
+ failure_reason?: string | null;
1881
+ processor_ref?: string | null;
1882
+ client_secret: string;
1883
+ expires_at: string;
1884
+ metadata: Metadata;
1885
+ }
1886
+ interface CreateSessionPayloads {
1887
+ reader: string;
1888
+ amount: number;
1889
+ description?: string;
1890
+ category?: string;
1891
+ metadata?: Metadata;
1892
+ }
1893
+ interface PresentPaymentPayloads {
1894
+ payment_method_type: TerminalPaymentMethodType;
1895
+ nonce: string;
1896
+ }
1897
+ interface SessionStatus {
1898
+ id: string;
1899
+ status: TerminalSessionStatus;
1900
+ payment_intent_status: string | null;
1901
+ failure_reason: string | null;
1902
+ }
1903
+ interface SessionCriteria extends ListParams {
1904
+ status?: TerminalSessionStatus;
1905
+ reader?: string;
1906
+ }
1907
+ interface OfflineTransactionPayload {
1908
+ local_id: string;
1909
+ amount: number;
1910
+ payment_method_type: TerminalPaymentMethodType;
1911
+ card_token?: string;
1912
+ captured_at: string;
1913
+ reader_id?: string;
1914
+ metadata?: Metadata;
1915
+ }
1916
+ interface SyncPayloads {
1917
+ transactions: OfflineTransactionPayload[];
1918
+ }
1919
+ interface SyncResult {
1920
+ local_id: string;
1921
+ sync_status: OfflineSyncStatus;
1922
+ payment_intent?: string | null;
1923
+ error?: string;
1924
+ }
1925
+ interface SyncResponse {
1926
+ synced: number;
1927
+ results: SyncResult[];
1928
+ }
1929
+ interface OfflineTransaction extends Timestamps {
1930
+ id: string;
1931
+ object: "offline_transaction";
1932
+ app: string;
1933
+ local_id: string;
1934
+ amount: number;
1935
+ currency: "XAF";
1936
+ payment_method_type: TerminalPaymentMethodType;
1937
+ captured_at: string;
1938
+ sync_status: OfflineSyncStatus;
1939
+ synced_at?: string | null;
1940
+ payment_intent?: string | null;
1941
+ sync_error?: string | null;
1942
+ metadata: Metadata;
1943
+ }
1944
+
1945
+ type ReadersProperties = {
1946
+ /**
1947
+ * Liste tous les terminaux enregistrés pour l'application authentifiée.
1948
+ * Les résultats sont paginés et filtrables par statut ou type.
1949
+ *
1950
+ * @param criteria - Filtres optionnels
1951
+ * @returns Liste paginée des terminaux
1952
+ *
1953
+ * @example
1954
+ * // Tous les terminaux
1955
+ * const all = await sangho.terminal.readers.list()
1956
+ *
1957
+ * // Seulement les terminaux Android en ligne
1958
+ * const actifs = await sangho.terminal.readers.list({
1959
+ * reader_type: "android",
1960
+ * status: "online",
1961
+ * })
1962
+ */
1963
+ list(criteria?: ReaderCriteria): Promise<ListResponse<TerminalReader>>;
1964
+ /**
1965
+ * Récupère un terminal par son identifiant.
1966
+ *
1967
+ * @param id - Identifiant du terminal (préfixe `rdr_`)
1968
+ * @returns Les données complètes du terminal
1969
+ *
1970
+ * @example
1971
+ * const reader = await sangho.terminal.readers.retrieve("rdr_xxx")
1972
+ * console.log(reader.status) // "online" | "offline" | "disabled"
1973
+ * console.log(reader.reader_type) // "android" | "firmware" | "virtual"
1974
+ */
1975
+ retrieve(id: string): Promise<TerminalReader>;
1976
+ /**
1977
+ * Enregistre un nouveau terminal physique ou virtuel.
1978
+ * À appeler **une seule fois** lors du provisionnement du device.
1979
+ * Le `reader_token` retourné doit être stocké dans le keystore sécurisé
1980
+ * de l'appareil (Android Keystore, HSM firmware, etc.).
1981
+ *
1982
+ * @param payloads - Données d'enregistrement
1983
+ * @returns Le terminal créé avec son `reader_token` initial (valide 24h)
1984
+ *
1985
+ * @example
1986
+ * // Provisionnement d'un terminal Android Sunmi T2
1987
+ * const reader = await sangho.terminal.readers.create({
1988
+ * label: "Caisse 1 — Libreville",
1989
+ * serial_number: "SN-SUNMI-T2-001",
1990
+ * reader_type: "android",
1991
+ * location: "Magasin Owendo, Libreville",
1992
+ * metadata: { store_id: "store_owendo" },
1993
+ * })
1994
+ *
1995
+ * // Stocker reader.reader_token dans le keystore Android sécurisé
1996
+ * await secureStorage.set("reader_token", reader.reader_token)
1997
+ */
1998
+ create(payloads: CreateReaderPayloads): Promise<TerminalReader>;
1999
+ /**
2000
+ * Met à jour les informations d'un terminal (mise à jour partielle).
2001
+ * Utile pour changer le label ou déplacer un terminal vers une autre localisation.
2002
+ *
2003
+ * @param id - Identifiant du terminal
2004
+ * @param payloads - Champs à modifier (tous optionnels)
2005
+ * @returns Le terminal mis à jour
2006
+ *
2007
+ * @example
2008
+ * const reader = await sangho.terminal.readers.update("rdr_xxx", {
2009
+ * label: "Caisse 2 — Owendo",
2010
+ * location: "Magasin Port, Libreville",
2011
+ * })
2012
+ */
2013
+ update(id: string, payloads: Partial<CreateReaderPayloads>): Promise<TerminalReader>;
2014
+ /**
2015
+ * Désactive définitivement un terminal.
2016
+ * Un terminal désactivé ne peut plus créer de sessions ni signaler son heartbeat.
2017
+ * Opération irréversible depuis le SDK — la réactivation se fait via le dashboard.
2018
+ *
2019
+ * @param id - Identifiant du terminal à désactiver
2020
+ * @returns Le terminal avec `status: "disabled"`
2021
+ *
2022
+ * @example
2023
+ * // Terminal volé ou hors service
2024
+ * await sangho.terminal.readers.disable("rdr_xxx")
2025
+ */
2026
+ disable(id: string): Promise<TerminalReader>;
2027
+ /**
2028
+ * Renouvelle le `reader_token` d'un terminal.
2029
+ * Le token a une durée de vie de **24h** ; à appeler automatiquement
2030
+ * au démarrage de l'application POS si `reader_token_expires` est dépassé.
2031
+ *
2032
+ * @param id - Identifiant du terminal
2033
+ * @returns Nouveau `reader_token` et sa date d'expiration `reader_token_expires`
2034
+ *
2035
+ * @example
2036
+ * const { reader_token, reader_token_expires } = await sangho.terminal.readers.refreshToken("rdr_xxx")
2037
+ * await secureStorage.set("reader_token", reader_token)
2038
+ * await secureStorage.set("reader_token_expires", reader_token_expires)
2039
+ */
2040
+ refreshToken(id: string): Promise<{
2041
+ reader_token: string;
2042
+ reader_token_expires: string;
2043
+ }>;
2044
+ /**
2045
+ * Signale que le terminal est actif (keep-alive).
2046
+ * À appeler en tâche de fond **toutes les 30 secondes**.
2047
+ * Met à jour `last_seen_at` et maintient le statut `"online"`.
2048
+ * Un terminal sans heartbeat depuis > 2 min passe automatiquement en `"offline"`.
2049
+ *
2050
+ * @param id - Identifiant du terminal
2051
+ * @returns Statut courant et timestamp de dernière activité
2052
+ *
2053
+ * @example
2054
+ * // Background worker — toutes les 30s
2055
+ * setInterval(async () => {
2056
+ * const { status, last_seen_at } = await sangho.terminal.readers.heartbeat("rdr_xxx")
2057
+ * if (status === "offline") reinitialiserConnexion()
2058
+ * }, 30_000)
2059
+ */
2060
+ heartbeat(id: string): Promise<{
2061
+ status: string;
2062
+ last_seen_at: string;
2063
+ }>;
2064
+ /**
2065
+ * Retourne les métadonnées DRF du endpoint `/terminal/readers/` :
2066
+ * actions autorisées, schéma de champs, filtres disponibles.
2067
+ */
2068
+ options(): Promise<DRFOptions>;
2069
+ };
2070
+ type SessionsProperties = {
2071
+ /**
2072
+ * Liste les sessions de paiement terminal.
2073
+ * Filtrables par statut ou par terminal.
2074
+ *
2075
+ * @param criteria - Filtres optionnels
2076
+ * @returns Liste paginée des sessions
2077
+ *
2078
+ * @example
2079
+ * // Sessions en attente sur un terminal donné
2080
+ * const pending = await sangho.terminal.sessions.list({
2081
+ * reader: "rdr_xxx",
2082
+ * status: "pending",
2083
+ * })
2084
+ */
2085
+ list(criteria?: SessionCriteria): Promise<ListResponse<TerminalSession>>;
2086
+ /**
2087
+ * Récupère une session de paiement terminal par son identifiant.
2088
+ *
2089
+ * @param id - Identifiant de la session (préfixe `tsess_`)
2090
+ * @returns Les données complètes de la session
2091
+ *
2092
+ * @example
2093
+ * const session = await sangho.terminal.sessions.retrieve("tsess_xxx")
2094
+ * console.log(session.status) // "pending" | "succeeded" | ...
2095
+ * console.log(session.amount) // montant en XAF
2096
+ */
2097
+ retrieve(id: string): Promise<TerminalSession>;
2098
+ /**
2099
+ * Crée une nouvelle session de paiement sur un terminal.
2100
+ * Déclenche l'affichage du montant sur l'écran du terminal.
2101
+ * La session expire automatiquement après le délai configuré (`expires_at`).
2102
+ *
2103
+ * @param payloads - Données de la session (reader, amount requis)
2104
+ * @returns La session créée avec son `client_secret` (utilisé par le POS)
2105
+ *
2106
+ * @example
2107
+ * const session = await sangho.terminal.sessions.create({
2108
+ * reader: "rdr_xxx",
2109
+ * amount: 15_000, // 15 000 XAF
2110
+ * description: "Vente caisse 1",
2111
+ * category: "product",
2112
+ * metadata: { order_id: "ORD-2024-001" },
2113
+ * })
2114
+ *
2115
+ * // Afficher le montant sur le terminal
2116
+ * afficherEcran(`Montant : ${session.amount} XAF — Présentez votre carte`)
2117
+ */
2118
+ create(payloads: CreateSessionPayloads): Promise<TerminalSession>;
2119
+ /**
2120
+ * Notifie le backend que le client a présenté un moyen de paiement.
2121
+ * Le `nonce` est fourni par le SDK constructeur du terminal (Sunmi, PAX, Ingenico…)
2122
+ * après lecture NFC/EMV — il ne doit **jamais** contenir le PAN brut.
2123
+ *
2124
+ * Authentification : accepte la `sk_xxx` **ou** le `reader_token` du terminal
2125
+ * (permission `IsTerminalToken` côté backend).
2126
+ *
2127
+ * @param id - Identifiant de la session
2128
+ * @param payloads - Type de moyen de paiement et nonce constructeur
2129
+ * @returns La session mise à jour (status → `"payment_method_presented"`)
2130
+ *
2131
+ * @example
2132
+ * // Après lecture NFC depuis le SDK Sunmi
2133
+ * const nonce = await sunmiSDK.readNFC() // ex: "emv_nonce_xxx"
2134
+ *
2135
+ * await sangho.terminal.sessions.presentPaymentMethod("tsess_xxx", {
2136
+ * payment_method_type: "card",
2137
+ * nonce,
2138
+ * })
2139
+ *
2140
+ * // Mobile Money (MTN, Airtel)
2141
+ * await sangho.terminal.sessions.presentPaymentMethod("tsess_xxx", {
2142
+ * payment_method_type: "mobile_money",
2143
+ * nonce: "mm_nonce_yyy",
2144
+ * })
2145
+ */
2146
+ presentPaymentMethod(id: string, payloads: PresentPaymentPayloads): Promise<TerminalSession>;
2147
+ /**
2148
+ * Interroge le statut courant d'une session (polling léger).
2149
+ * À appeler en boucle (~1,5s d'intervalle) jusqu'à obtenir un statut terminal.
2150
+ *
2151
+ * **Statuts terminaux** : `succeeded` | `failed` | `canceled` | `timed_out`
2152
+ * **Statuts transitoires** : `pending` | `payment_method_presented` | `processing`
2153
+ *
2154
+ * @param id - Identifiant de la session
2155
+ * @returns Statut de la session + statut du PaymentIntent associé
2156
+ *
2157
+ * @example
2158
+ * async function attendreResultat(sessionId: string): Promise<SessionStatus> {
2159
+ * const debut = Date.now()
2160
+ * while (Date.now() - debut < 30_000) {
2161
+ * const s = await sangho.terminal.sessions.pollStatus(sessionId)
2162
+ * if (["succeeded", "failed", "canceled", "timed_out"].includes(s.status)) {
2163
+ * return s
2164
+ * }
2165
+ * await sleep(1_500)
2166
+ * }
2167
+ * await sangho.terminal.sessions.cancel(sessionId)
2168
+ * throw new Error("Timeout dépassé")
2169
+ * }
2170
+ *
2171
+ * const result = await attendreResultat("tsess_xxx")
2172
+ * if (result.status === "succeeded") imprimerRecu(result)
2173
+ * else afficherEcran(`Refusé : ${result.failure_reason}`)
2174
+ */
2175
+ pollStatus(id: string): Promise<SessionStatus>;
2176
+ /**
2177
+ * Annule une session de paiement en cours.
2178
+ * Seules les sessions en statut `pending` ou `payment_method_presented`
2179
+ * peuvent être annulées. Une session `processing` ou `succeeded` ne peut plus l'être.
2180
+ *
2181
+ * @param id - Identifiant de la session à annuler
2182
+ * @returns La session avec `status: "canceled"`
2183
+ *
2184
+ * @example
2185
+ * // Annulation par le caissier
2186
+ * await sangho.terminal.sessions.cancel("tsess_xxx")
2187
+ * afficherEcran("Paiement annulé")
2188
+ */
2189
+ cancel(id: string): Promise<TerminalSession>;
2190
+ /**
2191
+ * Retourne les métadonnées DRF du endpoint `/terminal/sessions/`.
2192
+ */
2193
+ options(): Promise<DRFOptions>;
2194
+ };
2195
+ type OfflineProperties = {
2196
+ /**
2197
+ * Synchronise un batch de transactions capturées hors-ligne avec le backend.
2198
+ * À appeler dès que la connectivité réseau est rétablie.
2199
+ *
2200
+ * Chaque transaction est identifiée par son `local_id` (généré par le POS).
2201
+ * Le backend retourne le résultat individuel de chaque transaction
2202
+ * (`synced` | `conflict` | `failed`).
2203
+ *
2204
+ * ⚠️ Le `card_token` doit être un token constructeur — **jamais le PAN brut**.
2205
+ *
2206
+ * @param payloads - Tableau des transactions à synchroniser
2207
+ * @returns Nombre de transactions synchronisées + détail par `local_id`
2208
+ *
2209
+ * @example
2210
+ * const queue: OfflineTransactionPayload[] = [
2211
+ * {
2212
+ * local_id: "LOCAL-001",
2213
+ * amount: 8_500,
2214
+ * payment_method_type: "card",
2215
+ * card_token: "tok_constructeur_xxx",
2216
+ * captured_at: "2024-11-15T10:23:00Z",
2217
+ * reader_id: "rdr_xxx",
2218
+ * metadata: { order_id: "ORD-001" },
2219
+ * },
2220
+ * ]
2221
+ *
2222
+ * const result = await sangho.terminal.offline.sync({ transactions: queue })
2223
+ * console.log(`${result.synced} / ${queue.length} synchronisées`)
2224
+ *
2225
+ * result.results
2226
+ * .filter(r => r.sync_status === "failed")
2227
+ * .forEach(r => console.error(`Échec ${r.local_id} : ${r.error}`))
2228
+ */
2229
+ sync(payloads: SyncPayloads): Promise<SyncResponse>;
2230
+ /**
2231
+ * Liste les transactions offline enregistrées pour cette application.
2232
+ * Filtrables par `sync_status` pour retrouver les transactions en échec.
2233
+ *
2234
+ * @param criteria - Filtres optionnels (`sync_status`, `page`)
2235
+ * @returns Liste paginée des transactions offline
2236
+ *
2237
+ * @example
2238
+ * // Transactions en conflit à résoudre manuellement
2239
+ * const conflits = await sangho.terminal.offline.list({ sync_status: "conflict" })
2240
+ *
2241
+ * // Toutes les transactions non encore synchronisées
2242
+ * const pending = await sangho.terminal.offline.list({ sync_status: "pending" })
2243
+ */
2244
+ list(criteria?: {
2245
+ sync_status?: string;
2246
+ page?: number;
2247
+ }): Promise<ListResponse<OfflineTransaction>>;
2248
+ /**
2249
+ * Retourne les métadonnées DRF du endpoint `/terminal/offline/sync/`.
2250
+ */
2251
+ options(): Promise<DRFOptions>;
2252
+ };
2253
+ type TerminalProperties = {
2254
+ /**
2255
+ * Gestion des terminaux physiques (Android, firmware, virtuels).
2256
+ *
2257
+ * Un **terminal** représente un appareil de paiement enregistré :
2258
+ * caisse Android (Sunmi, PAX), firmware embarqué (Ingenico, Verifone),
2259
+ * ou terminal virtuel pour les tests.
2260
+ *
2261
+ * Cycle de vie d'un terminal :
2262
+ * ```
2263
+ * create() → heartbeat() (toutes 30s) → refreshToken() (toutes 24h) → disable()
2264
+ * ```
2265
+ *
2266
+ * @example
2267
+ * // Provisionnement initial
2268
+ * const reader = await sangho.terminal.readers.create({
2269
+ * label: "Caisse 1 — Libreville",
2270
+ * serial_number: "SN-SUNMI-T2-001",
2271
+ * reader_type: "android",
2272
+ * })
2273
+ */
2274
+ readers: ReadersProperties;
2275
+ /**
2276
+ * Gestion des sessions de paiement terminal.
2277
+ *
2278
+ * Une **session** représente une tentative de paiement initiée depuis
2279
+ * un terminal physique. Elle orchestre le cycle :
2280
+ * ```
2281
+ * create() → presentPaymentMethod() → pollStatus() → [succeeded | failed | cancel()]
2282
+ * ```
2283
+ *
2284
+ * @example
2285
+ * // Flux complet de paiement terminal
2286
+ * const session = await sangho.terminal.sessions.create({ reader: "rdr_xxx", amount: 15_000 })
2287
+ * await sangho.terminal.sessions.presentPaymentMethod(session.id, { payment_method_type: "card", nonce })
2288
+ * const result = await pollJusquaResultat(session.id)
2289
+ */
2290
+ sessions: SessionsProperties;
2291
+ /**
2292
+ * Synchronisation des transactions capturées hors-ligne.
2293
+ *
2294
+ * Quand la connexion réseau est indisponible (zone blanche, coupure),
2295
+ * le terminal capture les paiements localement puis les synchronise
2296
+ * avec `sync()` dès le retour du réseau.
2297
+ *
2298
+ * ```
2299
+ * [réseau absent] capturer localement → stocker en queue locale
2300
+ * [réseau rétabli] offline.sync({ transactions: queue })
2301
+ * ```
2302
+ *
2303
+ * @example
2304
+ * // Au retour du réseau
2305
+ * const result = await sangho.terminal.offline.sync({ transactions: localQueue })
2306
+ * console.log(`${result.synced} transactions synchronisées`)
2307
+ */
2308
+ offline: OfflineProperties;
2309
+ };
2310
+
2311
+ /** Résultat de la purge des données sandbox — voir SandboxModule.reset(). */
2312
+ interface SandboxResetResult {
2313
+ object: "sandbox.reset";
2314
+ /** Nombre d'enregistrements supprimés par modèle (ex: `{ customer: 12, product: 5 }`) */
2315
+ deleted: Record<string, number>;
2316
+ total_deleted: number;
2317
+ errors: string[];
2318
+ }
2319
+
2320
+ type SandboxProperties = {
2321
+ /**
2322
+ * Purge toutes les données sandbox de l'application (clé test uniquement).
2323
+ *
2324
+ * @example
2325
+ * await sangho.sandbox.reset()
2326
+ */
2327
+ reset(): Promise<SandboxResetResult>;
2328
+ };
2329
+
2330
+ type ApiKeyType = "public" | "secret";
2331
+ interface HttpClientConfig {
2332
+ baseURL: string;
2333
+ timeout: number;
2334
+ maxRetries: number;
2335
+ sandbox: boolean;
2336
+ apiKey: string;
2337
+ }
2338
+ declare class HttpClient {
2339
+ readonly keyType: ApiKeyType;
2340
+ private readonly config;
2341
+ constructor(config: HttpClientConfig);
2342
+ assertSecretKey(methodName: string): void;
2343
+ get<T, P extends object = object>(path: string, params?: P): Promise<T>;
2344
+ post<T>(path: string, body: unknown, idempotencyKey?: string): Promise<T>;
2345
+ patch<T>(path: string, body: unknown): Promise<T>;
2346
+ put<T>(path: string, body: unknown): Promise<T>;
2347
+ delete<T = void>(path: string): Promise<T>;
2348
+ options<T = unknown>(path: string): Promise<T>;
2349
+ private buildURL;
2350
+ private baseHeaders;
2351
+ private request;
2352
+ /**
2353
+ * Détermine si une SanghoError est transitoire et mérite un retry :
2354
+ * 429 (rate limit) ou 5xx (erreur serveur). Jamais les 4xx restants
2355
+ * (400/401/403/404/409/422) — ce sont des erreurs permanentes côté client.
2356
+ */
2357
+ private isRetryable;
2358
+ private handleResponse;
2359
+ private sleep;
2360
+ }
2361
+
2362
+ /**
2363
+ * Classe de base dont héritent tous les modules Sangho.
2364
+ *
2365
+ * Pattern : composition via injection de `HttpClient`.
2366
+ * Jamais d'héritage multiple — un seul HttpClient partagé par instance Sangho.
2367
+ *
2368
+ * @example
2369
+ * ```typescript
2370
+ * export class CustomersModule extends BaseModule {
2371
+ * async create(params: CreateCustomerParams): Promise<Customer> {
2372
+ * this.http.assertSecretKey("customers.create");
2373
+ * return this.http.post<Customer>("/customers/", params);
2374
+ * }
2375
+ * }
2376
+ * ```
2377
+ */
2378
+ declare class BaseModule {
2379
+ /** Client HTTP partagé — ne jamais exposer publiquement. */
2380
+ protected readonly http: HttpClient;
2381
+ constructor(http: HttpClient);
2382
+ }
2383
+
2384
+ declare const Sangho_base: {
2385
+ new (...args: any[]): {};
2386
+ } & typeof BaseModule;
2387
+ /**
2388
+ * Client principal du SDK Sangho.
2389
+ *
2390
+ * @example
2391
+ * ```typescript
2392
+ * // Côté serveur — clé secrète
2393
+ * const sangho = new Sangho("sk_prod_xxx")
2394
+ * const intent = await sangho.paymentIntents.create({ amount: 5000, currency: "XAF" })
2395
+ *
2396
+ * // Côté navigateur — clé publique (checkout uniquement)
2397
+ * const sangho = new Sangho("pk_prod_xxx")
2398
+ * const session = await sangho.checkoutSessions.retrieve("cs_xxx")
2399
+ * ```
2400
+ */
2401
+ declare class Sangho extends Sangho_base {
2402
+ readonly account: InterfaceOnly<AccountProperties>;
2403
+ readonly apps: InterfaceOnly<AppsProperties>;
2404
+ readonly addresses: InterfaceOnly<AddressesProperties>;
2405
+ readonly customers: InterfaceOnly<CustomersProperties>;
2406
+ readonly products: InterfaceOnly<ProductsProperties>;
2407
+ readonly paymentIntents: InterfaceOnly<PaymentIntentsProperties>;
2408
+ readonly transactions: InterfaceOnly<TransactionsProperties>;
2409
+ readonly refunds: InterfaceOnly<RefundsProperties>;
2410
+ readonly invoices: InterfaceOnly<InvoicesProperties>;
2411
+ readonly paymentLinks: InterfaceOnly<PaymentLinksProperties>;
2412
+ readonly checkoutSessions: InterfaceOnly<CheckoutSessionsProperties>;
2413
+ readonly subscriptions: InterfaceOnly<SubscriptionsProperties>;
2414
+ readonly paymentMethods: InterfaceOnly<PaymentMethodsProperties>;
2415
+ readonly receipts: InterfaceOnly<ReceiptsProperties>;
2416
+ readonly webhooks: InterfaceOnly<WebhooksProperties>;
2417
+ readonly security: InterfaceOnly<SecurityProperties>;
2418
+ readonly partners: InterfaceOnly<PartnersProperties>;
2419
+ readonly terminal: InterfaceOnly<TerminalProperties>;
2420
+ readonly sandbox: InterfaceOnly<SandboxProperties>;
2421
+ constructor(apiKey: string, options?: SanghoOptions);
2422
+ /**
2423
+ * Vérifie et parse un événement webhook entrant.
2424
+ * Valide la signature HMAC-SHA256 + protection anti-replay (5 min).
2425
+ *
2426
+ * @param payload - Corps brut de la requête (Buffer ou string)
2427
+ * @param signature - Header `Sangho-Signature` de la requête
2428
+ * @param secret - Secret du webhook (depuis le dashboard)
2429
+ *
2430
+ * @example
2431
+ * ```typescript
2432
+ * // Express
2433
+ * app.post('/webhooks/sangho', express.raw({ type: 'application/json' }), (req, res) => {
2434
+ * const event = Sangho.constructEvent(
2435
+ * req.body,
2436
+ * req.headers['sangho-signature'],
2437
+ * process.env.SANGHO_WEBHOOK_SECRET
2438
+ * )
2439
+ * if (event.type === 'payment_intent.succeeded') {
2440
+ * await fulfillOrder(event.data)
2441
+ * }
2442
+ * res.json({ received: true })
2443
+ * })
2444
+ * ```
2445
+ */
2446
+ static constructEvent: typeof constructEvent;
2447
+ }
2448
+
2449
+ /**
2450
+ * Catégorie large de l'erreur (`err.type`).
2451
+ *
2452
+ * Les 7 premières valeurs sont exactement le taxonomie `type` renvoyée par
2453
+ * le backend (cf. `backend/api/exceptions.py`) sur toute réponse HTTP
2454
+ * d'erreur. `NETWORK_ERROR` et `TIMEOUT_ERROR` sont deux catégories
2455
+ * additionnelles, propres au SDK : elles ne correspondent à aucune réponse
2456
+ * HTTP puisque la requête n'a justement jamais abouti côté serveur.
2457
+ */
2458
+ type SanghoErrorType = "AUTHENTICATION_ERROR" | "PERMISSION_ERROR" | "NOT_FOUND_ERROR" | "CONFLICT_ERROR" | "VALIDATION_ERROR" | "RATE_LIMIT_ERROR" | "API_ERROR" | "NETWORK_ERROR" | "TIMEOUT_ERROR";
2459
+ interface SanghoErrorResponse {
2460
+ message: string;
2461
+ type?: string;
2462
+ code?: string;
2463
+ detail?: string | Record<string, string[]>;
2464
+ errors?: Record<string, string[]>;
2465
+ status?: number;
2466
+ param?: string;
2467
+ }
2468
+ /**
2469
+ * Classe de base — toutes les erreurs Sangho en héritent.
2470
+ */
2471
+ declare class SanghoError extends Error {
2472
+ /**
2473
+ * Catégorie large de l'erreur, une des 9 valeurs `SanghoErrorType`
2474
+ * (`VALIDATION_ERROR`, `RATE_LIMIT_ERROR`, `NETWORK_ERROR`, ...).
2475
+ * Utile pour un `switch`/branchement générique.
2476
+ */
2477
+ readonly type: SanghoErrorType;
2478
+ /**
2479
+ * Code métier précis renvoyé par le backend (`raw.code`), ex :
2480
+ * `AMOUNT_TOO_SMALL`, `INSUFFICIENT_FUNDS`, `CUSTOMER_NOT_FOUND`,
2481
+ * `INVALID_API_KEY`, `CURRENCY_NOT_IN_PLAN`... Le catalogue de codes est
2482
+ * possédé et versionné côté backend et continuera de grandir — c'est
2483
+ * pourquoi ce champ est typé `string` plutôt qu'une union fermée.
2484
+ *
2485
+ * Quand l'erreur n'a jamais atteint le backend (`SanghoNetworkError`,
2486
+ * `SanghoTimeoutError` — pas de corps de réponse à lire), `code` retombe
2487
+ * sur la même valeur que `type`.
2488
+ */
2489
+ readonly code: string;
2490
+ readonly statusCode?: number;
2491
+ readonly raw?: SanghoErrorResponse;
2492
+ constructor(message: string, type?: SanghoErrorType, statusCode?: number, raw?: SanghoErrorResponse);
2493
+ }
2494
+ /**
2495
+ * 401 — Clé API invalide, expirée ou absente.
2496
+ */
2497
+ declare class SanghoAuthError extends SanghoError {
2498
+ constructor(message?: string, raw?: SanghoErrorResponse);
2499
+ }
2500
+ /**
2501
+ * 403 — Clé publique utilisée pour une opération réservée aux clés secrètes.
2502
+ * Catégorie (`type`) : `PERMISSION_ERROR` — c'est bien un problème de
2503
+ * permission ; `code` reste `PUBLIC_KEY_NOT_ALLOWED` (ou équivalent envoyé
2504
+ * par le backend) pour distinguer précisément ce cas des autres 403.
2505
+ */
2506
+ declare class SanghoPublicKeyError extends SanghoError {
2507
+ constructor(message?: string, raw?: SanghoErrorResponse);
2508
+ }
2509
+ /**
2510
+ * 403 — Permissions insuffisantes.
2511
+ */
2512
+ declare class SanghoPermissionError extends SanghoError {
2513
+ constructor(message?: string, raw?: SanghoErrorResponse);
2514
+ }
2515
+ /**
2516
+ * 404 — Ressource introuvable.
2517
+ */
2518
+ declare class SanghoNotFoundError extends SanghoError {
2519
+ constructor(message?: string, raw?: SanghoErrorResponse);
2520
+ }
2521
+ /**
2522
+ * 422 — Données invalides (erreurs de validation champ par champ).
2523
+ */
2524
+ declare class SanghoValidationError extends SanghoError {
2525
+ readonly fieldErrors: Record<string, string[]>;
2526
+ readonly param?: string;
2527
+ constructor(raw: SanghoErrorResponse);
2528
+ }
2529
+ /**
2530
+ * 429 — Trop de requêtes. `retryAfter` indique le délai (secondes) avant retry.
2531
+ */
2532
+ declare class SanghoRateLimitError extends SanghoError {
2533
+ readonly retryAfter?: number;
2534
+ constructor(retryAfter?: number, raw?: SanghoErrorResponse);
2535
+ }
2536
+ /**
2537
+ * 409 — Clé d'idempotence réutilisée avec un payload différent.
2538
+ * Catégorie (`type`) : `CONFLICT_ERROR` — même famille que les autres 409.
2539
+ */
2540
+ declare class SanghoIdempotencyError extends SanghoError {
2541
+ constructor(raw?: SanghoErrorResponse);
2542
+ }
2543
+ /**
2544
+ * Erreur réseau (pas de réponse du serveur). Catégorie SDK-only : la requête
2545
+ * n'a jamais atteint le backend, donc pas de `raw`/`code` métier précis —
2546
+ * `code` retombe sur `NETWORK_ERROR` (== `type`).
2547
+ */
2548
+ declare class SanghoNetworkError extends SanghoError {
2549
+ constructor(message?: string);
2550
+ }
2551
+ /**
2552
+ * Timeout dépassé. Catégorie SDK-only, même raisonnement que
2553
+ * `SanghoNetworkError` : `code` retombe sur `TIMEOUT_ERROR` (== `type`).
2554
+ */
2555
+ declare class SanghoTimeoutError extends SanghoError {
2556
+ constructor(timeout: number);
2557
+ }
2558
+
2559
+ export { type Address, type AmountInCents, type App, type AppKey, type AppKeys, type CheckoutSession, type CurrencyCode, type Customer, type Invoice, type ListParams, type ListResponse, type Metadata, type Partner, type PaymentIntent, type PaymentLink, type PaymentMethod, type Product, type ProductImage, type Receipt, type Refund, type SandboxResetResult, Sangho, SanghoAuthError, SanghoError, type SanghoErrorResponse, type SanghoErrorType, SanghoIdempotencyError, SanghoNetworkError, SanghoNotFoundError, type SanghoOptions, SanghoPermissionError, SanghoPublicKeyError, SanghoRateLimitError, SanghoTimeoutError, SanghoValidationError, type SecurityProfile, type Subscription, type Timestamps, type Transaction, type UpdateSecurityProfileParams, type Webhook, type WebhookDelivery, constructEvent, Sangho as default };