Skip to main content
The NetPOS REST API provides HTTP endpoints for user authentication, transaction management, terminal configuration, and data retrieval.

Base URLs

NetPOS uses multiple API base URLs for different services:
ServiceBase URLDescription
Main APIhttps://netpos.netpluspay.com/Core POS operations
Bills/Stormhttps://storm.netpluspay.com/Bill payments and Storm services
Cash Servicehttps://netpos.netpluspay.com/api/cash/Cash transaction tracking
Zenith PBThttps://api.zenith-pbt.netpluspay.com/Zenith Pay-by-Transfer
QR Paymentshttps://masterpassqr.netpluspay.com/api/v1/QR payment processing
SMS Servicehttps://sms.netpluspay.comSMS notifications

Authentication

App Token

Obtain application-level authentication token:
import com.google.gson.JsonObject
import com.woleapp.netpos.network.StormApiClient

val credentials = JsonObject().apply {
    addProperty("client_id", "your_client_id")
    addProperty("client_secret", "your_client_secret")
}

StormApiClient.getBillsInstance()
    .appToken(credentials)
    .subscribe { response, error ->
        response?.let {
            val token = it.token
            // Store token for subsequent requests
        }
    }
Endpoint: POST /api/token Request Body:
client_id
string
required
Application client ID
client_secret
string
required
Application client secret
Response:
token
string
JWT authentication token
expires_in
number
Token expiration time in seconds

User Authentication

Authenticate a user and obtain user token:
val credentials = JsonObject().apply {
    addProperty("username", "[email protected]")
    addProperty("password", "password123")
    addProperty("terminal_id", "2058XU23")
}

StormApiClient.getBillsInstance()
    .userToken(credentials)
    .subscribe { response, error ->
        response?.let {
            val userToken = it.token
            val user = it.user
            // Store user session
        }
    }
Endpoint: POST /api/auth Request Body:
username
string
required
User email or username
password
string
required
User password
terminal_id
string
required
Terminal ID for this session
Response:
token
string
User JWT token
user
object
User profile data including terminal_id, business_name, netplus_id

Transactions

Log Transaction (Before NIBSS)

Log transaction details before connecting to NIBSS:
val transactionData = TransactionToLogBeforeConnectingToNibbs(
    terminalId = "2058XU23",
    amount = "500000",  // Amount in kobo
    stan = "000123",
    rrn = "202112011234567",
    cardPan = "506066******1234",
    cardExpiry = "12/25",
    timestamp = System.currentTimeMillis()
)

StormApiClient.getStormApiLoginInstance()
    .logTransactionBeforeConnectingToNibss(transactionData)
    .subscribe { response, error ->
        response?.let {
            val transactionId = it.id
        }
    }
Endpoint: POST /pos_transaction Headers:
Authorization
string
required
Bearer token from user authentication
Request Body:
terminalId
string
required
Terminal identifier
amount
string
required
Transaction amount in kobo (minor units)
stan
string
required
System Trace Audit Number
rrn
string
required
Retrieval Reference Number
cardPan
string
Masked card PAN
cardExpiry
string
Card expiry date (MM/YY)

Update Transaction (After NIBSS)

Update transaction with response from NIBSS:
val rrn = "202112011234567"
val updateData = DataToLogAfterConnectingToNibss(
    responseCode = "00",
    responseMessage = "Approved",
    authCode = "123456",
    isoString = "0200...",
    responseTime = System.currentTimeMillis()
)

StormApiClient.getStormApiLoginInstance()
    .updateLogAfterConnectingToNibss(rrn, updateData)
    .subscribe { response, error ->
        response?.let {
            // Transaction updated
        }
    }
Endpoint: PUT /pos_transaction/{rrn} Path Parameters:
rrn
string
required
Retrieval Reference Number from initial transaction log
Request Body:
responseCode
string
required
ISO 8583 response code (“00” for approved)
responseMessage
string
required
Human-readable response message
authCode
string
Authorization code from issuer
isoString
string
Full ISO 8583 message for audit

Get Transactions

Retrieve transactions by terminal and date range:
val terminalId = "2058XU23"
val from = "2021-12-01 00:00:00"
val to = "2021-12-31 23:59:59"
val page = 1
val pageSize = 50

StormApiClient.getStormApiLoginInstance()
    .getTransactionsFromNewService(terminalId, from, to, page, pageSize)
    .subscribe { response, error ->
        response?.let {
            val transactions = it.data
            val totalPages = it.totalPages
        }
    }
Endpoint: GET /pos_transactions/terminal/{terminalId}/btw/{from}/{to}/{page}/{pageSize} Path Parameters:
terminalId
string
required
Terminal identifier
from
string
required
Start date (format: YYYY-MM-DD HH:mm:ss)
to
string
required
End date (format: YYYY-MM-DD HH:mm:ss)
page
number
required
Page number (1-based)
pageSize
number
required
Number of records per page
Response:
data
array
Array of transaction objects
totalPages
number
Total number of pages
currentPage
number
Current page number

Agent Management

Get Agent Details

val stormId = "AGT123456"

