Selcom
Selcom

Selcom Business API Gateway

The Selcom Business API Gateway provides a secure, REST-based interface that allows your applications to programmatically initiate payments, check account balances, and track transaction statuses — all from a single integration point.

Secure by Design

Every request is authenticated using an HMAC-based digest signature combining your API key, secret, and a time-bounded timestamp.

Real-time Processing

Transactions are processed in real time via the Selcom infrastructure, with instant status tracking through a dedicated status endpoint.

Multi-channel Support

Send money to bank accounts, mobile wallets, or other Selcom Business accounts — all through a unified API interface.

Sandbox URL: https://sandbox.selcom.business — All endpoints listed in this documentation are relative to this base URL.
Production URL: https://api.selcom.business/v1 — All endpoints listed in this documentation are relative to this base URL.

Getting Started

  1. Obtain API Credentials

    Log in to Selcom Business and navigate to My Account → API Credentials to generate your Signing Keys.

  2. Build Request Headers

    Compute the digest. See Authorization and Signature Generation for the formulas.

    api-key timestamp digest signed-fields
  3. Make Your First API Call

    Try the Balance API to verify your credentials and Bearer token are working correctly.

Overview

Client Packages

Following are links to the client library code repositories on GitHub and ways to install using package managers. For more information and source code visit the GitHub pages.

PHP

Installation
bash
composer require selcom/selcom-apigw-client
GitHub Link

PHP GitHub Repository

JAVA

Installation
bash
io.github.selcompaytechltd/apigwClient
Get the snippet for your package manager from https://central.sonatype.com/artifact/io.github.selcompaytechltd/apigwClient/1.0.3/overview

or search for io.github.selcompaytechltd/apigwClient using your package manager.

GitHub Link

JAVA GitHub Repository

C#

Installation
bash
dotnet add package selcom-apigw-client
GitHub Link

C# GitHub Repository

Python

Installation
bash
pip install selcom_apigw_client
GitHub Link

Python GitHub Repository

Node.js

Installation
bash
npm i selcom-apigw-client
GitHub Link

Node.js GitHub Repository

Security

Authorization

The API Gateway uses RSA-SHA256 asymmetric signing for authentication. Your api-key and RSA private key are available from the credentials panel — both are required to sign every request.

How It Works

Each request must include four headers: your api-key, a UTC ISO 8601 timestamp, a computed digest, and a signed-fields list. The server verifies the digest using your stored RSA public key and rejects requests with an invalid signature.

Signing String & digest Format

signing_string = "timestamp=<timestamp>&field1=value1&field2=value2&..."
digest = Base64( RSA_SHA256(signing_string, PrivateKey) )
  • timestamp is always first in the signing string.
  • Fields follow in the exact order listed in the signed-fields header.
  • Values must match the request payload exactly — no extra spaces.
  • timestamp format is ISO 8601 UTC with milliseconds (e.g. 2026-05-27T06:01:03.273Z).
  • The timestamp header value and the value in the signing string must be identical.

Implementation Examples

PHP
$apiKey     = 'YOUR_API_KEY';
$privateKey = file_get_contents('/path/to/private_key.pem');
$timestamp  = (new DateTime('now', new DateTimeZone('UTC')))->format('Y-m-d\TH:i:s.v\Z');

// Request fields (POST body or GET query params)
$fields = [
    'transId'          => '1234567899',
    'recipientFiCode'  => 'SELCOM',
    'recipientAccount' => '255711410410',
    'amount'           => 100,
];

$signedFields  = implode(',', array_keys($fields));
$signingString = 'timestamp=' . $timestamp;
foreach ($fields as $key => $value) {
    $signingString .= '&' . $key . '=' . $value;
}

openssl_sign($signingString, $signature, $privateKey, OPENSSL_ALGO_SHA256);
$digest = base64_encode($signature);

$headers = [
    'api-key: '       . $apiKey,
    'timestamp: '     . $timestamp,
    'digest: '        . $digest,
    'signed-fields: ' . $signedFields,
    'content-type: application/json',
];
Python
import base64
from datetime import datetime, timezone
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding

