Sales API
Create and manage sales transactions with automatic KRA/VSCU submission.
Overview
The Sales API allows you to submit sales transactions to KRA’s eTIMS system through your VSCU device. Sales are processed synchronously (default) or asynchronously for high-volume scenarios.
Create Sale
Submit a sales transaction to the KRA system. This is the primary endpoint for recording sales.
Invoice Number Auto-Generation
The
invoice_nofield is optional. If not provided, the system will automatically generate a sequential invoice number in the formatC-USRU-0000001per client. This ensures unique, sequential invoice numbers and prevents duplicate invoice errors.
/api/v1/salesCreate Sale
Submit a sales transaction to KRA/VSCU. Supports synchronous and asynchronous processing.
asyncProcess asynchronously (default: false)
Field Descriptions
Main Fields
| Field | Type | Required | Description |
|---|---|---|---|
branch_id | string | Yes | Branch identifier (bhf_id) |
invoice_no | string | No | Unique invoice number (auto-generated if not provided) |
original_invoice_no | string | No | Original invoice for refunds/credits |
sale_date | string | Yes | Date in YYYYMMDD format |
sale_time | string | Yes | Time in HHMMSS or HH:MM:SS format |
receipt_type | string | No | Receipt type (default: NORMAL) |
payment_type | string | Yes | Payment type |
sales_status | string | No | Sales status (default: COMPLETE) |
customer_tin | string | No | Customer TIN number |
customer_name | string | No | Customer name |
customer_id | string | No | Customer ID |
Receipt Types
| Value | Code | Description |
|---|---|---|
NORMAL | S | Standard sale |
COPY | R | Receipt copy |
PROFORMA | P | Proforma invoice |
DEBIT | T | Debit note |
CREDIT | C | Credit note |
Payment Types
| Value | Code | Description |
|---|---|---|
CASH | 01 | Cash payment |
CARD | 02 | Card payment |
MOBILE | 03 | Mobile money |
CREDIT | 04 | Credit |
BANK_TRANSFER | 05 | Bank transfer |
CHECK | 06 | Cheque |
OTHER | 07 | Other payment |
Sales Status
| Value | Code | Description |
|---|---|---|
COMPLETE | 02 | Completed sale |
PARTIAL | 01 | Partial sale |
CANCELLED | 03 | Cancelled sale |
Item Fields
| Field | Type | Required | Description |
|---|---|---|---|
item_seq | integer | Yes | Item sequence number (1, 2, 3…) |
item_code | string | Yes | Item code |
item_class_code | string | Yes | KRA item classification code (e.g., “5020230201”) |
item_name | string | Yes | Item name/description |
bcd | string | No | Barcode (optional) |
pkg_unit_code | string | Yes | Package unit code (must match item registration, typically “NT”) |
pkg | number | Yes | Package quantity |
qty_unit_code | string | Yes | Quantity unit code (e.g., “U”, “KG”, “LT”) |
qty | number | Yes | Quantity sold |
unit_price | number | Yes | Unit price |
supply_amount | number | Yes | Supply amount (qty × price) |
discount_rate | number | No | Discount rate percentage (default: 0) |
discount_amount | number | No | Discount amount (default: 0) |
tax_type | string | Yes | Tax type code (A, B, C, D, E) |
tax_rate | number | Yes | Tax rate percentage |
tax_amount | number | Yes | Tax amount |
total_amount | number | Yes | Total including tax |
Important: Tax-Inclusive Pricing
Kenya uses tax-inclusive pricing where displayed prices already include VAT. To calculate amounts:
total_amount= qty × unit_price (what customer pays)supply_amount= total_amount ÷ 1.16 (pre-tax amount)tax_amount= total_amount - supply_amount (16% VAT extracted)Example: Selling 2 items at 1,000 KES each (tax inclusive):
unit_price: 1000qty: 2total_amount: 2000 (2 × 1000)supply_amount: 1724.14 (2000 ÷ 1.16)tax_amount: 275.86 (2000 - 1724.14)
Tax Types
| Code | Name | Rate | Description |
|---|---|---|---|
| A | Exempt | 0% | VAT exempt items |
| B | 16.00% (Standard VAT) | 16% | Standard VAT rate |
| C | 0% | 0% | Special category |
| D | Non-VAT | 0% | Non-VAT items |
| E | 8% | 8% | Reduced VAT rate |
Common Package Unit Codes
Important: The package unit code (
pkg_unit_code) and quantity unit code (qty_unit_code) in the sale must exactly match what was used when registering the item. KRA will reject the sale if these codes don’t match the item registration.
| Code | Description |
|---|---|
NT | No Package (recommended default) |
BX | Box |
CT | Carton |
PK | Pack |
BG | Bag |
BT | Bottle |
Common Quantity Unit Codes
| Code | Description |
|---|---|
U | Unit/Piece |
KG | Kilogram |
LT | Liter |
M | Meter |
M2 | Square Meter |
M3 | Cubic Meter |
For complete lists of unit codes, see Codes API.
Response (Synchronous Mode)
Status: 200 OK
{
"status": "success",
"message": "Sale processed successfully with KRA",
"data": {
"transaction_id": "9d3f4b1a-7c8e-4d2f-b5a6-1e3c9f8d2b4a",
"invoice_no": "C-USRU-0000001",
"receipt_no": "20250115-00-00001",
"receipt_date": "2025-01-15",
"total_amount": 2000,
"tax_amount": 275.86,
"qr_code": "data:image/png;base64,...",
"synced_to_kra": true
},
"meta": {
"timestamp": "2025-01-15T14:30:30Z",
"request_id": "req_abc123"
}
}Response (Asynchronous Mode)
Status: 202 Accepted
{
"status": "processing",
"message": "Transaction is being processed",
"data": {
"transaction_id": "9d3f4b1a-7c8e-4d2f-b5a6-1e3c9f8d2b4a",
"invoice_no": "C-USRU-0000001",
"status": "pending"
},
"meta": {
"timestamp": "2025-01-15T14:30:00Z",
"request_id": "req_abc123",
"check_status_url": "/api/v1/transactions/9d3f4b1a-7c8e-4d2f-b5a6-1e3c9f8d2b4a"
}
}Get Sale Details
Retrieve details of a specific sales transaction.
/api/v1/sales/{id}Get Sale Details
Retrieve complete details of a sales transaction including items, tax breakdown, and KRA sync status.
id*Transaction UUID
Response
Status: 200 OK
{
"status": "success",
"data": {
"transaction_id": "9d3f4b1a-7c8e-4d2f-b5a6-1e3c9f8d2b4a",
"branch_id": "00",
"invoice_no": "C-USRU-0000001",
"receipt_no": "20250115-00-00001",
"sale_date": "20250115",
"sale_time": "143000",
"payment_type": "CASH",
"customer_name": "John Doe",
"total_amount": 2000,
"tax_amount": 275.86,
"status": "success",
"synced_to_kra": true,
"items": [
{
"item_code": "KE2BXU0000001",
"item_name": "Laptop Computer - HP ProBook 450",
"quantity": 2,
"unit_price": 1000,
"supply_amount": 1724.14,
"tax_type": "B",
"tax_rate": 16,
"tax_amount": 275.86,
"total_amount": 2000
}
],
"qr_code": "data:image/png;base64,...",
"created_at": "2025-01-15T14:30:00Z",
"processed_at": "2025-01-15T14:30:05Z"
}
}Status: 404 Not Found
{
"status": "error",
"message": "Sale transaction not found"
}Search Sales
Search sales transactions with filters.
/api/v1/sales/searchSearch Sales
Search and filter sales transactions by date range, status, invoice number, and more.
Filter Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
branch_id | string | No | Filter by branch |
from_date | string | No | Start date (YYYY-MM-DD) |
to_date | string | No | End date (YYYY-MM-DD) |
invoice_no | string | No | Search by invoice number (partial match) |
status | string | No | Filter by status (pending, processing, success, failed) |
per_page | integer | No | Results per page (max 100, default 50) |
page | integer | No | Page number (default 1) |
Response
Status: 200 OK
{
"data": [
{
"transaction_id": "9d3f4b1a-7c8e-4d2f-b5a6-1e3c9f8d2b4a",
"branch_id": "00",
"invoice_no": "C-USRU-0000001",
"receipt_no": "20250115-00-00001",
"sale_date": "20250115",
"customer_name": "John Doe",
"total_amount": 2000,
"status": "success",
"synced_to_kra": true,
"created_at": "2025-01-15T14:30:00Z"
}
],
"meta": {
"current_page": 1,
"per_page": 50,
"total": 156,
"total_pages": 4
}
}Credit Notes (Refunds)
To create a credit note for a previous sale, use the CREDIT receipt type and reference the original invoice.
/api/v1/salesCreate Credit Note
Create a credit note (refund) referencing an original sale.
Tax Calculation
The system automatically calculates tax totals by tax type:
Tax Types: A (16%), B (0%), C (0%), D (0%), E (0%)
For each item:
taxable_amount = supply_amount - discount_amount
tax_amount = taxable_amount * tax_rate / 100
Totals are aggregated by tax type for VSCU submission.Example Calculation
const item = {
quantity: 2,
unit_price: 1000,
supply_amount: 1724.14, // 2000 ÷ 1.16 (tax-inclusive)
discount_amount: 0,
tax_type: 'B', // 16% VAT
tax_rate: 16,
tax_amount: 275.86, // 2000 - 1724.14
total_amount: 2000 // 2 x 1000
};Code Examples
JavaScript
const axios = require('axios');
const apiKey = process.env.CTAX_API_KEY;
const baseURL = 'https://c-ushuru.com/api/v1';
// Create sale (synchronous) - invoice_no is auto-generated if not provided
const sale = await axios.post(`${baseURL}/sales`, {
branch_id: '00',
sale_date: new Date().toISOString().slice(0,10).replace(/-/g,''),
sale_time: new Date().toTimeString().slice(0,8).replace(/:/g,''),
payment_type: 'CASH',
customer_name: 'John Doe',
items: [
{
item_seq: 1,
item_code: 'KE2BXU0000001',
item_class_code: '5020230201',
item_name: 'Laptop Computer - HP ProBook 450',
bcd: '8471000001234',
pkg_unit_code: 'NT',
pkg: 1,
qty_unit_code: 'U',
qty: 2,
unit_price: 1000,
supply_amount: 1724.14,
discount_rate: 0,
discount_amount: 0,
tax_type: 'B',
tax_rate: 16,
tax_amount: 275.86,
total_amount: 2000
}
]
}, {
headers: { 'Authorization': `Bearer ${apiKey}` }
});
console.log('Invoice:', sale.data.data.invoice_no); // e.g., C-USRU-0000001
console.log('Receipt:', sale.data.data.receipt_no);JavaScript (Async with Webhook)
// Submit sale asynchronously
const response = await axios.post(`${baseURL}/sales?async=true`, saleData, {
headers: { 'Authorization': `Bearer ${apiKey}` }
});
const transactionId = response.data.data.transaction_id;
console.log('Transaction queued:', transactionId);
// Webhook will receive transaction.completed or transaction.failed eventPHP
// invoice_no is auto-generated if not provided
$data = [
'branch_id' => '00',
'sale_date' => date('Ymd'),
'sale_time' => date('His'),
'payment_type' => 'CASH',
'customer_name' => 'John Doe',
'items' => [
[
'item_seq' => 1,
'item_code' => 'KE2BXU0000001',
'item_class_code' => '5020230201',
'item_name' => 'Laptop Computer - HP ProBook 450',
'bcd' => '8471000001234',
'pkg_unit_code' => 'NT',
'pkg' => 1,
'qty_unit_code' => 'U',
'qty' => 2,
'unit_price' => 1000,
'supply_amount' => 1724.14,
'discount_rate' => 0,
'discount_amount' => 0,
'tax_type' => 'B',
'tax_rate' => 16,
'tax_amount' => 275.86,
'total_amount' => 2000,
],
],
];
$response = $client->post('/api/v1/sales', [
'json' => $data,
'headers' => ['Authorization' => 'Bearer ' . $apiKey],
]);
$result = json_decode($response->getBody(), true);
echo "Invoice: " . $result['data']['invoice_no']; // e.g., C-USRU-0000001
echo "Receipt: " . $result['data']['receipt_no'];Python
import requests
from datetime import datetime
import os
api_key = os.environ['CTAX_API_KEY']
base_url = 'https://c-ushuru.com/api/v1'
now = datetime.now()
# invoice_no is auto-generated if not provided
sale_data = {
'branch_id': '00',
'sale_date': now.strftime('%Y%m%d'),
'sale_time': now.strftime('%H%M%S'),
'payment_type': 'CASH',
'customer_name': 'John Doe',
'items': [{
'item_seq': 1,
'item_code': 'KE2BXU0000001',
'item_class_code': '5020230201',
'item_name': 'Laptop Computer - HP ProBook 450',
'bcd': '8471000001234',
'pkg_unit_code': 'NT',
'pkg': 1,
'qty_unit_code': 'U',
'qty': 2,
'unit_price': 1000,
'supply_amount': 1724.14,
'discount_rate': 0,
'discount_amount': 0,
'tax_type': 'B',
'tax_rate': 16,
'tax_amount': 275.86,
'total_amount': 2000
}]
}
response = requests.post(
f'{base_url}/sales',
json=sale_data,
headers={'Authorization': f'Bearer {api_key}'}
)
result = response.json()
print(f"Invoice: {result['data']['invoice_no']}") # e.g., C-USRU-0000001
print(f"Receipt: {result['data']['receipt_no']}")Error Handling
Common Errors
400 Bad Request - Invalid request data
{
"status": "error",
"message": "Invalid request data. Please check your input and try again.",
"meta": {
"timestamp": "2025-01-15T14:30:00Z",
"request_id": "req_abc123"
}
}422 Unprocessable Entity - Validation failed
{
"status": "error",
"message": "Sale could not be processed. Please try again.",
"data": {
"transaction_id": "9d3f4b1a-7c8e-4d2f-b5a6-1e3c9f8d2b4a",
"synced_to_kra": false,
"can_retry": true
},
"meta": {
"timestamp": "2025-01-15T14:30:30Z",
"request_id": "req_abc123"
}
}500 Internal Server Error
{
"status": "error",
"message": "An error occurred while processing the sale. Please try again or contact support.",
"meta": {
"timestamp": "2025-01-15T14:30:00Z",
"request_id": "req_abc123"
}
}Best Practices
- Use Async for High Volume - Set
async=truefor bulk transactions - Unique Invoice Numbers - Ensure invoice numbers are unique per branch
- Validate Calculations - Verify tax calculations before submission
- Handle Retries - Implement retry logic for failed transactions
- Use Webhooks - Subscribe to
transaction.completedandtransaction.failedevents - Store Transaction IDs - Keep transaction IDs for reference and support
- Test in Sandbox - Use sandbox environment for development
Related Endpoints
- Transactions API - Monitor transaction status
- Items API - Get item details for sales
- Webhooks - Real-time status notifications
- Codes API - Get tax types and payment types