StormApiClient.getInstance()
    .getAgentDetails(stormId)
    .subscribe { user, error ->
        user?.let {
            val terminalId = it.terminal_id
            val businessName = it.business_name
        }
    }
Endpoint: GET /api/agents/{stormId} Path Parameters:
stormId
string
required
Storm/NetPlus agent ID
Response:
netplus_id
string
Agent’s NetPlus ID
terminal_id
string
Assigned terminal ID
business_name
string
Business name
email
string
Agent email

NIP (Bank Transfer)

Get NIP Notifications

Retrieve NIP transfer notifications:
val terminalId = "2058XU23"
val from = "2021-12-01"
val to = "2021-12-31"
val clientId = "85522f45-e459-4548-8b20-3a922196c515"
val accessCode = "a14014e18e2cffc4d74e150ed68a472bd94189db82d374306d5b307dc7620f20"

StormApiClient.getInstance()
    .getNotifications(terminalId, from, to, clientId, accessCode)
    .subscribe { notifications, error ->
        notifications?.let {
            it.forEach { notification ->
                val amount = notification.amount
                val reference = notification.referenceNo
            }
        }
    }
Endpoint: GET /api/nip-notifications Headers:
X-CLIENT-ID
string
required
NIP client identifier
X-ACCESSCODE
string
required
NIP access code
Query Parameters:
terminalId
string
required
Terminal identifier
from
string
Start date (YYYY-MM-DD)
to
string
End date (YYYY-MM-DD)
referenceNo
string
Specific transaction reference (alternative to date range)

Get Session Code

Generate session code for NIP transfers:
StormApiClient.getNipInstance()
    .getSessionCode()
    .subscribe { sessionCode, error ->
        sessionCode?.let {
            val code = it.code
            val expiresAt = it.expiresAt
        }
    }
Endpoint: GET /api/sessionCode Response:
code
string
6-digit session code
expiresAt
string
Expiration timestamp

Cash Transactions

Add Cash Transaction

val cashTransaction = JsonObject().apply {
    addProperty("terminalId", "2058XU23")
    addProperty("amount", 50000)  // In kobo
    addProperty("type", "CASH_IN")
    addProperty("reference", "CASH202112011234")
    addProperty("timestamp", System.currentTimeMillis())
}

StormApiClient.getCashInstance()
    .addCashTransaction(cashTransaction)
    .subscribe { response, error ->
        response?.let {
            // Cash transaction logged
        }
    }
Endpoint: POST /addTransactions Request Body:
terminalId
string
required
Terminal identifier
amount
number
required
Amount in kobo
type
string
required
Transaction type: CASH_IN or CASH_OUT
reference
string
required
Unique transaction reference

QR Payments

Pay with QR

val qrPaymentRequest = PayWithQrRequest(
    qrData = "scanned_qr_code_data",
    amount = 500000,  // In kobo
    terminalId = "2058XU23"
)

val qrService = Retrofit.Builder()
    .baseUrl("https://masterpassqr.netpluspay.com/api/v1/")
    .build()
    .create(QrPaymentService::class.java)

qrService.payWithQr(qrPaymentRequest)
    .subscribe { response, error ->
        response?.let {
            if (it.isSuccessful) {
                // Payment successful
            }
        }
    }
Endpoint: POST /contactlessQr Request Body:
qrData
string
required
Scanned QR code data
amount
number
required
Payment amount in kobo
terminalId
string
required
Terminal identifier

Password Management

Reset Password

val resetPayload = JsonObject().apply {
    addProperty("email", "[email protected]")
    addProperty("terminal_id", "2058XU23")
}

StormApiClient.getBillsInstance()
    .passwordReset(resetPayload)
    .subscribe { response, error ->
        response?.let {
            // Password reset email sent
        }
    }
Endpoint: POST /api/passwordReset Request Body:
email
string
required
User email address
terminal_id
string
Terminal ID (optional)

API Client Configuration

NetPOS uses Retrofit with custom interceptors:
StormApiClient.kt
private fun getOkHttpClient() =
    OkHttpClient.Builder()
        .addInterceptor(TokenInterceptor())
        .addInterceptor(HttpLoggingInterceptor().apply {
            level = HttpLoggingInterceptor.Level.BODY
        })
        .connectTimeout(120, TimeUnit.SECONDS)
        .writeTimeout(120, TimeUnit.SECONDS)
        .readTimeout(120, TimeUnit.SECONDS)
        .build()

class TokenInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        var request = chain.request()
        val headersInReq = request.headers
        
        if (headersInReq["Authorization"].isNullOrEmpty()) {
            Prefs.getString(PREF_USER_TOKEN, null)?.let {
                request = request.newBuilder()
                    .addHeader("Authorization", "Bearer $it")
                    .build()
            }
        }
        
        return chain.proceed(request)
    }
}

Error Handling

API errors follow standard HTTP status codes:
Status CodeMeaning
200Success
400Bad Request - Invalid parameters
401Unauthorized - Invalid or expired token
403Forbidden - Insufficient permissions
404Not Found - Resource doesn’t exist
500Internal Server Error

Next Steps

Webhooks

Set up webhook notifications for real-time events

Build docs developers (and LLMs) love