api_key = 'YOUR_API_KEY'
now     = datetime.now(timezone.utc)
timestamp = now.strftime('%Y-%m-%dT%H:%M:%S.') + f"{now.microsecond // 1000:03d}Z"

with open('/path/to/private_key.pem', 'rb') as f:
    private_key = serialization.load_pem_private_key(f.read(), password=None)

fields = {
    'transId':          '1234567899',
    'recipientFiCode':  'SELCOM',
    'recipientAccount': '255711410410',
    'amount':           100,
}

signed_fields  = ','.join(fields.keys())
signing_string = 'timestamp=' + timestamp + '&' + \
                 '&'.join(f"{k}={v}" for k, v in fields.items())

signature = private_key.sign(signing_string.encode(), padding.PKCS1v15(), hashes.SHA256())
digest    = base64.b64encode(signature).decode()

headers = {
    'api-key':       api_key,
    'timestamp':     timestamp,
    'digest':        digest,
    'signed-fields': signed_fields,
    'content-type':  'application/json',
}
JavaScript / Node.js
const crypto = require('crypto');
const fs     = require('fs');

const apiKey     = 'YOUR_API_KEY';
const privateKey = fs.readFileSync('/path/to/private_key.pem', 'utf8');
const timestamp  = new Date().toISOString(); // e.g. 2026-05-27T06:01:03.273Z

const fields = {
    transId:          '1234567899',
    recipientFiCode:  'SELCOM',
    recipientAccount: '255711410410',
    amount:           100,
};

const signedFields  = Object.keys(fields).join(',');
const signingString = 'timestamp=' + timestamp + '&' +
    Object.entries(fields).map(([k, v]) => `${k}=${v}`).join('&');

const sign   = crypto.createSign('RSA-SHA256');
sign.update(signingString, 'utf8');
const digest = sign.sign(privateKey, 'base64');

const headers = {
    'api-key':       apiKey,
    'timestamp':     timestamp,
    'digest':        digest,
    'signed-fields': signedFields,
    'content-type':  'application/json',
};
Security reminder: Never expose your RSA private key in client-side code, mobile apps, or public repositories. Store it securely on your server. The timestamp header value must be identical to the one used in the signing string — even a single character difference will fail verification.
Reference

Request Headers

Every request to the API Gateway must include the following HTTP headers. Missing or malformed headers will result in a 400 Bad Request response.

Header Required Format / Example Description
api-key Required a1b2c3d4e5... Your unique API key obtained from the credentials panel.
timestamp Required 2026-05-27T06:01:03.273Z Current UTC time in ISO 8601 format with milliseconds. Must be identical to the value used in the signing string.
digest Required Base64 encoded string RSA-SHA256 signature of the signing string, Base64-encoded. See Authorization for the formula.
signed-fields Required transId,amount,msisdn Comma-separated list of request field names (POST body or GET query params) in the exact same order as the signing string. Do not include timestamp.
Content-Type Required for POST application/json Must be application/json for all POST endpoints.
Accept Optional application/json Recommended. All responses are returned as JSON.

Signing String Generation

The digest is an RSA-SHA256 signature over a canonical signing string built from the timestamp and the request fields listed in signed-fields.

Signing String & Digest Format
signing_string = "timestamp=" + timestamp + "&" + field1 + "=" + value1 + "&" + ...
digest = Base64( RSA_SHA256(signing_string, PrivateKey) )
  • timestamp is always first, even though it is not listed in signed-fields.
  • Fields follow in the exact order listed in the signed-fields header.
  • Values must match the request payload exactly — no extra spaces or type conversions.
  • For GET requests, use query parameter names and values.
  • For POST requests, use JSON body field names and values.
Implementation Examples
PHP
$apiKey     = 'YOUR_API_KEY';
$privateKey = file_get_contents('/path/to/private_key.pem');
$timestamp  = (new DateTime('now', new DateTimeZone('UTC')))->format('Y-m-d\TH:i:s.v\Z');

$fields = [
    'transId'          => '1234567899',
    'recipientFiCode'  => 'SELCOM',
    'recipientAccount' => '255711410410',
    'recipientName'    => 'John Doe',
    'amount'           => 100,
    'purpose'          => 'FT',
];

