Skip to main content

Introduction

The Surveillance API enables automated monitoring of multiple regulatory data sources including FDA, EMA, DIGEMID, and VigiAccess. Configure scheduled scraping, query results with advanced filters, and generate automated email reports. Base Path: /api/v1/surveillance

Key Features

Multi-Scope Architecture

Separate national and external surveillance with independent configurations

Automated Scraping

CRON-based scheduling with configurable data sources

Advanced Filtering

Query by severity, medication, date range, and full-text search

Multi-Format Reports

Generate HTML, PDF, CSV, and XLSX reports via email

Surveillance Scopes

VIGIA separates surveillance into two independent scopes:
ScopeDescriptionUse Case
nationalDomestic regulatory monitoringDIGEMID alerts, local health authorities
externalInternational monitoringFDA, EMA, VigiAccess, MHRA, Health Canada
Each scope maintains its own:
  • Data sources configuration
  • Scraping schedule (CRON expression)
  • Surveillance results
  • Report recipients

Authentication

All surveillance endpoints require authentication and one of the following roles:
{
  "allowed_roles": [
    "admin",
    "qf",
    "responsable_fv",
    "qa",
    "direccion_tecnica",
    "legal",
    "soporte"
  ]
}
Header:
Authorization: Bearer <your_jwt_token>

Core Endpoints

Configuration

MethodEndpointDescription
GET/surveillance/sourcesGet configured data sources for a scope
POST/surveillance/sourcesUpdate data sources (replaces entire list)
GET/surveillance/scheduleGet scraping schedule for a scope
POST/surveillance/scheduleConfigure CRON schedule

Execution

MethodEndpointDescription
POST/surveillance/runTrigger immediate scraping (all enabled sources)
POST/surveillance/run-and-sendScrape and email report

Querying

MethodEndpointDescription
GET/surveillance/resultsQuery surveillance items with filters
POST/surveillance/send-reportsGenerate and email filtered reports

Data Model

SurveillanceItem

Each scraped item contains:
interface SurveillanceItem {
  id: string;                    // UUID
  fuente: string;                // Source name (e.g., "FDA", "EMA", "DIGEMID")
  titulo: string;                // Alert/announcement title
  medicamento: string | null;    // Drug/device name
  evento: string | null;         // Adverse event or safety issue description
  severidad: string | null;      // Severity: "Alta" | "Media" | "Baja"
  tendencia: string | null;      // Trend: "Aumentando" | "Estable" | "Disminuyendo"
  url: string | null;            // Source URL
  fecha: string | null;          // Item date/timestamp (ISO 8601)
  fecha_publicada: string | null;// Publication date (ISO 8601)
  scope: "national" | "external";// Surveillance scope
}
Example:
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "fuente": "FDA",
  "titulo": "FDA advierte sobre riesgo de lesión hepática con acetaminofén",
  "medicamento": "Acetaminofén",
  "evento": "Hepatotoxicidad",
  "severidad": "Alta",
  "tendencia": "Aumentando",
  "url": "https://www.fda.gov/drugs/drug-safety-and-availability/...",
  "fecha": "2024-03-01T14:30:00Z",
  "fecha_publicada": "2024-03-01T10:00:00Z",
  "scope": "external"
}

Severity Levels

SeveridadCriteriaExamples
AltaDeath, hospitalization, product recallDrug contamination, device malfunction causing injury
MediaSerious ADR, label change, black box warningNew hepatotoxicity warning, dosage restrictions
BajaMinor ADR, information updateUpdated administration guidelines

Quick Start

1. Configure Data Sources

POST /api/v1/surveillance/sources?scope=external
Content-Type: application/json
Authorization: Bearer <token>

{
  "sources": [
    {
      "name": "FDA Drug Safety",
      "url": "https://www.fda.gov/drugs/drug-safety-and-availability",
      "enabled": true
    },
    {
      "name": "EMA Safety Updates",
      "url": "https://www.ema.europa.eu/en/human-regulatory/post-authorisation/pharmacovigilance",
      "enabled": true
    }
  ]
}

2. Set Up Schedule

POST /api/v1/surveillance/schedule?scope=external
Content-Type: application/json
Authorization: Bearer <token>

{
  "cron": "0 9 * * MON,THU",
  "next_run_iso": "2024-03-07T14:00:00Z"
}

3. Query Results

GET /api/v1/surveillance/results?
  scope=external&
  severity=Alta&
  date_from=2024-03-01&
  date_to=2024-03-31&
  limit=50

4. Send Reports

POST /api/v1/surveillance/send-reports?scope=external
Content-Type: application/json
Authorization: Bearer <token>

