API Documentation
Complete guide to integrating SikaPay Ghana into your application. Accept Mobile Money payments in minutes.
Getting Started
SikaPay GH provides a simple REST API to accept Mobile Money payments in Ghana. Base URL: https://api.sikapaygh.com
Quick Start Steps:
- 1Create account at sikapaygh.com/register
- 2Get API keys from Dashboard → Settings → API Keys
- 3Test with test keys (sk_test_*) in sandbox
- 4Go live with live keys (sk_live_*)
Authentication
All API requests require your secret key in the Authorization header:
Authorization: Bearer sk_live_your_secret_key⚠️ Important: Never expose secret keys in client-side code. Always make API calls from your server.
API Keys
| Key Type | Prefix | Usage |
|---|---|---|
| Test Secret Key | sk_test_ | Server-side, sandbox |
| Live Secret Key | sk_live_ | Server-side, production |
| Test Public Key | pk_test_ | Client-side, sandbox |
| Live Public Key | pk_live_ | Client-side, production |
OTP Login (SMS Verification)
SikaPay supports passwordless login using SMS OTP verification. This is ideal for merchants who prefer to login using their phone number instead of remembering passwords.
How OTP Login Works
- 1Merchant enters their registered email address
- 2System sends a 6-digit OTP code via SMS to their registered phone number
- 3Merchant enters the OTP code to verify and login
- 4JWT token is returned for authenticated access
Step 1: Request OTP
Send a request to receive an OTP code via SMS. The code is sent from sender ID sikapay.
// POST https://api.sikapaygh.com/api/v1/auth/login/request-otp
const response = await fetch('https://api.sikapaygh.com/api/v1/auth/login/request-otp', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: 'merchant@company.com'
})
});
const result = await response.json();
// Success Response:
{
"status": true,
"message": "OTP sent successfully",
"data": {
"email": "merchant@company.com",
"phone": "024****567", // Masked phone number
"expires_in": 600 // OTP valid for 10 minutes (600 seconds)
}
}
// Error Response (account not found):
{
"status": false,
"message": "No account found with this email"
}Note: The OTP is valid for 10 minutes and can only be used once. Maximum 3 verification attempts are allowed per OTP.
Step 2: Verify OTP & Login
After the merchant receives the SMS, verify the OTP code to complete login and receive a JWT token.
// POST https://api.sikapaygh.com/api/v1/auth/login/verify-otp
const response = await fetch('https://api.sikapaygh.com/api/v1/auth/login/verify-otp', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: 'merchant@company.com',
otp: '123456' // 6-digit code from SMS
})
});
const result = await response.json();
// Success Response:
{
"status": true,
"message": "Login successful",
"data": {
"merchant": {
"id": "64abc123...",
"email": "merchant@company.com",
"business_name": "My Shop Ghana",
"phone": "0241234567",
"is_verified": true,
"is_live": true
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}
// Error Responses:
{
"status": false,
"message": "Invalid OTP code" // Wrong code
}
{
"status": false,
"message": "OTP has expired" // Code expired (>10 mins)
}
{
"status": false,
"message": "Maximum attempts exceeded" // Too many wrong attempts
}Resend OTP
If the merchant didn't receive the SMS or it expired, they can request a new OTP. There's a 60-second cooldown between resend requests.
// POST https://api.sikapaygh.com/api/v1/auth/login/resend-otp
const response = await fetch('https://api.sikapaygh.com/api/v1/auth/login/resend-otp', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: 'merchant@company.com'
})
});
const result = await response.json();
// Success Response:
{
"status": true,
"message": "OTP resent successfully",
"data": {
"email": "merchant@company.com",
"phone": "024****567",
"expires_in": 600
}
}
// Rate limit error (requested too soon):
{
"status": false,
"message": "Please wait at least 1 minute before requesting a new OTP"
}SMS Message Format
The merchant will receive an SMS like this from sender "sikapay":
Security Note: OTP codes are one-time use only. Once verified, the code cannot be used again. Never share OTP codes with anyone - SikaPay staff will never ask for your OTP.
Accept Payments
Initialize Payment
Create a payment and redirect customer to hosted checkout:
// POST https://api.sikapaygh.com/v1/transaction/initialize
const response = await fetch('https://api.sikapaygh.com/v1/transaction/initialize', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_live_your_secret_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
amount: 100.00, // Amount in GHS
email: 'customer@email.com',
currency: 'GHS',
callback_url: 'https://yoursite.com/payment/callback',
metadata: {
order_id: '12345',
customer_name: 'Kwame Asante'
}
})
});
const { status, data } = await response.json();
// Response:
{
"status": true,
"message": "Transaction initialized",
"data": {
"reference": "SKPY_1234567890_abc123",
"authorization_url": "https://checkout.sikapaygh.com/pay/abc123",
"access_code": "abc123"
}
}
// Redirect customer to: data.authorization_urlVerify Payment
After payment, verify the transaction:
// GET https://api.sikapaygh.com/v1/transaction/verify/:reference
const response = await fetch(
'https://api.sikapaygh.com/v1/transaction/verify/SKPY_1234567890_abc123',
{
headers: {
'Authorization': 'Bearer sk_live_your_secret_key'
}
}
);
const { status, data } = await response.json();
// Response:
{
"status": true,
"message": "Transaction retrieved",
"data": {
"reference": "SKPY_1234567890_abc123",
"amount": 100.00,
"currency": "GHS",
"status": "success", // success, failed, pending
"channel": "mtn",
"customer": {
"email": "customer@email.com",
"phone": "0241234567"
},
"paid_at": "2024-01-15T10:30:00.000Z"
}
}Direct Charge (Mobile Money)
Charge directly without redirect:
// POST https://api.sikapaygh.com/v1/charge
const response = await fetch('https://api.sikapaygh.com/v1/charge', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_live_your_secret_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
amount: 50.00,
email: 'customer@email.com',
mobile_money: {
phone: '0241234567',
provider: 'mtn' // mtn, vodafone, airteltigo
}
})
});
// Customer receives prompt on their phone to authorize paymentPayouts
Create Recipient
// POST https://api.sikapaygh.com/v1/transferrecipient
const response = await fetch('https://api.sikapaygh.com/v1/transferrecipient', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_live_your_secret_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
type: 'mobile_money',
name: 'Kwame Asante',
account_number: '0241234567',
bank_code: 'MTN' // MTN, VODA, AIRTELTIGO
})
});
// Response:
{
"status": true,
"data": {
"recipient_code": "RCP_abc123xyz",
"name": "Kwame Asante",
"account_number": "0241234567",
"bank_code": "MTN"
}
}Initiate Transfer
// POST https://api.sikapaygh.com/v1/transfer
const response = await fetch('https://api.sikapaygh.com/v1/transfer', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_live_your_secret_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
amount: 100.00,
recipient: 'RCP_abc123xyz',
reason: 'Salary payment'
})
});
// Response:
{
"status": true,
"data": {
"reference": "TRF_1234567890",
"amount": 100.00,
"status": "pending",
"recipient": {
"name": "Kwame Asante",
"account_number": "0241234567"
}
}
}Webhooks
Webhooks notify your server when events happen. Configure your webhook URL in the dashboard.
Events
| Event | Description |
|---|---|
charge.success | Payment was successful |
charge.failed | Payment failed |
transfer.success | Payout was successful |
transfer.failed | Payout failed |
Verify Signature
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const hash = crypto
.createHmac('sha512', secret)
.update(JSON.stringify(payload))
.digest('hex');
return hash === signature;
}
// Express.js example:
app.post('/webhook', (req, res) => {
const signature = req.headers['x-sikapay-signature'];
if (!verifyWebhook(req.body, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const { event, data } = req.body;
switch (event) {
case 'charge.success':
console.log('Payment received:', data.reference);
// Update order status in your database
break;
case 'transfer.success':
console.log('Payout sent:', data.reference);
break;
}
res.status(200).send('OK');
});API Reference
Base URL: https://api.sikapaygh.com
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/auth/login | Login with email & password |
| POST | /api/v1/auth/login/request-otp | Request OTP for login |
| POST | /api/v1/auth/login/verify-otp | Verify OTP & login |
| POST | /api/v1/auth/login/resend-otp | Resend OTP code |
| POST | /api/v1/transaction/initialize | Initialize payment |
| GET | /api/v1/transaction/verify/:ref | Verify payment |
| GET | /api/v1/transaction | List transactions |
| POST | /api/v1/charge | Direct charge |
| POST | /api/v1/payout/send | Send single payout |
| POST | /api/v1/payout/bulk | Send bulk payouts |
| GET | /api/v1/payout/verify/:ref | Verify payout |
| GET | /api/v1/payout/history | Payout history |
| POST | /api/v1/transferrecipient | Create recipient |
| GET | /api/v1/transferrecipient | List recipients |
| GET | /api/v1/balance | Get balance |
Mobile Money Providers
| Provider | Code | Phone Prefix |
|---|---|---|
| MTN Mobile Money | MTN or mtn | 024, 054, 055, 059 |
| Vodafone Cash | VODA or vodafone | 020, 050 |
| AirtelTigo Money | AIRTELTIGO or airteltigo | 026, 027, 056, 057 |
Need Help?
Our developer support team is here to help you integrate SikaPay GH.