PayNexus M-Pesa Payment Integration Guide
This comprehensive guide helps developers integrate PayNexus M-Pesa payment processing into their external websites and applications.
Table of Contents
1. [Overview](#overview)
2. [Authentication](#authentication)
3. [API Endpoints](#api-endpoints)
4. [Integration Examples](#integration-examples)
- [PHP](#php)
- [JavaScript/Node.js](#javascriptnodejs)
- [Python](#python)
- [cURL](#curl)
5. [Webhook Integration](#webhook-integration)
6. [Error Handling](#error-handling)
7. [Security Best Practices](#security-best-practices)
8. [Testing](#testing)
9. [Support](#support)
Overview
PayNexus provides a simple REST API for processing M-Pesa payments through your merchant account. The API supports:
- STK Push Payments: Initiate M-Pesa payments directly from customer phones
- Payment Status Tracking: Check transaction status in real-time
- Phone Validation: Validate and normalize phone numbers
- Webhook Callbacks: Receive payment notifications
- Multi-account Support: Manage multiple payment accounts
Base URL
Production: https://paynexus.mcbankske.space/api
Authentication
PayNexus uses API key authentication. Include your API key in the request header:
bash
X-API-Key: your_api_key_here
Types of API Keys
- Public Keys (
pk_...): For read operations (merchant info, payment accounts, status checks)- Secret Keys (
sk_...): For write operations (initiate payments, manage webhooks)Never expose your secret keys in client-side code!
API Endpoints
Core Endpoints
| Method | Endpoint | Description | Auth Required |
|--------|----------------------------|------------------------|---------------|
| GET |
/health | API health check | No || GET |
/mpesa/health | M-Pesa service status | No || GET |
/merchant | Get merchant information | Public Key || GET |
/merchant/payment-accounts | List payment accounts | Public Key || POST |
/mpesa/validate-phone | Validate phone number | Public Key || POST |
/mpesa/payment/initiate | Initiate STK push payment | Secret Key || POST |
/mpesa/payment/status | Check payment status | Secret Key || GET |
/api-keys | List API keys | Public Key |Integration Examples
PHP
#### 1. Install Guzzle HTTP Client
bash
composer require guzzlehttp/guzzle
#### 2. Payment Integration Example
php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
class PayNexusClient
{
private $client;
private $apiKey;
private $baseUrl;
public function __construct($apiKey, $baseUrl = 'https://paynexus.mcbankske.space/api')
{
$this->apiKey = $apiKey;
$this->baseUrl = $baseUrl;
$this->client = new Client([
'base_uri' => $baseUrl,
'headers' => [
'X-API-Key' => $apiKey,
'Content-Type' => 'application/json',
'Accept' => 'application/json'
],
'timeout' => 30
]);
}
/
* Initiate M-Pesa STK Push Payment
*/
public function initiatePayment($paymentAccountId, $amount, $phone, $accountReference = null, $description = null)
{
try {
$payload = [
'payment_account_id' => $paymentAccountId,
'amount' => $amount,
'phone' => $phone,
'account_reference' => $accountReference ?: 'ORDER_' . time(),
'description' => $description ?: 'Payment for order',
'remark' => 'Website Payment'
];
$response = $this->client->post('/mpesa/payment/initiate', [
'json' => $payload
]);
$data = json_decode($response->getBody()->getContents(), true);
if ($data['success']) {
return [
'success' => true,
'payment_id' => $data['data']['payment_id'],
'checkout_request_id' => $data['data']['checkout_request_id'],
'customer_message' => $data['data']['customer_message']
];
} else {
return [
'success' => false,
'error' => $data['error'] ?? 'Payment initiation failed'
];
}
} catch (RequestException $e) {
return [
'success' => false,
'error' => $e->getMessage(),
'response' => $e->hasResponse() ? $e->getResponse()->getBody()->getContents() : null
];
}
}
/
* Check payment status
*/
public function checkPaymentStatus($transactionId)
{
try {
$response = $this->client->post('/mpesa/payment/status', [
'json' => [
'transaction_id' => $transactionId
]
]);
$data = json_decode($response->getBody()->getContents(), true);
return [
'success' => true,
'status' => $data['data']['status'] ?? 'unknown',
'transaction_id' => $data['data']['transaction_id'] ?? null,
'amount' => $data['data']['amount'] ?? null
];
} catch (RequestException $e) {
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
/
* Validate phone number
*/
public function validatePhone($phone)
{
try {
$response = $this->client->post('/mpesa/validate-phone', [
'json' => ['phone' => $phone]
]);
$data = json_decode($response->getBody()->getContents(), true);
return [
'success' => true,
'valid' => $data['data']['valid'],
'normalized' => $data['data']['normalized'] ?? $phone
];
} catch (RequestException $e) {
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
}
// Usage Example
$paynexus = new PayNexusClient('sk_your_secret_key_here');
// Validate phone number
$phoneValidation = $paynexus->validatePhone('0798808796');
if ($phoneValidation['success'] && $phoneValidation['valid']) {
$normalizedPhone = $phoneValidation['normalized'];
// Initiate payment
$payment = $paynexus->initiatePayment(
1, // Payment account ID
100, // Amount in KES
$normalizedPhone,
'ORDER_12345',
'Payment for website order'
);
if ($payment['success']) {
echo "Payment initiated! Checkout Request ID: " . $payment['checkout_request_id'];
echo "Customer message: " . $payment['customer_message'];
// Store checkout_request_id for status checking
// Redirect to payment confirmation page
} else {
echo "Payment failed: " . $payment['error'];
}
}
?>
#### 3. Webhook Handler
php
// webhook_handler.php
header('Content-Type: application/json');
// Get the webhook payload
$payload = file_get_contents('php://input');
$data = json_decode($payload, true);
// Verify webhook (implement your verification logic)
if (!verifyWebhookSignature($payload)) {
http_response_code(401);
echo json_encode(['error' => 'Unauthorized']);
exit;
}
// Process the callback
if (isset($data['ResultCode']) && $data['ResultCode'] == 0) {
// Payment successful
$transactionId = $data['TransactionID'] ?? null;
$checkoutRequestId = $data['CheckoutRequestID'] ?? null;
$amount = $data['Amount'] ?? null;
$phoneNumber = $data['PhoneNumber'] ?? null;
// Update your database
// Mark order as paid
// Send confirmation email
// Update customer account
logTransaction($transactionId, $checkoutRequestId, 'completed', $amount, $phoneNumber);
} else {
// Payment failed
$checkoutRequestId = $data['CheckoutRequestID'] ?? null;
$errorCode = $data['ResultCode'] ?? null;
$errorMessage = $data['ResultDesc'] ?? 'Payment failed';
// Update your database
// Mark order as failed
// Notify customer
logTransaction(null, $checkoutRequestId, 'failed', null, null, $errorMessage);
}
// Always return success to avoid retries
echo json_encode(['ResultCode' => 0, 'ResultDesc' => 'Callback received']);
function verifyWebhookSignature($payload)
{
// Implement your webhook verification logic
// Check against stored secrets, verify timestamps, etc.
return true; // Simplified for example
}
function logTransaction($transactionId, $checkoutRequestId, $status, $amount, $phone, $error = null)
{
// Implement your database logging
$logEntry = [
'transaction_id' => $transactionId,
'checkout_request_id' => $checkoutRequestId,
'status' => $status,
'amount' => $amount,
'phone' => $phone,
'error' => $error,
'timestamp' => date('Y-m-d H:i:s')
];
// Save to database or log file
file_put_contents('payment_log.txt', json_encode($logEntry) . "\n", FILE_APPEND);
}
?>
JavaScript/Node.js
#### 1. Install Axios
bash
npm install axios
#### 2. Payment Integration Example
javascript
// paynexus-client.js
const axios = require('axios');
class PayNexusClient {
constructor(apiKey, baseUrl = 'https://paynexus.mcbankske.space/api') {
this.apiKey = apiKey;
this.baseUrl = baseUrl;
this.client = axios.create({
baseURL: baseUrl,
headers: {
'X-API-Key': apiKey,
'Content-Type': 'application/json',
'Accept': 'application/json'
},
timeout: 30000
});
}
/
* Initiate M-Pesa STK Push Payment
*/
async initiatePayment(paymentAccountId, amount, phone, accountReference = null, description = null) {
try {
const payload = {
payment_account_id: paymentAccountId,
amount: amount,
phone: phone,
account_reference: accountReference || ORDER_${Date.now()},
description: description || 'Payment for order',
remark: 'Website Payment'
};
const response = await this.client.post('/mpesa/payment/initiate', payload);
if (response.data.success) {
return {
success: true,
payment_id: response.data.data.payment_id,
checkout_request_id: response.data.data.checkout_request_id,
customer_message: response.data.data.customer_message
};
} else {
return {
success: false,
error: response.data.error || 'Payment initiation failed'
};
}
} catch (error) {
return {
success: false,
error: error.response?.data?.error || error.message,
details: error.response?.data
};
}
}
/
* Check payment status
*/
async checkPaymentStatus(transactionId) {
try {
const response = await this.client.post('/mpesa/payment/status', {
transaction_id: transactionId
});
return {
success: true,
status: response.data.data.status,
transaction_id: response.data.data.transaction_id,
amount: response.data.data.amount
};
} catch (error) {
return {
success: false,
error: error.response?.data?.error || error.message
};
}
}
/
* Validate phone number
*/
async validatePhone(phone) {
try {
const response = await this.client.post('/mpesa/validate-phone', {
phone: phone
});
return {
success: true,
valid: response.data.data.valid,
normalized: response.data.data.normalized || phone
};
} catch (error) {
return {
success: false,
error: error.response?.data?.error || error.message
};
}
}
/
* Get merchant information
*/
async getMerchantInfo() {
try {
const response = await this.client.get('/merchant');
return {
success: true,
data: response.data.data
};
} catch (error) {
return {
success: false,
error: error.response?.data?.error || error.message
};
}
}
/
* Get payment accounts
*/
async getPaymentAccounts() {
try {
const response = await this.client.get('/merchant/payment-accounts');
return {
success: true,
data: response.data.data
};
} catch (error) {
return {
success: false,
error: error.response?.data?.error || error.message
};
}
}
}
// Usage Example
async function processPayment() {
const paynexus = new PayNexusClient('sk_your_secret_key_here');
try {
// Get merchant payment accounts
const accounts = await paynexus.getPaymentAccounts();
if (accounts.success && accounts.data.length > 0) {
const mpesaAccount = accounts.data.find(acc => acc.provider === 'mpesa');
if (mpesaAccount) {
// Validate phone number
const phoneValidation = await paynexus.validatePhone('0798808796');
if (phoneValidation.success && phoneValidation.valid) {
// Initiate payment
const payment = await paynexus.initiatePayment(
mpesaAccount.id,
100,
phoneValidation.normalized,
'ORDER_12345',
'Payment for website order'
);
if (payment.success) {
console.log('Payment initiated successfully!');
console.log('Checkout Request ID:', payment.checkout_request_id);
console.log('Customer message:', payment.customer_message);
// Store checkout_request_id for status checking
// Show payment confirmation to user
} else {
console.error('Payment failed:', payment.error);
}
} else {
console.error('Invalid phone number:', phoneValidation.error);
}
} else {
console.error('No M-Pesa account found');
}
} else {
console.error('Failed to get payment accounts:', accounts.error);
}
} catch (error) {
console.error('Payment processing error:', error);
}
}
processPayment();
#### 3. Express.js Webhook Handler
javascript
// webhook-server.js
const express = require('express');
const crypto = require('crypto');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
// Webhook endpoint
app.post('/webhook/mpesa', (req, res) => {
const payload = req.body;
// Verify webhook signature (implement your verification)
if (!verifyWebhookSignature(req)) {
return res.status(401).json({ error: 'Unauthorized' });
}
// Process the callback
if (payload.ResultCode === 0) {
// Payment successful
const transactionId = payload.TransactionID;
const checkoutRequestId = payload.CheckoutRequestID;
const amount = payload.Amount;
const phoneNumber = payload.PhoneNumber;
console.log(Payment successful: ${transactionId} for ${amount} KES);
// Update database
// Mark order as paid
// Send confirmation email
// Update customer account
updatePaymentStatus(checkoutRequestId, 'completed', {
transactionId,
amount,
phoneNumber
});
} else {
// Payment failed
const checkoutRequestId = payload.CheckoutRequestID;
const errorCode = payload.ResultCode;
const errorMessage = payload.ResultDesc;
console.log(Payment failed: ${checkoutRequestId} - ${errorMessage});
// Update database
// Mark order as failed
// Notify customer
updatePaymentStatus(checkoutRequestId, 'failed', {
errorCode,
errorMessage
});
}
// Always return success to avoid retries
res.json({ ResultCode: 0, ResultDesc: 'Callback received' });
});
function verifyWebhookSignature(req) {
// Implement your webhook verification logic
// Check against stored secrets, verify timestamps, etc.
return true; // Simplified for example
}
function updatePaymentStatus(checkoutRequestId, status, details) {
// Implement your database update logic
console.log(Updating payment ${checkoutRequestId} to ${status}, details);
// Example: Update in database
// db.collection('payments').updateOne(
// { checkout_request_id: checkoutRequestId },
// {
// $set: {
// status,
// updated_at: new Date(),
// ...details
// }
// }
// );
}
const PORT = process.env.WEBHOOK_PORT || 3000;
app.listen(PORT, () => {
console.log(Webhook server listening on port ${PORT});
});
Python
#### 1. Install Requests
bash
pip install requests
#### 2. Payment Integration Example
python
paynexus_client.py
import requests
import json
from typing import Dict, Optional, Any
class PayNexusClient:
def __init__(self, api_key: str, base_url: str = 'https://paynexus.mcbankske.space/api'):
self.api_key = api_key
self.base_url = base_url
self.session = requests.Session()
self.session.headers.update({
'X-API-Key': api_key,
'Content-Type': 'application/json',
'Accept': 'application/json'
})
self.session.timeout = 30
def initiate_payment(self, payment_account_id: int, amount: float, phone: str,
account_reference: Optional[str] = None,
description: Optional[str] = None) -> Dict[str, Any]:
"""
Initiate M-Pesa STK Push Payment
"""
try:
payload = {
'payment_account_id': payment_account_id,
'amount': amount,
'phone': phone,
'account_reference': account_reference or f'ORDER_{int(time.time())}',
'description': description or 'Payment for order',
'remark': 'Website Payment'
}
response = self.session.post(f'{self.base_url}/mpesa/payment/initiate', json=payload)
response.raise_for_status()
data = response.json()
if data.get('success'):
return {
'success': True,
'payment_id': data['data']['payment_id'],
'checkout_request_id': data['data']['checkout_request_id'],
'customer_message': data['data']['customer_message']
}
else:
return {
'success': False,
'error': data.get('error', 'Payment initiation failed')
}
except requests.exceptions.RequestException as e:
return {
'success': False,
'error': str(e),
'response': e.response.text if e.response else None
}
def check_payment_status(self, transaction_id: str) -> Dict[str, Any]:
"""
Check payment status
"""
try:
payload = {
'transaction_id': transaction_id
}
response = self.session.post(f'{self.base_url}/mpesa/payment/status', json=payload)
response.raise_for_status()
data = response.json()
return {
'success': True,
'status': data['data'].get('status', 'unknown'),
'transaction_id': data['data'].get('transaction_id'),
'amount': data['data'].get('amount')
}
except requests.exceptions.RequestException as e:
return {
'success': False,
'error': str(e)
}
def validate_phone(self, phone: str) -> Dict[str, Any]:
"""
Validate phone number
"""
try:
payload = {'phone': phone}
response = self.session.post(f'{self.base_url}/mpesa/validate-phone', json=payload)
response.raise_for_status()
data = response.json()
return {
'success': True,
'valid': data['data']['valid'],
'normalized': data['data'].get('normalized', phone)
}
except requests.exceptions.RequestException as e:
return {
'success': False,
'error': str(e)
}
def get_merchant_info(self) -> Dict[str, Any]:
"""
Get merchant information
"""
try:
response = self.session.get(f'{self.base_url}/merchant')
response.raise_for_status()
return {
'success': True,
'data': response.json()['data']
}
except requests.exceptions.RequestException as e:
return {
'success': False,
'error': str(e)
}
def get_payment_accounts(self) -> Dict[str, Any]:
"""
Get payment accounts
"""
try:
response = self.session.get(f'{self.base_url}/merchant/payment-accounts')
response.raise_for_status()
return {
'success': True,
'data': response.json()['data']
}
except requests.exceptions.RequestException as e:
return {
'success': False,
'error': str(e)
}
Usage Example
import time
def process_payment():
paynexus = PayNexusClient('sk_your_secret_key_here')
try:
# Get merchant payment accounts
accounts = paynexus.get_payment_accounts()
if accounts['success'] and accounts['data']:
mpesa_account = next((acc for acc in accounts['data'] if acc['provider'] == 'mpesa'), None)
if mpesa_account:
# Validate phone number
phone_validation = paynexus.validate_phone('0798808796')
if phone_validation['success'] and phone_validation['valid']:
# Initiate payment
payment = paynexus.initiate_payment(
mpesa_account['id'],
100,
phone_validation['normalized'],
'ORDER_12345',
'Payment for website order'
)
if payment['success']:
print(f"Payment initiated successfully!")
print(f"Checkout Request ID: {payment['checkout_request_id']}")
print(f"Customer message: {payment['customer_message']}")
# Store checkout_request_id for status checking
# Show payment confirmation to user
return payment
else:
print(f"Payment failed: {payment['error']}")
else:
print(f"Invalid phone number: {phone_validation['error']}")
else:
print("No M-Pesa account found")
else:
print(f"Failed to get payment accounts: {accounts['error']}")
except Exception as e:
print(f"Payment processing error: {e}")
if __name__ == "__main__":
process_payment()
#### 3. Flask Webhook Handler
python
webhook_server.py
from flask import Flask, request, jsonify
import hashlib
import hmac
import json
from datetime import datetime
app = Flask(__name__)
@app.route('/webhook/mpesa', methods=['POST'])
def mpesa_webhook():
payload = request.get_json()
# Verify webhook signature (implement your verification)
if not verify_webhook_signature(request):
return jsonify({'error': 'Unauthorized'}), 401
# Process the callback
if payload.get('ResultCode') == 0:
# Payment successful
transaction_id = payload.get('TransactionID')
checkout_request_id = payload.get('CheckoutRequestID')
amount = payload.get('Amount')
phone_number = payload.get('PhoneNumber')
print(f"Payment successful: {transaction_id} for {amount} KES")
# Update database
# Mark order as paid
# Send confirmation email
# Update customer account
update_payment_status(checkout_request_id, 'completed', {
'transaction_id': transaction_id,
'amount': amount,
'phone_number': phone_number
})
else:
# Payment failed
checkout_request_id = payload.get('CheckoutRequestID')
error_code = payload.get('ResultCode')
error_message = payload.get('ResultDesc')
print(f"Payment failed: {checkout_request_id} - {error_message}")
# Update database
# Mark order as failed
# Notify customer
update_payment_status(checkout_request_id, 'failed', {
'error_code': error_code,
'error_message': error_message
})
# Always return success to avoid retries
return jsonify({'ResultCode': 0, 'ResultDesc': 'Callback received'})
def verify_webhook_signature(request):
# Implement your webhook verification logic
# Check against stored secrets, verify timestamps, etc.
return True # Simplified for example
def update_payment_status(checkout_request_id, status, details):
# Implement your database update logic
print(f"Updating payment {checkout_request_id} to {status}", details)
# Example: Update in database
# db.payments.update_one(
# {'checkout_request_id': checkout_request_id},
# {
# '$set': {
# 'status': status,
# 'updated_at': datetime.utcnow(),
# details
# }
# }
# )
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
cURL Examples
#### Basic API Calls
bash
Health Check
curl -X GET "https://paynexus.mcbankske.space/api/health" \
-H "Accept: application/json"
Get Merchant Info
curl -X GET "https://paynexus.mcbankske.space/api/merchant" \
-H "X-API-Key: pk_your_public_key_here" \
-H "Accept: application/json"
Get Payment Accounts
curl -X GET "https://paynexus.mcbankske.space/api/merchant/payment-accounts" \
-H "X-API-Key: pk_your_public_key_here" \
-H "Accept: application/json"
Validate Phone Number
curl -X POST "https://paynexus.mcbankske.space/api/mpesa/validate-phone" \
-H "X-API-Key: pk_your_public_key_here" \
-H "Content-Type: application/json" \
-d '{"phone": "0798808796"}'
Initiate Payment
curl -X POST "https://paynexus.mcbankske.space/api/mpesa/payment/initiate" \
-H "X-API-Key: sk_your_secret_key_here" \
-H "Content-Type: application/json" \
-d '{
"payment_account_id": 1,
"amount": 100,
"phone": "254798808796",
"account_reference": "ORDER_12345",
"description": "Payment for website order",
"remark": "Website Payment"
}'
Check Payment Status
curl -X POST "https://paynexus.mcbankske.space/api/mpesa/payment/status" \
-H "X-API-Key: sk_your_secret_key_here" \
-H "Content-Type: application/json" \
-d '{
"transaction_id": "YOUR_TRANSACTION_ID_HERE"
}'
Webhook Integration
Setting Up Webhooks
1. Register Webhook URL (via API or dashboard)
2. Handle Incoming Callbacks from M-Pesa
3. Verify Webhook Signatures for security
4. Update Your Database based on payment status
Webhook Payload Structure
json
{
"ResultCode": 0,
"ResultDesc": "Success. Request accepted for processing",
"CheckoutRequestID": "ws_CO_27012026101718139798808796",
"MerchantRequestID": "e569-40f5-bc0a-03c08bc2061a3446498",
"Amount": "100",
"MpesaReceiptNumber": "OEI2AK4Q16",
"TransactionDate": "20260127101718",
"PhoneNumber": "254798808796"
}
Result Codes
| Code | Description |
|------|-------------|
| 0 | Success |
| 1 | Insufficient funds |
| 1032 | Account closed |
| 1037 | Account blocked |
| 2001 | Invalid amount |
| 2002 | Invalid phone number |
| 2003 | Invalid transaction |
| 2004 | Invalid security credential |
| 2005 | Invalid receiver party |
| 2006 | Invalid initiator |
| 2007 | Invalid short code |
Error Handling
Common Error Responses
json
{
"success": false,
"error": "Validation failed",
"code": "VALIDATION_FAILED",
"details": {
"payment_account_id": ["The payment account id field is required."],
"amount": ["The amount must be at least 1."]
}
}
HTTP Status Codes
| Status | Description |
|--------|-------------|
| 200 | Success |
| 400 | Bad Request |
| 401 | Unauthorized |
| 403 | Forbidden |
| 422 | Validation Error |
| 500 | Server Error |
Error Handling Best Practices
1. Always check the
success field in API responses2. Handle validation errors gracefully
3. Implement retry logic for network failures
4. Log errors for debugging
5. Provide user-friendly error messages
Security Best Practices
API Key Security
1. Never expose secret keys in client-side code
2. Use environment variables to store API keys
3. Rotate API keys regularly
4. Use different keys for different environments
5. Implement IP restrictions where possible
Webhook Security
1. Verify webhook signatures using HMAC
2. Check request timestamps to prevent replay attacks
3. Use HTTPS for all webhook endpoints
4. Validate payload structure before processing
Example Environment Setup
bash
.env file
PAYNEXUS_PUBLIC_KEY=pk_your_public_key_here
PAYNEXUS_SECRET_KEY=sk_your_secret_key_here
PAYNEXUS_WEBHOOK_SECRET=your_webhook_secret_here
PAYNEXUS_BASE_URL=https://api.paynexus.co.ke/api
javascript
// JavaScript example
const apiKey = process.env.PAYNEXUS_SECRET_KEY;
const baseUrl = process.env.PAYNEXUS_BASE_URL;
Testing
Using the Test Suite
Run the included test suite to verify your integration:
bash
Run the test script
bash test_mpesa_postman.sh
Test Cards/Numbers
For testing, use these phone numbers:
-
254798808796 - Valid test number-
0798808796 - Valid test number (will be normalized)Test Amounts
- Use small amounts (1-10 KES) for testing
- Maximum test amount: 150,000 KES
Support
Documentation
- API Reference:
/api/docs endpoint- Health Check:
/api/health- M-Pesa Health:
/api/mpesa/healthCommon Issues
1. "Insufficient permissions" - Use correct API key type
2. "Invalid phone number" - Validate phone numbers first
3. "Payment account not found" - Check payment account ID
4. "Webhook timeout" - Ensure webhook endpoint is accessible
Getting Help
- Check the API logs for detailed error messages
- Verify your API keys and permissions
- Test with the provided test suite
- Contact support with error details and request IDs
---
Quick Start Checklist
- [ ] Get your API keys from the PayNexus dashboard
- [ ] Choose your integration language (PHP, Node.js, Python)
- [ ] Set up your development environment
- [ ] Test the health endpoints
- [ ] Implement phone validation
- [ ] Implement payment initiation
- [ ] Set up webhook handler
- [ ] Test the complete flow
- [ ] Deploy to production
- [ ] Monitor payment status and errors
Happy coding! 🚀