{"_id":"@bloonio/lokotro-pay-js","name":"@bloonio/lokotro-pay-js","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@bloonio/lokotro-pay-js","version":"1.0.0","description":"Framework-agnostic JavaScript SDK for Lokotro Pay - drop-in payment checkout widget and headless payment engine for React, Next.js, Vue, Svelte or plain JS. Cards, mobile money, e-wallets, bank transfer.","keywords":["payment","lokotro","checkout","mobile-money","card-payment","e-wallet","bank-transfer","react","nextjs","vanilla-js","fintech"],"author":{"name":"Bloonio"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/Bloonio/lokotro-pay-js.git"},"homepage":"https://lokotroo.com","type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"sideEffects":false,"scripts":{"build":"tsup","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest","prepublishOnly":"npm run typecheck && npm run test && npm run build"},"devDependencies":{"jsdom":"^24.0.0","tsup":"^8.0.0","typescript":"^5.4.0","vitest":"^1.6.0"},"engines":{"node":">=18"},"gitHead":"8d61c2e8fd5052ba769ee11e18a5e0ce0a7f93c1","_id":"@bloonio/lokotro-pay-js@1.0.0","bugs":{"url":"https://github.com/Bloonio/lokotro-pay-js/issues"},"_nodeVersion":"26.3.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-a6q3NdFgBMS2/687ZKpx0DN/9BZDJBd8qXroPy5b4g1NxOkTdEt9DEN7yJm6noG/AaFz6vVcp8WTEtjLeSB+aw==","shasum":"3e4497f49833cb471cb05aab31dc661cba2986c5","tarball":"https://registry.npmjs.org/@bloonio/lokotro-pay-js/-/lokotro-pay-js-1.0.0.tgz","fileCount":10,"unpackedSize":1240354,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHOiRchm0bSgJAvKJl6jT43GPudHGq6KmT3f2NxtK/NiAiBf2AEf0v8vPZa8770E0sNzwMfb/hJuBCst23LRdPJLog=="}]},"_npmUser":{"name":"bloonio.dev025","email":"dev.bloonio025@gmail.com"},"directories":{},"maintainers":[{"name":"bloonio.dev025","email":"dev.bloonio025@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/lokotro-pay-js_1.0.0_1787214438072_0.23391893382762707"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-20T08:27:17.866Z","1.0.0":"2026-08-20T08:27:18.253Z","modified":"2026-08-20T08:27:18.613Z"},"maintainers":[{"name":"bloonio.dev025","email":"dev.bloonio025@gmail.com"}],"description":"Framework-agnostic JavaScript SDK for Lokotro Pay - drop-in payment checkout widget and headless payment engine for React, Next.js, Vue, Svelte or plain JS. Cards, mobile money, e-wallets, bank transfer.","homepage":"https://lokotroo.com","keywords":["payment","lokotro","checkout","mobile-money","card-payment","e-wallet","bank-transfer","react","nextjs","vanilla-js","fintech"],"repository":{"type":"git","url":"git+https://github.com/Bloonio/lokotro-pay-js.git"},"author":{"name":"Bloonio"},"bugs":{"url":"https://github.com/Bloonio/lokotro-pay-js/issues"},"license":"MIT","readme":"# @bloonio/lokotro-pay-js\n\nFramework-agnostic JavaScript SDK for **Lokotro Pay** — a drop-in payment\ncheckout widget plus a headless payment engine. Works in **React / Next.js,\nVue, Svelte, Angular, or plain `<script>` pages**. Cards (Mastercard Hosted\nSession), mobile money, e-wallets, Flash, and bank transfer.\n\nThis package is the JS equivalent of the `@bloonio/lokotro-pay` Angular SDK:\nsame gateway flow, same models, same theming — no framework required.\n\n## ✨ Features\n\n- 🧩 **Framework-agnostic** — vanilla DOM widget + headless core, zero runtime dependencies\n- ⚛️ **React/Next.js-ready** — mount in a `useEffect`; SSR-safe imports; `useSyncExternalStore`-compatible state\n- 🎨 **Clean white-surface UI** — neutral payment look out of the box, fully themeable, styles scoped to the widget\n- 🌍 **Multi-language** — English, French, Chinese (中文)\n- 💳 **Multiple payment methods** — Card (Hosted Session), Mobile Money, E-Wallet, Flash, Bank Transfer\n- 🔒 **Secure by default** — fail-closed environment selection, redirect URL allow-listing, no sensitive logging\n- 🎯 **Type safe** — full TypeScript declarations, ESM + CJS builds\n\n## 📦 Installation\n\n```bash\nnpm install @bloonio/lokotro-pay-js\n```\n\n## 🚀 Quick Start (plain JS)\n\n```ts\nimport { LokotroCheckout } from '@bloonio/lokotro-pay-js';\n\nconst checkout = new LokotroCheckout({\n  configs: {\n    token: 'your_session_token',   // minted by YOUR backend (see Authentication)\n    isProduction: false,           // REQUIRED: true = production, false = sandbox\n    acceptLanguage: 'en',\n  },\n  paymentBody: {\n    paymentMethod: 'wallet',\n    userInfo: 'full',\n    paymentMethodInfo: 'none',\n    firstName: 'John',\n    lastName: 'Doe',\n    phoneNumber: '2439978540000',\n    email: 'johndoe@email.com',\n  },\n  language: 'en',\n  onResponse: (response) => console.log('Payment successful!', response),\n  onError: (error) => console.error('Payment failed:', error.message),\n  onClosed: () => console.log('Widget closed'),\n});\n\ncheckout.mount('#checkout');   // element or CSS selector\n// later:\ncheckout.unmount();\n```\n\nThe widget injects its own scoped stylesheet on first mount — no CSS import\nneeded. All styles live under `.lokotro-pay-root` and cannot leak into your app.\n\n## ⚛️ React / Next.js\n\nThe package never touches `window` or `document` at import time, so it is safe\nto import in Next.js (App Router or Pages Router). Mount in an effect:\n\n```tsx\n'use client';\n\nimport { useEffect, useRef } from 'react';\nimport { LokotroCheckout, type LokotroPayOnResponse } from '@bloonio/lokotro-pay-js';\n\nexport function PayButton({ sessionToken }: { sessionToken: string }) {\n  const containerRef = useRef<HTMLDivElement>(null);\n\n  useEffect(() => {\n    if (!containerRef.current) return;\n\n    const checkout = new LokotroCheckout({\n      configs: { token: sessionToken, isProduction: false },\n      paymentBody: { paymentMethod: 'mobile_money' },\n      onResponse: (response: LokotroPayOnResponse) => {\n        // navigate to your success page, update order state, etc.\n      },\n      onError: (error) => console.error(error.message),\n    });\n    checkout.mount(containerRef.current);\n\n    return () => checkout.unmount();\n  }, [sessionToken]);\n\n  return <div ref={containerRef} />;\n}\n```\n\n### Headless usage (custom UI)\n\nSkip the widget entirely and drive the payment state machine yourself. The\n`(getState, subscribe)` pair plugs straight into `useSyncExternalStore`:\n\n```tsx\nimport { useSyncExternalStore, useMemo } from 'react';\nimport {\n  LokotroHttpClient,\n  LokotroPaymentService,\n  LokotroPayEnv,\n} from '@bloonio/lokotro-pay-js';\n\nfunction usePayment(token: string) {\n  const service = useMemo(() => {\n    LokotroPayEnv.initialize(false);          // sandbox\n    const client = new LokotroHttpClient();\n    const svc = new LokotroPaymentService(client);\n    svc.setAppKey(token);\n    return svc;\n  }, [token]);\n\n  const state = useSyncExternalStore(\n    (cb) => service.subscribe(cb, { emitCurrent: false }),\n    service.getState,\n    service.getState,\n  );\n\n  return { service, state };\n}\n```\n\n`state.currentScreen` tells you what to render (`loadingScreen`,\n`paymentMethodSelectionScreen`, `ewalletOtpScreen`, `successScreen`, …) and the\nservice exposes the same operations the widget uses: `createPayment`,\n`selectPaymentMethod`, `submitPaymentDetails`, `verifyOtp`, `resendOtp`,\n`fetchAvailableBanks`, `confirmBankTransferSwitch`.\n\n## 🔑 Authentication\n\n`configs.token` is a **session token minted server-to-server by your backend**\nagainst the Lokotro Gateway's session endpoint. Never embed long-lived API\nkeys in browser code — your backend creates a short-lived session bound to the\namount/currency/reference, and hands the token to the page.\n\n## 📖 Configuration\n\n### `configs` (LokotroPayConfig)\n\n| Property | Type | Required | Default | Description |\n|----------|------|----------|---------|-------------|\n| `token` | `string` | Yes | – | Session token from your backend |\n| `isProduction` | `boolean` | **Yes** | – | `true` → production gateway (real money), `false` → sandbox (simulated). No default — omitting it throws. |\n| `customApiUrl` | `string` | No | – | Custom gateway URL (e.g. `https://api.example.com`) |\n| `timeout` | `number` | No | `30000` | Request timeout (ms) |\n| `acceptLanguage` | `string` | No | `'fr'` | Language for API responses |\n\n### `paymentBody` (LokotroPaymentBody)\n\nSame shape as the Angular SDK — payment method, user info mode, payment-method\ninfo mode, prefill fields per channel (wallet number/PIN, mobile-money phone,\ncard holder info, flash number/PIN), redirect/notify URLs, merchant branding\nand metadata. All fields optional when your session token already binds\namount/currency/reference.\n\n| `userInfo` / `paymentMethodInfo` | Behavior |\n|----------------------------------|----------|\n| `'full'` | Values are sent with the request; the corresponding form is skipped |\n| `'none'` | The widget shows a form and collects the values from the customer |\n\n### Widget options (LokotroCheckoutOptions)\n\n| Option | Type | Description |\n|--------|------|-------------|\n| `title` | `string` | Optional header title (header renders only when set) |\n| `themeConfig` | `LokotroPayThemeConfig` | Brand colors/typography — see Theming |\n| `language` | `'en' \\| 'fr' \\| 'zh'` | UI language (defaults to browser language) |\n| `darkTheme` | `boolean` | Opt-in dark surface |\n| `enableHapticFeedback` | `boolean` | Vibrate on selection where supported (default `true`) |\n| `onResponse` | `(r: LokotroPayOnResponse) => void` | Success callback — fires when the payment reaches the success screen, and again on Done/auto-redirect |\n| `onError` | `(e: LokotroPayOnError) => void` | Failure callback |\n| `onClosed` | `() => void` | Widget dismissed (close, cancel, done, auto-redirect) |\n\n## 🎨 Theming\n\nPass a `themeConfig` — only the fields you set are overridden, and everything\nis scoped to the widget root:\n\n```ts\nconst checkout = new LokotroCheckout({\n  configs,\n  paymentBody,\n  themeConfig: {\n    primaryColor: '#2563EB',     // primary buttons, focused inputs\n    secondaryColor: '#1E40AF',   // secondary actions, gradient companion\n    tertiaryColor: '#3BFBDA',    // highlights, OTP focus rings\n    backgroundColor: '#FFFFFF',\n    surfaceColor: '#F7F8FA',\n    textColor: '#0F172A',\n    borderRadius: '12px',\n    fontFamily: 'Inter, sans-serif',\n  },\n});\n```\n\n## 💳 Payment Methods\n\n| Method | `paymentMethod` value | Notes |\n|--------|----------------------|-------|\n| E-Wallet | `wallet` | Wallet number + PIN, OTP verification |\n| Card | `card` | Mastercard **Hosted Session** — card data never touches your page or this SDK |\n| Mobile Money | `mobile_money` | Push-to-phone with automatic status polling |\n| Flash | `flash` | Flash number + PIN |\n| Bank Transfer | `bank_transfer` | City → bank → account selection, proof upload by email link |\n\nWhen the chosen method can't carry the amount, the gateway may offer a\n**bank-transfer switch**; the widget shows a confirm screen — nothing is\nswitched silently.\n\n## 📡 Payment Status Tracking\n\nTrack a payment by ID only (e.g. initiated from a mobile app or server):\n\n```ts\nimport { LokotroPaymentStatusWidget } from '@bloonio/lokotro-pay-js';\n\nconst status = new LokotroPaymentStatusWidget({\n  statusConfig: {\n    paymentId: 'your-payment-id',\n    config: { token: 'your_session_token', isProduction: false },\n    pollingInterval: 5000,     // default 5s\n    maxPollingAttempts: 60,    // default 60 (≈5 minutes)\n  },\n  onStatusChange: (r) => console.log('status:', r.status),\n  onPaymentComplete: (r) => console.log('completed!', r),\n  onPaymentFailed: (r) => console.error('failed:', r.message),\n  onClose: () => {},\n});\n\nstatus.mount('#status');\n```\n\nHeadless equivalent: `LokotroPaymentStatusTracker` (same polling logic, no UI).\n\n## 🌐 Languages\n\n| Language | Code |\n|----------|------|\n| English | `en` |\n| French | `fr` |\n| Chinese (Simplified) | `zh` |\n\nUnknown codes are ignored gracefully (the widget stays on its current\nlanguage). Custom strings can be patched per language via\n`LokotroLocalizationService.addTranslations`.\n\n## 🔒 Security Notes\n\n- **Fail-closed environments**: `isProduction` has no default. Omitting it is\n  a TypeScript error and a runtime error before any network call.\n- **Redirect allow-listing**: server-supplied redirect/hosted-checkout URLs\n  are validated (http/https only; https-only in production) before navigation.\n- **No sensitive logging**: the SDK never logs tokens, request bodies or\n  response bodies.\n- **Hosted card sessions**: for `card`, the SDK mints a hosted-checkout\n  session; PAN/CVV/expiry are entered on the card network's own page.\n\n## 📋 Requirements\n\n- Browsers: modern evergreen (uses `fetch`, `AbortController`, CSS custom properties)\n- Node 18+ for SSR imports (widgets themselves require a browser to `mount()`)\n\n## 📄 License\n\nMIT © Bloonio\n","readmeFilename":"README.md","_rev":"1-687bad369bc8a9381d88d7c6f2306d7f"}