Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.bookovia.com/llms.txt

Use this file to discover all available pages before exploring further.

Bookovia JavaScript SDK

The official JavaScript SDK for the Bookovia Telematics API provides seamless integration for web applications and Node.js backends with universal compatibility.

Features

  • Universal Compatibility - Works in browser and Node.js environments
  • Promise-based API - Modern async/await and Promise support
  • Automatic Retries - Built-in retry logic with exponential backoff
  • Request/Response Transformation - Automatic JSON handling
  • TypeScript Definitions - Full TypeScript support included
  • Lightweight - Minimal dependencies and small bundle size

Installation

npm

npm install @bookovia/javascript-sdk

yarn

yarn add @bookovia/javascript-sdk

CDN (Browser)

<script src="https://unpkg.com/@bookovia/javascript-sdk@latest/dist/bookovia.min.js"></script>
Compatibility: Node.js 16+, Modern browsers (ES2017+)

Quick Start

Initialize the Client

// ES6 Modules
import Bookovia from '@bookovia/javascript-sdk';

// CommonJS
const Bookovia = require('@bookovia/javascript-sdk');

// Initialize client
const client = new Bookovia('bkv_live_your_api_key_here');

// With custom configuration
const client = new Bookovia('bkv_live_your_api_key_here', {
  baseUrl: 'https://api.bookovia.com/v1',
  timeout: 30000,
  retryCount: 3,
  debug: false
});

Browser Usage

<!DOCTYPE html>
<html>
<head>
    <script src="https://unpkg.com/@bookovia/javascript-sdk@latest/dist/bookovia.min.js"></script>
</head>
<body>
    <script>
        const client = new Bookovia('bkv_live_your_api_key_here');
        
        // Your code here
    </script>
</body>
</html>

Start a Trip

async function startTrip() {
  try {
    const trip = await client.trips.start({
      vehicleId: 'vehicle_123',
      driverId: 'driver_456',
      startLocation: {
        latitude: 40.7128,
        longitude: -74.0060
      },
      metadata: {
        purpose: 'delivery',
        route: 'downtown'
      }
    });
    
    console.log('Trip started:', trip.tripId);
    return trip;
  } catch (error) {
    console.error('Failed to start trip:', error);
  }
}

Upload Location Data

async function uploadLocations(tripId) {
  const locations = [
    {
      latitude: 40.7128,
      longitude: -74.0060,
      timestamp: new Date().toISOString(),
      speed: 35,
      heading: 180
    },
    {
      latitude: 40.7130,
      longitude: -74.0058,
      timestamp: new Date(Date.now() + 30000).toISOString(),
      speed: 42,
      heading: 175
    }
  ];
  
  try {
    await client.locations.batchUpload({
      tripId: tripId,
      locations: locations
    });
    
    console.log('Locations uploaded successfully');
  } catch (error) {
    console.error('Failed to upload locations:', error);
  }
}

API Reference

Client Configuration

const client = new Bookovia(apiKey, {
  baseUrl: 'https://api.bookovia.com/v1',  // API base URL
  timeout: 30000,                          // Request timeout in milliseconds
  retryCount: 3,                          // Number of retry attempts
  retryDelay: 1000,                       // Initial retry delay in milliseconds
  debug: false,                           // Enable debug logging
  defaultHeaders: {},                     // Additional headers for all requests
  
  // Request/Response interceptors
  requestInterceptor: (config) => config,
  responseInterceptor: (response) => response
});

Trip Management

User Trip Queries

// Get all active trips for a user
const activeTrips = await client.getUserActiveTrips('user_123');
console.log(`User has ${activeTrips.data.count} active trips`);

// Get trip history for a user
const completedTrips = await client.getUserTripHistory('user_123', 'completed');
const allHistory = await client.getUserTripHistory('user_123'); // defaults to completed

Organization Trip Queries

// Get all active trips for an organization
const orgActiveTrips = await client.getOrgActiveTrips('org_123');
console.log(`Organization has ${orgActiveTrips.data.count} active trips`);

// Get trip history for an organization
const orgHistory = await client.getOrgTripHistory('org_123', 'completed');
const cancelledTrips = await client.getOrgTripHistory('org_123', 'cancelled');

Vehicle Trip Queries