$signedFields  = implode(',', array_keys($fields));
$signingString = 'timestamp=' . $timestamp;
foreach ($fields as $key => $value) {
    $signingString .= '&' . $key . '=' . $value;
}

openssl_sign($signingString, $signature, $privateKey, OPENSSL_ALGO_SHA256);
$digest = base64_encode($signature);

$headers = [
    'api-key: '       . $apiKey,
    'timestamp: '     . $timestamp,
    'digest: '        . $digest,
    'signed-fields: ' . $signedFields,
    'content-type: application/json',
];
Python
import base64
from datetime import datetime, timezone
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding

api_key = 'YOUR_API_KEY'
now     = datetime.now(timezone.utc)
timestamp = now.strftime('%Y-%m-%dT%H:%M:%S.') + f"{now.microsecond // 1000:03d}Z"

with open('/path/to/private_key.pem', 'rb') as f:
    private_key = serialization.load_pem_private_key(f.read(), password=None)

fields = {
    'transId':          '1234567899',
    'recipientFiCode':  'SELCOM',
    'recipientAccount': '255711410410',
    'recipientName':    'John Doe',
    'amount':           100,
    'purpose':          'FT',
}

signed_fields  = ','.join(fields.keys())
signing_string = 'timestamp=' + timestamp + '&' + \
                 '&'.join(f"{k}={v}" for k, v in fields.items())

signature = private_key.sign(signing_string.encode(), padding.PKCS1v15(), hashes.SHA256())
digest    = base64.b64encode(signature).decode()

headers = {
    'api-key':       api_key,
    'timestamp':     timestamp,
    'digest':        digest,
    'signed-fields': signed_fields,
    'content-type':  'application/json',
}
JavaScript / Node.js
const crypto = require('crypto');
const fs     = require('fs');

const apiKey     = 'YOUR_API_KEY';
const privateKey = fs.readFileSync('/path/to/private_key.pem', 'utf8');
const timestamp  = new Date().toISOString(); // e.g. 2026-05-27T06:01:03.273Z

const fields = {
    transId:          '1234567899',
    recipientFiCode:  'SELCOM',
    recipientAccount: '255711410410',
    recipientName:    'John Doe',
    amount:           100,
    purpose:          'FT',
};

const signedFields  = Object.keys(fields).join(',');
const signingString = 'timestamp=' + timestamp + '&' +
    Object.entries(fields).map(([k, v]) => `${k}=${v}`).join('&');

const sign   = crypto.createSign('RSA-SHA256');
sign.update(signingString, 'utf8');
const digest = sign.sign(privateKey, 'base64');

const headers = {
    'api-key':       apiKey,
    'timestamp':     timestamp,
    'digest':        digest,
    'signed-fields': signedFields,
    'content-type':  'application/json',
};

Sample Raw Request (Protected Endpoint)

HTTP
POST /v1/transaction/process HTTP/1.1
Host: api.selcom.business
api-key: a1b2c3d4e5f6g7h8i9j0
timestamp: 2026-05-27T06:01:03.273Z
digest: Base64EncodedRSASignature==
signed-fields: transId,recipientFiCode,recipientAccount,recipientName,amount,purpose,remarks
content-type: application/json
Accept: application/json

{
    "transId": "1234567899",
    "recipientFiCode": "SELCOM",
    "recipientAccount": "255711410410",
    "recipientName": "John Doe",
    "amount": 100,
    "purpose": "FT",
    "remarks": "Test transfer"
}

Error Responses for Header Failures

HTTP Status error_code Cause
400 612 One or more required headers are missing.
401 613 API key not found or inactive.
401 631 digest does not match — invalid RSA signature.
403 611 Client IP is not whitelisted for this credential.
503 613 Authentication service is temporarily unavailable — retry the request after a short delay.
Reference

Purpose Codes

Every transaction request requires a purpose field. Use the Code value from the table below. Only active purposes are listed.

