curl --request GET \
--url https://api.bookovia.com/v1/analytics/safety-score/{trip_id} \
--header 'X-API-Key: <api-key>'{
"error": {
"code": "trip_not_found",
"message": "Trip not found or insufficient data for safety analysis",
"details": "Trip must have at least 50 location points and 10 minutes duration"
}
}
Retrieve detailed safety score analysis including driving behavior metrics, risk assessment, and improvement recommendations
curl --request GET \
--url https://api.bookovia.com/v1/analytics/safety-score/{trip_id} \
--header 'X-API-Key: <api-key>'{
"error": {
"code": "trip_not_found",
"message": "Trip not found or insufficient data for safety analysis",
"details": "Trip must have at least 50 location points and 10 minutes duration"
}
}
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.
X-API-Key header.
Required permissions: analytics:read
curl -X GET "https://api.bookovia.com/v1/analytics/safety-score/trip_1234567890abcdef?include_breakdown=true&include_benchmarks=true" \
-H "X-API-Key: bkv_test_your_api_key_here"
Show trip_context properties
Show score_breakdown properties
{
"trip_id": "trip_1234567890abcdef",
"overall_safety_score": 87,
"score_grade": "B+",
"analysis_timestamp": "2024-04-13T12:20:00Z",
"trip_context": {
"distance_km": 45.2,
"duration_minutes": 105,
"road_types": {
"highway_percentage": 65.0,
"city_percentage": 30.0,
"rural_percentage": 5.0
},
"weather_conditions": "clear",
"traffic_density": "moderate",
"time_of_day": "morning",
"day_of_week": "tuesday"
},
"score_breakdown": {
"acceleration_score": 92,
"braking_score": 78,
"cornering_score": 95,
"speed_compliance_score": 85,
"following_distance_score": 88,
"distraction_score": 91,
"consistency_score": 89,
"score_weights": {
"acceleration": 0.15,
"braking": 0.20,
"cornering": 0.15,
"speed_compliance": 0.25,
"following_distance": 0.15,
"distraction": 0.05,
"consistency": 0.05
}
},
"risk_factors": [
{
"factor_id": "harsh_braking_001",
"factor_type": "harsh_braking",
"severity": "moderate",
"frequency": 2,
"score_impact": 8,
"description": "Two moderate harsh braking events detected during city driving",
"timestamps": [
"2024-04-13T11:22:15Z",
"2024-04-13T11:45:30Z"
],
"locations": [
{"latitude": 40.7298, "longitude": -73.9973},
{"latitude": 40.7412, "longitude": -73.9897}
]
},
{
"factor_id": "speed_exceed_001",
"factor_type": "speed_violation",
"severity": "low",
"frequency": 1,
"score_impact": 5,
"description": "Brief speed limit exceedance on highway segment",
"duration_seconds": 45,
"max_speed_over_limit": 8,
"location": {"latitude": 40.7589, "longitude": -73.9612}
}
],
"positive_indicators": [
{
"indicator_type": "smooth_acceleration",
"frequency": 18,
"score_bonus": 3,
"description": "Consistently smooth acceleration patterns"
},
{
"indicator_type": "safe_following_distance",
"percentage": 92.5,
"score_bonus": 2,
"description": "Maintained safe following distance 92.5% of the time"
}
],
"benchmarks": {
"vs_driver_average": {
"driver_id": "driver_456",
"driver_30d_average": 82,
"comparison": "+5 points above driver average",
"percentile": 68
},
"vs_fleet_average": {
"organization_id": "org_abcdef123456",
"fleet_30d_average": 79,
"comparison": "+8 points above fleet average",
"percentile": 75
},
"vs_industry_benchmark": {
"industry_segment": "commercial_delivery",
"industry_average": 76,
"comparison": "+11 points above industry average",
"percentile": 82
}
},
"recommendations": [
{
"category": "braking",
"priority": "high",
"title": "Improve braking smoothness",
"description": "Focus on earlier brake application to avoid harsh braking events, especially in city driving conditions",
"specific_actions": [
"Increase following distance in traffic",
"Anticipate traffic light changes",
"Practice gradual deceleration techniques"
],
"potential_improvement": "+5-8 safety score points"
},
{
"category": "speed_management",
"priority": "medium",
"title": "Maintain consistent speed compliance",
"description": "Monitor speed more closely on highway segments to avoid exceeding limits",
"specific_actions": [
"Use cruise control on highways when appropriate",
"Set speed limit alerts on navigation system",
"Practice checking speedometer regularly"
],
"potential_improvement": "+2-4 safety score points"
}
],
"improvement_potential": {
"maximum_possible_score": 95,
"current_score": 87,
"improvement_points_available": 8,
"primary_focus_areas": ["braking", "speed_compliance"],
"estimated_timeline": "2-4 weeks with focused practice"
}
}
{
"error": {
"code": "trip_not_found",
"message": "Trip not found or insufficient data for safety analysis",
"details": "Trip must have at least 50 location points and 10 minutes duration"
}
}
import Bookovia from '@bookovia/javascript-sdk';
const client = new Bookovia('bkv_test_your_api_key');
// Get comprehensive safety analysis
const safetyAnalysis = await client.analytics.getSafetyScore('trip_1234567890abcdef', {
includeBreakdown: true,
includeBenchmarks: true,
includeRecommendations: true,
comparePeriod: '30d'
});
console.log(`Safety Score: ${safetyAnalysis.overallSafetyScore} (${safetyAnalysis.scoreGrade})`);
// Display risk factors
console.log('\nRisk Factors:');
safetyAnalysis.riskFactors.forEach(risk => {
console.log(`- ${risk.factorType}: ${risk.description} (Impact: -${risk.scoreImpact} points)`);
});
// Display improvement recommendations
console.log('\nRecommendations for improvement:');
safetyAnalysis.recommendations.forEach(rec => {
console.log(`${rec.priority.toUpperCase()}: ${rec.title}`);
console.log(` ${rec.description}`);
console.log(` Potential improvement: ${rec.potentialImprovement}`);
});
// Driver performance dashboard
const createSafetyDashboard = async (driverTrips) => {
const analyses = await Promise.all(
driverTrips.map(tripId =>
client.analytics.getSafetyScore(tripId, { includeBenchmarks: true })
)
);
const averageScore = analyses.reduce((sum, a) => sum + a.overallSafetyScore, 0) / analyses.length;
const trendDirection = analyses.length > 1 ?
(analyses[analyses.length - 1].overallSafetyScore > analyses[0].overallSafetyScore ? 'improving' : 'declining') :
'stable';
return {
averageScore,
trendDirection,
totalTrips: analyses.length,
riskPatterns: analyses.flatMap(a => a.riskFactors)
.reduce((acc, risk) => {
acc[risk.factorType] = (acc[risk.factorType] || 0) + 1;
return acc;
}, {}),
recommendations: analyses.flatMap(a => a.recommendations)
.filter(rec => rec.priority === 'high')
};
};
// Fleet safety comparison
const compareFleetSafety = async (vehicleTrips) => {
const fleetAnalyses = {};
for (const [vehicleId, tripIds] of Object.entries(vehicleTrips)) {
const vehicleScores = await Promise.all(
tripIds.map(tripId => client.analytics.getSafetyScore(tripId))
);
fleetAnalyses[vehicleId] = {
averageScore: vehicleScores.reduce((sum, s) => sum + s.overallSafetyScore, 0) / vehicleScores.length,
totalTrips: vehicleScores.length,
riskCount: vehicleScores.reduce((sum, s) => sum + s.riskFactors.length, 0)
};
}
// Rank vehicles by safety performance
const rankings = Object.entries(fleetAnalyses)
.sort(([,a], [,b]) => b.averageScore - a.averageScore)
.map(([vehicleId, analysis], index) => ({
rank: index + 1,
vehicleId,
...analysis
}));
return {
fleetAverage: Object.values(fleetAnalyses)
.reduce((sum, a) => sum + a.averageScore, 0) / Object.keys(fleetAnalyses).length,
rankings,
topPerformer: rankings[0],
needsImprovement: rankings.filter(r => r.averageScore < 75)
};
};
// Comprehensive driver performance management system
class DriverPerformanceManager {
constructor(client) {
this.client = client;
this.performanceThresholds = {
excellent: 90,
good: 80,
acceptable: 70,
needsImprovement: 60
};
}
async generateDriverPerformanceReport(driverId, evaluationPeriod = '30d') {
// Get all trips for the driver in the period
const trips = await this.getDriverTrips(driverId, evaluationPeriod);
// Analyze safety scores for all trips
const safetyAnalyses = await Promise.all(
trips.map(trip =>
this.client.analytics.getSafetyScore(trip.trip_id, {
includeBreakdown: true,
includeBenchmarks: true,
includeRecommendations: true
})
)
);
// Generate comprehensive performance analysis
return this.generatePerformanceAnalysis(driverId, safetyAnalyses, evaluationPeriod);
}
generatePerformanceAnalysis(driverId, safetyAnalyses, period) {
const scores = safetyAnalyses.map(a => a.overallSafetyScore);
const currentAverage = scores.reduce((sum, score) => sum + score, 0) / scores.length;
// Trend analysis
const trendAnalysis = this.calculatePerformanceTrend(scores);
// Behavior analysis
const behaviorAnalysis = this.analyzeBehaviorPatterns(safetyAnalyses);
// Risk assessment
const riskAssessment = this.assessRiskProfile(safetyAnalyses);
// Generate coaching recommendations
const coachingPlan = this.generateCoachingPlan(behaviorAnalysis, riskAssessment);
return {
driverId,
evaluationPeriod: period,
overallPerformance: {
currentScore: Math.round(currentAverage),
grade: this.calculateGrade(currentAverage),
performanceLevel: this.getPerformanceLevel(currentAverage),
trend: trendAnalysis,
totalTripsAnalyzed: safetyAnalyses.length
},
behaviorAnalysis,
riskAssessment,
coachingPlan,
benchmarkComparison: this.extractBenchmarkData(safetyAnalyses),
nextEvaluationDate: this.calculateNextEvaluationDate(currentAverage, trendAnalysis.direction)
};
}
calculatePerformanceTrend(scores) {
if (scores.length < 3) return { direction: 'insufficient_data', stability: 'unknown' };
const recentScores = scores.slice(-Math.min(5, scores.length));
const olderScores = scores.slice(0, Math.min(5, scores.length));
const recentAverage = recentScores.reduce((sum, s) => sum + s, 0) / recentScores.length;
const olderAverage = olderScores.reduce((sum, s) => sum + s, 0) / olderScores.length;
const difference = recentAverage - olderAverage;
const standardDeviation = this.calculateStandardDeviation(scores);
let direction;
if (Math.abs(difference) < 2) direction = 'stable';
else if (difference > 0) direction = 'improving';
else direction = 'declining';
return {
direction,
changePoints: Math.abs(Math.round(difference)),
stability: standardDeviation < 5 ? 'consistent' : standardDeviation < 10 ? 'variable' : 'volatile',
volatility: standardDeviation
};
}
analyzeBehaviorPatterns(safetyAnalyses) {
const behaviors = {
acceleration: [],
braking: [],
cornering: [],
speedCompliance: [],
followingDistance: [],
distraction: []
};
// Aggregate behavior scores
safetyAnalyses.forEach(analysis => {
const breakdown = analysis.scoreBreakdown;
behaviors.acceleration.push(breakdown.accelerationScore);
behaviors.braking.push(breakdown.brakingScore);
behaviors.cornering.push(breakdown.corneringScore);
behaviors.speedCompliance.push(breakdown.speedComplianceScore);
behaviors.followingDistance.push(breakdown.followingDistanceScore);
behaviors.distraction.push(breakdown.distractionScore);
});
// Calculate averages and identify strengths/weaknesses
const behaviorSummary = {};
const strengths = [];
const weaknesses = [];
for (const [behavior, scores] of Object.entries(behaviors)) {
const average = scores.reduce((sum, s) => sum + s, 0) / scores.length;
const trend = this.calculateBehaviorTrend(scores);
behaviorSummary[behavior] = {
averageScore: Math.round(average),
trend: trend.direction,
consistency: trend.consistency,
grade: this.calculateGrade(average)
};
if (average >= 85) strengths.push(behavior);
if (average < 75) weaknesses.push(behavior);
}
return {
behaviorScores: behaviorSummary,
strengths,
weaknesses,
primaryFocusArea: weaknesses[0] || null
};
}
assessRiskProfile(safetyAnalyses) {
const allRiskFactors = [];
const riskFrequency = {};
let totalScoreImpact = 0;
safetyAnalyses.forEach(analysis => {
analysis.riskFactors.forEach(risk => {
allRiskFactors.push(risk);
riskFrequency[risk.factorType] = (riskFrequency[risk.factorType] || 0) + 1;
totalScoreImpact += risk.scoreImpact;
});
});
// Calculate risk metrics
const avgRisksPerTrip = allRiskFactors.length / safetyAnalyses.length;
const mostCommonRisk = Object.entries(riskFrequency)
.sort(([,a], [,b]) => b - a)[0];
// Determine risk level
let riskLevel;
if (avgRisksPerTrip < 0.5) riskLevel = 'low';
else if (avgRisksPerTrip < 1.5) riskLevel = 'moderate';
else if (avgRisksPerTrip < 3) riskLevel = 'high';
else riskLevel = 'critical';
return {
riskLevel,
avgRisksPerTrip: Math.round(avgRisksPerTrip * 10) / 10,
totalRiskIncidents: allRiskFactors.length,
avgScoreImpactPerTrip: Math.round(totalScoreImpact / safetyAnalyses.length),
mostCommonRiskType: mostCommonRisk ? mostCommonRisk[0] : null,
riskFrequencyDistribution: riskFrequency,
recentRiskTrend: this.analyzeRiskTrend(safetyAnalyses)
};
}
generateCoachingPlan(behaviorAnalysis, riskAssessment) {
const coachingPlan = {
priority: this.determineCoachingPriority(behaviorAnalysis, riskAssessment),
focusAreas: [],
recommendedActions: [],
timeframe: '',
expectedImprovement: ''
};
// Identify focus areas based on weaknesses
if (behaviorAnalysis.weaknesses.length > 0) {
coachingPlan.focusAreas = behaviorAnalysis.weaknesses.slice(0, 2); // Top 2 weaknesses
}
// Add risk-based focus areas
if (riskAssessment.mostCommonRiskType) {
coachingPlan.focusAreas.push(`risk_reduction_${riskAssessment.mostCommonRiskType}`);
}
// Generate specific actions
coachingPlan.recommendedActions = this.generateSpecificActions(
behaviorAnalysis.weaknesses,
riskAssessment.mostCommonRiskType,
coachingPlan.priority
);
// Set timeframe and expectations
switch (coachingPlan.priority) {
case 'high':
coachingPlan.timeframe = '2-3 weeks';
coachingPlan.expectedImprovement = '5-10 points';
break;
case 'medium':
coachingPlan.timeframe = '1-2 months';
coachingPlan.expectedImprovement = '3-7 points';
break;
case 'low':
coachingPlan.timeframe = '2-3 months';
coachingPlan.expectedImprovement = '2-5 points';
break;
}
return coachingPlan;
}
// Helper methods
calculateStandardDeviation(values) {
const mean = values.reduce((sum, val) => sum + val, 0) / values.length;
const variance = values.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / values.length;
return Math.sqrt(variance);
}
calculateGrade(score) {
if (score >= 95) return 'A+';
if (score >= 90) return 'A';
if (score >= 85) return 'B+';
if (score >= 80) return 'B';
if (score >= 75) return 'C+';
if (score >= 70) return 'C';
if (score >= 65) return 'D+';
if (score >= 60) return 'D';
return 'F';
}
getPerformanceLevel(score) {
if (score >= this.performanceThresholds.excellent) return 'excellent';
if (score >= this.performanceThresholds.good) return 'good';
if (score >= this.performanceThresholds.acceptable) return 'acceptable';
return 'needs_improvement';
}
}
// Usage example
const performanceManager = new DriverPerformanceManager(client);
const driverReport = await performanceManager.generateDriverPerformanceReport('driver_456', '30d');
console.log('Driver Performance Report');
console.log('========================');
console.log(`Current Score: ${driverReport.overallPerformance.currentScore} (${driverReport.overallPerformance.grade})`);
console.log(`Performance Level: ${driverReport.overallPerformance.performanceLevel}`);
console.log(`Trend: ${driverReport.overallPerformance.trend.direction}`);
console.log('\nBehavior Analysis:');
console.log(`Strengths: ${driverReport.behaviorAnalysis.strengths.join(', ') || 'None identified'}`);
console.log(`Weaknesses: ${driverReport.behaviorAnalysis.weaknesses.join(', ') || 'None identified'}`);
console.log('\nRisk Assessment:');
console.log(`Risk Level: ${driverReport.riskAssessment.riskLevel}`);
console.log(`Avg Risks per Trip: ${driverReport.riskAssessment.avgRisksPerTrip}`);
console.log('\nCoaching Recommendations:');
console.log(`Priority: ${driverReport.coachingPlan.priority}`);
console.log(`Timeframe: ${driverReport.coachingPlan.timeframe}`);
console.log(`Expected Improvement: ${driverReport.coachingPlan.expectedImprovement}`);
Score Ranges
Contextual Factors
Fleet Management
// Regular safety score monitoring
const monitorFleetSafety = async () => {
const activeTrips = await client.trips.list({ status: 'completed', limit: 100 });
for (const trip of activeTrips.trips) {
const safetyScore = await client.analytics.getSafetyScore(trip.trip_id);
if (safetyScore.overallSafetyScore < 70) {
await alertFleetManager(trip.driver_id, safetyScore);
}
}
};
setInterval(monitorFleetSafety, 24 * 60 * 60 * 1000); // Daily
Driver Development
Was this page helpful?