# EMA (European Medicines Agency) API Research

**Research Date:** 2026-03-07  
**Purpose:** Find European drug interaction data for Phase 2.8  
**Status:** Research Complete

---

## ❌ Conclusion: EMA APIs Not Suitable

### EMA SPOR API Status

**Problem:** EMA SPOR API now requires authentication

**Evidence:**
- v1 endpoints return 404 errors
- v2 endpoints redirect to login page
- No public API access available
- Requires registered account with approval

**Verdict:** ❌ **NOT SUITABLE** for our proof-of-concept

---

## ✅ Recommended Solution

### OpenFDA with Manual Ingredient Mapping

Since EMA APIs are not accessible, we'll use:

1. **OpenFDA API** - For drug interaction checking
2. **User-provided data** - For EU drug ingredient mappings
3. **Common ingredient knowledge** - Build a simple lookup table

---

## Implementation Strategy

### Phase 1: Simple Mapping Table

Create a manual EU → US ingredient mapping:

```rust
// backend/src/services/ingredient_mapper.rs

pub struct IngredientMapper;

impl IngredientMapper {
    pub fn map_eu_to_us(&self, eu_name: &str) -> Option<&str> {
        match eu_name.to_lowercase().as_str() {
            "paracetamol" => Some("acetaminophen"),
            "ibuprofen" => Some("ibuprofen"),
            "amoxicillin" => Some("amoxicillin"),
            "metformin" => Some("metformin"),
            "lisinopril" => Some("lisinopril"),
            "atorvastatin" => Some("atorvastatin"),
            // ... more mappings
            _ => Some(eu_name), // Fallback: use as-is
        }
    }
}
```

### Phase 2: OpenFDA Integration

Use OpenFDA to check interactions:

```rust
pub async fn check_interactions(&self, medications: &[String]) -> Result<Vec<Interaction>> {
    let us_names: Vec<String> = medications
        .iter()
        .map(|m| self.mapper.map_eu_to_us(m).unwrap_or(m))
        .collect();
    
    self.openFDA.check_interactions(&us_names).await
}
```

### Phase 3: User-Provided Data

Allow user to upload CSV/JSON with:
- EU drug names
- Ingredient mappings
- Custom interaction rules

---

## Advantages of This Approach

✅ **Simple** - No complex API integration  
✅ **Reliable** - No external dependencies  
✅ **Fast** - No network calls for mapping  
✅ **Free** - No API costs  
✅ **Extensible** - User can add mappings  
✅ **Transparent** - Users can see/edit mappings  

---

## Common EU-US Drug Name Mappings

| EU Name | US Name | Type |
|---------|---------|------|
| Paracetamol | Acetaminophen | Analgesic |
| Ibuprofen | Ibuprofen | NSAID (same) |
| Amoxicillin | Amoxicillin | Antibiotic (same) |
| Metformin | Metformin | Diabetes (same) |
| Lisinopril | Lisinopril | BP (same) |
| Atorvastatin | Atorvastatin | Statin (same) |

**Note:** Many drug names are identical globally!

---

## Implementation Plan

### 1. Create Ingredient Mapper

```rust
// backend/src/services/ingredient_mapper.rs

use std::collections::HashMap;

pub struct IngredientMapper {
    mappings: HashMap<String, String>,
}

impl IngredientMapper {
    pub fn new() -> Self {
        let mut mappings = HashMap::new();
        
        // EU to US mappings
        mappings.insert("paracetamol".to_string(), "acetaminophen".to_string());
        mappings.insert("paracetamolum".to_string(), "acetaminophen".to_string());
        
        // Add more as needed...
        
        Self { mappings }
    }
    
    pub fn map_to_us(&self, eu_name: &str) -> String {
        let normalized = eu_name.to_lowercase();
        self.mappings.get(&normalized)
            .unwrap_or(&eu_name.to_string())
            .clone()
    }
}
```

### 2. Integrate with OpenFDA

```rust
// backend/src/services/openfda_service.rs

use reqwest::Client;

pub struct OpenFDAService {
    client: Client,
    base_url: String,
}

impl OpenFDAService {
    pub fn new() -> Self {
        Self {
            client: Client::new(),
            base_url: "https://api.fda.gov/drug/event.json".to_string(),
        }
    }
    
    pub async fn check_interactions(
        &self,
        medications: &[String]
    ) -> Result<Vec<Interaction>, Error> {
        // Query OpenFDA for drug interactions
        // Parse response
        // Return interaction list
    }
}
```

### 3. Combined Service

```rust
// backend/src/services/interaction_service.rs

pub struct InteractionService {
    mapper: IngredientMapper,
    fda: OpenFDAService,
}

impl InteractionService {
    pub async fn check(&self, eu_medications: &[String]) -> Result<Vec<Interaction>> {
        // Map EU names to US names
        let us_medications: Vec<String> = eu_medications
            .iter()
            .map(|m| self.mapper.map_to_us(m))
            .collect();
        
        // Check interactions via OpenFDA
        self.fda.check_interactions(&us_medications).await
    }
}
```

---

## Next Steps

### For Drug Interaction Checker (Phase 2.8.1)

- [ ] Create `backend/src/services/ingredient_mapper.rs`
- [ ] Add common EU-US drug name mappings (50-100 common drugs)
- [ ] Create `backend/src/services/openfda_service.rs`
- [ ] Implement OpenFDA interaction checking
- [ ] Create `backend/src/services/interaction_service.rs`
- [ ] Write comprehensive tests
- [ ] Document mapping coverage
- [ ] Prepare CSV template for user to add custom mappings

---

## Data Sources for Mappings

1. **WHO ATC Classification** - https://www.whocc.no/
2. **INN (International Nonproprietary Names)** - Global standard names
3. **User-provided CSV/JSON** - Custom mappings

---

## Summary

❌ EMA SPOR API requires authentication (not suitable)  
✅ Use OpenFDA + manual ingredient mapping  
✅ Simple, reliable, and free  
✅ Works for both EU and US drugs  

---

*Research Completed: 2026-03-07*  
*Recommendation: Use OpenFDA with manual ingredient mapping*  
*Status: Ready for implementation*