# Purpose Name Code
1 Payment PAYMENT
2 Airfare AIRFARE
3 Airtime AIRTIME
4 Betting and gaming BETTING
5 Business expense BUSINESSEXPENSES
6 Car repair CARREPAIR
7 Cash CASH
8 Contribution CONTRIBUTE
9 Contributions CONTRIBUTES
10 Dining DINING
11 Donation DONATION
12 Dry cleaning DRYCLEANING
13 Education EDUCATION
14 Entertainment ENTERTAINMENT
15 Fitness FITNESS
16 Fuel FUEL
17 Funds transfer FT
18 General repairs GENERALREPAIRS
19 General/uncategorized GENERAL
20 Gift GIFT
21 Gift Cards GIFTCARD
22 Government payment GOV
23 Groceries and essentials GROCERIES
24 Health and fitness HEALTH
25 House repair HOUSEREPAIR
26 Insurance INSURANCE
27 Internet and broadband INTERNET
28 Investments INVEST
29 Legal fees LEGALFEES
30 Loan repayment LOAN
31 Logistics & Shipment SHIPMENT
32 Lottery LOTTERY
33 Medical Bills MEDICALBILLS
34 Office/business expense OFFICEEXPENSE
35 Personal care PERSONALCARE
36 Renewable energy RENERGY
37 Salary and other income INCOME
38 Salary or wages SALARYOFWAGES
39 Savings SAVINGS
40 Shopping SHOPPING
41 Social contribution SOCIALCONTRIBUSTION
42 Stocks & Securities STOCKS
43 Taxes and fines TAX
44 Transport TRANSPORT
45 Travel TRAVEL
46 TV subscription TV
47 Utility payment UTILITY
Use the exact Code value in the purpose field of your transaction request. Invalid codes will result in a validation error (error_code: 651).
Endpoint

Balance API

Retrieve the current available balance for a linked organization account.

POST /v1/balance

Request Body

Parameter Type Required Description
account_number string Required The account number associated with your API credentials. Must be an active B2C account registered under your organization.

Response Fields

Field Type Description
success boolean true on success, false on failure.
error_code integer 1 on success; negative value on error (see Error Codes).
message string Human-readable status message.
data.account_number string The queried account number.
data.currency string Account currency (e.g., TZS).
data.available_balance float Current available balance in the account.
data.active boolean true if the account is currently active; false otherwise.
result string Transaction result based on actual status. See API Response — Result column.
resultcode string Result code based on actual transaction status. See API Response — Errorcode column.

Example

Request
{
    "account_number": "0123456789"
}
Response 200 OK
{
    "success": true,
    "error_code": 1,
    "message": "Balance fetched successfully.",
    "result": "SUCCESS",
    "resultcode": "000",
    "data": {
        "account_number": "000011636",
        "currency": "TZS",
        "available_balance": 100000000,
        "active": true
    }
}
Error Response 400
{
    "success": false,
    "error_code": 641,
    "message": "Invalid or unauthorized account number.",
    "result": "FAIL",
    "resultcode": "641",
    "data": []
}
Webhook

Webhook (Callback)

Selcom sends a POST request to your registered callback URL when an API-initiated transaction completes successfully. Only the parameters you select will be included in the payload. For TIPS / TISS transactions, the callback fires after final network confirmation is received.

Callback URL *

A publicly reachable HTTPS endpoint on your server. Selcom will POST the transaction payload to this URL on every successful transaction.

Configuration Fields

Field Type Required Description
callback_url string Required The HTTPS URL that will receive the POST callback. Maximum 500 characters.
callback_parameters array Required The payload fields to include in the callback. At least one parameter must be selected.

Callback Payload

Every callback always includes reference_id and status. All other fields are included only if selected in the callback configuration.

Payload Fields

Field Type Description
reference_id string Your unique transaction reference ID from the original API request. Always included.
status string Always SUCCESS. Callbacks are only sent for successful transactions. Always included.
sender_account_name string Name of the sending (debit) account.
sender_account_number string Account number of the sender.
recipient_name string Name of the transaction recipient.
recipient_account_number string Destination account number or phone number of the recipient.
amount numeric Principal transaction amount excluding charges.
charges numeric Transaction charges applied. May be 0 if no charges apply.
selcom_receipt string Selcom-issued receipt number for the transaction.

Example