// Get all active trips for a vehicle
const vehicleActiveTrips = await client.getVehicleActiveTrips('vehicle_123');

// Get trip history for a vehicle
const vehicleHistory = await client.getVehicleTripHistory('vehicle_123', 'completed');

Legacy Methods

// Get trip details
const trip = await client.trips.get('tripId');

// Get trip summary with analytics
const summary = await client.trips.getSummary('tripId');

Location Services

// Upload single location
await client.locations.upload({
  tripId: 'trip_123',
  latitude: 40.7128,
  longitude: -74.0060,
  timestamp: new Date().toISOString(),
  speed: 35,
  heading: 180,
  accuracy: 5                   // Optional
});

// Batch upload locations
await client.locations.batchUpload({
  tripId: 'trip_123',
  locations: [
    {
      latitude: 40.7128,
      longitude: -74.0060,
      timestamp: '2024-04-13T10:30:00Z',
      speed: 35,
      heading: 180
    }
    // ... more locations
  ]
});

// Get route for trip
const route = await client.locations.getRoute('tripId');

// Find nearby locations
const nearby = await client.locations.findNearby({
  latitude: 40.7128,
  longitude: -74.0060,
  radius: 1000                  // meters
});

Safety Analytics

// Get safety score
const score = await client.safety.getScore({
  tripId: 'trip_123',          // OR
  driverId: 'driver_456',      // OR
  vehicleId: 'vehicle_123',
  dateRange: {                 // Optional
    start: '2024-01-01',
    end: '2024-01-31'
  }
});

// Analyze driving behavior
const analysis = await client.safety.analyzeBehavior({
  tripId: 'trip_123'
});

// Get harsh events
const events = await client.safety.getHarshEvents({
  tripId: 'trip_123',          // Optional
  eventType: 'harsh_braking',  // Optional
  severity: 'medium',          // Optional
  limit: 50
});

// Get crash risk assessment
const risk = await client.safety.getCrashRisk({
  driverId: 'driver_456',
  timeframe: '30days'
});

Fleet Management

// Get fleet overview
const overview = await client.fleet.getOverview();

// List vehicles
const vehicles = await client.fleet.getVehicles({
  status: 'active',            // Optional
  limit: 100
});

// Get vehicle utilization
const utilization = await client.fleet.getUtilization({
  vehicleId: 'vehicle_123',    // Optional
  timeframe: '7days'
});

// Get fleet optimization suggestions
const optimization = await client.fleet.getOptimization({
  fleetId: 'fleet_456'
});

Data Types

Trip Object

{
  tripId: 'trip_1234567890',
  vehicleId: 'vehicle_123',
  driverId: 'driver_456',
  status: 'active',                    // active | completed | paused | cancelled
  startTime: '2024-04-13T10:30:00Z',
  endTime: null,
  startLocation: {
    latitude: 40.7128,
    longitude: -74.0060,
    address: 'New York, NY'
  },
  endLocation: null,
  analytics: {
    distanceKm: 45.7,
    durationMinutes: 67,
    maxSpeedKmh: 85,
    avgSpeedKmh: 42,
    idleTimeMinutes: 12,
    locationsCount: 892,
    eventsCount: 3,
    safetyScore: 87,
    ecoScore: 92
  },
  metadata: {
    purpose: 'delivery',
    route: 'downtown'
  }
}

Location Point

{
  latitude: 40.7128,
  longitude: -74.0060,
  timestamp: '2024-04-13T10:30:00Z',
  speed: 35,                          // km/h
  heading: 180,                       // degrees (0-360)
  accuracy: 5,                        // meters
  altitude: 10                        // meters (optional)
}

Error Handling

The SDK throws specific error types for different scenarios:
try {
  const trip = await client.trips.start({
    vehicleId: 'vehicle_123'
  });
} catch (error) {
  if (error instanceof Bookovia.AuthenticationError) {
    console.error('Authentication failed:', error.message);
    // Handle auth error (check API key)
    
  } else if (error instanceof Bookovia.ValidationError) {
    console.error('Validation error:', error.message);
    console.error('Invalid fields:', error.fields);
    // Handle validation error
    
  } else if (error instanceof Bookovia.RateLimitError) {
    console.error('Rate limit exceeded, retry after:', error.retryAfter);
    // Handle rate limiting
    
  } else if (error instanceof Bookovia.NotFoundError) {
    console.error('Resource not found:', error.message);
    // Handle not found error
    
  } else {
    console.error('Unexpected error:', error);
  }
}

