CironetPay
The unified payment layer for the Cironet ecosystem. One gateway, one merchant identity, powering every product and client platform.
What is CironetPay?
CironetPay is a centrally hosted payment gateway developed and operated by Cironet Technologies. It sits between the applications that need to accept payments (Nodes) and the payment service providers (PSPs) that process them. It acts as the single, unified layer through which all payment activity in the Cironet ecosystem flows.
Powers payments inside CironetSmart ERP, Marketplace, and Messaging through a single internal API — no provider logic needed in each product.
A drop-in payment layer for platforms Cironet builds for clients. Clients accept payments via MoMo and Cards instantly without separate PSP onboarding.
In one sentence: CironetPay is the payment backbone of the Cironet ecosystem — one gateway, one merchant account per provider, powering every product Cironet builds and every client platform Cironet delivers.
The Problem
Accepting digital payments in Uganda and across Africa is complex. Every PSP has its own API, authentication mechanism, sandbox environment, and webhook format. For a technology company operating multiple products and building platforms for various clients, this creates significant overhead:
- Integration Duplication: Building the same MTN MoMo or PayPal integration repeatedly is inefficient.
- Credential Sprawl: Managing separate API keys across dozens of products is a security risk.
- Onboarding Friction: Clients often find PSP registration processes slow and inaccessible.
- Fragmented Records: Payment data lives in separate silos with no unified overview.
The Solution
The "Node" Principle
Any application connects to CironetPay as a node. Nodes send requests to CironetPay and receive notifications when payments complete. The node never interacts with a payment provider directly.
CironetPay centralizes infrastructure, maintenance, and compliance. A bug fixed or provider added in CironetPay is immediately reflected across all connected products and clients.
How It Works
Initiation
Node POSTs a request to /api/initiate.php with amount, currency, and provider.
Engine Processing
CironetPay records a Pending transaction and selects the specific Gateway class.
Provider Action
The PSP processes the payment (USSD push for MoMo or redirect for Cards).
Webhook/Callback
PSP notifies CironetPay of the outcome. CironetPay updates the status to Completed or Failed.
Node Notification
CironetPay sends a signed webhook to the Node's registered callback URL to finalize the order.
Merchant Identity Model
CironetPay operates on a single-merchant, multi-source model. Payment providers only ever see traffic from Cironet Technologies.
| Perspective | What they see | Why |
|---|---|---|
| Payment Providers | One merchant: Cironet Technologies. | Simplifies compliance and onboarding. Providers only deal with one trusted entity. |
| Inside CironetPay | Every transaction is tagged with its node_source. |
Allows for granular per-product and per-client reporting, billing, and reconciliation. |
Who It Serves
Cironet Products
Internal platforms owned by Cironet Technologies.
- CironetSmart ERP — Invoice & payroll
- CironetMarketplace — Storefront payments
- CironetMessaging — Top-ups & billing
- cironetug.com — Domains & hosting
Client Platforms
Solutions Cironet develops for external businesses.
- SACCO & Microfinance systems
- School Fees platforms
- NGO Donor management
- E-commerce custom builds
Core Capabilities
Multi-Provider Routing
Route to any of 8 PSPs via a single field in the API request.
Node Isolation
Every node has its own API key and isolated transaction history.
Signed Callbacks
HMAC-SHA256 signatures ensure Node-side webhook integrity.
System-Wide Audit
Central ledger for all payments across the entire ecosystem.
Technical Architecture
Built with PHP 8.1+ on a standard LAMP stack. Hosted at pay.cironetug.com.
Component Overview
| Component | Responsibility |
|---|---|
| CironetPay Engine | Core logic, database orchestration, and gateway selection. |
| Gateways | One class per PSP (e.g., MtnGateway) handling API specifics. |
| API Layer | REST-like endpoints for Initiation and Verification. |
| Webhook Layer | Receives and normalizes provider notifications. |
Installation & Setup
Database Schema
CironetPay requires two primary tables: transactions and nodes.
-- Core Transactions Table
CREATE TABLE transactions (
id INT AUTO_INCREMENT PRIMARY KEY,
transaction_ref VARCHAR(100) UNIQUE,
external_id VARCHAR(100),
node_source VARCHAR(50),
merchant_id INT,
provider VARCHAR(50),
amount DECIMAL(20,2),
currency VARCHAR(10),
status ENUM('Pending', 'Completed', 'Failed', 'Cancelled'),
provider_reference VARCHAR(255),
raw_log JSON,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Configuration
All sensitive credentials live in the .env file. Never commit this file.
| Variable | Description |
|---|---|
DB_HOST / NAME / USER / PASS | MySQL connection details |
CIRONET_API_KEY_{NODE} | Keys for internal product nodes |
WEBHOOK_OUTGOING_SECRET | Secret used to sign callbacks sent to nodes |
{PSP}_API_KEY / SECRET | Credentials for individual payment providers |
Security: If a node's API key is compromised, it must be rotated immediately in both the .env file and the nodes table.
Database Schema Details
The nodes table is the source of truth for all authorized applications.
| Column | Purpose |
|---|---|
node_name | Slug identifier (e.g., smart_erp_node) |
api_key | Secret key used in the X-CironetPay-Key header |
webhook_url | Node endpoint where CironetPay sends payment results |
status | Active or Suspended |
Authentication
Every API request must include a valid key in the header:
X-CironetPay-Key: cp_live_smart_8823x91
API — Initiate Payment
POST /api/initiate.php
JSON Body:
{
"amount": 50000,
"currency": "UGX",
"provider": "mtn",
"external_id": "INV-101",
"payer_data": { "phone": "25677..." }
}
API — Verify Status
GET /api/verify.php?provider={slug}&ref={provider_ref}
Checks current transaction status directly with the provider.
API — Webhook Receiver
POST /api/webhook.php?provider={slug}
This is the URL registered with PSPs. It receives raw notifications and forwards them to the Node.
Signature Security
CironetPay signs all outgoing webhooks using the WEBHOOK_OUTGOING_SECRET.
Nodes must verify this signature to prevent spoofing.
// Node-side Verification (PHP)
$received_sig = $_SERVER['HTTP_X_CIRONETPAY_SIGNATURE'];
$payload = file_get_contents('php://input');
$expected_sig = hash_hmac('sha256', $payload, $secret);
if (!hash_equals($expected_sig, $received_sig)) {
die("Invalid Signature");
}
Supported Providers
| Slug | Provider | Type |
|---|---|---|
mtn | MTN MoMo | Mobile Money (UG) |
airtel | Airtel Money | Mobile Money (UG) |
yo | Yo! Payments | Multi-MoMo (UG) |
paypal | PayPal | Cards/Global |
pesapal | PesaPal | Card/MoMo (EA) |
dpo | DPO Group | Card/Pan-Africa |
interswitch | Interswitch | Cards |
network | Network Intl. | Cards |
Client Onboarding
Key Generation
Generate a secure key using bin2hex(random_bytes(16)).
Node Registration
Insert the node name, key, and client callback URL into the nodes table.
Environment Config
Update the Node's application to use the new API key.
Troubleshooting
| Symptom | Fix |
|---|---|
| 401 Unauthorized | Verify the X-CironetPay-Key header matches the nodes table. |
| Stuck in Pending | Use /api/verify.php to poll status manually. Check log for PSP errors. |
| Signature Mismatch | Confirm WEBHOOK_OUTGOING_SECRET is identical in both systems. |
Roadmap
- Admin Dashboard: Visual interface for management reporting across all nodes.
- Per-Node Billing: Automated generation of commission statements for clients.
- Refunds API: Unified endpoint for initiating refunds across providers.
- Bank Direct: Direct Stanbic and Equity bank transfer integrations.