Skip to Content
C-Ushuru v1.0 is now available
API ReferenceSales API

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_no field is optional. If not provided, the system will automatically generate a sequential invoice number in the format C-USRU-0000001 per client. This ensures unique, sequential invoice numbers and prevents duplicate invoice errors.

POST/api/v1/sales

Create Sale

Submit a sales transaction to KRA/VSCU. Supports synchronous and asynchronous processing.

Authentication
Parameters
async
boolean · query

Process asynchronously (default: false)

Request BodyJSON

Field Descriptions

Main Fields

FieldTypeRequiredDescription
branch_idstringYesBranch identifier (bhf_id)
invoice_nostringNoUnique invoice number (auto-generated if not provided)
original_invoice_nostringNoOriginal invoice for refunds/credits
sale_datestringYesDate in YYYYMMDD format
sale_timestringYesTime in HHMMSS or HH:MM:SS format
receipt_typestringNoReceipt type (default: NORMAL)
payment_typestringYesPayment type
sales_statusstringNoSales status (default: COMPLETE)
customer_tinstringNoCustomer TIN number
customer_namestringNoCustomer name
customer_idstringNoCustomer ID

Receipt Types

ValueCodeDescription
NORMALSStandard sale
COPYRReceipt copy
PROFORMAPProforma invoice
DEBITTDebit note
CREDITCCredit note

Payment Types

ValueCodeDescription
CASH01Cash payment
CARD02Card payment
MOBILE03Mobile money
CREDIT04Credit
BANK_TRANSFER05Bank transfer
CHECK06Cheque
OTHER07Other payment

Sales Status

ValueCodeDescription
COMPLETE02Completed sale
PARTIAL01Partial sale
CANCELLED03Cancelled sale

Item Fields

FieldTypeRequiredDescription
item_seqintegerYesItem sequence number (1, 2, 3…)
item_codestringYesItem code
item_class_codestringYesKRA item classification code (e.g., “5020230201”)
item_namestringYesItem name/description
bcdstringNoBarcode (optional)
pkg_unit_codestringYesPackage unit code (must match item registration, typically “NT”)
pkgnumberYesPackage quantity
qty_unit_codestringYesQuantity unit code (e.g., “U”, “KG”, “LT”)
qtynumberYesQuantity sold
unit_pricenumberYesUnit price
supply_amountnumberYesSupply amount (qty × price)
discount_ratenumberNoDiscount rate percentage (default: 0)
discount_amountnumberNoDiscount amount (default: 0)
tax_typestringYesTax type code (A, B, C, D, E)
tax_ratenumberYesTax rate percentage
tax_amountnumberYesTax amount
total_amountnumberYesTotal 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: 1000
  • qty: 2
  • total_amount: 2000 (2 × 1000)
  • supply_amount: 1724.14 (2000 ÷ 1.16)
  • tax_amount: 275.86 (2000 - 1724.14)

Tax Types

CodeNameRateDescription
AExempt0%VAT exempt items
B16.00% (Standard VAT)16%Standard VAT rate
C0%0%Special category
DNon-VAT0%Non-VAT items
E8%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.

CodeDescription
NTNo Package (recommended default)
BXBox
CTCarton
PKPack
BGBag
BTBottle

Common Quantity Unit Codes

CodeDescription
UUnit/Piece
KGKilogram
LTLiter
MMeter
M2Square Meter
M3Cubic 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.

GET/api/v1/sales/{id}

Get Sale Details

Retrieve complete details of a sales transaction including items, tax breakdown, and KRA sync status.

Authentication
Parameters
id*
string · path

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.

POST/api/v1/sales/search

Search Sales

Search and filter sales transactions by date range, status, invoice number, and more.

Authentication
Request BodyJSON

Filter Parameters

ParameterTypeRequiredDescription
branch_idstringNoFilter by branch
from_datestringNoStart date (YYYY-MM-DD)
to_datestringNoEnd date (YYYY-MM-DD)
invoice_nostringNoSearch by invoice number (partial match)
statusstringNoFilter by status (pending, processing, success, failed)
per_pageintegerNoResults per page (max 100, default 50)
pageintegerNoPage 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.

POST/api/v1/sales

Create Credit Note

Create a credit note (refund) referencing an original sale.

Authentication
Request BodyJSON

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 event

PHP

// 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

  1. Use Async for High Volume - Set async=true for bulk transactions
  2. Unique Invoice Numbers - Ensure invoice numbers are unique per branch
  3. Validate Calculations - Verify tax calculations before submission
  4. Handle Retries - Implement retry logic for failed transactions
  5. Use Webhooks - Subscribe to transaction.completed and transaction.failed events
  6. Store Transaction IDs - Keep transaction IDs for reference and support
  7. Test in Sandbox - Use sandbox environment for development

Last updated on