SENTINEL provides a FastAPI REST API for the frontend dashboard. During development, the API serves live data from the DataStore. In production (GitHub Pages), the frontend reads directly from static JSON files.
Base URL: http://localhost:8000 (development)
Returns service health status.
Response:
{
"status": "ok",
"service": "sentinel"
}List all events with optional filtering. Results are sorted by Swiss relevance (descending).
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
date_from |
date |
Filter events reported on or after this date (YYYY-MM-DD) |
date_to |
date |
Filter events reported on or before this date |
source |
string |
Filter by source: WHO_DON, WHO_EIOS, PROMED, ECDC, WOAH |
disease |
string |
Filter by disease name (case-insensitive substring match) |
risk_category |
string |
Filter by risk category: CRITICAL, HIGH, MEDIUM, LOW |
country |
string |
Filter by country code (ISO 3166 alpha-2, case-insensitive) |
min_swiss_relevance |
float |
Minimum Swiss relevance score (0--10) |
Response: 200 OK
[
{
"id": "a1b2c3d4e5f67890",
"source": "ECDC",
"title": "Avian influenza A(H5N1) - Germany",
"date_reported": "2026-03-05",
"date_collected": "2026-03-06",
"disease": "Avian influenza A(H5N1)",
"pathogen": null,
"countries": ["DE"],
"regions": ["EURO"],
"species": "animal",
"case_count": 50,
"death_count": null,
"summary": "Outbreak of HPAI H5N1 detected in poultry farm...",
"url": "https://www.ecdc.europa.eu/...",
"raw_content": "...",
"risk_score": 6.5,
"swiss_relevance": 6.5,
"risk_category": "HIGH",
"one_health_tags": ["zoonotic"],
"analysis": "**Risk Assessment:** ..."
}
]Get events from the most recent collection date, sorted by Swiss relevance.
Query Parameters: None
Response: 200 OK -- Same format as GET /api/events
Get aggregate statistics across all events.
Response: 200 OK
{
"total": 142,
"by_source": {
"WHO_DON": 28,
"ECDC": 35,
"PROMED": 40,
"WOAH": 20,
"WHO_EIOS": 19
},
"by_risk": {
"CRITICAL": 3,
"HIGH": 12,
"MEDIUM": 45,
"LOW": 82
},
"by_disease": {
"Avian influenza A(H5N1)": 15,
"Dengue": 12,
"Cholera": 10,
"Mpox": 8,
"COVID-19": 7
}
}The by_disease field returns the top 20 diseases by event count.
Get a single event by ID.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
event_id |
string |
Event ID (16-character hex hash) |
Response: 200 OK -- Single event object
Error: 404 Not Found
{
"detail": "Event not found"
}List all situations.
Response: 200 OK
[
{
"id": "sit-a1b2c3d4",
"title": "H5N1 European Spread 2026",
"status": "ACTIVE",
"created": "2026-03-01",
"updated": "2026-03-06T08:30:00Z",
"events": ["a1b2c3d4e5f67890", "b2c3d4e5f6789012"],
"diseases": ["Avian influenza A(H5N1)"],
"countries": ["DE", "FR", "NL"],
"lead_analyst": "Dr. Mueller",
"priority": "P1",
"summary": "HPAI H5N1 spreading across Western Europe...",
"annotations": [],
"swiss_impact_assessment": "High risk of introduction via migratory birds...",
"recommended_actions": [
"Increase surveillance of wild bird populations",
"Alert cantonal veterinary offices"
],
"human_health_status": "No human cases",
"animal_health_status": "Active outbreaks in poultry",
"environmental_status": "Wild bird die-offs reported"
}
]Create a new situation.
Request Body:
{
"title": "H5N1 European Spread 2026",
"diseases": ["Avian influenza A(H5N1)"],
"countries": ["DE", "FR"],
"lead_analyst": "Dr. Mueller",
"priority": "P2",
"summary": "Monitoring spread of H5N1 across European countries.",
"events": ["a1b2c3d4e5f67890"]
}| Field | Type | Required | Default |
|---|---|---|---|
title |
string |
Yes | -- |
diseases |
string[] |
Yes | -- |
countries |
string[] |
Yes | -- |
lead_analyst |
string |
Yes | -- |
priority |
string |
No | P2 |
summary |
string |
Yes | -- |
events |
string[] |
No | [] |
Response: 201 Created -- Full situation object with generated id
Get a single situation by ID.
Response: 200 OK -- Full situation object
Error: 404 Not Found
Update a situation. Only include fields you want to change.
Request Body:
{
"status": "ESCALATED",
"priority": "P1",
"summary": "Updated: Human case confirmed in poultry worker.",
"swiss_impact_assessment": "Direct risk to Swiss poultry sector.",
"recommended_actions": [
"Activate BLV emergency protocol",
"Notify BAG for human health coordination"
]
}All fields are optional. Only non-null fields are applied.
Response: 200 OK -- Updated situation object
Error: 404 Not Found
Link events to an existing situation.
Request Body:
{
"event_ids": ["c3d4e5f678901234", "d4e5f67890123456"]
}Events that are already linked are not duplicated.
Response: 200 OK -- Updated situation object
Error: 404 Not Found
Create a new annotation on an event.
Request Body:
{
"event_id": "a1b2c3d4e5f67890",
"author": "Dr. Mueller",
"type": "ASSESSMENT",
"content": "This outbreak is significant for Swiss poultry sector. Recommend enhanced border surveillance.",
"visibility": "SHARED",
"risk_override": 7.5,
"status_change": "ESCALATED",
"linked_event_ids": ["b2c3d4e5f6789012"],
"tags": ["urgent", "BLV-action"]
}| Field | Type | Required | Description |
|---|---|---|---|
event_id |
string |
Yes | ID of the event being annotated |
author |
string |
Yes | Analyst name |
type |
string |
Yes | ASSESSMENT, NOTE, ACTION, LINK, ESCALATION |
content |
string |
Yes | Annotation text |
visibility |
string |
Yes | INTERNAL, SHARED, CONFIDENTIAL |
risk_override |
float |
No | Override the event's risk score (0--10) |
status_change |
string |
No | NEW, MONITORING, ESCALATED, RESOLVED, ARCHIVED |
linked_event_ids |
string[] |
No | Related event IDs |
tags |
string[] |
No | Custom tags |
Response: 201 Created -- Full annotation object with generated id and timestamp
List annotations, optionally filtered by event.
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
event_id |
string |
Filter annotations for a specific event |
Response: 200 OK
[
{
"id": "a1b2c3d4e5f6",
"event_id": "a1b2c3d4e5f67890",
"author": "Dr. Mueller",
"timestamp": "2026-03-06T09:15:00Z",
"type": "ASSESSMENT",
"content": "This outbreak is significant...",
"visibility": "SHARED",
"risk_override": 7.5,
"status_change": "ESCALATED",
"linked_event_ids": ["b2c3d4e5f6789012"],
"tags": ["urgent", "BLV-action"]
}
]Events per day grouped by disease. Used for trend line charts.
Response: 200 OK
[
{
"date": "2026-03-04",
"diseases": {
"Avian influenza A(H5N1)": 3,
"Dengue": 5,
"Cholera": 2
}
},
{
"date": "2026-03-05",
"diseases": {
"Avian influenza A(H5N1)": 4,
"Dengue": 3,
"Mpox": 1
}
}
]Events per source per day. Used for source comparison charts.
Response: 200 OK
[
{
"date": "2026-03-04",
"sources": {
"WHO_DON": 5,
"ECDC": 7,
"PROMED": 8,
"WOAH": 4,
"WHO_EIOS": 3
}
}
]Average risk score and Swiss relevance per day with event count.
Response: 200 OK
[
{
"date": "2026-03-04",
"avg_risk_score": 4.23,
"avg_swiss_relevance": 3.15,
"event_count": 27
},
{
"date": "2026-03-05",
"avg_risk_score": 4.87,
"avg_swiss_relevance": 3.42,
"event_count": 31
}
]List all watchlists.
Response: 200 OK
[
{
"id": "a1b2c3d4",
"name": "Swiss Border Zoonoses",
"diseases": ["Avian influenza A(H5N1)", "Rabies"],
"countries": ["DE", "FR", "IT", "AT", "LI"],
"min_risk_score": 4.0,
"one_health_tags": ["zoonotic"]
}
]Create a new watchlist.
Request Body:
{
"name": "Swiss Border Zoonoses",
"diseases": ["Avian influenza A(H5N1)", "Rabies"],
"countries": ["DE", "FR", "IT", "AT", "LI"],
"min_risk_score": 4.0,
"one_health_tags": ["zoonotic"]
}All fields except name are optional (default to empty lists or 0.0).
Response: 201 Created -- Full watchlist object with generated id
Delete a watchlist.
Response: 204 No Content
Error: 404 Not Found
Export events as CSV with optional filtering.
Request Body:
{
"date_from": "2026-03-01",
"date_to": "2026-03-06",
"source": "ECDC",
"disease": "influenza",
"risk_category": "HIGH",
"country": "DE",
"min_swiss_relevance": 5.0,
"limit": 500
}All fields are optional. Default limit is 1000, maximum is 10000.
Response: 200 OK
- Content-Type:
text/csv - Content-Disposition:
attachment; filename=sentinel_export.csv
CSV columns: id, title, source, date_reported, date_collected, disease, pathogen, countries, regions, species, case_count, death_count, risk_score, risk_category, swiss_relevance, one_health_tags, url, summary
Export events as JSON with the same filtering options as CSV export.
Request Body: Same as CSV export.
Response: 200 OK -- Array of event objects (same format as GET /api/events)
Get the daily Markdown report for a specific date.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
report_date |
date |
Report date (YYYY-MM-DD) |
Response: 200 OK
- Content-Type:
text/markdown - Body: Markdown-formatted daily intelligence brief
Error: 404 Not Found
{
"detail": "Report not found"
}For local development:
cd backend
uv run uvicorn sentinel.main:app --reloadThe API will be available at http://localhost:8000.
Interactive API documentation (Swagger UI) is available at http://localhost:8000/docs.