Overview
Retrieve daily review statistics for the specified time period, including total reviews, completed reviews, and failed reviews. Data is deduplicated by unique PR per day to provide accurate daily metrics.
Authentication
Requires a valid JWT token in the Authorization header:
Authorization: Bearer YOUR_JWT_TOKEN
Query Parameters
Number of days to include in the timeline (7-90)
Response
Returns an array of daily statistics, ordered chronologically.
Array of daily review statistics
Date in ISO format (YYYY-MM-DD)
Total number of unique PRs reviewed on this day
Number of reviews that completed successfully
Number of reviews that failed
Example Request
curl -X GET "https://api.nectr.ai/api/v1/analytics/timeline?days=30" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
Example Response
[
{
"date": "2026-02-08",
"total": 3,
"completed": 3,
"failed": 0
},
{
"date": "2026-02-09",
"total": 5,
"completed": 4,
"failed": 1
},
{
"date": "2026-02-10",
"total": 2,
"completed": 2,
"failed": 0
},
{
"date": "2026-03-07",
"total": 7,
"completed": 6,
"failed": 1
},
{
"date": "2026-03-08",
"total": 4,
"completed": 4,
"failed": 0
},
{
"date": "2026-03-09",
"total": 6,
"completed": 5,
"failed": 0
},
{
"date": "2026-03-10",
"total": 8,
"completed": 7,
"failed": 1
}
]
Deduplication Logic
For each day, if multiple events exist for the same PR (repo + PR number), only the event with the highest priority status is counted:
- completed (highest priority)
- failed
- processing
- pending (lowest priority)
This ensures accurate daily counts even when a PR triggers multiple webhook events.
Use Cases
Activity Chart
import matplotlib.pyplot as plt
from datetime import datetime
timeline = get_timeline(days=30)
dates = [datetime.fromisoformat(d['date']) for d in timeline]
totals = [d['total'] for d in timeline]
completed = [d['completed'] for d in timeline]
plt.figure(figsize=(12, 6))
plt.plot(dates, totals, label='Total Reviews', marker='o')
plt.plot(dates, completed, label='Completed', marker='s')
plt.xlabel('Date')
plt.ylabel('Reviews')
plt.title('PR Review Activity (Last 30 Days)')
plt.legend()
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
Success Rate Trend
timeline = get_timeline(days=30)
print("Daily Success Rate:")
for day in timeline[-7:]:
if day['total'] > 0:
success_rate = (day['completed'] / day['total']) * 100
print(f"{day['date']}: {success_rate:.1f}% ({day['completed']}/{day['total']})")
else:
print(f"{day['date']}: No reviews")
Weekly Aggregation
from datetime import datetime, timedelta
from collections import defaultdict
timeline = get_timeline(days=90)
weeks = defaultdict(lambda: {'total': 0, 'completed': 0, 'failed': 0})
for day in timeline:
date = datetime.fromisoformat(day['date'])
week_start = date - timedelta(days=date.weekday())
week_key = week_start.strftime('%Y-%m-%d')
weeks[week_key]['total'] += day['total']
weeks[week_key]['completed'] += day['completed']
weeks[week_key]['failed'] += day['failed']
print("Weekly Review Summary:")
for week, stats in sorted(weeks.items()):
success_rate = (stats['completed'] / stats['total'] * 100) if stats['total'] > 0 else 0
print(f"Week of {week}: {stats['total']} reviews, {success_rate:.1f}% success rate")
Detect Anomalies
import numpy as np
timeline = get_timeline(days=30)
totals = [d['total'] for d in timeline]
mean = np.mean(totals)
std = np.std(totals)
print("Anomaly Detection:")
for day in timeline[-7:]:
z_score = (day['total'] - mean) / std if std > 0 else 0
if z_score > 2:
print(f"⬆️ {day['date']}: Unusually high activity ({day['total']} reviews, z={z_score:.1f})")
elif z_score < -2:
print(f"⬇️ {day['date']}: Unusually low activity ({day['total']} reviews, z={z_score:.1f})")
else:
print(f"✅ {day['date']}: Normal activity ({day['total']} reviews)")
Compare Periods
timeline = get_timeline(days=60)
this_month = timeline[-30:]
last_month = timeline[-60:-30]
this_month_total = sum(d['total'] for d in this_month)
last_month_total = sum(d['total'] for d in last_month)
change = ((this_month_total - last_month_total) / last_month_total * 100) if last_month_total > 0 else 0
print(f"This Month: {this_month_total} reviews")
print(f"Last Month: {last_month_total} reviews")
print(f"Change: {change:+.1f}%")
Notes
- All days in the specified range are included, even if no reviews occurred (total = 0)
- The timeline always starts from
(current_date - days + 1) to ensure consistent range
- Data is ordered chronologically from oldest to newest
- Failed reviews typically indicate webhook processing errors or AI service failures
- Reviews in
processing or pending state are counted in total but not in completed or failed