Skip to main content

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

  1. Sign up for a tax.ke developer account
  2. Navigate to your dashboard and generate an API key
  3. Store your API key securely (never commit it to version control)
  4. Start making API calls!

Base URL

https://api.tax.ke

All 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:

js
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.

http
Authorization: Bearer YOUR_API_KEY

Security 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

POST

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

Request Body

json
{
  "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

json
{
  "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"
}
POST

Validate Receipt

Validate an eTIMS receipt against KRA records to ensure authenticity.

POST /api/etims/validate-receipt

Request Body

json
{
  "receiptNumber": "RCP-2024-001",
  "invoiceNumber": "INV-2024-001",
  "kraReference": "KRA-REF-123456",
  "date": "2024-01-15",
  "amount": 2320
}

Response

json
{
  "valid": true,
  "receiptNumber": "RCP-2024-001",
  "invoiceNumber": "INV-2024-001",
  "kraReference": "KRA-REF-123456",
  "validatedAt": "2024-01-15T10:35:00Z",
  "status": "valid"
}
POST

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

Request Body

json
{
  "invoiceId": "inv_abc123",
  "force": false
}

Response

json
{
  "success": true,
  "invoiceId": "inv_abc123",
  "kraReference": "KRA-REF-123456",
  "syncedAt": "2024-01-15T10:30:00Z",
  "status": "synced"
}
GET

Get Invoice Status

Retrieve invoice details and sync status by invoice ID.

GET /api/etims/invoice/{invoiceId}

Response

json
{
  "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"
}
GET

List Invoices

List all invoices with pagination and filtering options.

GET /api/etims/invoices?page=1&limit=20&status=synced

Query Parameters

ParameterTypeDescription
pageintegerPage number (default: 1)
limitintegerItems per page (default: 20, max: 100)
statusstringFilter by status (pending, synced, failed)
fromDatestringFilter from date (ISO 8601)
toDatestringFilter to date (ISO 8601)

Response

json
{
  "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

StatusDescriptionAction
pendingInvoice created, waiting for initial syncAutomatic retry will begin
syncingCurrently attempting to sync with KRAIn progress
retryingPrevious sync failed, retrying automaticallyAutomatic retry in progress
syncedSuccessfully synced with KRAComplete
failedAll 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/webhooks

Request Body

json
{
  "url": "https://your-app.com/webhooks/etims",
  "events": [
    "invoice.synced",
    "invoice.failed",
    "invoice.retrying"
  ],
  "secret": "your-webhook-secret"
}

Response

json
{
  "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

json
{
  "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

json
{
  "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

json
{
  "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)

javascript
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)

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', 200

Webhook Management

List Webhooks

GET /api/etims/webhooks

Update 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

FieldTypeRequiredDescription
invoiceNumberstringUnique invoice identifier
datestring (ISO 8601)Invoice date
businessobjectBusiness information
customerobjectCustomer information
itemsarrayInvoice line items
taxRatenumberVAT rate percentage (e.g., 16)

Error Handling

Error Response Format

json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid invoice number format",
    "details": {
      "field": "invoiceNumber",
      "reason": "Must match pattern: INV-YYYY-NNNN"
    }
  }
}

Error Codes

CodeHTTP StatusDescription
AUTHENTICATION_ERROR401Invalid or missing API key
VALIDATION_ERROR400Request validation failed
RATE_LIMIT_EXCEEDED429Too many requests
KRA_SYNC_ERROR500Failed to sync with KRA
INVOICE_NOT_FOUND404Invoice 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: 1640995200

Free 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.ke

Note: 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.