Callback POST (to your server)
{
    "reference_id": "2024061500123",
    "status": "SUCCESS",
    "sender_account_name": "Acme Limited",
    "sender_account_number": "0000123456",
    "recipient_name": "John Doe",
    "recipient_account_number": "255712345678",
    "amount": 50000,
    "charges": 500,
    "selcom_receipt": "202406150001"
}
Endpoint

Transaction API

Initiate a fund transfer, look up a recipient account before transferring, or query the status of a previously submitted transaction. The debit account is automatically resolved from your API credentials.

Transaction Process

POST /v1/transaction/process

Request Body

Parameter Type Required Description
transId string Required Your unique transaction reference ID. Must be unique across all transactions. Used for idempotency and status tracking.
recipientFiCode string Required Destination institution code (bank, wallet, or SELCOM for internal transfers). See destination codes below.
recipientAccount string Required Recipient account number or phone number depending on the recipientFiCode.
recipientName string Required Recipient full name (max 100 characters).
amount numeric Required Transaction amount. Must be at least 1.
purpose string Required Transaction purpose code. See Purpose Codes.
remarks string Optional Free-text remark (max 140 characters). Appears on statements.

Response Fields

Field Type Description
success boolean true on success.
error_code integer 1 on success; negative on error.
message string Human-readable status message.
data.trans_id string Your unique transId for status tracking.
data.selcom_receipt string Selcom internal transaction identifier.
data.status string Initial status: ACCEPTED (async) or COMPLETED (sync). See Transaction Status Values.
data.amount float Transaction amount.
data.currency string Transaction currency.
result string Transaction result based on actual status. See API Response — Result column.
resultcode string Result code based on actual transaction status. See API Response — Errorcode column.

Account Lookup

GET /v1/account/lookup

Look up a recipient account before initiating a transfer. Returns the account holder name, applicable charges, and operator details.

Query Parameters

Parameter Type Required Description
bank string Required Destination institution code (bank, wallet, or SELCOM). See destination codes below.
account string Required Recipient account number or phone number to look up.
transId string Required Unique reference ID for this lookup request.
amount numeric Optional Transfer amount. When provided, the response includes charge calculations for that amount.

Response Fields

Field Type Description
success boolean true on success.
error_code integer 1 on success; negative on error.
message string Human-readable status message.
transId string The reference ID you sent in the request.
resultcode string 000 on success.
data.bank string Institution code used in the lookup.
data.account string Recipient account number used in the lookup.
data.accountName string Recipient account holder name.
data.operator string Institution or operator name.
data.charges array Breakdown of applicable transaction charges.
data.totalCharges float Total of all applicable charges.
data.categoryCode string Category code returned by the bridge.
result string Transaction result based on actual status. See API Response — Result column.
resultcode string Result code based on actual transaction status. See API Response — Errorcode column.

Transaction Status

GET /v1/transaction/query

Query the status and details of a previously submitted transaction using your transId.

Query Parameters

Parameter Type Required Description
transId string Required The unique transaction reference ID submitted in the process request.

Response Fields

Field Type Description
success boolean true on success.
error_code integer 1 on success; negative on error.
message string Human-readable status message.
data.transId string Your transaction reference ID.
data.status string ACCEPTED, COMPLETED, or FAILED.
data.amount float Transaction amount.
data.currency string Transaction currency.
data.selcomReceipt string Selcom internal transaction identifier.
data.transDatetime string Transaction datetime (Y-m-d H:i:s).
data.senderAccount string Sender account number (resolved from your API credentials).
data.senderName string Sender account name (resolved from your API credentials).
result string Transaction result based on actual status. See API Response — Result column.
resultcode string Result code based on actual transaction status. See API Response — Errorcode column.

Destination Shortcodes

