Transactions API
Manage and monitor all transaction types across your account. The Transactions API provides a unified view of sales, purchases, and stock movements.
Overview
Transactions represent business operations that need to be reported to KRA. Each transaction goes through a lifecycle from creation to completion or failure.
Transaction Types
| Type | Description |
|---|---|
sales | Sales to customers |
purchase | Purchases from suppliers |
stock | Stock movements and adjustments |
import | Imported items |
Transaction Statuses
| Status | Description |
|---|---|
pending | Created, awaiting processing |
processing | Being sent to KRA |
success | Successfully processed |
failed | Processing failed |
List Transactions
Get all transactions with optional filtering.
/api/v1/transactionsList Transactions
Retrieve all transactions with optional filters by type, status, branch, and date range.
typeFilter by type: sales, purchase, stock
statusFilter by status: pending, processing, success, failed
branch_idFilter by branch ID
from_dateStart date (YYYY-MM-DD)
to_dateEnd date (YYYY-MM-DD)
per_pageResults per page (max 100, default 50)
pagePage number (default 1)
Response
Status: 200 OK
{
"data": [
{
"transaction_id": "9d3f4b1a-7c8e-4d2f-b5a6-1e3c9f8d2b4a",
"type": "sales",
"status": "success",
"branch_id": "00",
"invoice_no": "INV-2025-001",
"receipt_no": "20250115-00-00001",
"synced_to_kra": true,
"can_retry": false,
"created_at": "2025-01-15T14:30:00Z",
"processed_at": "2025-01-15T14:30:05Z"
},
{
"transaction_id": "8c2e3a0f-6b7d-4c1e-a4b5-0d2c8e7f1a3b",
"type": "purchase",
"status": "failed",
"branch_id": "00",
"invoice_no": "PO-2025-001",
"receipt_no": null,
"synced_to_kra": false,
"can_retry": true,
"created_at": "2025-01-15T14:25:00Z",
"processed_at": "2025-01-15T14:25:10Z"
}
],
"meta": {
"current_page": 1,
"per_page": 50,
"total": 156,
"total_pages": 4
}
}Get Transaction Details
Retrieve complete details of a specific transaction.
/api/v1/transactions/{id}Get Transaction Details
Retrieve complete details of a specific transaction including request and response data.
id*Transaction UUID
Response
Status: 200 OK
{
"status": "success",
"data": {
"transaction_id": "9d3f4b1a-7c8e-4d2f-b5a6-1e3c9f8d2b4a",
"type": "sales",
"status": "success",
"branch_id": "00",
"invoice_no": "INV-2025-001",
"receipt_no": "20250115-00-00001",
"request_data": {
"branch_id": "00",
"invoice_no": "INV-2025-001",
"sale_date": "20250115",
"sale_time": "143000",
"payment_type": "CASH",
"customer_name": "John Doe",
"customer_tin": "",
"items": [
{
"item_code": "ITEM001",
"item_name": "Product A",
"quantity": 2,
"unit_price": 1000,
"supply_amount": 2000,
"tax_type": "A",
"tax_rate": 16,
"tax_amount": 320,
"total_amount": 2320
}
]
},
"response_data": {
"receipt_no": "20250115-00-00001",
"receipt_date": "2025-01-15",
"qr_code": "data:image/png;base64,..."
},
"synced_to_kra": true,
"can_retry": false,
"created_at": "2025-01-15T14:30:00Z",
"processed_at": "2025-01-15T14:30:05Z"
}
}Status: 404 Not Found
{
"status": "error",
"message": "Transaction not found"
}Retry Failed Transaction
Retry a transaction that previously failed.
/api/v1/transactions/{id}/retryRetry Failed Transaction
Retry a transaction that previously failed. Only transactions with can_retry=true can be retried.
id*Transaction UUID
Response
Status: 200 OK (Retry successful)
{
"status": "success",
"message": "Transaction processed successfully with KRA",
"data": {
"transaction_id": "8c2e3a0f-6b7d-4c1e-a4b5-0d2c8e7f1a3b",
"status": "success",
"synced_to_kra": true,
"receipt_no": "20250115-00-00002"
},
"meta": {
"timestamp": "2025-01-15T15:00:00Z"
}
}Status: 422 Unprocessable Entity (Cannot retry)
{
"status": "error",
"message": "Transaction cannot be retried",
"reason": "Maximum retry attempts reached"
}Status: 422 Unprocessable Entity (Retry failed)
{
"status": "error",
"message": "Transaction could not be processed. Please try again.",
"data": {
"transaction_id": "8c2e3a0f-6b7d-4c1e-a4b5-0d2c8e7f1a3b",
"synced_to_kra": false,
"can_retry": true
},
"meta": {
"timestamp": "2025-01-15T15:00:00Z"
}
}Retry Conditions
A transaction can only be retried if:
- Status is
failed - Retry count is less than 3
- Transaction is not already being processed
Transaction Statistics
Get aggregated statistics for transactions.
/api/v1/transactions/statsTransaction Statistics
Get aggregated statistics for transactions including counts by status and type.
from_dateStart date (YYYY-MM-DD), default: 30 days ago
to_dateEnd date (YYYY-MM-DD), default: today
Response
Status: 200 OK
{
"status": "success",
"data": {
"total": 256,
"by_status": {
"success": 240,
"failed": 10,
"pending": 4,
"processing": 2
},
"by_type": {
"sales": 180,
"purchase": 56,
"stock": 20
},
"success_rate": 93.75
},
"period": {
"from": "2024-12-16",
"to": "2025-01-15"
}
}Async Processing
For high-volume scenarios, transactions can be processed asynchronously:
Create Async Transaction
POST /api/v1/sales?async=trueReturns immediately with transaction ID:
{
"status": "processing",
"message": "Transaction is being processed",
"data": {
"transaction_id": "9d3f4b1a-7c8e-4d2f-b5a6-1e3c9f8d2b4a",
"invoice_no": "INV-2025-001",
"status": "pending"
},
"meta": {
"timestamp": "2025-01-15T14:30:00Z",
"request_id": "req_abc123",
"check_status_url": "/api/v1/transactions/9d3f4b1a-7c8e-4d2f-b5a6-1e3c9f8d2b4a"
}
}Check Status
Poll the transaction endpoint or use webhooks for real-time updates:
// Polling approach
async function waitForTransaction(transactionId) {
while (true) {
const response = await axios.get(`/api/v1/transactions/${transactionId}`, {
headers: { Authorization: `Bearer ${apiKey}` }
});
const { status } = response.data.data;
if (status === 'success' || status === 'failed') {
return response.data.data;
}
// Wait 2 seconds before next check
await new Promise(resolve => setTimeout(resolve, 2000));
}
}Webhook Notification
Configure webhooks to receive instant notifications:
{
"event": "transaction.completed",
"timestamp": "2025-01-15T14:30:05Z",
"data": {
"transaction_id": "9d3f4b1a-7c8e-4d2f-b5a6-1e3c9f8d2b4a",
"type": "sales",
"status": "success",
"invoice_no": "INV-2025-001",
"receipt_no": "20250115-00-00001"
}
}Transaction Lifecycle
Created (pending)
│
▼
Processing
│
├── Success ──────► Complete
│
└── Failed
│
├── Can Retry ──► Processing (retry)
│
└── Max Retries Reached ──► Permanently FailedStatus Transitions
| From | To | Trigger |
|---|---|---|
pending | processing | Queue processes transaction |
processing | success | KRA accepts transaction |
processing | failed | KRA rejects or error occurs |
failed | processing | Manual or automatic retry |
Code Examples
JavaScript
const axios = require('axios');
const apiKey = process.env.CTAX_API_KEY;
const baseURL = 'https://c-tax.1809ltd.co.ke/api/v1';
// List transactions
const response = await axios.get(`${baseURL}/transactions`, {
params: {
type: 'sales',
status: 'success',
from_date: '2025-01-01',
to_date: '2025-01-31',
per_page: 50
},
headers: { Authorization: `Bearer ${apiKey}` }
});
const transactions = response.data.data;
// Get statistics
const stats = await axios.get(`${baseURL}/transactions/stats`, {
headers: { Authorization: `Bearer ${apiKey}` }
});
console.log(`Success rate: ${stats.data.data.success_rate}%`);
console.log(`Total transactions: ${stats.data.data.total}`);PHP
use GuzzleHttp\Client;
$client = new Client([
'base_uri' => 'https://c-tax.1809ltd.co.ke/api/v1/',
'headers' => [
'Authorization' => 'Bearer ' . env('CTAX_API_KEY'),
'Content-Type' => 'application/json',
],
]);
// List transactions
$response = $client->get('transactions', [
'query' => [
'type' => 'sales',
'status' => 'success',
'from_date' => '2025-01-01',
'to_date' => '2025-01-31',
],
]);
$transactions = json_decode($response->getBody(), true)['data'];
// Get statistics
$statsResponse = $client->get('transactions/stats', [
'query' => [
'from_date' => '2025-01-01',
'to_date' => '2025-01-31',
],
]);
$stats = json_decode($statsResponse->getBody(), true)['data'];
echo "Success rate: {$stats['success_rate']}%\n";Python
import requests
import os
api_key = os.environ['CTAX_API_KEY']
base_url = 'https://c-tax.1809ltd.co.ke/api/v1'
headers = {'Authorization': f'Bearer {api_key}'}
# List transactions
response = requests.get(
f'{base_url}/transactions',
params={
'type': 'sales',
'status': 'success',
'from_date': '2025-01-01',
'to_date': '2025-01-31'
},
headers=headers
)
transactions = response.json()['data']
# Get statistics
stats = requests.get(f'{base_url}/transactions/stats', headers=headers)
print(f"Success rate: {stats.json()['data']['success_rate']}%")Error Handling
Common Errors
500 Internal Server Error
{
"status": "error",
"message": "Failed to retrieve transactions"
}404 Not Found
{
"status": "error",
"message": "Transaction not found"
}Handling Failed Transactions
- Check transaction details to understand the failure
- Verify the request data is correct
- Check VSCU device connectivity
- Retry if
can_retryis true - Contact support if issue persists
Best Practices
- Use Async for Bulk - Use async processing for high-volume transactions
- Implement Webhooks - Use webhooks instead of polling for status updates
- Monitor Success Rate - Track statistics and investigate drops in success rate
- Handle Retries - Implement retry logic for failed transactions
- Store Transaction IDs - Keep transaction IDs for reference and debugging
- Use Idempotency - Use unique invoice numbers to prevent duplicates
Related Endpoints
- Sales API - Create sales transactions
- Purchases API - Create purchase transactions
- Stock API - Create stock movements
- Webhooks - Real-time notifications