react-klasha
v1.0.0
Published
React hooks and components for accepting payments with the Klasha payment gateway
Maintainers
Readme
react-klasha
React hooks and components for accepting payments with the Klasha payment gateway.

⚠️ Version 0.0.x is completely non-functional — upgrade to 1.0.0
Two things were wrong with 0.0.x, and both are fatal:
The script it loaded no longer exists. 0.0.x fetched
https://klastatic.fra1.digitaloceanspaces.com/{test,prod}/js/klasha-integration.js. That bucket has been deleted; both URLs now return a 404.window.KlashaClientis therefore never defined and no payment can start at all. Klasha's current script ishttps://js.klasha.com/pay.js, which 1.0.0 loads.isTestModewas never sent to the gateway. The Klasha client takes the test flag as its 9th constructor argument; 0.0.x stopped at 8. Inside the Klasha script the flag then read asundefined, so the base URL, the iframe and the redirect URL all took the production branch. This matters now: the currentpay.jsserves one URL for both environments and decides which gateway to use from that argument alone, so repointing 0.0.x at the new script without adding it would route sandbox traffic to production. 1.0.0 passes it, coerced to a real boolean.To be clear about the past: while the old CDN still existed, 0.0.x picked
/test/js/or/prod/js/correctly based onisTestMode, and that old script was environment-specific by URL. There is no reason to believe your historical sandbox payments went to production, and nothing to reconcile.
1.0.0 also fixes a silently dropped phone number, duplicate DOM ids, a load race
that reported "ready" before the Klasha script had run, and console.log calls
that printed your merchantKey to the browser console. See
Migrating from 0.0.x.
Requirements
- React 16.8 or later (17, 18 and 19 are supported)
- Node 18+ to build from source
0.0.x declared support for React 15, but the library is built on hooks and has never worked below 16.8.
Install
npm install react-klashayarn add react-klashaQuick start
import {KlashaButton} from 'react-klasha';
export default function Checkout() {
return (
<KlashaButton
text="Make Payment"
className="payButton"
merchantKey="YOUR_MERCHANT_KEY"
businessId="YOUR_BUSINESS_ID"
amount={1000}
sourceCurrency="USD"
destinationCurrency="NGN"
tx_ref={`tx-${Date.now()}`}
fullname="John Doe"
email="[email protected]"
phone="+2348143108254"
paymentDescription="Order #1234"
isTestMode
callBack={(response) => console.log('payment complete', response)}
/>
);
}isTestMode selects the environment
There is a single script — https://js.klasha.com/pay.js — for both test and
live traffic. The environment is chosen entirely by isTestMode, which this
library forwards as the 9th constructor argument:
| isTestMode | Gateway used |
| --- | --- |
| true | Klasha test environment |
| false (default) | Klasha live environment |
Use your test merchant key with isTestMode, and your live key without it.
Usage
useKlashaPayment hook
import {useKlashaPayment} from 'react-klasha';
function DonateButton() {
const config = {
merchantKey: 'YOUR_MERCHANT_KEY',
businessId: 'YOUR_BUSINESS_ID',
amount: 1000,
sourceCurrency: 'USD',
destinationCurrency: 'NGN',
tx_ref: `tx-${Date.now()}`,
fullname: 'John Doe',
email: '[email protected]',
phone: '+2348143108254',
isTestMode: true,
};
const initializePayment = useKlashaPayment(config);
const callBack = (response) => console.log('payment complete', response);
return <button onClick={() => initializePayment(callBack)}>Donate</button>;
}initializePayment throws if it is called before the Klasha script has
loaded, or if the script failed to load. Gate your button on the script state:
import {useKlashaScript, useKlashaPayment} from 'react-klasha';
function PayButton({config, callBack}) {
const [ready, failed] = useKlashaScript(config.isTestMode);
const initializePayment = useKlashaPayment(config);
if (failed) return <p>Payment is unavailable right now.</p>;
return (
<button disabled={!ready} onClick={() => initializePayment(callBack)}>
{ready ? 'Pay' : 'Loading…'}
</button>
);
}useKlashaScript returns [loaded, error]. loaded only turns true once
pay.js itself has executed — never merely because a load was started.
KlashaConsumer render prop
import {KlashaConsumer} from 'react-klasha';
<KlashaConsumer {...config} callBack={callBack}>
{({initializePayment}) => <button onClick={initializePayment}>Pay with Klasha</button>}
</KlashaConsumer>;KlashaConsumer forwards refs. The ref is handed to the render prop:
<KlashaConsumer {...config} ref={myRef}>
{({initializePayment, ref}) => (
<button ref={ref} onClick={initializePayment}>
Pay
</button>
)}
</KlashaConsumer>;KlashaProvider
Wrap a subtree so nested components share one payment configuration. Nested
components read initializePayment and callBack from context.
import {KlashaProvider} from 'react-klasha';
<KlashaProvider {...config} callBack={callBack}>
<Checkout />
</KlashaProvider>;API
Payment options
Accepted by useKlashaPayment, KlashaButton, KlashaConsumer and KlashaProvider.
| Option | Type | Required | Description |
| --- | --- | --- | --- |
| merchantKey | string | ✅ | Merchant API key from the Klasha dashboard |
| businessId | string \| number | ✅ | Merchant business id |
| amount | number | ✅ | Amount to charge |
| isTestMode | boolean | | Use the Klasha test environment. Defaults to false |
| sourceCurrency | string | | Currency the customer is charged in. Defaults to NGN |
| destinationCurrency | string | | Currency the merchant is settled in. Defaults to NGN |
| tx_ref | string | | Your unique transaction reference. Generated when omitted |
| fullname | string | | Customer's full name |
| email | string | | Customer's email |
| phone | string | | Customer's phone number |
| phone_number | string | | Deprecated alias of phone |
| callbackUrl | string | | URL the gateway calls when the transaction completes |
| paymentDescription | string | | Description of what is being paid for |
| metadata | object | | Extra data to keep alongside the transaction |
| kit | KlashaKitOptions | | Extra fields forwarded to the Klasha client |
| containerId | string | | Render the checkout into a specific element. One is created per component when omitted |
The kit object
kit is passed straight to the Klasha client. The keys pay.js actually reads
are businessId, currency, redirect_url, email, phone, productType,
amount, sourceAmount, callBack and tx_ref.
You rarely need to set any of them — this library fills in currency, email,
fullname, phone, amount, tx_ref and callBack from the top-level options
and builds a fresh kit for every payment (the Klasha script mutates the
object it is given, so a shared one leaks state between transactions).
const config = {
// …payment options…
kit: {
productType: 'digital',
sourceAmount: 12,
},
};
kit.phoneis the key the gateway reads. 0.0.x set onlykit.phone_number, whichpay.jsnever looks at, so the customer's phone number was silently dropped from the exchange-rate request. 1.0.0 sets both.
KlashaButton props
Everything above, plus:
| Prop | Type | Description |
| --- | --- | --- |
| text | string | Button label |
| children | ReactNode | Used when text is absent |
| className | string | CSS class |
| disabled | boolean | Disable the button |
| type | 'button', 'submit' or 'reset' | Defaults to 'button' |
| callBack | Function | Called when the payment flow completes |
Exports
import {
useKlashaPayment,
useKlashaScript,
useKlashaContainer,
KlashaButton,
KlashaConsumer,
KlashaProvider,
ensureKlashaContainer,
removeKlashaContainer,
getKlashaScriptUrl,
KLASHA_SDK_URL,
} from 'react-klasha';TypeScript types KlashaOptionsProps, KlashaKitOptions, KlashaClientConstructor,
KlashaClientInstance and KlashaRenderProps are exported too.
Migrating from 0.0.x
| Change | Impact |
| --- | --- |
| Loads https://js.klasha.com/pay.js | The old CDN bucket was deleted and returns 404, so 0.0.x cannot start a payment at all. |
| isTestMode is forwarded to the gateway | Test-mode integrations no longer hit the live environment. Use your test merchant key when isTestMode is set. |
| jQuery is no longer loaded | pay.js does not need it. If you relied on this library to provide window.$, load jQuery yourself. |
| useKlashaScript reports loaded only once pay.js has executed | It used to resolve on whichever of jQuery/Klasha loaded first, so loaded was frequently true while window.KlashaClient was undefined. |
| Script error no longer reports loaded: true | useKlashaScript returns [false, true] on failure instead of [true, true]. |
| initializePayment throws instead of silently doing nothing when the script is not ready | Gate the call on useKlashaScript, or catch the error. |
| The checkout container has a unique per-component id | The hardcoded <div id="ktest"> was appended on every effect run. Pass containerId if you need a specific element. |
| kit.phone is populated | The phone number used to be dropped. kit.phone_number is still set for compatibility. |
| tx_ref is generated when omitted | It is interpolated into the redirect URL and must not be empty. |
| console.log of the options (including merchantKey) removed | Nothing is written to the console any more. |
| KlashaConsumer ref actually reaches the render prop | It was always undefined before. |
| Peer range is now react@^16.8 \|\| ^17 \|\| ^18 \|\| ^19 | React 15 was never actually supported. |
| react-dom peer dependency removed | The library never imported it. |
| Build output is dist/index.cjs + dist/index.mjs with an exports map | Deep imports into dist/ are no longer supported. |
Development
npm install
npm run typecheck
npm test
npm run buildDocumentation
See the Klasha documentation for the full list of options and for how to verify a transaction server-side.
Always verify a payment on your server before fulfilling an order. Never trust the browser callback alone.
Contributing
- Fork it
- Create your feature branch:
git checkout -b feature-name - Commit your changes:
git commit -am 'Some commit message' - Push to the branch:
git push origin feature-name - Submit a pull request 😉
How can I thank you?
Star the repo, and share it! Don't forget to follow me on twitter.
Thanks! Adekanbi Dansteve.
License
MIT — see LICENSE.md.
