Paystack API Keys: Public, Secret, Test and Live
Paystack issues two key pairs: one for test mode and one for live mode. Each pair has a public key (prefixed pk_test_ or pk_live_) used on the frontend, and a secret key (prefixed sk_test_ or sk_live_) used only on the server. The public key initializes the checkout popup. The secret key authenticates API calls. Never expose a secret key in frontend code, and never use test keys in production.
The Four Keys and What Each One Does
When you create a Paystack account and navigate to Settings, then API Keys & Webhooks, you see four values. Each key has a prefix that tells you exactly what it is.
| Key | Prefix | Where It Belongs | What It Can Do |
|---|---|---|---|
| Test Public Key | pk_test_ | Frontend (browser) | Initialize test checkouts only |
| Test Secret Key | sk_test_ | Server only | Full API access in test mode |
| Live Public Key | pk_live_ | Frontend (browser) | Initialize live checkouts only |
| Live Secret Key | sk_live_ | Server only | Full API access in live mode |
The prefix is your first line of defence against mistakes. If you see sk_ anywhere in your frontend bundle, your build logs, or a browser network tab, something is wrong.
Public keys are deliberately limited. They can initialize the Paystack checkout popup and nothing else. They cannot list transactions, issue refunds, initiate transfers, or read customer data. That is why they are safe to embed in client-side JavaScript.
Secret keys have full access to every Paystack API endpoint. They can charge cards, move money to bank accounts, read all transaction history, create and delete subaccounts, and issue refunds. Treat them with the same care you would treat a database password.
Using the Public Key on the Frontend
The public key appears in one place in your frontend code: the Paystack Inline JS initialization. This is expected and safe.
<script src="https://js.paystack.co/v2/inline.js"></script>
<script>
var popup = new PaystackPop();
popup.checkout({
key: 'pk_live_xxxxxxxxxxxxxxxxxxxx',
email: 'customer@example.com',
amount: 500000,
onSuccess: function(transaction) {
// Send transaction.reference to your server for verification
window.location.href = '/verify?ref=' + transaction.reference;
},
onCancel: function() {
alert('Payment cancelled');
}
});
</script>
Notice the key starts with pk_. This key can do exactly one thing: open a checkout. It cannot verify a transaction, read customer data, or perform any other API operation. That is why it is safe to put it in HTML that every visitor can view.
In many frontend frameworks (React, Vue, Next.js), you will pass the public key through an environment variable like NEXT_PUBLIC_PAYSTACK_KEY or VITE_PAYSTACK_KEY. These variables are embedded into the JavaScript bundle at build time, so they are still publicly visible. That is fine for public keys. It is not fine for secret keys.
Using the Secret Key on the Server
Every Paystack API call from your server uses the secret key in the Authorization header.
const https = require('https');
const options = {
hostname: 'api.paystack.co',
port: 443,
path: '/transaction/verify/ref_abc123',
method: 'GET',
headers: {
Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
},
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => { data += chunk; });
res.on('end', () => {
var response = JSON.parse(data);
console.log('Status:', response.data.status);
console.log('Amount:', response.data.amount);
});
});
req.end();
The secret key authenticates you to Paystack's servers. It proves that the API call is coming from your application, not an impersonator. If someone obtains your secret key, they can:
- Initiate transfers from your Paystack balance to any bank account
- Read all your transaction history and customer data
- Issue refunds on any transaction
- Create subaccounts and modify your split configuration
- Charge saved cards using authorization codes
This is why the secret key never leaves your server. It never goes in frontend code, mobile app code, or anywhere a user could extract it.
Test Mode vs Live Mode
Test keys and live keys connect to separate environments on Paystack's side. Transactions created with test keys do not move real money. Transactions created with live keys debit real bank accounts and cards.
Key differences between the two modes:
- Test mode accepts specific test card numbers (like 4084 0840 8408 4081). Real card numbers are rejected. No money moves. Webhooks fire normally so you can test your integration end to end.
- Live mode accepts real cards. Money moves. Fees are deducted. Settlements are paid to your bank account. Webhook payloads contain real customer data.
- Data is separate. Customers, transactions, subscriptions, and plans created in test mode do not appear in live mode and vice versa.
- Dashboard filtering. The Paystack dashboard lets you toggle between test and live data using a switch at the top of the page.
Your code should be identical between test and live. The only difference is which key pair is loaded from your environment variables. This is the whole point of environment-based configuration: you deploy the same code to staging (with test keys) and production (with live keys).
// Your code does not change between environments.
// Only the environment variable changes.
var secret = process.env.PAYSTACK_SECRET_KEY;
// In staging: sk_test_xxxxx
// In production: sk_live_xxxxx
Common Mistakes That Cause Real Problems
These are the mistakes developers make most often with Paystack keys. Every one of them has caused real incidents for real businesses.
1. Hardcoding the secret key in source code. The file gets committed to Git. The repo is public (or becomes public later). Now the key is exposed. Use environment variables instead. Always.
2. Using the secret key on the frontend. A developer copies the API example from the docs and puts it in a React component. The key is now in the JavaScript bundle that every browser downloads. Anyone can extract it from the browser's DevTools.
3. Using test keys in production. The checkout opens but no money is collected. Customers think they paid. Your database records a "successful" transaction. But the money is not real. This happens when you forget to swap environment variables during deployment.
4. Using live keys in development. You charge real cards while testing. You accidentally debit a customer for a test transaction. You process real refunds on test orders. Always use test keys in your development and staging environments.
5. Sharing keys in chat or email. A developer pastes the secret key in a Slack message or WhatsApp group. That message is now searchable, backed up, and stored on servers you do not control. Use a secrets manager or a password manager to share keys.
6. Logging the secret key. Your error handler logs the full request headers or environment variables to a file or a monitoring service. The secret key appears in plain text in your logs. Redact it before logging. See logging payments without logging secrets.
Where to Find Your Keys on the Dashboard
Log in to your Paystack dashboard at dashboard.paystack.com. Navigate to Settings, then select API Keys & Webhooks.
You will see your test keys immediately. Your live keys are available only after your business has been activated (KYC verification completed). Until activation, you can only use test mode.
Important details about the dashboard:
- Secret keys are shown once. When you generate or regenerate a secret key, Paystack shows it to you one time. Copy it immediately and store it in your secrets manager. If you lose it, you will need to generate a new one.
- Public keys are always visible. You can view your public key at any time from the dashboard.
- You can regenerate keys. If a key is compromised, click the regenerate button for that key. The old key is immediately invalidated. Any API call using the old key will return 401 Unauthorized. See rotating keys without downtime for the safe procedure.
When and Why to Rotate Keys
Key rotation means generating a new secret key and replacing the old one in all your systems. You should rotate keys in these situations:
- A team member with access to the key leaves the organization
- The key was accidentally committed to a Git repository
- The key appeared in logs, error reports, or a monitoring dashboard
- You suspect unauthorized access to your Paystack account
- As a routine security practice (every 3 to 6 months is reasonable)
When you regenerate a key on the Paystack dashboard, the old key stops working immediately. If your server is still using the old key, all API calls will fail. This is why you need a deployment plan for key rotation. Deploy the new key to your environment variables first, restart your servers, and confirm the new key works before treating the rotation as complete.
For a detailed procedure that avoids downtime, see rotating Paystack secret keys without downtime.
Setting Up Environment Variables for Your Keys
Store your Paystack keys in environment variables so they never appear in your source code. Here is the standard naming convention most teams follow:
# .env file (never committed to Git)
PAYSTACK_SECRET_KEY=sk_test_xxxxxxxxxxxxxxxxxxxxxxx
PAYSTACK_PUBLIC_KEY=pk_test_xxxxxxxxxxxxxxxxxxxxxxx
On your server, load these from your hosting platform's environment configuration. On Vercel, Railway, Render, or Heroku, you set them in the dashboard. In Docker, you pass them through environment flags or a secrets file.
// server.js
var crypto = require('crypto');
var secret = process.env.PAYSTACK_SECRET_KEY;
if (!secret) {
throw new Error('PAYSTACK_SECRET_KEY is not set');
}
// Use the key for API calls and webhook verification
function verifyWebhook(body, signature) {
var hash = crypto.createHmac('sha512', secret).update(body).digest('hex');
return hash === signature;
}
Add .env to your .gitignore file. Confirm it is listed before your first commit. If you have already committed a .env file, the key is already in your Git history even if you delete the file. You need to rotate the key immediately. See detecting and remediating committed keys.
This article is part of the Paystack security and PCI compliance guide.
Key Takeaways
- ✓Paystack gives you four keys: test public, test secret, live public, and live secret.
- ✓Public keys (pk_test_ and pk_live_) are safe for frontend code. They can only initialize checkouts.
- ✓Secret keys (sk_test_ and sk_live_) must stay on the server. They authenticate all API calls.
- ✓Test keys work only in test mode and process no real money. Live keys process real transactions.
- ✓Exposing a secret key in frontend code, a GitHub repo, or client logs is a security incident that requires immediate key rotation.
- ✓Store all keys in environment variables. Never hardcode them in source files.
- ✓Switching from test to live is a matter of swapping the key pair in your environment variables, not changing code.
Frequently Asked Questions
- Can someone use my public key to charge customers?
- No. The public key can only initialize the Paystack checkout popup. It cannot verify transactions, initiate charges, issue refunds, or perform any other API operation. Even if someone extracts your public key from your frontend code, they cannot use it to steal money or access your data.
- What happens if I use a test key in production?
- The checkout popup will open and appear to work, but no real money will move. Customers will see a "success" message, but no funds will be debited from their accounts. Your system will record successful transactions that have no real value. This is a business-critical bug because customers believe they paid when they did not.
- Do I need different Paystack accounts for test and live?
- No. A single Paystack account provides both test and live key pairs. Test and live data are stored separately within the same account. You switch between viewing test and live data on the dashboard using a toggle. Your application switches between modes by using the appropriate key pair from environment variables.
- How do I know if my secret key has been compromised?
- Watch for unexpected activity on your Paystack dashboard: transactions you did not initiate, transfers to bank accounts you do not recognize, or new subaccounts you did not create. GitHub will also notify you if it detects a Paystack key in a public repository through its secret scanning feature. Set up alerts for unusual transaction patterns as an additional safeguard.
- Can I have multiple secret keys active at the same time?
- Paystack allows one active secret key per mode (test or live). When you regenerate a key, the old key is immediately invalidated. If you need a brief overlap period for zero-downtime rotation, you will need to coordinate the deployment so the new key is in place before or immediately after the old one is revoked.
Ready to build real-world apps?
Join the McTaba Labs full-stack marathon (4 months full-time · 6 months part-time). Learn M-Pesa, USSD, and WhatsApp engineering while shipping 8 production apps.
Apply to the McTaba Marathon