/** * Monegasy Payment SDK * @version 1.0.0 * @description SDK JavaScript officiel pour intégrer les paiements Monegasy * @author Monegasy * @license MIT * @see https://docs.monegasy.com */ /** Version du SDK — doit rester synchro avec `package.json`. */ export declare const SDK_VERSION = "1.2.0"; /** URLs de production par défaut */ export declare const DEFAULT_API_URL = "https://api.monegasy.com"; export declare const DEFAULT_WEB_URL = "https://monegasy.com"; /** URLs de sandbox par défaut */ export declare const SANDBOX_API_URL = "http://localhost:3000"; export declare const SANDBOX_WEB_URL = "http://localhost:5173"; /** Deep Link Configuration */ export declare const DEEP_LINK_SCHEME = "monegasy"; export declare const APP_STORE_URL = "https://apps.apple.com/app/monegasy"; export declare const PLAY_STORE_URL = "https://play.google.com/store/apps/details?id=com.monegasy.wallet"; /** * Erreur de base pour toutes les erreurs SDK Monegasy. * Permet aux intégrateurs de filtrer via `instanceof` : * * ```ts * try { * await sdk.createPaymentLink(...); * } catch (err) { * if (err instanceof MonegasyNetworkError) { * // pas de connexion * } else if (err instanceof MonegasyApiError && err.statusCode === 401) { * // clé API invalide * } * } * ``` */ export declare class MonegasyError extends Error { /** Code court interne, ex: "INVALID_AMOUNT", "NETWORK". */ readonly code: string; constructor(message: string, code?: string); } /** Validation locale : montant invalide, description vide, etc. */ export declare class MonegasyValidationError extends MonegasyError { constructor(message: string); } /** Échec réseau : DNS, timeout, offline. */ export declare class MonegasyNetworkError extends MonegasyError { constructor(message: string); } /** Réponse API non-2xx (avec statut HTTP). */ export declare class MonegasyApiError extends MonegasyError { readonly statusCode: number; readonly data: unknown; constructor(message: string, statusCode: number, data?: unknown); } /** * Information sur le device de l'utilisateur */ export interface DeviceInfo { /** Est-ce un appareil mobile ? */ isMobile: boolean; /** Est-ce un iPhone/iPad/iPod ? */ isIOS: boolean; /** Est-ce un appareil Android ? */ isAndroid: boolean; /** Est-ce une tablette ? */ isTablet: boolean; /** Est-ce un ordinateur ? */ isDesktop: boolean; /** URL du store approprié */ storeUrl: string; /** Nom du store (App Store ou Google Play) */ storeName: string; /** User Agent */ userAgent: string; } /** * Configuration du SDK Monegasy */ export interface MonegasyConfig { /** Clé API du marchand (requis) */ apiKey: string; /** URL de base de l'API (optionnel) */ baseURL?: string; /** URL de la page web de paiement (optionnel) */ webURL?: string; /** Mode sandbox/test (optionnel, défaut: false) */ sandbox?: boolean; /** Timeout HTTP par requête en millisecondes (défaut: 30 000). */ timeoutMs?: number; /** Nombre max de retries auto sur 429/5xx (défaut: 3, 0 = désactivé). */ maxRetries?: number; } /** * Paramètres pour créer un lien de paiement */ /** * Mode de paiement étalé disponible. * - `"3x"` : 3 échéances égales * - `"4x"` : 4 échéances égales * - `"deposit_balance"` : acompte + solde */ export type InstallmentMode = "3x" | "4x" | "deposit_balance"; /** * Options pour activer le paiement en plusieurs fois sur un lien. * * Si `enabled = true`, le client verra un picker à la confirmation * du paiement. Les modes proposés sont l'intersection de : * 1. `allowedModes` (passé ici) — si omis, tous les modes activés * par le marchand sont disponibles * 2. La configuration globale du marchand (modes activés, bornes * min/max amount) * * Si aucun mode n'est compatible (montant hors bornes, etc.), le * client ne voit que le paiement classique en une fois. */ export interface InstallmentOptions { /** Activer la facilité sur ce lien */ enabled: boolean; /** Sous-ensemble des modes autorisés. Si omis, tous activés. */ allowedModes?: InstallmentMode[]; /** Override du pourcentage d'acompte (config marchand sinon) */ depositPercentage?: number; /** Override du délai du solde en jours (config marchand sinon) */ balanceDueDays?: number; } /** * Status d'un plan d'échéancier côté serveur. */ export type InstallmentPlanStatus = "active" | "completed" | "failed" | "cancelled"; /** * Status d'une échéance individuelle. */ export type InstallmentLineStatus = "pending" | "due" | "retrying" | "paid" | "failed" | "cancelled"; /** * Preview d'une option de facilité de paiement (avant création du plan). */ export interface InstallmentPreview { type: InstallmentMode; installments: Array<{ sequence: number; amount: number; feeAmount: number; dueDate: string; label: string; }>; totalAmount: number; totalFees: number; description: string; } /** * Configuration des facilités de paiement par marchand. */ export interface MerchantInstallmentConfig { id: string; merchantId: string; enabled3x: boolean; enabled4x: boolean; enabledDepositBalance: boolean; minAmount: number | null; maxAmount: number | null; intervalDays: number; depositPercentage: number | null; balanceDueDays: number | null; customerFeePercentage: number; createdAt: string; updatedAt: string; } /** * Échéance individuelle d'un plan. */ export interface InstallmentLineInfo { id: string; planId: string; sequence: number; amount: number; feeAmount: number; dueDate: string; status: InstallmentLineStatus; transactionId: string | null; paidAt: string | null; failedAttempts: number; nextRetryAt: string | null; } /** * Plan d'échéancier complet (vue marchand). */ export interface InstallmentPlanInfo { id: string; paymentLinkId: string | null; orderId: string | null; merchantId: string; buyerUserId: string; type: InstallmentMode; totalInstallments: number; totalAmount: number; collectedAmount: number; customerFeePercentage: number; status: InstallmentPlanStatus; createdAt: string; completedAt: string | null; cancelledAt: string | null; installments?: InstallmentLineInfo[]; } /** * Configuration webhook d'un marchand. */ export interface WebhookConfig { id: string; merchantId: string; url: string; events: string[]; secret?: string; retryCount: number; isActive: boolean; createdAt: string; updatedAt: string; } /** * Statut possible d'une livraison webhook. */ export type WebhookLogStatus = "success" | "failed" | "retrying"; /** * Log d'une tentative de livraison webhook. */ export interface WebhookLog { id: string; webhookId: string; event: string; payload: Record; attemptCount: number; status: WebhookLogStatus; responseStatus: number | null; responseBody: string | null; errorMessage: string | null; createdAt: string; } /** * Résultat du test d'un webhook avec un événement personnalisé. */ export interface WebhookTestResult { success: boolean; statusCode?: number; latencyMs: number; responseBody?: string; responseHeaders?: Record; error?: string; sentPayload: Record; targetUrl: string; } export interface CreatePaymentLinkParams { /** Montant en Ariary (requis, doit être > 0) */ amount: number; /** Description du paiement (requis) */ description: string; /** Nom du produit (optionnel) */ productName?: string; /** URL de l'image du produit (optionnel) */ productImage?: string; /** Métadonnées personnalisées (optionnel) */ metadata?: Record; /** URL de redirection après succès (optionnel) */ successUrl?: string; /** URL de redirection après annulation (optionnel) */ cancelUrl?: string; /** URL du webhook pour les notifications (optionnel) */ webhookUrl?: string; /** Durée de validité en heures (optionnel, défaut: 24) */ expiresInHours?: number; /** * Activer le paiement en plusieurs fois (3x, 4x, acompte+solde). * * Exemple : * ```ts * await monegasy.createPaymentLink({ * amount: 150000, * description: "Smartphone Samsung", * installments: { * enabled: true, * allowedModes: ["3x", "4x"], * }, * }); * ``` * * À la confirmation du paiement, le client choisit son mode dans * l'application Monegasy. Les premières échéances sont prélevées * immédiatement ; les suivantes le seront automatiquement aux dates * planifiées. Vous recevez un webhook `installment.paid` à chaque * échéance prélevée, et `plan.completed` quand toutes ont été * encaissées. */ installments?: InstallmentOptions; } /** * Réponse d'un lien de paiement */ export interface PaymentLink { /** ID interne du paiement */ id: string; /** ID public du lien de paiement */ linkId: string; /** Montant en Ariary */ amount: number; /** Devise (MGA) */ currency: string; /** Description du paiement */ description: string; /** Statut du paiement */ status: PaymentStatus; /** URL de la page de paiement web */ paymentUrl: string; /** Deep link pour l'app mobile */ mobileDeepLink: string; /** Nom du produit */ productName?: string; /** Date de création */ createdAt?: string; /** Date d'expiration */ expiresAt?: string; /** Permet des propriétés additionnelles */ [key: string]: unknown; } /** * Statuts possibles d'un paiement */ export type PaymentStatus = "pending" | "paid" | "expired" | "cancelled"; export interface CreatePlatformMerchantParams { /** Numéro du pro = son identité Monegasy (`0XXXXXXXXX` ou `+261XXXXXXXXX`). */ phone: string; businessName: string; businessDescription?: string; businessAddress?: string; businessEmail?: string; /** Id de ce pro dans ton système (mapping retour via webhook). */ externalRef?: string; } export interface PlatformMerchant { merchantId: string; userId: string; /** `provisioned` = compte créé ; `linked_existing` = compte Monegasy déjà présent. */ status: "provisioned" | "linked_existing"; /** true si le pro doit encore réclamer son compte (connexion-SMS) pour retirer. */ claimRequired: boolean; businessName: string; } export interface PlatformSubMerchant { merchantId: string; businessName: string; slug: string | null; externalRef: string | null; isVerified: boolean; createdAt: string; } export interface CreatePlatformPaymentLinkParams extends CreatePaymentLinkParams { /** Sous-marchand bénéficiaire (doit appartenir à la plateforme). */ merchantId: string; } export interface ProductCategory { id: string; name: string; icon?: string | null; color?: string | null; } /** * Produit dans le catalogue public. Forme allégée — pour le détail complet, * utilise l'endpoint `/products/:id/public` (cf. mobile scan QR). */ export interface CatalogProduct { id: string; name: string; price: number; /** Prix effectif si en promo (sinon === price). */ effectivePrice: number; onSale: boolean; imageUrl: string | null; stock: number; merchantName: string; merchantId: string; merchantSlug: string | null; /** Distance en km si lat/lng fournis dans la recherche, sinon null. */ distanceKm: number | null; category: ProductCategory | null; } export interface CatalogResponse { items: CatalogProduct[]; total: number; page: number; pageSize: number; } export interface SearchProductsParams { /** Mot-clé recherché dans nom/description. */ search?: string; /** ID d'une catégorie système (cf. `/product-categories`). */ categoryId?: string; /** Géolocalisation : si fournie, les résultats sont triés par proximité. */ lat?: number; lng?: number; /** Rayon de recherche en km. Combiner avec lat/lng. */ radiusKm?: number; page?: number; pageSize?: number; } export interface StorefrontMerchant { id: string; userId: string; businessName: string; businessDescription: string | null; tagline: string | null; logo: string | null; coverImageUrl: string | null; slug: string; latitude: number | null; longitude: number | null; businessAddress: string | null; isVerified: boolean; } export interface StorefrontResponse { merchant: StorefrontMerchant; products: Array<{ id: string; name: string; description?: string; price: number; discountPrice: number | null; imageUrl: string | null; stock: number; category: ProductCategory | null; }>; productsCount: number; } /** * Paramètres pour afficher un bouton de paiement */ export interface RenderButtonParams extends CreatePaymentLinkParams { /** Texte du bouton (optionnel) */ buttonText?: string; /** Styles CSS personnalisés pour le bouton (optionnel) */ buttonStyle?: Record; /** Callback appelé en cas de succès */ onSuccess?: (payment: PaymentLink) => void; /** Callback appelé en cas d'erreur */ onError?: (error: Error) => void; /** Callback appelé en cas d'annulation */ onCancel?: () => void; } /** * Période de facturation pour les abonnements */ export type BillingPeriod = "monthly" | "quarterly" | "yearly"; /** * Statut d'un plan d'abonnement */ export type PlanStatus = "active" | "inactive" | "archived"; /** * Statut d'un abonnement utilisateur */ export type SubscriptionStatus = "active" | "trial" | "paused" | "cancelled" | "expired" | "payment_failed"; /** * Paramètres pour créer un plan d'abonnement */ export interface CreateSubscriptionPlanParams { /** Nom du plan (requis) */ name: string; /** Description du plan (optionnel) */ description?: string; /** Prix en Ariary (requis, doit être > 0) */ price: number; /** Période de facturation (requis) */ billingPeriod: BillingPeriod; /** Nombre de jours d'essai gratuit (optionnel, défaut: 0) */ trialDays?: number; /** Liste des fonctionnalités incluses (optionnel) */ features?: string[]; } /** * Paramètres pour mettre à jour un plan d'abonnement */ export interface UpdateSubscriptionPlanParams { /** Nom du plan (optionnel) */ name?: string; /** Description du plan (optionnel) */ description?: string; /** Prix en Ariary (optionnel) */ price?: number; /** Période de facturation (optionnel) */ billingPeriod?: BillingPeriod; /** Nombre de jours d'essai gratuit (optionnel) */ trialDays?: number; /** Liste des fonctionnalités incluses (optionnel) */ features?: string[]; /** Statut du plan (optionnel) */ status?: PlanStatus; } /** * Réponse d'un plan d'abonnement */ export interface SubscriptionPlan { id: string; name: string; description?: string; price: number; billingPeriod: BillingPeriod; trialDays: number; features?: string[]; status: PlanStatus; subscriberCount: number; qrCodeData?: string; createdAt: string; updatedAt?: string; } /** * Réponse d'un abonné */ export interface Subscriber { id: string; userId: string; userName?: string; userPhone?: string; plan: { id: string; name: string; price: number; }; status: SubscriptionStatus; startDate: string; currentPeriodStart: string; currentPeriodEnd: string; trialEndDate?: string; nextBillingDate: string; amount: number; createdAt: string; } /** * Statistiques des abonnements */ export interface SubscriptionStats { plans: { total: number; active: number; }; subscribers: { total: number; active: number; byStatus: Record; }; revenue: { monthlyEstimate: number; currency: string; }; } /** * Liens d'inscription à un plan */ export interface SubscribeLinks { plan: { id: string; name: string; price: number; billingPeriod: BillingPeriod; trialDays: number; }; links: { webUrl: string; mobileDeepLink: string; qrCodeData?: string; }; } /** * Événements webhook disponibles */ export type WebhookEventType = "payment.completed" | "payment.failed" | "payment.cancelled" | "payment.refunded" | "payment.test"; /** * Données du webhook pour un paiement réussi */ export interface WebhookPaymentCompletedData { /** ID du lien de paiement (ex: "pl_abc123") */ paymentLinkId: string; /** Montant en Ariary */ amount: number; /** Devise (ex: "Ar") */ currency: string; /** Statut du paiement */ status: "completed"; /** Description du paiement */ description: string; /** Nom du produit (si fourni) */ productName?: string; /** Téléphone du client */ customerPhone?: string; /** Date du paiement */ paidAt: string; /** ID de la transaction Monegasy */ transactionId?: string; /** Métadonnées personnalisées */ metadata?: string; /** URL de succès (si fournie) */ successUrl?: string; } /** * Données du webhook pour un paiement échoué */ export interface WebhookPaymentFailedData { paymentLinkId: string; amount: number; currency: string; status: "failed"; description: string; error: string; metadata?: string; } /** * Données du webhook pour un paiement annulé */ export interface WebhookPaymentCancelledData { paymentLinkId: string; amount: number; currency: string; status: "cancelled"; description: string; metadata?: string; } /** * Données du webhook pour un remboursement */ export interface WebhookPaymentRefundedData { refundId: string; originalTransactionId: string; amount: number; currency: string; status: "refunded"; reason?: string; } /** * Payload complet d'un webhook Monegasy */ export interface WebhookPayload> { /** Type d'événement */ event: WebhookEventType; /** Données de l'événement */ data: T; /** Horodatage ISO */ timestamp: string; /** ID du webhook */ webhook_id: string; } /** * Headers envoyés avec chaque webhook */ export interface WebhookHeaders { /** Signature HMAC SHA256 du payload */ "x-monegasy-signature": string; /** Type d'événement */ "x-monegasy-event": string; "content-type": "application/json"; } /** * Options pour la popup de paiement */ export interface PopupOptions { /** Largeur de la popup (défaut: 500) */ width?: number; /** Hauteur de la popup (défaut: 700) */ height?: number; } /** * SDK Monegasy pour l'intégration des paiements * @example * ```typescript * const sdk = new MonegasySDK({ * apiKey: 'mk_live_xxxxxxx', * sandbox: false * }); * * await sdk.renderPaymentButton({ * amount: 50000, * description: 'Achat produit' * }, '#payment-button'); * ``` */ export default class MonegasySDK { private readonly apiKey; private readonly baseURL; private readonly webURL; private readonly isSandbox; /** Type détecté depuis le préfixe de la clé. Permet au SDK de * throw early sur les routes qui exigent une secret key. */ private readonly keyType; /** Timeout par défaut en millisecondes pour les requêtes HTTP. */ private readonly timeoutMs; /** Nombre max de retries automatiques sur 429/5xx (avec backoff). */ private readonly maxRetries; /** * Crée une nouvelle instance du SDK Monegasy * @param config - Configuration du SDK * @throws {Error} Si la clé API n'est pas fournie */ constructor(config: MonegasyConfig); /** * Retourne la version du SDK */ static getVersion(): string; /** * Vérifie si le SDK est en mode sandbox */ get sandbox(): boolean; /** * Retourne l'URL de base de l'API */ get apiUrl(): string; /** * Retourne l'URL de la page web de paiement */ get paymentWebUrl(): string; /** * Normalise une URL en `origin` (scheme + host + port). Utilisé pour * comparer `event.origin` de manière robuste : un trailing slash ou * un `www.` ne casse plus la comparaison. */ private _normalizeOrigin; /** * Renvoie `true` si l'origin du message vient bien de la page web Monegasy * configurée (`webURL`). Compare normalisé pour ignorer trailing slash. */ private _isTrustedOrigin; /** * Wrapper interne de `fetch` qui retourne le JSON ou lance * une `MonegasyNetworkError` / `MonegasyApiError` typée. * * Améliorations vs un fetch direct : * - Timeout configurable (défaut 30s, abort propre via AbortController) * - Retry automatique sur 429 et 5xx avec backoff exponentiel * (max `this.maxRetries`, honore le header `Retry-After`) * - Idempotency-Key auto-généré sur POST/PUT/PATCH (UUID v4) si pas * fourni explicitement par le caller * - Erreurs typées (MonegasyApiError, MonegasyNetworkError) * * @param path - Chemin relatif à `baseURL` (commence par "/") * @param init - Options fetch (méthode, body, etc.) * @param signal - AbortSignal optionnel pour annuler la requête * @param options - Options SDK additionnelles (idempotencyKey explicite, etc.) */ private _apiFetch; /** Combine plusieurs AbortSignal en un seul. Si l'un abort, le merged abort. */ private _mergeSignals; /** Délai exponentiel + jitter (Math.random() ±20%) pour éviter le * thundering herd quand plusieurs clients retentent en même temps. */ private _backoffDelay; /** Génère un UUID v4 simple (sans dépendance externe). Utilisé pour * les Idempotency-Key auto. RFC 4122 v4. */ private static _generateIdempotencyKey; /** Vérifie que la clé courante est de type secret. Throw early avec un * message clair si publishable → évite un round-trip réseau pour * recevoir un 403 du backend. */ private _assertSecretKey; /** * Crée un lien de paiement * @param params - Paramètres du paiement * @returns Promise - Le lien de paiement créé * @throws {Error} Si le montant est invalide ou la description manquante * @example * ```typescript * const payment = await sdk.createPaymentLink({ * amount: 50000, * description: 'Achat iPhone 15', * productName: 'iPhone 15 Pro' * }); * console.log(payment.paymentUrl); * ``` */ createPaymentLink(params: CreatePaymentLinkParams & { signal?: AbortSignal; }): Promise; /** * Récupère les détails d'un lien de paiement * @param linkId - ID du lien de paiement (ex: "pl_abc123") * @returns Promise - Les détails du paiement * @throws {Error} Si le paiement n'est pas trouvé * @example * ```typescript * const payment = await sdk.getPaymentLink('pl_abc123'); * console.log(payment.status); // 'pending' | 'paid' | 'expired' | 'cancelled' * ``` */ getPaymentLink(linkId: string, signal?: AbortSignal): Promise; /** * Recherche dans le catalogue public Monegasy (tous marchands confondus). * * Endpoint public — ne consomme pas de quota. Pratique pour intégrer un * "marketplace" Monegasy dans une app tierce. * * @example * ```ts * const results = await sdk.searchProducts({ search: "café", lat: -18.91, lng: 47.52 }); * results.items.forEach((p) => console.log(p.name, p.distanceKm, "km")); * ``` */ searchProducts(params?: SearchProductsParams, signal?: AbortSignal): Promise; /** * Récupère la vitrine publique d'un marchand par son slug. * * Retourne le profil marchand + jusqu'à 100 produits actifs. Idéal pour * intégrer une page marchand dans un site externe ou une mini-app. * * @example * ```ts * const store = await sdk.getMerchantBySlug("bastih-store"); * console.log(store.merchant.businessName, store.products.length); * ``` */ getMerchantBySlug(slug: string, signal?: AbortSignal): Promise; /** * Alias de `getMerchantBySlug` — équivalent sémantique "liste des * produits d'un marchand", utile dans le contexte d'intégrateurs qui * veulent juste embarquer le catalogue d'un seul marchand. */ getMerchantProducts(slug: string, signal?: AbortSignal): Promise; /** * Vérifie périodiquement le statut d'un lien de paiement jusqu'à ce qu'il * passe en `paid` / `expired` / `cancelled`, ou que le timeout soit atteint. * * @param linkId - ID du lien de paiement * @param options - Callbacks et options de polling * @returns Promise - Le lien dans son état final * * @example * ```typescript * const final = await sdk.pollPaymentStatus("pl_abc123", { * intervalMs: 3000, * timeoutMs: 5 * 60 * 1000, * onUpdate: (link) => console.log("Statut :", link.status), * }); * if (final.status === "paid") { * console.log("Paiement confirmé !"); * } * ``` */ pollPaymentStatus(linkId: string, options?: { /** Intervalle entre deux checks (défaut 3000ms) */ intervalMs?: number; /** Durée max avant timeout (défaut 5min) */ timeoutMs?: number; /** Callback appelé à chaque update (avant le statut terminal) */ onUpdate?: (link: PaymentLink) => void; /** Permet d'annuler le polling */ signal?: AbortSignal; }): Promise; /** * Ouvre le paiement dans une popup centrée * @param linkId - ID du lien de paiement * @param options - Options de la popup (largeur, hauteur) * @returns Window | null - La fenêtre popup ou null si bloquée * @example * ```typescript * const popup = sdk.openPaymentPopup('pl_abc123', { * width: 500, * height: 700 * }); * ``` */ openPaymentPopup(linkId: string, options?: PopupOptions): Window | null; /** * Redirige vers la page de paiement * @param linkId - ID du lien de paiement * @example * ```typescript * sdk.redirectToPayment('pl_abc123'); * ``` */ redirectToPayment(linkId: string): void; /** * Génère l'URL de paiement pour un lien donné * @param linkId - ID du lien de paiement * @returns string - URL complète de paiement */ getPaymentUrl(linkId: string): string; /** * Crée et affiche un bouton de paiement stylisé * @param params - Paramètres du bouton et du paiement * @param container - Sélecteur CSS du conteneur (ex: "#payment-button") * @returns Promise - Le bouton créé * @throws {Error} Si le conteneur n'est pas trouvé * @example * ```typescript * await sdk.renderPaymentButton({ * amount: 50000, * description: 'Achat produit', * buttonText: 'Payer maintenant', * onSuccess: (payment) => console.log('Payé!', payment), * onError: (error) => console.error('Erreur:', error), * onCancel: () => console.log('Annulé') * }, '#payment-container'); * ``` */ renderPaymentButton(params: RenderButtonParams, container: string | HTMLElement): Promise; /** * Formate un montant en Ariary * @param amount - Montant à formater * @returns string - Montant formaté (ex: "50 000 Ar") */ static formatAmount(amount: number): string; /** * Émet un remboursement sur une transaction antérieure. * * ⚠️ Nécessite une **secret key** (mk_sec_*) — le SDK throw early * si initialisé avec une publishable. * * @example * ```ts * await sdk.refund({ * transactionId: "tx_abc123", * amount: 50000, // optionnel — full refund si omis * reason: "Article défectueux", * }); * ``` */ refund(params: { transactionId: string; amount?: number; reason?: string; }): Promise<{ refundId: string; status: string; amount: number; }>; /** * Configure (ou met à jour) l'URL et les événements écoutés du webhook * du marchand. Génère ou conserve le webhook secret automatiquement. * * ⚠️ Nécessite une **secret key**. * * @example * ```ts * await sdk.configureWebhook({ * url: "https://votre-site.com/webhooks/monegasy", * events: ["payment.completed", "payment.failed", "installment.paid"], * retryCount: 3, * }); * ``` */ configureWebhook(params: { url: string; events: string[]; retryCount?: number; }): Promise; /** Récupère la config webhook courante du marchand. */ getWebhookConfig(): Promise; /** Récupère l'historique des envois webhook (success / fail / retry). */ getWebhookLogs(params?: { page?: number; limit?: number; }): Promise<{ logs: WebhookLog[]; total: number; page: number; totalPages: number; }>; /** * Désactive le webhook actuel (passe `isActive: false`). Réactivable * via `configureWebhook(...)`. */ disableWebhook(): Promise; /** * Envoie un événement de test (du type souhaité) à votre URL webhook. * Idéal pour vérifier votre intégration sans attendre une vraie * transaction. La signature HMAC est calculée comme en prod. * * @example * ```ts * const result = await sdk.testWebhookEvent("payment.completed"); * console.log(result.statusCode, result.latencyMs); * ``` */ testWebhookEvent(eventType: string, customData?: Record): Promise; /** * Calcule les options de facilité de paiement disponibles pour un * montant donné chez un marchand. Renvoie un tableau vide si aucune * facilité n'est applicable (montant hors bornes, modes non activés). * * Accessible avec une publishable key — utile pour afficher les * options de paiement étalé sur votre page produit avant que le * client clique sur "Payer". */ previewInstallments(params: { merchantId: string; amount: number; allowedModes?: InstallmentMode[]; depositPercentage?: number; balanceDueDays?: number; }): Promise; /** Récupère la config des facilités du marchand. ⚠️ Secret key. */ getInstallmentConfig(): Promise; /** Met à jour la config des facilités. ⚠️ Secret key. */ updateInstallmentConfig(config: Partial): Promise; /** Liste les plans d'échéancier du marchand. ⚠️ Secret key. */ getInstallmentPlans(params?: { status?: "active" | "completed" | "failed" | "cancelled"; page?: number; limit?: number; }): Promise<{ plans: InstallmentPlanInfo[]; total: number; page: number; totalPages: number; }>; /** Détail d'un plan + ses échéances. ⚠️ Secret key. */ getInstallmentPlan(planId: string): Promise; /** Annule un plan en cours. Les échéances déjà payées ne sont PAS * remboursées automatiquement. ⚠️ Secret key. */ cancelInstallmentPlan(planId: string, reason?: string): Promise; /** Échéances dues sous N jours — pour widget dashboard. ⚠️ Secret key. */ getUpcomingInstallments(withinDays?: number): Promise; /** * Génère les headers de signature HMAC pour une requête sortante. * * À utiliser depuis votre **backend** pour appeler les routes très * sensibles de Monegasy qui exigent la signature (refunds, modifs * config, opérations admin). La signature résiste au replay (timestamp * ±5min) et garantit que vous êtes bien le propriétaire de la clé. * * @example * ```ts * import { MonegasySDK } from "monegasy-js"; * * const sdk = new MonegasySDK({ apiKey: process.env.MONEGASY_SECRET! }); * const body = { amount: 50000, description: "Test" }; * const headers = sdk.signRequest(body); * * await fetch("https://api.monegasy.com/sdk/payment-links", { * method: "POST", * headers: { "Content-Type": "application/json", ...headers }, * body: JSON.stringify(body), * }); * ``` * * Renvoie `{ Authorization, X-Monegasy-Timestamp, X-Monegasy-Signature }`. */ signRequest(body: unknown): { Authorization: string; "X-Monegasy-Timestamp": string; "X-Monegasy-Signature": string; }; /** * Crée un plan d'abonnement * @param params - Paramètres du plan * @returns Promise - Le plan créé * @throws {Error} Si les paramètres sont invalides * @example * ```typescript * const plan = await sdk.createSubscriptionPlan({ * name: 'Premium', * price: 50000, * billingPeriod: 'monthly', * trialDays: 7, * features: ['Accès illimité', 'Support prioritaire'] * }); * ``` */ createSubscriptionPlan(params: CreateSubscriptionPlanParams, signal?: AbortSignal): Promise; /** * Récupère tous les plans d'abonnement du merchant * @returns Promise - Liste des plans * @example * ```typescript * const plans = await sdk.getSubscriptionPlans(); * plans.forEach(plan => console.log(plan.name, plan.price)); * ``` */ getSubscriptionPlans(signal?: AbortSignal): Promise; /** * Récupère un plan d'abonnement par son ID * @param planId - ID du plan * @returns Promise - Détails du plan * @example * ```typescript * const plan = await sdk.getSubscriptionPlan('plan_123'); * console.log(plan.subscriberCount); * ``` */ getSubscriptionPlan(planId: string, signal?: AbortSignal): Promise; /** * Met à jour un plan d'abonnement * @param planId - ID du plan * @param params - Paramètres à mettre à jour * @returns Promise - Plan mis à jour * @example * ```typescript * const plan = await sdk.updateSubscriptionPlan('plan_123', { * price: 75000, * features: ['Nouvelles fonctionnalités'] * }); * ``` */ updateSubscriptionPlan(planId: string, params: UpdateSubscriptionPlanParams, signal?: AbortSignal): Promise; /** * Supprime un plan d'abonnement * @param planId - ID du plan * @throws {Error} Si le plan a des abonnés actifs * @example * ```typescript * await sdk.deleteSubscriptionPlan('plan_123'); * ``` */ deleteSubscriptionPlan(planId: string, signal?: AbortSignal): Promise; /** * Récupère la liste des abonnés * @returns Promise - Liste des abonnés * @example * ```typescript * const subscribers = await sdk.getSubscribers(); * console.log(`${subscribers.length} abonnés`); * ``` */ getSubscribers(signal?: AbortSignal): Promise; /** * Récupère les statistiques des abonnements * @returns Promise - Statistiques * @example * ```typescript * const stats = await sdk.getSubscriptionStats(); * console.log(`Revenu mensuel: ${stats.revenue.monthlyEstimate} Ar`); * ``` */ getSubscriptionStats(signal?: AbortSignal): Promise; /** * Génère un lien d'inscription pour un plan * @param planId - ID du plan * @returns Promise - Liens d'inscription * @example * ```typescript * const links = await sdk.getSubscribeLink('plan_123'); * console.log(links.links.webUrl); * ``` */ getSubscribeLink(planId: string, signal?: AbortSignal): Promise; /** * API PARTENAIRE (« Connect ») — réservée aux clés PLATEFORME (secret). * * Permet à une app verticale (pharmacie, hôtel…) de provisionner ses pros * comme sous-marchands Monegasy et d'encaisser pour eux. Les fonds vont dans * le wallet du sous-marchand (commission Monegasy normale, pas de split). * * @example * ```typescript * const monegasy = new MonegasySDK({ apiKey: "mk_sec_live_..." }); // clé PLATEFORME * * // À l'inscription pro sur ton app → compte Monegasy créé en même temps : * const pro = await monegasy.platform.createMerchant({ * phone: "0340000000", * businessName: "Pharmacie Avaratra", * externalRef: "pharma_user_42", * }); * * // Encaisser pour lui : * const link = await monegasy.platform.createPaymentLink({ * merchantId: pro.merchantId, * amount: 15000, * description: "Commande #1234", * }); * ``` */ get platform(): { /** Provisionne (ou lie) un sous-marchand à partir de son numéro. */ createMerchant: (params: CreatePlatformMerchantParams, signal?: AbortSignal) => Promise; /** Liste les sous-marchands de la plateforme. */ listMerchants: (signal?: AbortSignal) => Promise; /** Crée un lien de paiement POUR un sous-marchand (fonds → SON wallet). */ createPaymentLink: (params: CreatePlatformPaymentLinkParams, signal?: AbortSignal) => Promise; }; /** * Vérifie la signature d'un webhook Monegasy (côté serveur uniquement - Node.js) * * IMPORTANT: Cette méthode est destinée à être utilisée côté serveur (Node.js) * pour valider que le webhook provient bien de Monegasy. * * @param payload - Le body brut de la requête (string JSON) * @param signature - La valeur du header "X-Monegasy-Signature" * @param secret - Le secret webhook de votre dashboard Monegasy * @returns boolean - true si la signature est valide * @throws {Error} Si l'environnement Node.js n'est pas disponible * * @example * ```typescript * // Express.js / Next.js API Route * import { MonegasySDK } from 'monegasy-js'; * * app.post('/api/webhooks/monegasy', (req, res) => { * const signature = req.headers['x-monegasy-signature']; * const rawBody = JSON.stringify(req.body); * * const isValid = MonegasySDK.verifyWebhookSignature( * rawBody, * signature, * process.env.MONEGASY_WEBHOOK_SECRET * ); * * if (!isValid) { * return res.status(401).json({ error: 'Invalid signature' }); * } * * // Traiter le webhook en toute sécurité... * const { event, data } = req.body; * * if (event === 'payment.completed') { * // Enregistrer la commande dans votre base de données * await saveOrder(data); * } * * res.status(200).json({ received: true }); * }); * ``` */ static verifyWebhookSignature(payload: string, signature: string, secret: string): boolean; /** * Parse et type un payload webhook Monegasy * * @param body - Le body JSON parsé de la requête webhook * @returns WebhookPayload typé selon l'événement * * @example * ```typescript * const webhook = MonegasySDK.parseWebhookPayload(req.body); * * switch (webhook.event) { * case 'payment.completed': * console.log('Paiement reçu:', webhook.data.amount, 'Ar'); * console.log('Transaction:', webhook.data.transactionId); * break; * case 'payment.failed': * console.log('Paiement échoué:', webhook.data.error); * break; * } * ``` */ static parseWebhookPayload(body: any): WebhookPayload; /** * Détecte les informations sur le device de l'utilisateur * @returns DeviceInfo - Informations sur le device * @example * ```typescript * const device = sdk.detectDevice(); * if (device.isMobile) { * console.log(`Ouvrir sur ${device.storeName}`); * } * ``` */ static detectDevice(): DeviceInfo; /** * Instance method pour détecter le device */ detectDevice(): DeviceInfo; /** * Génère un deep link pour ouvrir l'app mobile * @param linkId - ID du lien de paiement * @returns string - Deep link URL * @example * ```typescript * const deepLink = sdk.generateDeepLink('pl_abc123'); * // => "monegasy://pay/pl_abc123" * ``` */ generateDeepLink(linkId: string): string; /** * Génère un Universal Link (iOS) / App Link (Android) * @param linkId - ID du lien de paiement * @returns string - Universal/App link URL * @example * ```typescript * const link = sdk.generateUniversalLink('pl_abc123'); * // => "https://monegasy.com/pay/pl_abc123" * ``` */ generateUniversalLink(linkId: string): string; /** * Tente d'ouvrir l'application mobile avec fallback * @param linkId - ID du lien de paiement * @param options - Options pour le comportement de fallback * @returns Promise - true si l'app s'est ouverte, false sinon * @example * ```typescript * const opened = await sdk.openMobileApp('pl_abc123', { * fallbackToStore: true, * fallbackDelay: 2000 * }); * ``` */ openMobileApp(linkId: string, options?: { /** Rediriger vers le store si l'app n'est pas installée */ fallbackToStore?: boolean; /** Délai avant de considérer que l'app n'est pas installée (ms) */ fallbackDelay?: number; /** Callback si l'app n'est pas installée */ onNotInstalled?: () => void; }): Promise; /** * Crée un bouton de paiement intelligent avec détection mobile * Sur mobile: tente d'ouvrir l'app, sinon propose le téléchargement * Sur desktop: affiche le QR Code ou redirige vers la page de paiement * @param params - Paramètres du paiement * @param container - Conteneur pour le bouton * @returns Promise */ renderSmartPaymentButton(params: RenderButtonParams & { /** * Mode d'affichage du paiement: * - 'iframe' : overlay iframe sur la page du merchant (recommandé) * - 'popup' : nouvelle fenêtre popup * - 'redirect' : redirection complète vers la page de paiement * - 'deeplink' : deep link mobile uniquement * Défaut: 'iframe' */ mode?: "iframe" | "popup" | "redirect" | "deeplink"; /** @deprecated Utiliser `mode` à la place */ mobileAction?: "deeplink" | "redirect"; }, container: string | HTMLElement): Promise; /** * Ouvre le paiement dans un iframe modal superposé à la page du merchant. * L'utilisateur ne quitte jamais le site du merchant. * @param linkId - ID du lien de paiement * @param options - Callbacks onSuccess / onError / onCancel * @returns Fonction pour fermer le modal manuellement */ openIframeModal(linkId: string, options?: { onSuccess?: (payment: PaymentLink) => void; onError?: (error: Error) => void; onCancel?: () => void; }): () => void; /** * Affiche un modal de choix sur mobile quand l'app n'est pas installée. * Propose : Ouvrir l'app (deep link retry) / Continuer sur le web / Télécharger l'app * @internal */ private _showMobileFallbackModal; } export { MonegasySDK }; export { buildMonegasyEmvQr, parseEmvQr, isEmvQr, crc16ccitt, MONEGASY_GUID, CURRENCY_MGA, } from "./emv"; export type { EmvQrParams, ParsedEmvQr } from "./emv";