Destination Name Destination Shortcode Reference Type Lookup
Selcom Bank/Selcom Pesa/Selcom Business SELCOM NUMERIC Enabled
Absa Bank ABSA NUMERIC Enabled
Access Bank BANCABC NUMERIC Enabled
Akiba Bank ACB NUMERIC Enabled
Amana Bank AMANA NUMERIC Enabled
Azania Bank AZANIA NUMERIC Enabled
Bank of Africa BOA NUMERIC Enabled
Bank of Baroda BOBTZ NUMERIC Enabled
Bank of India BOI NUMERIC Enabled
Bank of Tanzania BOT NUMERIC No
Canara Bank CANARA NUMERIC Enabled
Citi Bank CITI NUMERIC Enabled
CRDB Bank CRDB ALPHANUMERIC Enabled
DCB Commercial Bank DCB NUMERIC Enabled
Diamond Trust Bank DTB NUMERIC Enabled
Ecobank ECOBANK NUMERIC Enabled
Equity Bank EQUITY NUMERIC Enabled
Exim Bank EXIM NUMERIC Enabled
Finca Microfinance Bank FINCA NUMERIC Enabled
Guaranty Trust Bank GTBANK NUMERIC Enabled
Habib African Bank HABIB NUMERIC Enabled
I&M Bank IMBANK NUMERIC Enabled
International Commercial Bank ICB NUMERIC Enabled
KCB Bank KCB NUMERIC Enabled
Letshego Bank LETSHEGO NUMERIC Enabled
Maendeleo Bank MAENDELEO NUMERIC Enabled
Mkombozi Commercial Bank MKOMBOZI NUMERIC Enabled
MUCOBA Bank MUCOBA NUMERIC Enabled
Mwalimu Commercial Bank MWALIMU NUMERIC Enabled
Mwanga Hakika Bank MWANGA NUMERIC Enabled
National Bank of Commerce NBC NUMERIC Enabled
NCBA Bank NCBA NUMERIC Enabled
NMB Bank NMB NUMERIC Enabled
People's Bank of Zanzibar PBZ NUMERIC Enabled
Stanbic Bank STANBIC NUMERIC Enabled
Standard Chartered Bank SCB NUMERIC Enabled
Tanzania Commercial Bank TCB NUMERIC Enabled
Uchumi Commercial Bank UCHUMI NUMERIC Enabled
United Bank for Africa UBA NUMERIC Enabled
Airtel Money AIRTELMONEY NUMERIC Enabled
Halo Pesa HALOPESA NUMERIC Enabled
Mixx by Yas MIXXBYYAS NUMERIC Enabled
TTCL Pesa TTCLPESA NUMERIC Enabled
Vodacom M-pesa MPESA NUMERIC Enabled
Example

Sample Response

Examples

Bank Transfer
Request
{
    "transId": "TXN20250715093045ABC",
    "recipientFiCode": "CRDB",
    "recipientAccount": "01234567890",
    "recipientName": "John Doe",
    "amount": 50000,
    "purpose": "SALARY",
    "remarks": "Monthly salary payment"
}
Response 200 OK
{
    "success": true,
    "error_code": 1,
    "message": "Transaction processed successfully.",
    "result": "INPROGRESS",
    "resultcode": "111",
    "data": {
        "trans_id": "TXN20250715093045ABC",
        "selcom_receipt": "SLK-987654321",
        "status": "ACCEPTED",
        "amount": 50000,
        "currency": "TZS"
    }
}
Wallet Transfer
Request
{
    "transId": "TXN20250715093210XYZ",
    "recipientFiCode": "MPESA",
    "recipientAccount": "255712345678",
    "recipientName": "Jane Smith",
    "amount": 10000,
    "purpose": "VENDOR",
    "remarks": "Payment for services"
}
Response 200 OK
{
    "success": true,
    "error_code": 1,
    "message": "Transaction processed successfully.",
    "result": "INPROGRESS",
    "resultcode": "111",
    "data": {
        "trans_id": "TXN20250715093210XYZ",
        "selcom_receipt": "SLK-112233445",
        "status": "ACCEPTED",
        "amount": 10000,
        "currency": "TZS"
    }
}
Internal Transfer (Selcom to Selcom)
Request
{
    "transId": "TXN20250715095900INT",
    "recipientFiCode": "SELCOM",
    "recipientAccount": "9876543210",
    "recipientName": "Alex Mwangi",
    "amount": 100000,
    "purpose": "BUSINESS",
    "remarks": "Inter-account settlement"
}
Response 200 OK
{
    "success": true,
    "error_code": 1,
    "message": "Transaction processed successfully.",
    "result": "SUCCESS",
    "resultcode": "000",
    "data": {
        "trans_id": "TXN20250715095900INT",
        "selcom_receipt": "SLK-998877665",
        "status": "COMPLETED",
        "amount": 100000,
        "currency": "TZS"
    }
}

