Accepting payments online in Nigeria shouldn't require a computer science degree.
Yet, every time I integrated Pay stack into a React app, I found myself writing 50+ lines of boilerplate code. Manual script loading. Error handling. Callback management. It was repetitive, error-prone, and frankly, unnecessary.
So I built NaijaPay — a React component that handles Pay stack integration in 5 lines of code.
And I open sourced it.
The Problem
Here's what integrating Pay stack traditionally looks like:
JavaScript
// Check if script already loaded
if (!window.PaystackPop) {
const script = document.createElement('script');
script.src = 'https://js.paystack.co/v1/inline.js';
script.async = true;
script.onload = () => {
initializePayment();
};
script.onerror = () => {
console.error('Failed to load Paystack');
};
document.body.appendChild(script);
} else {
initializePayment();
}
function initializePayment() {
const handler = window.PaystackPop.setup({
key: process.env.REACT_APP_PAYSTACK_KEY,
email: user.email,
amount: amount * 100, // Convert to kobo
currency: 'NGN',
ref: 'pay_' + Math.floor(Math.random() * 1000000),
metadata: {
custom_fields: [
{
display_name: "Order ID",
variable_name: "order_id",
value: orderId
}
]
},
callback: function(response) {
if (response.status === 'success') {
verifyPayment(response.reference);
} else {
handleFailedPayment();
}
},
onClose: function() {
// User closed popup
cleanup();
}
});
handler.openIframe();
}
Then add error handling. Then add loading states. Then handle the metadata properly. Then test on mobile. Then realize the script didn't load on slow networks.
By the time you're done, you've written 60+ lines for a single button.
And you'll write it again on the next project.
The Solution
After building this pattern for the 5th time on ZabethLab, I extracted it into NaijaPay:
import { NaijaPay } from 'naija-pay';
// In your checkout component
function Checkout({ user, cartTotal }) {
const handleSuccess = (reference: string) => {
// Verify payment on your backend
fetch('/api/verify-payment', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ reference, userId: user.id })
})
.then(res => res.json())
.then(data => {
if (data.verified) {
router.push('/order-success');
}
});
};
return (
<div className="checkout">
<h2>Complete Your Order</h2>
<p>Total: ₦{(cartTotal / 100).toLocaleString()}</p>
<NaijaPay
amount={cartTotal}
email={user.email}
publicKey={process.env.NEXT_PUBLIC_PAYSTACK_KEY}
currency="NGN"
metadata={{
orderId: cart.id,
userId: user.id,
items: cart.items.length
}}
buttonText="Pay Now"
onSuccess={handleSuccess}
onClose={() => console.log('Payment cancelled')}
/>
</div>
);
}
What happens under the hood:
Script loads automatically (no manual injection)
Email format is validated before opening popup
Amount is checked (minimum ₦1)
Public key presence is verified
Loading state shows "Processing..." while Paystack initializes
Errors display in red below the button (not console)
Callbacks are typed and predictable
| *Feature * | *Traditional * | ** NaijaPay** |
|---|---|---|
| Script loading | Manual | ✅ Automatic |
| Form validation | You build it | ✅ Built-in |
| Error messages | Console logs | ✅ User-friendly UI |
| TypeScript | Configure yourself | ✅ Fully typed |
| Loading states | Manual | ✅ Built-in |
Built for Nigerian Developers
This isn't abstract. I built this while working on ZabethLab — a beauty tech platform where payment integration was critical.
Every Nigerian developer building for Nigerian businesses faces the same friction. I wanted to remove it.
Try It
npm install naija-pay
GitHub: https://github.com/softcodestudio44-tech/naija-pay
Features:
TypeScript support
Automatic Pay stack script loading
Built-in validation (email, amount, public key)
Error handling with clear messages
Loading states
Customizable button styling
Supports NGN, GHS, USD
What's Next
This is v1.0.0. I'm actively maintaining it and adding features based on community feedback.
If you build with it, let me know. If you find issues, open a PR. If you have ideas, share them.
Why Open Source
Payment integration shouldn't be a barrier for Nigerian developers. Whether you're building for a small business in Lagos or a startup in Abuja, accepting payments should be simple.
NaijaPay is my contribution to that.
Built by a Nigerian developer, for Nigerian developers.
Top comments (0)