Introduction
The Export API provides functionality to generate pharmacovigilance documents and ICSR (Individual Case Safety Report) exports in various formats. All exports include digital signatures from the authenticated user and support both official regulatory submissions and internal documentation.
Base URL
Authentication
All export endpoints require authentication with appropriate role permissions.
Allowed Roles:
admin
qf (Químico Farmacéutico)
responsable_fv (Farmacovigilancia Manager)
qa (Quality Assurance)
direccion_tecnica (Technical Director)
legal
soporte (Support)
Authorization: Bearer < your_toke n >
Export Modelo B (DOCX)
Export the “Formato Profesionales Salud” template for an ICSR case as a fully populated DOCX file.
GET /api/v1/icsr/{icsr_id}/export/modelo-b.docx
Python
curl -X GET https://api.vigia.com/api/v1/icsr/123/export/modelo-b.docx \
-H "Authorization: Bearer YOUR_TOKEN" \
-o ICSR_123_Formato.docx
Path Parameters
Response
Returns a fully populated DOCX file with:
Patient information (initials, age, sex)
Suspected product details and registry number
Adverse event description and timeline
Medical history and concomitant medications
Reporter information
DIGEMID regulatory format fields
Use Cases
Review template before PDF conversion
Manual editing of specific fields
Archive in editable format
Internal documentation
Export Modelo B (PDF)
Generate PDF version of the “Formato Profesionales Salud” template with digital signature.
GET /api/v1/icsr/{icsr_id}/export/modelo-b.pdf
Python
curl -X GET https://api.vigia.com/api/v1/icsr/123/export/modelo-b.pdf \
-H "Authorization: Bearer YOUR_TOKEN" \
-o ICSR_123_Formato.pdf
Path Parameters
Response
Returns a PDF file with:
Complete ICSR data from the DOCX template
Embedded digital signature from authenticated user
Company logo (if configured)
Signer’s contact information
PDF Conversion Methods
The system attempts conversion using:
docx2pdf (Windows with MS Word)
LibreOffice (cross-platform fallback)
If conversion fails, returns the DOCX file as fallback.
Storage
Generated PDFs are stored in:
storage/icsr_exports/ICSR_{icsr_id}_Formato-Profesionales-Salud.pdf
Export Official DIGEMID Report
Generate the official DIGEMID regulatory submission PDF with OTP verification support.
GET /api/v1/icsr/{icsr_id}/export/digemid
Python
curl -X GET "https://api.vigia.com/api/v1/icsr/123/export/digemid?formato=pdf" \
-H "Authorization: Bearer YOUR_TOKEN" \
-o ICSR_123_DIGEMID_Oficial.pdf
Path Parameters
ICSR case ID to export for DIGEMID submission
Query Parameters
Export format. Currently only "pdf" is supported.
Response
Returns official DIGEMID submission PDF with:
Complete regulatory-compliant ICSR data
Digital signature with verification
Timestamp of generation
Signer’s credentials and contact info
Company branding (logo, letterhead)
Signature Context
The export includes signature data from the authenticated user:
{
"firma_nombre" : "Dr. Juan Pérez Ramírez" ,
"firma_cargo" : "Químico Farmacéutico - Responsable de Farmacovigilancia" ,
"firma_company" : "OTARVASQ S.A.C." ,
"firma_celular" : "+51-987-654-321" ,
"firma_email_alt" : "[email protected] " ,
"firma_website" : "https://www.otarvasq.com" ,
"firma_img_path" : "/full/path/to/signature.png" ,
"firma_logo_path" : "/full/path/to/logo.png"
}
Storage
Generated reports are stored in:
storage/icsr_exports/ICSR_{icsr_id}_DIGEMID-Oficial.pdf
Error Handling
If PDF generation fails:
System returns fully populated DOCX as fallback
HTTP 500 error if both PDF and DOCX generation fail
Detailed error logged for debugging
Preview ICSR (Lightweight PDF)
Generate a quick preview PDF without using the full template (for rapid review).
GET /api/v1/icsr/{icsr_id}/preview/pdf
Python
curl -X GET "https://api.vigia.com/api/v1/icsr/123/preview/pdf?source=light" \
-H "Authorization: Bearer YOUR_TOKEN" \
-o preview.pdf
Path Parameters
Query Parameters
Preview source:
"official": Use official template (slower)
"light": Generate quick text-based preview (faster)
Response
Returns a lightweight PDF with:
ICSR case number
Patient initials, age, and sex
Suspected product name
Event start date
Brief adverse event description
Generated in-memory using ReportLab for speed.
Content-Disposition: inline; filename="ICSR_000123_preview.pdf"
X-Generated-At: 2026-03-03T15:30:00Z
Use Cases
Quick case review without full export
Testing data completeness
Internal team discussions
Pre-submission validation
Export Context (Debug)
Retrieve the complete data context used for template rendering (for debugging).
GET /api/v1/icsr/{icsr_id}/export/context
Python
curl -X GET https://api.vigia.com/api/v1/icsr/123/export/context \
-H "Authorization: Bearer YOUR_TOKEN"
Path Parameters
Response
Returns JSON object with complete template context:
{
"paciente_iniciales" : "J.D." ,
"paciente_edad" : "45" ,
"paciente_sexo" : "M" ,
"producto_sospechoso" : "Paracetamol 500mg" ,
"registro_sanitario" : "RS-12345" ,
"fecha_inicio_evento" : "2026-02-15" ,
"descripcion_evento" : "Paciente presenta urticaria generalizada..." ,
"gravedad" : "Moderado" ,
"desenlace" : "Recuperado" ,
"firma_nombre" : "Dr. Juan Pérez Ramírez" ,
"firma_cargo" : "Químico Farmacéutico" ,
"firma_company" : "OTARVASQ S.A.C." ,
"firma_celular" : "+51-987-654-321" ,
"firma_email_alt" : "[email protected] " ,
"firma_website" : "https://www.otarvasq.com" ,
"reportero_nombre" : "Dra. María García" ,
"reportero_profesion" : "Médico" ,
"fecha_reporte" : "2026-02-20"
}
Use Cases
Debug template rendering issues
Verify data mapping correctness
Test signature integration
Validate required fields
API integration testing
Export Workflow
Standard Export Process
DIGEMID Official Export (with OTP)
DOCX (Microsoft Word)
Template Engine : docxtpl (python-docx-template)
Features :
Jinja2-style placeholders: {{ variable_name }}
Conditional sections
Table rows iteration
Image embedding
Template Location :
app/templates/docs/Formato Profesionales Salud.docx
MIME Type :
application/vnd.openxmlformats-officedocument.wordprocessingml.document
Conversion Tools :
docx2pdf : Windows-only, requires MS Word installed
LibreOffice : Cross-platform, uses soffice --headless --convert-to pdf
Features :
Preserves document formatting
Embeds signature images
Includes company branding
Non-editable final format
MIME Type :
Preview PDF (Lightweight)
Generation Tool : ReportLab
Features :
Fast in-memory generation
Basic text layout
No template processing
Minimal file size
Signature Integration
All exports automatically include the digital signature from the authenticated user’s profile.
Signature Resolution Process
Retrieve Employee ID : Extract from authenticated user token
Load Firma Record : Query rrhh_firma table by empleado_id
Resolve Image Paths : Convert relative URLs to absolute file paths
Build Context : Add signature fields to template context
Embed in Document : Render signature image and metadata
Path Resolution
The system attempts to resolve signature images using:
Candidates:
1 . Absolute path ( if exists)
2 . backend_root / raw_path
3 . backend_root / storage / firmas / filename
Example:
/uploads/firmas_42/firma.png
→ /home/vigia/backend/storage/firmas/firma.png
Signature Fields in Template
Template Variable Source Field {{ firma_nombre }}firma.nombre{{ firma_cargo }}firma.cargo{{ firma_company }}firma.company{{ firma_celular }}firma.celular or firma.telefono{{ firma_email_alt }}firma.email_alt{{ firma_website }}firma.websiteImage placeholder Resolved from firma.firma_img_url Logo placeholder Resolved from firma.logo_url
Error Codes
Status Code Description Solution 200 Success Export completed successfully 400 Bad Request Invalid ICSR ID or unsupported format 404 Not Found ICSR case does not exist 500 Internal Server Error PDF conversion failed, check logs
Common Error Messages
“ICSR no encontrado”
ICSR case ID does not exist in database
Verify case ID is correct
“Formato no soportado por ahora (solo pdf)”
Requested format is not implemented
Use formato=pdf parameter
“No se pudo generar ni PDF ni DOCX”
Template rendering failed
Check ICSR data completeness
Verify template file exists
“PDF vacío”
PDF conversion produced empty file
Check LibreOffice/Word installation
Review conversion logs
Best Practices
1. Verify Data Completeness
Before exporting, ensure all required ICSR fields are populated:
# Check context data
response = requests.get( f " { base_url } /icsr/123/export/context" , headers = headers)
context = response.json()
required_fields = [ 'paciente_iniciales' , 'producto_sospechoso' , 'fecha_inicio_evento' ]
missing = [f for f in required_fields if not context.get(f)]
if missing:
print ( f "Missing required fields: { missing } " )
else :
print ( "All required fields present, proceeding with export" )
2. Use Preview for Quick Review
Use lightweight preview for rapid iteration:
# Quick preview
preview_response = requests.get( f " { base_url } /icsr/123/preview/pdf" , headers = headers)
# Only generate full export when ready
if preview_looks_good():
export_response = requests.get( f " { base_url } /icsr/123/export/digemid" , headers = headers)
3. Handle Conversion Failures
Always check response Content-Type:
response = requests.get( f " { base_url } /icsr/123/export/modelo-b.pdf" , headers = headers)
if response.headers[ 'Content-Type' ] == 'application/pdf' :
print ( "PDF generated successfully" )
elif 'wordprocessingml' in response.headers[ 'Content-Type' ]:
print ( "PDF conversion failed, received DOCX fallback" )
Ensure signature is configured before exporting:
# 1. Setup signature
firma_response = requests.get( f " { base_url } /firmas/me" , headers = headers)
firma = firma_response.json()
if not firma.get( 'firma_img_url' ):
print ( "Warning: No signature image configured" )
# Upload signature before proceeding
# 2. Then export
export_response = requests.get( f " { base_url } /icsr/123/export/digemid" , headers = headers)
import datetime
response = requests.get( f " { base_url } /icsr/123/export/digemid" , headers = headers)
if response.ok:
timestamp = datetime.datetime.now().strftime( "%Y%m %d _%H%M%S" )
filename = f "ICSR_123_DIGEMID_ { timestamp } .pdf"
with open (filename, 'wb' ) as f:
f.write(response.content)
# Store metadata
metadata = {
'icsr_id' : 123 ,
'export_date' : timestamp,
'exported_by' : user_email,
'file_size' : len (response.content),
'filename' : filename
}
Complete Export Example
import requests
import json
class ICSRExporter :
def __init__ ( self , base_url , token ):
self .base_url = base_url
self .headers = { "Authorization" : f "Bearer { token } " }
def verify_signature ( self ):
"""Ensure signature is configured"""
response = requests.get(
f " { self .base_url } /firmas/me" ,
headers = self .headers
)
firma = response.json()
if not firma.get( 'firma_img_url' ):
raise ValueError ( "Signature not configured. Please upload signature image." )
return firma
def check_data_completeness ( self , icsr_id ):
"""Verify ICSR data is complete"""
response = requests.get(
f " { self .base_url } /icsr/ { icsr_id } /export/context" ,
headers = self .headers
)
context = response.json()
required = [ 'paciente_iniciales' , 'producto_sospechoso' , 'fecha_inicio_evento' ]
missing = [f for f in required if not context.get(f)]
if missing:
raise ValueError ( f "Missing required fields: { missing } " )
return context
def preview ( self , icsr_id ):
"""Generate quick preview"""
response = requests.get(
f " { self .base_url } /icsr/ { icsr_id } /preview/pdf" ,
headers = self .headers,
params = { "source" : "light" }
)
if response.ok:
with open ( f "preview_ { icsr_id } .pdf" , "wb" ) as f:
f.write(response.content)
return True
return False
def export_docx ( self , icsr_id ):
"""Export editable DOCX"""
response = requests.get(
f " { self .base_url } /icsr/ { icsr_id } /export/modelo-b.docx" ,
headers = self .headers
)
if response.ok:
filename = f "ICSR_ { icsr_id } _Formato.docx"
with open (filename, "wb" ) as f:
f.write(response.content)
print ( f "DOCX exported: { filename } " )
return filename
else :
raise Exception ( f "Export failed: { response.status_code } " )
def export_official_pdf ( self , icsr_id ):
"""Export official DIGEMID PDF"""
response = requests.get(
f " { self .base_url } /icsr/ { icsr_id } /export/digemid" ,
headers = self .headers,
params = { "formato" : "pdf" }
)
if response.ok:
# Check if we got PDF or DOCX fallback
content_type = response.headers.get( 'Content-Type' , '' )
if 'pdf' in content_type:
filename = f "ICSR_ { icsr_id } _DIGEMID_Oficial.pdf"
print ( "PDF generated successfully" )
else :
filename = f "ICSR_ { icsr_id } _DIGEMID_Oficial.docx"
print ( "PDF conversion failed, saved as DOCX" )
with open (filename, "wb" ) as f:
f.write(response.content)
return filename
else :
raise Exception ( f "Export failed: { response.status_code } " )
def full_export_workflow ( self , icsr_id ):
"""Complete export workflow with validation"""
print ( f "Starting export for ICSR { icsr_id } ..." )
# 1. Verify signature
print ( "1. Verifying signature configuration..." )
firma = self .verify_signature()
print ( f " ✓ Signature configured for { firma[ 'nombre' ] } " )
# 2. Check data completeness
print ( "2. Checking data completeness..." )
context = self .check_data_completeness(icsr_id)
print ( f " ✓ All required fields present" )
# 3. Generate preview
print ( "3. Generating preview..." )
if self .preview(icsr_id):
print ( f " ✓ Preview saved as preview_ { icsr_id } .pdf" )
# 4. Export DOCX
print ( "4. Exporting DOCX..." )
docx_file = self .export_docx(icsr_id)
print ( f " ✓ { docx_file } " )
# 5. Export official PDF
print ( "5. Exporting official DIGEMID PDF..." )
pdf_file = self .export_official_pdf(icsr_id)
print ( f " ✓ { pdf_file } " )
print ( " \n ✓ Export workflow completed successfully!" )
return {
'preview' : f "preview_ { icsr_id } .pdf" ,
'docx' : docx_file,
'pdf' : pdf_file
}
# Usage
exporter = ICSRExporter(
base_url = "https://api.vigia.com/api/v1" ,
token = "your_token_here"
)
try :
files = exporter.full_export_workflow( icsr_id = 123 )
print ( f " \n Generated files: { json.dumps(files, indent = 2 ) } " )
except Exception as e:
print ( f "Error: { e } " )
Document Upload Create and upload documents
Digital Signatures Configure signature profiles
Overview Document management overview