Common Error Responses

Validation Error 422
{
    "success": false,
    "error_code": 651,
    "message": "Validation failed.",
    "result": "FAIL",
    "resultcode": "651",
    "data": {
        "purpose": ["The selected purpose is invalid."]
    }
}
Duplicate Transaction 422
{
    "success": false,
    "error_code": 643,
    "message": "Duplicate transaction detected.",
    "result": "FAIL",
    "resultcode": "643",
    "data": []
}
Endpoint

Statement API

Retrieve a paginated transaction statement for a linked organization account, or export it as PDF, XLSX, CSV, or JSON. Date ranges can be specified via a preset label or explicit from_date / to_date values.

POST /v1/statements

Request Body

Parameter Type Required Description
account_number string Required The account number associated with your API credentials. Must be an active account registered under your organization.
preset string Optional Preset date range shortcut. When provided, from_date and to_date are computed automatically server-side.
Allowed values: Today, Last 7 Days, This Month, Last Month, Last 10 Transactions.
from_date string Optional Start date in Y-m-d format (e.g., 2025-01-01). Required when to_date is provided and no preset is given.
to_date string Optional End date in Y-m-d format. Must be on or after from_date. Required when from_date is provided and no preset is given.
per_page integer Optional Number of transactions per page. Min: 1, Max: 500. Defaults to 10.
order string Optional Sort order of transactions. Allowed values: ASC, DESC. Defaults to DESC.
export_type string Optional Controls the response format. Allowed values: pdf, xlsx, csv, json.
File types (pdf, xlsx, csv) return a downloadable file URL instead of paginated data.
json returns the same paginated JSON response as omitting this field entirely.
Date range rules: Either supply a preset or a from_date + to_date pair. If neither is provided the statement returns an empty result set. The two approaches are mutually exclusive — preset values auto-compute their own dates server-side.

Response Fields — Listing

Field Type Description
success boolean true on success, false on failure.
error_code integer 1 on success; negative value on error (see Error Codes).
message string Human-readable status message.
data.filters_applied object Echo of the resolved filters used for the query (account_number, preset, from_date, to_date, per_page, order).
data.account.account_name string Registered organization name.
data.account.account_number string Formatted account number.
data.account.sub_account_name string Sub-account / business label for the queried account.
data.currency string Account currency (e.g., TZS).
data.opening_balance float Balance at the start of the requested date range.
data.closing_balance float Balance at the end of the requested date range.
data.pagination.total integer Total number of matching transactions.
data.pagination.per_page integer Records returned per page.
data.pagination.current_page integer Current page number.
data.pagination.last_page integer Last page number.
data.transactions array Array of transaction objects for the current page.
result string Transaction result based on actual status. See API Response — Result column.
resultcode string Result code based on actual transaction status. See API Response — Errorcode column.

Response Fields — Export (pdf / xlsx / csv)

When export_type is pdf, xlsx, or csv, the listing fields are replaced by:

Field Type Description
data.export_type string The requested export format (pdf, xlsx, or csv).
data.file_url string Temporary public URL to download the generated file.
data.expires_at string ISO 8601 timestamp indicating when the download link expires (1 hour from generation).
data.filters_applied object Echo of the resolved filters used for the export.
result string Transaction result based on actual status. See API Response — Result column.
resultcode string Result code based on actual transaction status. See API Response — Errorcode column.

Example — Listing (Preset)

Request
{
    "account_number": "0123456789",
    "preset": "This Month",
    "per_page": 10,
    "order": "DESC"
}
Response 200 OK
{
    "success": true,
    "error_code": 1,
    "message": "Statement fetched successfully.",
    "result": "SUCCESS",
    "resultcode": "000",
    "data": {
        "filters_applied": {
            "account_number": "0123456789",
            "preset": "This Month",
            "from_date": "2025-07-01",
            "to_date": "2025-07-31",
            "per_page": 10,
            "order": "DESC"
        },
        "account": {
            "account_name": "Acme Ltd",
            "account_number": "01234 56789",
            "sub_account_name": "Main Account"
        },
        "currency": "TZS",
        "opening_balance": 500000,
        "closing_balance": 450000,
        "pagination": {
            "total": 42,
            "per_page": 10,
            "current_page": 1,
            "last_page": 5,
            "from": 1,
            "to": 10
        },
        "transactions": [...]
    }
}

