/** * Supported currencies for payment transactions. * @default "XOF" - West African CFA Franc (default for Benin) */ type Currency = "XOF" | "USD" | "EUR"; /** * Available payment methods. */ type PaymentMethod = "momo" | "card" | "direct_debit"; /** * HTTP methods for backend verification. */ type VerifyMethod = "POST" | "GET"; /** * Backend verification configuration. * Used to automatically verify transactions with your backend. */ interface VerificationConfig { /** * URL of your backend API endpoint for transaction verification. * The transaction_id will be sent to this endpoint. * @example "https://api.yoursite.com/payments/verify" */ verifyUrl?: string; /** * HTTP method to use for verification. * @default "POST" */ verifyMethod?: VerifyMethod; /** * Custom headers to include in the verification request. * Useful for authentication tokens. * @example { "Authorization": "Bearer xxx" } */ customVerifyHeaders?: Record; } /** * Response from backend verification. */ interface VerificationResponse { /** Whether verification was successful */ success: boolean; /** Optional message from the backend */ message?: string; /** Optional additional data from the backend */ data?: Record; } /** * FedaPay transaction details. * Contains information about the payment amount and metadata. */ interface FedaPayTransaction { /** Unique transaction ID (auto-generated if not provided) */ id?: number; /** Amount to charge in the smallest currency unit (e.g., 5000 for 5000 XOF) */ amount: number; /** Human-readable description of the transaction */ description?: string; /** URL to redirect after successful payment */ callback_url?: string; /** Custom data to attach to the transaction (accessible in webhooks) */ custom_metadata?: Record; } /** * FedaPay customer information. * Used to pre-fill the payment form and for transaction records. */ interface FedaPayCustomer { /** Customer's first name */ firstname?: string; /** Customer's last name */ lastname?: string; /** Customer's email address (required for receipts) */ email: string; /** Customer's phone number with country code */ phone_number?: { /** Phone number without country code */ number: string; /** ISO country code (e.g., "BJ" for Benin) */ country: string; }; } /** * Configuration object for useFedaPay hook. * @example * ```tsx * const config: FedaPayConfig = { * public_key: "pk_live_xxxxxxxxxxxx", * transaction: { amount: 5000, description: "Premium subscription" }, * customer: { email: "user@example.com" }, * sandbox: false, * verifyUrl: "https://api.yoursite.com/payments/verify", * onComplete: (response) => console.log("Paid!", response.transaction.id) * }; * ``` */ interface FedaPayConfig extends VerificationConfig { /** * Your FedaPay public key. * Starts with `pk_live_` for production or `pk_sandbox_` for testing. * @example "pk_live_xxxxxxxxxxxxxxxx" */ public_key: string; /** Transaction details including amount */ transaction: FedaPayTransaction; /** Optional customer information to pre-fill the form */ customer?: FedaPayCustomer; /** * Currency configuration. * @default { iso: "XOF" } */ currency?: { /** ISO 4217 currency code */ iso: Currency; }; /** Additional metadata to attach to the transaction */ metadata?: Record; /** * Enable sandbox/test mode. * When true, no real transactions are processed. * @default false */ sandbox?: boolean; /** * Allowed payment methods. * @default ["momo", "card"] */ allowedPaymentMethods?: PaymentMethod[]; /** * Callback fired when payment is completed successfully. * @param response - Contains transaction details and status */ onComplete?: (response: FedaPayCallbackResponse) => void; /** Callback fired when the payment dialog is closed without completing */ onClose?: () => void; } /** * Response received after a FedaPay transaction. * Passed to the `onComplete` callback. */ interface FedaPayCallbackResponse { /** Reason for the callback (e.g., "transaction_completed") */ reason: string; /** Transaction details */ transaction: { /** Unique transaction ID */ id: number; /** Transaction reference for tracking */ reference: string; /** Amount charged */ amount: number; /** Final transaction status */ status: "approved" | "declined" | "canceled" | "pending"; }; } /** * FedaPay checkout widget instance. * Returned by `window.FedaPay.init()`. */ interface FedaPayCheckoutInstance { /** Open the payment dialog */ open: () => void; } /** * Internal configuration for FedaPay widget initialization. * @internal */ interface FedaPayWidgetConfig { public_key: string; transaction: FedaPayTransaction; customer?: FedaPayCustomer; currency?: { iso: Currency; }; onComplete?: (response: FedaPayCallbackResponse) => void; onClose?: () => void; } /** * Configuration object for useKkiaPay hook. * @example * ```tsx * const config: KkiaPayConfig = { * amount: 5000, * key: "pk_xxxxxxxxxxxxxxxx", * sandbox: true, * name: "John Doe", * phone: "22967000000", * theme: "#4E6BFF", * verifyUrl: "https://api.yoursite.com/payments/verify", * paymentMethods: ["momo", "card"] * }; * ``` */ interface KkiaPayConfig extends VerificationConfig { /** * Amount to charge in the smallest currency unit. * @example 5000 // 5000 XOF */ amount: number; /** * Your KKiaPay public API key. * @example "pk_xxxxxxxxxxxxxxxx" */ key: string; /** * Enable sandbox mode for testing. * When true, no real transactions are processed. * @default false */ sandbox?: boolean; /** Customer's phone number (used for mobile money) */ phone?: string; /** Customer's full name */ name?: string; /** Customer's email address */ email?: string; /** Reason or description for the payment */ reason?: string; /** * Primary color for the widget theme. * @default "#4E6BFF" * @example "#22C55E" */ theme?: string; /** Your KKiaPay partner ID (if applicable) */ partnerId?: string; /** * Allowed payment methods. * @default ["momo", "card"] */ paymentMethods?: PaymentMethod[]; /** Custom data to attach to the transaction */ data?: Record; } /** * Response received after a successful KKiaPay payment. * Passed to the `onSuccess` callback. */ interface KkiaPaySuccessResponse { /** Unique transaction ID from KKiaPay */ transactionId: string; /** Amount that was charged */ amount: number; /** Phone number used for the transaction */ phone: string; } /** * Response received when a KKiaPay payment fails. * Passed to the `onFailed` callback. */ interface KkiaPayFailedResponse { /** Error code */ error: string; /** Human-readable error message */ message: string; } /** * KKiaPay event types for listeners. */ type KkiaPayEventType = "success" | "failed" | "close"; /** * Generic callback type for KKiaPay events. * @template T - The type of data passed to the callback */ type KkiaPayEventCallback = (data: T) => void; /** * General payment status. * Useful for tracking payment flow in your UI. */ type PaymentStatus = "idle" | "pending" | "success" | "error"; /** * Generic payment error structure. */ interface PaymentError { /** Machine-readable error code */ code: string; /** Human-readable error message */ message: string; } declare global { interface Window { FedaPay?: { init: (containerOrOptions: string | FedaPayWidgetConfig, maybeOptions?: FedaPayWidgetConfig) => FedaPayCheckoutInstance; CHECKOUT_COMPLETED?: number; DIALOG_DISMISSED?: number; }; openKkiapayWidget?: (config: KkiaPayConfig) => void; addKkiapayListener?: (event: KkiaPayEventType, callback: KkiaPayEventCallback) => void; removeKkiapayListener?: (event: KkiaPayEventType) => void; } } /** * Creates a styled logger for debug mode. * * When enabled, logs are color-coded by level: * - Info: Blue (#4E6BFF) * - Success: Green (#0AB67A) * - Error: Red (#EF4444) * - Warn: Orange (#F59E0B) * * @param enabled - Whether logging is enabled * @returns Logger object with info, success, error, and warn methods * * @example * ```ts * const log = createLogger(true); * log.info("Loading SDK..."); * log.success("SDK loaded!"); * log.error("Failed to load", error); * ``` */ declare function createLogger(enabled: boolean): Logger; /** * Logger interface with color-coded methods. */ interface Logger { /** Log informational message (blue) */ info: (message: string, ...args: unknown[]) => void; /** Log success message (green) */ success: (message: string, ...args: unknown[]) => void; /** Log error message (red) */ error: (message: string, ...args: unknown[]) => void; /** Log warning message (orange) */ warn: (message: string, ...args: unknown[]) => void; } /** * Overrides the wording of the dev-time console warnings emitted by * `validateKeyEnvironment`/`logSandboxMode`. Every field is optional — any * warning you don't override keeps its default English text. */ interface EnvironmentWarningMessages { /** Shown when a live key is used while sandbox mode is on. Receives the provider name (e.g. "FedaPay"). */ liveKeyInSandbox?: (provider: string) => string; /** Shown when a test/sandbox key is used while sandbox mode is off. Receives the provider name. */ testKeyInProduction?: (provider: string) => string; /** Shown once whenever sandbox mode is active. Receives the provider name. */ sandboxModeActive?: (provider: string) => string; } /** * Validates API key consistency with sandbox mode. * Warns developers about potential misconfigurations. * * @param key - The API public key * @param sandbox - Whether sandbox mode is enabled * @param provider - The payment provider name (for logging) * @param messages - Optional overrides for the warning text */ declare function validateKeyEnvironment(key: string, sandbox: boolean, provider: "FedaPay" | "KKiaPay", messages?: EnvironmentWarningMessages): void; /** * Logs sandbox mode warning if enabled. * * @param sandbox - Whether sandbox mode is enabled * @param provider - The payment provider name * @param messages - Optional overrides for the warning text */ declare function logSandboxMode(sandbox: boolean, provider: "FedaPay" | "KKiaPay", messages?: EnvironmentWarningMessages): void; /** * Validation error codes for payment operations. */ type ValidationErrorCode = "INVALID_AMOUNT" | "MISSING_PUBLIC_KEY" | "SDK_NOT_LOADED" | "SDK_ERROR" | "PRE_VALIDATION_FAILED"; /** * Validation error returned when payment configuration is invalid. */ interface PaymentValidationError { /** Machine-readable error code */ code: ValidationErrorCode; /** Human-readable error message */ message: string; } /** * Overrides the wording of built-in validation error messages, keyed by * `ValidationErrorCode`. Any code you don't include keeps its default * (English) message. Set globally via `BeninPaymentProvider`, or per-hook * via `useFedaPay`/`useKkiaPay` options (which take precedence). * * @example * ```ts * const messages: PaymentMessageOverrides = { * MISSING_PUBLIC_KEY: "Clé API manquante.", * INVALID_AMOUNT: "Montant invalide.", * }; * ``` */ type PaymentMessageOverrides = Partial>; /** * Resolves a user-facing message for an arbitrary caught error (SDK load * failures, network errors...). Return `undefined` to fall through to the * next resolver (local → global → the built-in `parseError` translations), * so you can override just the cases you care about. * * @example * ```ts * const resolveErrorMessage: ErrorMessageResolver = (error) => { * const msg = error instanceof Error ? error.message : String(error); * if (/network|offline/i.test(msg)) return "No internet connection."; * return undefined; // fall back to the default translation * }; * ``` */ type ErrorMessageResolver = (error: unknown) => string | undefined; /** * Payment providers built into this package. */ type PaymentProvider = "fedapay" | "kkiapay"; /** * Identifier for any payment provider driver — the two built-in ones plus * whatever string a custom driver picks (e.g. `"cinetpay"`, `"paydunya"`, * `"stripe"`). Kept separate from `PaymentProvider` so that `useBeninPay`, * `usePaymentHistory` and analytics for the built-in providers keep exact * `"fedapay" | "kkiapay"` autocomplete, while `PaymentDriver.name` and * `BeninPaymentAnalyticsEvent.provider` stay open to custom providers. */ type PaymentProviderId = PaymentProvider | (string & {}); /** * Public, subscribable state exposed by a payment engine instance. */ interface PaymentEngineState { loading: boolean; scriptLoaded: boolean; error: Error | null; isVerifying: boolean; isPreparing: boolean; } /** Data extracted from a provider's raw success payload, needed to verify a transaction with a backend. */ interface VerifyPayloadInput { transactionId: string; amount: number; metadata?: Record; } /** Stable callbacks a driver uses to report SDK events back to the engine. */ interface PaymentDriverHandlers { onSuccess: (raw: TRaw) => void; onFailure: (raw: unknown) => void; onClose: () => void; } /** Context handed to a driver's `open()` call for logging and analytics. */ interface PaymentDriverContext { log: Logger; isMockMode: boolean; /** Emits a standardized analytics event; `provider`, `mode` and `amount` are filled in automatically unless overridden. */ emit: (event: Partial> & { name: BeninPaymentAnalyticsEvent["name"]; }) => void; } /** * Adapter contract a payment provider (FedaPay, KKiaPay, or a custom one) * must implement to plug into `createPaymentEngine`. * * The engine has zero dependency on React or on any specific provider — it * only talks to this interface. That's what makes it reusable outside of * this package (a different UI framework, or a provider we don't ship). */ interface PaymentDriver { name: PaymentProviderId; scriptUrl: string; scriptId: string; /** Returns true once the provider's SDK is available on `window`. */ isSdkReady: () => boolean; /** Optional dev-time warnings (e.g. a live key used while sandbox mode is on). */ logEnvironmentWarnings?: (config: TConfig, ctx: { isMockMode: boolean; environmentWarnings?: EnvironmentWarningMessages; }) => void; /** Returns a validation error, or `null` if the config is valid for this provider. */ validate: (config: TConfig, ctx: { isMockMode: boolean; }) => PaymentValidationError | null; getAmount: (config: TConfig | undefined) => number | undefined; /** Extra fields (e.g. `currency`) merged into every analytics event for this provider. */ getAnalyticsExtras?: (config: TConfig | undefined) => Record; /** Builds the fake success payload used when `mock: true`. */ buildMockSuccess: (config: TConfig) => TRaw; /** Normalizes a raw success payload into what's needed for backend verification. */ toVerifyPayload: (raw: TRaw, config: TConfig) => VerifyPayloadInput; getStatus?: (raw: TRaw) => string | undefined; /** * Triggers the actual checkout/widget for a single payment attempt. * * `handlers` is bound to this specific call's `config` — for an SDK that * only exposes a persistent/global event bus instead of per-call * callbacks (e.g. KKiaPay's `addKkiapayListener`), store `handlers` in a * module-level "active call" reference before triggering the SDK, and * clear it once a terminal event (success/failure/close) fires. Don't * keep a persistent per-engine subscription — the SDK only supports one * open widget at a time, so a persistent subscription would relay events * to every mounted instance instead of just the one that opened it. */ open: (config: TConfig, handlers: PaymentDriverHandlers, ctx: PaymentDriverContext) => void; } interface PaymentEngineOptions { debug?: boolean; isMockMode: boolean; verification?: { verifyUrl?: string; verifyMethod?: "POST" | "GET"; customVerifyHeaders?: Record; }; onBeforePayment?: () => void | boolean | Promise; onAnalyticsEvent?: BeninPaymentAnalyticsHandler; globalAnalyticsHandler?: BeninPaymentAnalyticsHandler; onRawSuccess?: (raw: TRaw) => void; onRawFailure?: (raw: unknown) => void; onClose?: () => void; onValidationError?: (error: PaymentValidationError) => void; /** Latest known config, used only for analytics emitted before any `open()` call (e.g. SDK load events). */ getAnalyticsConfig?: () => TConfig | undefined; /** Overrides the wording of validation error messages, keyed by error code. */ messages?: PaymentMessageOverrides; /** Resolves the message for arbitrary caught errors (SDK load failures...); falls back to `parseError`. */ resolveErrorMessage?: ErrorMessageResolver; /** Overrides the wording of dev-time console warnings (live key in sandbox, etc.). */ environmentWarnings?: EnvironmentWarningMessages; } interface PaymentEngine { getState: () => PaymentEngineState; subscribe: (listener: () => void) => () => void; /** Starts the background lifecycle (script loading, persistent listeners). Returns a cleanup function. */ start: () => () => void; open: (config: TConfig) => void; } type BeninPaymentAnalyticsEventName = "sdk_load_started" | "sdk_load_succeeded" | "sdk_load_failed" | "payment_validation_failed" | "payment_pre_validation_started" | "payment_pre_validation_succeeded" | "payment_pre_validation_cancelled" | "payment_pre_validation_failed" | "payment_open_attempted" | "payment_opened" | "payment_completed" | "payment_failed" | "payment_closed" | "payment_verification_started" | "payment_verification_succeeded" | "payment_verification_failed"; interface BeninPaymentAnalyticsEvent { name: BeninPaymentAnalyticsEventName; /** `"fedapay"` / `"kkiapay"`, or a custom provider identifier for a driver you wrote yourself. */ provider: PaymentProviderId; amount?: number; currency?: string; mode: "mock" | "live"; transactionId?: string; status?: string; errorCode?: string; errorMessage?: string; timestamp: string; metadata?: Record; } type BeninPaymentAnalyticsHandler = (event: BeninPaymentAnalyticsEvent) => void | Promise; /** * Formats an amount in XOF (West African CFA Franc). * * @param amount - The amount to format * @returns Formatted string with FCFA suffix (e.g., "5 000 FCFA") * * @example * ```ts * formatXOF(5000); // "5 000 FCFA" * formatXOF(1500000); // "1 500 000 FCFA" * formatXOF(0); // "0 FCFA" * ``` */ declare function formatXOF(amount: number): string; /** * Formats an amount in the specified currency. * * @param amount - The amount to format * @param currency - The currency code (XOF, USD, EUR) * @returns Formatted string with currency symbol * * @example * ```ts * formatCurrency(5000, "XOF"); // "5 000 FCFA" * formatCurrency(100, "USD"); // "$100.00" * formatCurrency(100, "EUR"); // "100,00 €" * ``` */ declare function formatCurrency(amount: number, currency: Currency): string; /** * Generates a mock transaction ID for testing. * * @returns A unique mock transaction ID */ declare function generateMockTransactionId(): string; /** * A pattern matched against a raw error message, with the user-facing * message to show when it matches. */ interface ErrorPattern { pattern: RegExp; message: string; } /** * Options to fully control `parseError`'s output — pass your own patterns * and/or fallback message to translate or reword the built-in French * defaults, instead of being stuck with them. */ interface ParseErrorOptions { /** * Patterns checked in order; the first match wins. Defaults to * `DEFAULT_ERROR_PATTERNS`. Spread the defaults in if you only want to * add or reorder a few: `{ patterns: [...myPatterns, ...DEFAULT_ERROR_PATTERNS] }`. */ patterns?: ErrorPattern[]; /** Returned when nothing matches and the error has no usable message. */ fallbackMessage?: string; } /** * Default error patterns and their French, user-friendly translations. * Exported so you can extend rather than fully replace them — see * `ParseErrorOptions.patterns`. */ declare const DEFAULT_ERROR_PATTERNS: ErrorPattern[]; /** * Parses an error and returns a user-friendly message. * * Defaults to French translations (`DEFAULT_ERROR_PATTERNS`), but you're * never stuck with them — pass your own `patterns` and/or `fallbackMessage` * to translate or reword every message this library can produce. * * @param error - The error to parse (can be any type) * @param options - Optional custom patterns / fallback message * @returns A clean, user-friendly error message * * @example * ```ts * parseError(new Error("Network connection failed")); * // Returns: "Problème de connexion internet." * * // Full control — e.g. an English-speaking product: * parseError(err, { * patterns: [ * { pattern: /closed|dismissed|cancel/i, message: "Payment cancelled." }, * { pattern: /network|connection|offline/i, message: "No internet connection." }, * ], * fallbackMessage: "Something went wrong.", * }); * ``` */ declare function parseError(error: unknown, options?: ParseErrorOptions): string; /** * Creates a standardized error object with parsed message. * * @param error - The raw error * @param options - Optional custom patterns / fallback message, forwarded to `parseError` * @returns An Error object with a user-friendly message */ declare function createParsedError(error: unknown, options?: ParseErrorOptions): Error; export { type ErrorPattern as A, type BeninPaymentAnalyticsEventName as B, type Currency as C, DEFAULT_ERROR_PATTERNS as D, type ErrorMessageResolver as E, type FedaPayTransaction as F, type ParseErrorOptions as G, type PaymentDriver as H, type PaymentEngineOptions as I, type PaymentEngine as J, type KkiaPayConfig as K, type PaymentEngineState as L, type PaymentDriverHandlers as M, type PaymentDriverContext as N, type VerifyPayloadInput as O, type PaymentProviderId as P, createLogger as Q, type Logger as R, validateKeyEnvironment as S, logSandboxMode as T, type ValidationErrorCode as V, type PaymentProvider as a, type PaymentValidationError as b, type PaymentMessageOverrides as c, type EnvironmentWarningMessages as d, type BeninPaymentAnalyticsEvent as e, type BeninPaymentAnalyticsHandler as f, type PaymentMethod as g, type VerifyMethod as h, type VerificationConfig as i, type VerificationResponse as j, type FedaPayCustomer as k, type FedaPayConfig as l, type FedaPayCallbackResponse as m, type FedaPayCheckoutInstance as n, type FedaPayWidgetConfig as o, type KkiaPaySuccessResponse as p, type KkiaPayFailedResponse as q, type KkiaPayEventType as r, type KkiaPayEventCallback as s, type PaymentStatus as t, type PaymentError as u, formatXOF as v, formatCurrency as w, generateMockTransactionId as x, parseError as y, createParsedError as z };