{
  "recipients": ["[email protected]"],
  "formats": {
    "inline": true,
    "pdf": true,
    "xlsx": true
  },
  "filters": {
    "severity": "Alta"
  }
}

Common Use Cases

Weekly High-Severity Monitoring

# 1. Configure weekly schedule
POST /api/v1/surveillance/schedule?scope=external
{
  "cron": "0 9 * * MON"  # Every Monday at 9 AM
}

# 2. Set up automated high-severity alerts
POST /api/v1/surveillance/send-reports?scope=external
{
  "recipients": ["[email protected]"],
  "formats": {"inline": true, "pdf": true},
  "filters": {"severity": "Alta"}
}

Drug-Specific Surveillance

GET /api/v1/surveillance/results?
  scope=external&
  medicamento=Paracetamol&
  date_from=2024-01-01&
  limit=100

On-Demand Scraping

# Scrape all enabled sources immediately
POST /api/v1/surveillance/run?scope=national
Response:
{
  "ok": true,
  "results": {
    "source-uuid-1": {
      "items_found": 15,
      "items_new": 3,
      "source": "DIGEMID Alertas"
    },
    "source-uuid-2": {
      "error": "Connection timeout"
    }
  }
}
The /results endpoint supports multiple filters:
ParameterTypeDescriptionExample
scopestringnational or externalscope=external
querystringFull-text search (title, medication, event)query=hepatotoxicity
severitystringFilter by severity levelseverity=Alta
medicamentostringMedication name (partial match)medicamento=Paracetamol
date_fromstringStart date (ISO 8601)date_from=2024-01-01
date_tostringEnd date (ISO 8601)date_to=2024-03-31
limitintegerResults per page (1-200)limit=50
offsetintegerPagination offsetoffset=100
Example:
GET /api/v1/surveillance/results?
  scope=external&
  query=cardiac&
  severity=Alta&
  date_from=2024-03-01&
  limit=25&
  offset=0

Report Formats

Generate reports in multiple formats:
FormatDescriptionUse Case
Inline HTMLEmbedded table in email bodyQuick review in email client
PDFFormatted documentArchiving, regulatory submissions
CSVComma-separated valuesData analysis, Excel import
XLSXExcel spreadsheetAdvanced filtering, pivot tables
{
  "formats": {
    "inline": true,   // HTML table in email
    "pdf": true,      // Attach PDF
    "csv": false,     // Skip CSV
    "xlsx": true      // Attach Excel
  }
}

Timezone Handling

Important: All CRON schedules execute in America/Lima timezone (UTC-5).
Dates in API responses use ISO 8601 format with UTC timezone:
{
  "fecha": "2024-03-01T14:30:00Z",
  "fecha_publicada": "2024-03-01T10:00:00Z"
}
When setting next_run_iso, you can provide any timezone—it will be converted:
{
  "cron": "0 9 * * MON",
  "next_run_iso": "2024-03-07T09:00:00-05:00"  // Lima time
}

Error Handling

Common Error Codes

StatusErrorCause
400Bad RequestInvalid filters, missing required fields
401UnauthorizedMissing or invalid JWT token
403ForbiddenUser lacks required role
502Bad GatewayEmail service unavailable
Example Error Response:
{
  "detail": {
    "message": "Fallo al enviar correo",
    "error": "SMTPAuthenticationError: Username and Password not accepted",
    "trace": "Traceback (most recent call last)...\n"
  }
}

Rate Limits

To prevent abuse, manual scraping (/run) is limited to:
  • National scope: Once per hour
  • External scope: Once every 2 hours
Scheduled jobs are not subject to these limits.

Implementation References

ComponentFile Location
Routerbackend/app/routers/surveillance.py:29
Schemasbackend/app/schemas/surveillance.py:1-87
Modelsbackend/app/models/surveillance.py
CRUD Operationsbackend/app/crud/surveillance.py
Scraper Servicebackend/app/services/scraper.py
Report Generationbackend/app/services/reports.py
Filter Builderbackend/app/services/report_filters.py:27

Schedule Management

Configure CRON-based scraping

Global Data Sources

Query FDA, EMA, DIGEMID directly

ICSR Integration

Create cases from surveillance signals

Next Steps

  1. Configure Sources: Set up national and external data sources
  2. Test Scraping: Run manual scrape to verify source accessibility
  3. Set Schedule: Configure automated scraping frequency
  4. Query Results: Test filtering and pagination
  5. Setup Reports: Configure weekly email reports for stakeholders

Build docs developers (and LLMs) love