Skip to Content
C-Tax 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.

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_nostringYesUnique invoice number (trader invoice number)
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_codestringYesItem code
item_namestringYesItem name
quantitynumberYesQuantity sold
unit_pricenumberYesUnit price
supply_amountnumberYesSupply amount (qty x price)
discount_amountnumberNoDiscount amount (default: 0)
tax_typestringYesTax type (A, B, C, D, E)
tax_ratenumberYesTax rate percentage
tax_amountnumberYesTax amount
total_amountnumberYesTotal including tax

Tax Types

CodeNameRateDescription
AStandard Rate16%Standard VAT rate
BExempt0%VAT exempt items
CSpecial0%Special category
DZero-rated0%Zero-rated supplies
ESpecial Exemption0%Special exemption

Response (Synchronous Mode)

Status: 200 OK

{ "status": "success", "message": "Sale processed successfully with KRA", "data": { "transaction_id": "9d3f4b1a-7c8e-4d2f-b5a6-1e3c9f8d2b4a", "invoice_no": "INV-2025-001", "receipt_no": "20250115-00-00001", "receipt_date": "2025-01-15", "total_amount": 2320, "tax_amount": 320, "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": "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" } }

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": "INV-2025-001", "receipt_no": "20250115-00-00001", "sale_date": "20250115", "sale_time": "143000", "payment_type": "CASH", "customer_name": "John Doe", "total_amount": 2320, "tax_amount": 320, "status": "success", "synced_to_kra": true, "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 } ], "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": "INV-2025-001", "receipt_no": "20250115-00-00001", "sale_date": "20250115", "customer_name": "John Doe", "total_amount": 2320, "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: 2000, // 2 x 1000 discount_amount: 0, tax_type: 'A', tax_rate: 16, tax_amount: 320, // 2000 x 0.16 total_amount: 2320 // 2000 + 320 };

Code Examples

JavaScript

const axios = require('axios'); const apiKey = process.env.CTAX_API_KEY; const baseURL = 'https://c-tax.1809ltd.co.ke/api/v1'; // Create sale (synchronous) const sale = await axios.post(`${baseURL}/sales`, { branch_id: '00', invoice_no: `INV-${Date.now()}`, 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_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 } ] }, { headers: { 'Authorization': `Bearer ${apiKey}` } }); 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

$data = [ 'branch_id' => '00', 'invoice_no' => 'INV-' . time(), 'sale_date' => date('Ymd'), 'sale_time' => date('His'), 'payment_type' => 'CASH', 'customer_name' => 'John Doe', '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 = $client->post('/api/v1/sales', [ 'json' => $data, 'headers' => ['Authorization' => 'Bearer ' . $apiKey], ]); $result = json_decode($response->getBody(), true); 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-tax.1809ltd.co.ke/api/v1' now = datetime.now() sale_data = { 'branch_id': '00', 'invoice_no': f'INV-{int(datetime.timestamp(now))}', 'sale_date': now.strftime('%Y%m%d'), 'sale_time': now.strftime('%H%M%S'), 'payment_type': 'CASH', 'customer_name': 'John Doe', '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 = requests.post( f'{base_url}/sales', json=sale_data, headers={'Authorization': f'Bearer {api_key}'} ) result = response.json() 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