Error Types

// Available error classes
Bookovia.AuthenticationError    // 401 - Invalid API key
Bookovia.ValidationError        // 400 - Invalid request data  
Bookovia.NotFoundError         // 404 - Resource not found
Bookovia.RateLimitError        // 429 - Rate limit exceeded
Bookovia.ServerError           // 500+ - Server errors
Bookovia.NetworkError          // Network connectivity issues

Advanced Usage

Custom Request Interceptors

const client = new Bookovia('your-api-key', {
  requestInterceptor: (config) => {
    // Add custom headers
    config.headers['X-Custom-Header'] = 'custom-value';
    
    // Log requests in debug mode
    if (process.env.NODE_ENV === 'development') {
      console.log('Request:', config);
    }
    
    return config;
  },
  
  responseInterceptor: (response) => {
    // Log response times
    console.log('Response time:', response.responseTime, 'ms');
    
    return response;
  }
});

Retry Logic with Custom Backoff

async function startTripWithRetry(client, tripData, maxRetries = 3) {
  let lastError;
  
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await client.trips.start(tripData);
    } catch (error) {
      lastError = error;
      
      // Don't retry for certain error types
      if (error instanceof Bookovia.AuthenticationError || 
          error instanceof Bookovia.ValidationError) {
        throw error;
      }
      
      if (attempt < maxRetries) {
        const delay = Math.pow(2, attempt - 1) * 1000; // Exponential backoff
        await new Promise(resolve => setTimeout(resolve, delay));
        console.log(`Retry attempt ${attempt} after ${delay}ms`);
      }
    }
  }
  
  throw lastError;
}

Real-time Location Streaming

class LocationTracker {
  constructor(client) {
    this.client = client;
    this.intervalId = null;
  }
  
  start(tripId, intervalMs = 30000) {
    this.intervalId = setInterval(async () => {
      try {
        // Get current location (browser geolocation API)
        const position = await this.getCurrentPosition();
        
        await this.client.locations.upload({
          tripId: tripId,
          latitude: position.coords.latitude,
          longitude: position.coords.longitude,
          timestamp: new Date().toISOString(),
          speed: position.coords.speed || 0,
          heading: position.coords.heading || 0,
          accuracy: position.coords.accuracy
        });
        
        console.log('Location uploaded successfully');
      } catch (error) {
        console.error('Failed to upload location:', error);
      }
    }, intervalMs);
  }
  
  stop() {
    if (this.intervalId) {
      clearInterval(this.intervalId);
      this.intervalId = null;
    }
  }
  
  getCurrentPosition() {
    return new Promise((resolve, reject) => {
      navigator.geolocation.getCurrentPosition(resolve, reject, {
        enableHighAccuracy: true,
        timeout: 10000,
        maximumAge: 30000
      });
    });
  }
}

// Usage
const tracker = new LocationTracker(client);
tracker.start('trip_123', 30000); // Upload every 30 seconds

Browser Integration

<!DOCTYPE html>
<html>
<head>
    <title>Bookovia Fleet Tracker</title>
    <script src="https://unpkg.com/@bookovia/javascript-sdk@latest/dist/bookovia.min.js"></script>
