PlusPesa API Documentation
Welcome to the PlusPesa API documentation. This guide will help you integrate our payment gateway into your application. PlusPesa provides a secure, reliable, and easy-to-use payment solution for businesses across Africa.
Our API follows REST principles and uses JSON for request and response bodies. All requests must be made over HTTPS.
Authorization
PlusPesa uses API keys to authenticate requests. You can obtain your API keys from your PlusPesa Dashboard. Your API keys carry many privileges, so be sure to keep them secure. Do not share your secret API keys in publicly accessible areas.
Authentication to the API is performed via HTTP Basic Auth. Provide your API key as the basic auth username value. You do not need to provide a password.
// Using cURL curl -X POST https://api.pluspesa.com/v2/auth/token \ -u "your_api_key:" \ -H "Content-Type: application/json" \ -d '{ "grant_type": "client_credentials" }' // Using Node.js const axios = require('axios'); const authResponse = await axios.post( 'https://api.pluspesa.com/v2/auth/token', { grant_type: 'client_credentials' }, { auth: { username: 'your_api_key', password: '' } } ); const accessToken = authResponse.data.access_token;
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600
}
Transaction Request
To initiate a payment transaction, send a POST request to the transaction endpoint with the required parameters. The customer will be redirected to the PlusPesa payment page to complete the transaction.
| Parameter | Type | Required | Description |
|---|---|---|---|
| amount | number | Yes | Transaction amount in the smallest currency unit (e.g., cents) |
| currency | string | Yes | Three-letter ISO currency code (e.g., "TZS", "KES", "UGX") |
| reference | string | Yes | Your unique transaction reference |
| customer_email | string | Yes | Customer's email address |
| customer_phone | string | Yes | Customer's phone number in international format |
| callback_url | string | Yes | URL where we'll send transaction status updates |
| return_url | string | No | URL to redirect customer after payment completion |
| description | string | No | Description of the transaction item |
const axios = require('axios'); const FormData = require('form-data'); const createTransaction = async () => { const formData = new FormData(); formData.append('amount', '50000'); // 50,000 TZS formData.append('currency', 'TZS'); formData.append('reference', 'ORDER-123456'); formData.append('customer_email', 'customer@example.com'); formData.append('customer_phone', '+255712345678'); formData.append('callback_url', 'https://yourdomain.com/callback'); formData.append('return_url', 'https://yourdomain.com/success'); formData.append('description', 'Premium Plan Subscription'); const response = await axios.post( 'https://api.pluspesa.com/v2/transactions', formData, { headers: { ...formData.getHeaders(), 'Authorization': `Bearer ${accessToken}` } } ); return response.data; }; // Usage createTransaction() .then(data => console.log('Transaction created:', data)) .catch(error => console.error('Error:', error));
Callback
PlusPesa will send a POST request to your callback URL with the transaction status whenever there's an update. Your server must respond with a 200 OK status to acknowledge receipt.
const express = require('express'); const router = express.Router(); // Verify the signature to ensure the request is from PlusPesa const verifySignature = (req) => { const signature = req.headers['x-pluspesa-signature']; const payload = JSON.stringify(req.body); // Implement your signature verification logic here // Compare with HMAC-SHA256 hash of payload using your webhook secret return true; // Replace with actual verification }; router.post('/callback', (req, res) => { // Verify the request signature if (!verifySignature(req)) { return res.status(401).json({ error: 'Invalid signature' }); } const { transaction_id, reference, status, amount, currency } = req.body; // Update your database with the transaction status console.log(`Transaction ${reference} status: ${status}`); // Process based on status if (status === 'completed') { // Fulfill the order/service } else if (status === 'failed') { // Handle failed transaction } // Always respond with 200 OK res.status(200).json({ received: true }); }); module.exports = router;
Check Order Status
You can check the status of a transaction at any time by making a GET request to the transaction status endpoint. This is useful for verifying transactions when callbacks might have been missed.
import requests import json def check_transaction_status(reference, access_token): url = f"https://api.pluspesa.com/v2/transactions/{reference}" headers = { "Authorization": f"Bearer {access_token}", "Content-Type": "application/json" } response = requests.get(url, headers=headers) if response.status_code == 200: data = response.json() print(f"Status: {data['status']}") print(f"Amount: {data['amount']} {data['currency']}") return data else: print(f"Error: {response.status_code}") return None # Usage status = check_transaction_status("ORDER-123456", "your_access_token")
Create Sub Wallets
Sub wallets allow you to create separate balances for different departments, projects, or users within your organization. Each sub wallet has its own balance and transaction history while being managed under your main account.
<?php // Create a sub wallet for a department $url = "https://api.pluspesa.com/v2/wallets/sub"; $access_token = "your_access_token"; $data = [ "name" => "Marketing Department", "currency" => "TZS", "initial_balance" => 1000000, // 1,000,000 TZS "description" => "Budget for Q3 marketing campaigns", "permissions" => [ "send", "receive", "withdraw" ] ]; $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); curl_setopt($ch, CURLOPT_HTTPHEADER, [ "Authorization: Bearer $access_token", "Content-Type: application/json" ]); $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($http_code == 201) { $wallet = json_decode($response, true); echo "Sub wallet created successfully!\n"; echo "Wallet ID: " . $wallet['id'] . "\n"; echo "Balance: " . $wallet['balance'] . " " . $wallet['currency']; } else { echo "Error creating sub wallet: " . $response; } ?>
Disbursement
The disbursement API allows you to send money directly to mobile money wallets, bank accounts, or other payment methods supported by PlusPesa. This is ideal for payroll, vendor payments, refunds, and commissions.
import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; import org.json.JSONObject; public class PlusPesaDisbursement { public static void main(String[] args) throws Exception { String accessToken = "your_access_token"; String url = "https://api.pluspesa.com/v2/disbursements"; JSONObject payload = new JSONObject(); payload.put("amount", 75000); // 75,000 TZS payload.put("currency", "TZS"); payload.put("recipient_phone", "+255712345678"); payload.put("recipient_name", "John Doe"); payload.put("reference", "PAYROLL-OCT-001"); payload.put("description", "October salary payment"); payload.put("payment_method", "momo"); // momo, bank, card HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .header("Authorization", "Bearer " + accessToken) .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(payload.toString())) .build(); HttpClient client = HttpClient.newHttpClient(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); if (response.statusCode() == 201) { System.out.println("Disbursement successful!"); System.out.println(response.body()); } else { System.out.println("Disbursement failed with status: " + response.statusCode()); System.out.println(response.body()); } } }