eTIMS API Documentation
Integrate KRA-compliant eTIMS invoicing into your applications with our RESTful API. Generate invoices, validate receipts, and sync with KRA in real-time.
RESTful API
Standard HTTP methods and JSON responses
KRA Compliant
Automatic compliance with KRA eTIMS requirements
Secure
API key authentication and HTTPS encryption
Quick Start
Get Your API Key
- Sign up for a tax.ke developer account
- Navigate to your dashboard and generate an API key
- Store your API key securely (never commit it to version control)
- Start making API calls!
Base URL
https://api.tax.keAll API requests should be made to this base URL. Use HTTPS for all requests.
Your First API Call
Choose your preferred language to see example code:
const axios = require('axios');
async function generateInvoice(invoiceData) {
try {
const response = await axios.post(
'https://api.tax.ke/api/etims/generate-invoice',
invoiceData,
{
headers: {
'Authorization': `Bearer ${process.env.TAX_KE_API_KEY}`,
'Content-Type': 'application/json'
}
}
);
return response.data;
} catch (error) {
console.error('Error:', error.response?.data || error.message);
throw error;
}
}
// Example usage
const invoice = await generateInvoice({
invoiceNumber: "INV-2024-001",
date: "2024-01-15",
business: {
name: "My Company Ltd",
address: "123 Business Street, Nairobi, Kenya",
taxId: "P051234567A"
},
customer: {
name: "Customer Name",
address: "Customer Address"
},
items: [{
description: "Product Name",
quantity: 2,
unitPrice: 1000.00,
total: 2000.00
}],
subtotal: 2000.00,
taxRate: 16,
taxAmount: 320.00,
total: 2320.00
});Authentication
API Key Authentication
All API requests require authentication using an API key. Include your API key in the Authorization header of every request.
Authorization: Bearer YOUR_API_KEYSecurity Best Practices
- Never commit API keys to version control
- Use environment variables to store API keys
- Rotate API keys regularly
- Use HTTPS for all API requests
- Restrict API key permissions when possible
API Endpoints
Generate Invoice
Generate a KRA-compliant eTIMS invoice. The invoice will be automatically synced with KRA and a QR code will be generated for validation.
POST /api/etims/generate-invoiceRequest Body
{
"invoiceNumber": "INV-2024-001",
"date": "2024-01-15",
"dueDate": "2024-02-15",
"business": {
"name": "Company Name",
"address": "Street, City, Country",
"email": "business@example.com",
"phone": "+254712345678",
"taxId": "P051234567A"
},
"customer": {
"name": "Customer Name",
"address": "Customer Address",
"email": "customer@example.com",
"phone": "+254798765432",
"taxId": "P059876543B"
},
"items": [
{
"description": "Product/Service Name",
"quantity": 2,
"unitPrice": 1000,
"total": 2000
}
],
"subtotal": 2000,
"taxRate": 16,
"taxAmount": 320,
"total": 2320,
"notes": "Payment terms and conditions"
}Response
{
"success": true,
"invoiceId": "inv_abc123",
"invoiceNumber": "INV-2024-001",
"kraReference": "KRA-REF-123456",
"qrCode": "data:image/png;base64,...",
"pdfUrl": "https://api.tax.ke/invoices/inv_abc123.pdf",
"status": "synced",
"syncedAt": "2024-01-15T10:30:00Z"
}Validate Receipt
Validate an eTIMS receipt against KRA records to ensure authenticity.
POST /api/etims/validate-receiptRequest Body
{
"receiptNumber": "RCP-2024-001",
"invoiceNumber": "INV-2024-001",
"kraReference": "KRA-REF-123456",
"date": "2024-01-15",
"amount": 2320
}Response
{
"valid": true,
"receiptNumber": "RCP-2024-001",
"invoiceNumber": "INV-2024-001",
"kraReference": "KRA-REF-123456",
"validatedAt": "2024-01-15T10:35:00Z",
"status": "valid"
}Sync with KRA
Manually trigger synchronization of an invoice with KRA. Useful for retrying failed syncs. Note: Automatic retry is enabled by default for all invoices.
POST /api/etims/sync-kraRequest Body
{
"invoiceId": "inv_abc123",
"force": false
}Response
{
"success": true,
"invoiceId": "inv_abc123",
"kraReference": "KRA-REF-123456",
"syncedAt": "2024-01-15T10:30:00Z",
"status": "synced"
}Get Invoice Status
Retrieve invoice details and sync status by invoice ID.
GET /api/etims/invoice/{invoiceId}Response
{
"invoiceId": "inv_abc123",
"invoiceNumber": "INV-2024-001",
"status": "synced",
"kraReference": "KRA-REF-123456",
"createdAt": "2024-01-15T10:00:00Z",
"syncedAt": "2024-01-15T10:30:00Z",
"pdfUrl": "https://api.tax.ke/invoices/inv_abc123.pdf"
}List Invoices
List all invoices with pagination and filtering options.
GET /api/etims/invoices?page=1&limit=20&status=syncedQuery Parameters
| Parameter | Type | Description |
|---|---|---|
| page | integer | Page number (default: 1) |
| limit | integer | Items per page (default: 20, max: 100) |
| status | string | Filter by status (pending, synced, failed) |
| fromDate | string | Filter from date (ISO 8601) |
| toDate | string | Filter to date (ISO 8601) |
Response
{
"invoices": [
{
"invoiceId": "inv_abc123",
"invoiceNumber": "INV-2024-001",
"status": "synced",
"total": 2320,
"createdAt": "2024-01-15T10:00:00Z"
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 150,
"totalPages": 8
}
}Automatic Retry Mechanism
Built-in Resilience
Our system automatically handles eTIMS downtime and connection issues. When the KRA eTIMS system is unavailable or a sync fails, the system will automatically and periodically retry connecting to eTIMS until successful.
Retry Strategy
- Exponential Backoff: Retry intervals increase exponentially (1min, 2min, 4min, 8min, 16min, up to 1 hour)
- Maximum Retries: System will retry for up to 72 hours before marking as permanently failed
- Status Updates: Invoice status is updated in real-time (pending → syncing → synced/failed)
- Webhook Notifications: You'll receive webhook events for each retry attempt and final status
Important Notes
- Invoices remain accessible and can be downloaded even while sync is pending
- You can manually trigger a retry using the Sync with KRA endpoint
- Monitor sync status via the Get Invoice Status endpoint or webhooks
- All retry attempts are logged for audit purposes
Retry Status Codes
| Status | Description | Action |
|---|---|---|
| pending | Invoice created, waiting for initial sync | Automatic retry will begin |
| syncing | Currently attempting to sync with KRA | In progress |
| retrying | Previous sync failed, retrying automatically | Automatic retry in progress |
| synced | Successfully synced with KRA | Complete |
| failed | All retry attempts exhausted (after 72 hours) | Manual retry required |
Webhooks
Webhooks allow you to receive real-time notifications about invoice events. Instead of polling the API, you can configure webhook URLs to receive instant updates when invoices are synced, fail, or retry.
Setting Up Webhooks
POST /api/etims/webhooksRequest Body
{
"url": "https://your-app.com/webhooks/etims",
"events": [
"invoice.synced",
"invoice.failed",
"invoice.retrying"
],
"secret": "your-webhook-secret"
}Response
{
"webhookId": "wh_abc123",
"url": "https://your-app.com/webhooks/etims",
"events": [
"invoice.synced",
"invoice.failed",
"invoice.retrying"
],
"status": "active",
"createdAt": "2024-01-15T10:00:00Z"
}Webhook Events
invoice.synced
Triggered when an invoice is successfully synced with KRA
{
"event": "invoice.synced",
"timestamp": "2024-01-15T10:30:00Z",
"data": {
"invoiceId": "inv_abc123",
"invoiceNumber": "INV-2024-001",
"kraReference": "KRA-REF-123456",
"syncedAt": "2024-01-15T10:30:00Z",
"status": "synced"
}
}invoice.failed
Triggered when all retry attempts are exhausted and sync has permanently failed
{
"event": "invoice.failed",
"timestamp": "2024-01-15T12:00:00Z",
"data": {
"invoiceId": "inv_abc123",
"invoiceNumber": "INV-2024-001",
"status": "failed",
"lastAttemptAt": "2024-01-15T12:00:00Z",
"retryCount": 10,
"error": "KRA_SYNC_ERROR: Connection timeout"
}
}invoice.retrying
Triggered when a retry attempt is being made after a failed sync
{
"event": "invoice.retrying",
"timestamp": "2024-01-15T10:35:00Z",
"data": {
"invoiceId": "inv_abc123",
"invoiceNumber": "INV-2024-001",
"status": "retrying",
"retryAttempt": 3,
"nextRetryAt": "2024-01-15T10:39:00Z",
"previousError": "KRA_SYNC_ERROR: Service unavailable"
}
}Webhook Security
All webhook requests include a signature header that you can verify to ensure the request is from tax.ke. The signature is computed using HMAC-SHA256.
X-TaxKe-Signature: sha256=abc123def456...Signature Verification (Node.js)
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const hmac = crypto.createHmac('sha256', secret);
const computed = 'sha256=' + hmac.update(payload).digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(computed)
);
}
// In your webhook handler
app.post('/webhooks/etims', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-taxke-signature'];
const isValid = verifyWebhookSignature(req.body, signature, process.env.WEBHOOK_SECRET);
if (!isValid) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body);
// Process webhook event
res.status(200).send('OK');
});Signature Verification (Python)
import hmac
import hashlib
import json
def verify_webhook_signature(payload, signature, secret):
computed = hmac.new(
secret.encode('utf-8'),
payload.encode('utf-8'),
hashlib.sha256
).hexdigest()
expected = f'sha256={computed}'
return hmac.compare_digest(signature, expected)
# In your webhook handler
@app.route('/webhooks/etims', methods=['POST'])
def handle_webhook():
signature = request.headers.get('X-TaxKe-Signature')
payload = request.get_data(as_text=True)
if not verify_webhook_signature(payload, signature, os.environ['WEBHOOK_SECRET']):
return 'Invalid signature', 401
event = json.loads(payload)
# Process webhook event
return 'OK', 200Webhook Management
List Webhooks
GET /api/etims/webhooksUpdate Webhook
PUT /api/etims/webhooks/{webhookId}Delete Webhook
DELETE /api/etims/webhooks/{webhookId}Best Practices: Always verify webhook signatures, use HTTPS endpoints, implement idempotency (webhooks may be retried), and respond with 200 OK within 5 seconds.
Data Models
Invoice Object
| Field | Type | Required | Description |
|---|---|---|---|
| invoiceNumber | string | Unique invoice identifier | |
| date | string (ISO 8601) | Invoice date | |
| business | object | Business information | |
| customer | object | Customer information | |
| items | array | Invoice line items | |
| taxRate | number | VAT rate percentage (e.g., 16) |
Error Handling
Error Response Format
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid invoice number format",
"details": {
"field": "invoiceNumber",
"reason": "Must match pattern: INV-YYYY-NNNN"
}
}
}Error Codes
| Code | HTTP Status | Description |
|---|---|---|
| AUTHENTICATION_ERROR | 401 | Invalid or missing API key |
| VALIDATION_ERROR | 400 | Request validation failed |
| RATE_LIMIT_EXCEEDED | 429 | Too many requests |
| KRA_SYNC_ERROR | 500 | Failed to sync with KRA |
| INVOICE_NOT_FOUND | 404 | Invoice doesn't exist |
Rate Limits
To ensure fair usage and system stability, API requests are rate-limited. Rate limit information is included in response headers.
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640995200Free Tier
100 requests per minute
Paid Tier
1000 requests per minute
Testing & Sandbox
Sandbox Environment
Use our sandbox environment to test your integration before going live. The sandbox uses test data and doesn't sync with KRA.
https://sandbox-api.tax.keNote: Sandbox API keys are different from production keys. Contact support to get sandbox access.
Frequently Asked Questions
How do I get an API key?
Sign up for a developer account on tax.ke and navigate to the API section in your dashboard. You can generate and manage API keys from there.
Are invoices automatically synced with KRA?
Yes, all invoices generated through the API are automatically synced with KRA's eTIMS system in real-time. You can check the sync status using the Get Invoice Status endpoint.
What happens if sync fails?
If sync fails, the invoice status will be marked as "failed". You can retry synchronization using the Sync with KRA endpoint. Failed syncs are also logged for troubleshooting.
Can I use the API for production?
Yes, once you've tested your integration in the sandbox environment, you can switch to the production API. Make sure to use production API keys and handle errors appropriately.
How do webhooks work?
Webhooks allow you to receive real-time notifications about invoice events. Set up a webhook URL in your dashboard, and you'll receive POST requests when invoices are synced, fail, or retry. Always verify the webhook signature for security. See the Webhooks section for detailed documentation.
What happens if eTIMS is down?
Our system automatically retries syncing with KRA using exponential backoff. Retries continue for up to 72 hours before marking an invoice as permanently failed. You'll receive webhook notifications for each retry attempt. See the Automatic Retry section for more details.
Need Help?
Have questions or need assistance with the API? We're here to help.