</head>
<body>
    <div id="status">Initializing...</div>
    <button id="startTrip">Start Trip</button>
    <button id="stopTrip" disabled>Stop Trip</button>
    
    <script>
        const client = new Bookovia('bkv_live_your_api_key');
        let currentTrip = null;
        let tracker = null;
        
        document.getElementById('startTrip').onclick = async () => {
          try {
            currentTrip = await client.trips.start({
              vehicleId: 'web_vehicle_001',
              metadata: { source: 'web_app' }
            });
            
            document.getElementById('status').textContent = 
              `Trip started: ${currentTrip.tripId}`;
            document.getElementById('startTrip').disabled = true;
            document.getElementById('stopTrip').disabled = false;
            
            // Start location tracking
            startLocationTracking();
            
          } catch (error) {
            alert('Failed to start trip: ' + error.message);
          }
        };
        
        document.getElementById('stopTrip').onclick = async () => {
          try {
            if (tracker) {
              clearInterval(tracker);
              tracker = null;
            }
            
            await client.trips.stop(currentTrip.tripId);
            
            document.getElementById('status').textContent = 'Trip completed';
            document.getElementById('startTrip').disabled = false;
            document.getElementById('stopTrip').disabled = true;
            
          } catch (error) {
            alert('Failed to stop trip: ' + error.message);
          }
        };
        
        function startLocationTracking() {
          tracker = setInterval(async () => {
            if (navigator.geolocation && currentTrip) {
              navigator.geolocation.getCurrentPosition(async (position) => {
                try {
                  await client.locations.upload({
                    tripId: currentTrip.tripId,
                    latitude: position.coords.latitude,
                    longitude: position.coords.longitude,
                    timestamp: new Date().toISOString(),
                    speed: position.coords.speed || 0,
                    accuracy: position.coords.accuracy
                  });
                  
                  document.getElementById('status').textContent = 
                    `Tracking trip: ${currentTrip.tripId}`;
                    
                } catch (error) {
                  console.error('Location upload failed:', error);
                }
              });
            }
          }, 30000); // Every 30 seconds
        }
    </script>
</body>
</html>

Testing

Jest Testing Example

// __tests__/bookovia.test.js
import Bookovia from '@bookovia/javascript-sdk';

// Mock the SDK for testing
jest.mock('@bookovia/javascript-sdk');

describe('Bookovia SDK', () => {
  let client;
  
  beforeEach(() => {
    client = new Bookovia('test_api_key');
  });
  
  test('should start a trip successfully', async () => {
    const mockTrip = {
      tripId: 'trip_123',
      vehicleId: 'vehicle_123',
      status: 'active'
    };
    
    client.trips.start.mockResolvedValue(mockTrip);
    
    const result = await client.trips.start({
      vehicleId: 'vehicle_123'
    });
    
    expect(result).toEqual(mockTrip);
    expect(client.trips.start).toHaveBeenCalledWith({
      vehicleId: 'vehicle_123'
    });
  });
  
  test('should handle authentication errors', async () => {
    const authError = new Bookovia.AuthenticationError('Invalid API key');
    client.trips.start.mockRejectedValue(authError);
    
    await expect(client.trips.start({ vehicleId: 'test' }))
      .rejects.toThrow('Invalid API key');
  });
});

Examples

Fleet Dashboard

class FleetDashboard {
  constructor(apiKey) {
    this.client = new Bookovia(apiKey);
    this.activeTrips = new Map();
  }
  
  async initialize() {
    // Load active trips
    const trips = await this.client.trips.list({ status: 'active' });
    trips.trips.forEach(trip => {
      this.activeTrips.set(trip.tripId, trip);
    });
    
    console.log(`Loaded ${this.activeTrips.size} active trips`);
  }
  
  async startFleetTrip(vehicleId, driverId) {
    try {
      const trip = await this.client.trips.start({
        vehicleId: vehicleId,
        driverId: driverId,
        metadata: {
          fleet: 'main_fleet',
          startedBy: 'dashboard'
        }
      });
      
      this.activeTrips.set(trip.tripId, trip);
      console.log(`Started trip ${trip.tripId} for vehicle ${vehicleId}`);
      
      return trip;
    } catch (error) {
      console.error(`Failed to start trip for ${vehicleId}:`, error);
      throw error;
    }
  }
  
  async getFleetStatus() {
    const status = {
      totalVehicles: 0,
      activeTrips: this.activeTrips.size,
      totalDistance: 0,
      avgSafetyScore: 0
    };
    
    for (const trip of this.activeTrips.values()) {
      if (trip.analytics) {
        status.totalDistance += trip.analytics.distanceKm || 0;
        status.avgSafetyScore += trip.analytics.safetyScore || 0;
      }
    }
    
    if (this.activeTrips.size > 0) {
      status.avgSafetyScore /= this.activeTrips.size;
    }
    
    return status;
  }
}

// Usage
const dashboard = new FleetDashboard('bkv_live_your_api_key');
await dashboard.initialize();

const status = await dashboard.getFleetStatus();
console.log('Fleet Status:', status);

Support


Ready to integrate? Check out our quickstart guide and API reference for more examples.