Skip to main content

API Endpoints

The Email Assistant web interface exposes several API endpoints for data retrieval and control.

Base URLโ€‹

http://localhost:8001

Endpointsโ€‹

Pagesโ€‹

GET /โ€‹

Main digest page.

Response: HTML page with email digest


GET /testsโ€‹

Test results page.

Response: HTML page with test execution results


API Endpointsโ€‹

GET /api/digestโ€‹

Get current digest data.

Response:

{
"generated_at": "2024-12-22T09:30:00",
"categories": {
"Need-Action": [
{
"id": "msg_123",
"subject": "Meeting invite",
"from": "john@example.com",
"date": "2024-12-22",
"snippet": "Please join..."
}
],
"FYI": [...],
"Newsletter": [...],
"Promotional": [...],
"Social": [...]
},
"summaries": {
"Need-Action": "3 emails requiring response...",
"Newsletter": "Highlights from tech newsletters..."
},
"stats": {
"total_emails": 15,
"api_calls": 12,
"execution_time": 8.5
}
}

POST /api/refreshโ€‹

Trigger email processing refresh.

Request: No body required

Response (Success):

{
"status": "success",
"message": "Digest refreshed",
"execution_time": 12.3
}

Response (Already Running):

{
"status": "busy",
"message": "Refresh already in progress"
}

Response (Error):

{
"status": "error",
"message": "Failed to refresh: API error"
}

GET /api/statusโ€‹

Check if refresh script is running.

Response:

{
"running": false,
"last_run": "2024-12-22T09:30:00",
"lock_file_exists": false
}

GET /api/metricsโ€‹

Get performance metrics.

Query Parameters:

ParameterTypeDefaultDescription
periodstring24hTime period: 24h, 7d, all

Response:

{
"period": "24h",
"metrics": {
"emails_processed": 45,
"api_calls": 127,
"cache_hit_rate": 87.5,
"avg_execution_time": 8.2,
"success_rate": 98.2,
"estimated_cost": 1.27,
"script_run_count": 12,
"error_count": 2
},
"category_breakdown": {
"Need-Action": 15,
"FYI": 12,
"Newsletter": 10,
"Promotional": 5,
"Social": 3
}
}

GET /api/errorsโ€‹

Get recent errors.

Query Parameters:

ParameterTypeDefaultDescription
limitint10Maximum errors to return

Response:

{
"errors": [
{
"timestamp": "2024-12-22T09:15:23",
"module": "gemini_utils",
"error_type": "RateLimitError",
"message": "API rate limit exceeded",
"traceback": "..."
},
{
"timestamp": "2024-12-21T14:30:45",
"module": "email_utils",
"error_type": "ConnectionError",
"message": "Failed to connect to Gmail API"
}
]
}

Test Endpointsโ€‹

POST /api/tests/runโ€‹

Run test suite.

Request:

{
"suite": "basic" // basic, extended, comprehensive
}

Response:

{
"status": "success",
"suite": "basic",
"results": {
"passed": 18,
"failed": 2,
"skipped": 0,
"total": 20,
"duration": 15.3
},
"failures": [
{
"test": "test_api_rate_limit",
"message": "Expected retry, got immediate failure"
}
]
}

GET /api/tests/resultsโ€‹

Get latest test results.

Response:

{
"last_run": "2024-12-22T10:00:00",
"suite": "comprehensive",
"results": {
"passed": 53,
"failed": 2,
"skipped": 0,
"total": 55,
"duration": 45.7
}
}

Implementationโ€‹

Flask Serverโ€‹

# server.py

from flask import Flask, jsonify, request, render_template
import subprocess
import json

app = Flask(__name__)

@app.route('/')
def index():
"""Render main digest page."""
digest = load_digest()
return render_template('digest.html', digest=digest)

@app.route('/api/digest')
def get_digest():
"""API: Get digest data."""
digest = load_digest()
return jsonify(digest)

@app.route('/api/refresh', methods=['POST'])
def refresh():
"""API: Trigger refresh."""
if is_script_running():
return jsonify({'status': 'busy', 'message': 'Already running'}), 409

try:
result = subprocess.run(
['python', 'src/main.py'],
capture_output=True,
timeout=120,
)

if result.returncode == 0:
return jsonify({'status': 'success', 'message': 'Refreshed'})
else:
return jsonify({
'status': 'error',
'message': result.stderr.decode()
}), 500

except subprocess.TimeoutExpired:
return jsonify({
'status': 'error',
'message': 'Script timed out'
}), 504

@app.route('/api/status')
def status():
"""API: Check script status."""
return jsonify({
'running': is_script_running(),
'last_run': get_last_run_time(),
'lock_file_exists': Path('script.lock').exists(),
})

@app.route('/api/metrics')
def metrics():
"""API: Get metrics."""
period = request.args.get('period', '24h')
metrics_data = get_metrics_for_period(period)
return jsonify(metrics_data)

@app.route('/api/errors')
def errors():
"""API: Get recent errors."""
limit = request.args.get('limit', 10, type=int)
errors = get_recent_errors(limit)
return jsonify({'errors': errors})

Error Handlingโ€‹

@app.errorhandler(404)
def not_found(e):
return jsonify({'error': 'Not found'}), 404

@app.errorhandler(500)
def server_error(e):
return jsonify({'error': 'Internal server error'}), 500

@app.errorhandler(Exception)
def handle_exception(e):
logger.exception(f"Unhandled exception: {e}")
return jsonify({'error': str(e)}), 500

Usage Examplesโ€‹

cURLโ€‹

# Get digest
curl http://localhost:8001/api/digest

# Trigger refresh
curl -X POST http://localhost:8001/api/refresh

# Get metrics for 7 days
curl "http://localhost:8001/api/metrics?period=7d"

# Get recent errors
curl "http://localhost:8001/api/errors?limit=5"

JavaScriptโ€‹

// Fetch digest
const digest = await fetch('/api/digest').then(r => r.json());

// Refresh
const result = await fetch('/api/refresh', { method: 'POST' })
.then(r => r.json());

// Get metrics
const metrics = await fetch('/api/metrics?period=24h')
.then(r => r.json());

Pythonโ€‹

import requests

# Get digest
response = requests.get('http://localhost:8001/api/digest')
digest = response.json()

# Refresh
response = requests.post('http://localhost:8001/api/refresh')
result = response.json()

# Get metrics
response = requests.get('http://localhost:8001/api/metrics', params={'period': '7d'})
metrics = response.json()