Example — Export

Request
{
    "account_number": "0123456789",
    "from_date": "2025-07-01",
    "to_date": "2025-07-31",
    "export_type": "pdf"
}
Response 200 OK
{
    "success": true,
    "error_code": 1,
    "message": "Statement exported successfully.",
    "result": "SUCCESS",
    "resultcode": "000",
    "data": {
        "export_type": "pdf",
        "file_url": "https://your-domain.com/storage/exports/statement-1234.pdf",
        "expires_at": "2025-07-15T10:30:00+00:00",
        "filters_applied": {
            "account_number": "0123456789",
            "preset": "",
            "from_date": "2025-07-01",
            "to_date": "2025-07-31",
            "per_page": 10,
            "order": "ASC"
        }
    }
}

Example — Export (JSON)

Passing "export_type": "json" returns the same paginated JSON listing as omitting the field.

Request
{
    "account_number": "0123456789",
    "from_date": "2025-07-01",
    "to_date": "2025-07-31",
    "export_type": "json",
    "per_page": 10,
    "order": "DESC"
}
Response 200 OK
{
    "success": true,
    "error_code": 1,
    "message": "Statement fetched successfully.",
    "result": "SUCCESS",
    "resultcode": "000",
    "data": {
        "filters_applied": {
            "account_number": "0123456789",
            "preset": "",
            "from_date": "2025-07-01",
            "to_date": "2025-07-31",
            "per_page": 10,
            "order": "DESC"
        },
        "account": {
            "account_name": "Acme Ltd",
            "account_number": "01234 56789",
            "sub_account_name": "Main Account"
        },
        "currency": "TZS",
        "opening_balance": 500000,
        "closing_balance": 450000,
        "pagination": {
            "total": 42,
            "per_page": 10,
            "current_page": 1,
            "last_page": 5,
            "from": 1,
            "to": 10
        },
        "transactions": [...]
    }
}
Error Response 422
{
    "success": false,
    "error_code": 641,
    "message": "Account number not found or not authorized.",
    "result": "FAIL",
    "resultcode": "641",
    "data": []
}
Reference

API Response

The table below describes the possible transaction results returned in the API response, along with their associated error codes and meanings.

Result Errorcode Description
SUCCESS 000 Transaction successful.
INPROGRESS 111 927 Transaction in progress — please query to know the exact status of the transaction.
AMBIGUOUS 999 Transaction status unknown — wait for reconciliation.
FAIL All others Transaction failed.
Reference

Error Codes

All error responses share a consistent structure. Use the error_code integer to programmatically handle specific failure scenarios.

Error Response Structure

JSON
{
    "success": false,
    "error_code": 613,
    "message": "Invalid or inactive API key.",
    "result": "FAIL",
    "resultcode": "613",
    "data": []
}

Complete Error Code Reference

error_code HTTP Status Category Description
000 200 Success Request completed successfully.
611 403 Authentication Requesting IP address is not whitelisted.
612 400 Authentication One or more required headers are missing (api-key, request-timestamp, digest).
613 401 Authentication API key is invalid or has been deactivated.
621 400/404 General Generic server-side error or resource not found.
631 401 Authentication digest signature does not match. Check your formula or secret key.
632 400 Authentication Request timestamp is stale (outside ±5 minute window) or format is invalid. Ensure your server clock is synchronized with UTC.
641 400 Balance Account not found, not authorized, or account type not permitted for balance fetch.
642 400 Transaction Transaction processing failed at the bank or wallet level.
643 422 Transaction Duplicate transaction detected. A transaction with the same parameters was recently processed.
646 403 Transaction Transaction exists but was not initiated by this API key (ownership violation).
651 422 Validation Request body failed field validation. Check the data object for field-level error details.