Reporting adverse events into FAERS / ICH E2B(R3)
A pharmacovigilance case starts as free-text narrative ("68 yo on warfarin
developed GI bleed, hospitalized"). To make it reportable you must structure it
into the ICH E2B(R3) data elements that the FDA's FAERS (and EMA's
EudraVigilance) expect: a suspect drug, one or more reactions coded to
MedDRA Preferred Terms, seriousness criteria, and a reaction outcome.
OpenMed extracts the drug and condition spans on-device; this skill turns those
spans plus the narrative into the E2B(R3) skeleton. The reaction coding step
needs MedDRA, which is licensed by the MSSO and user-supplied — it is
never bundled with OpenMed and must be loaded from the user's own subscription.
When to use
- A narrative names a drug and an adverse reaction and you need an ICSR
(Individual Case Safety Report) shell with the right E2B(R3) fields.
- You must classify seriousness (E2B sections C.1.7 / E.i.3) — death,
life-threatening, hospitalization/prolongation, disability, congenital
anomaly, or "other medically important condition".
- You need to characterize each drug as suspect / concomitant / interacting
(the
drugcharacterization axis FAERS uses).
- You are pre-filling a 3500A / FAERS electronic submission or staging cases for
a safety database.
This skill produces a structured draft for human safety review — it does not
file reports or perform causality assessment autonomously.
Quick start
import openmed
narrative = (
"68-year-old patient on warfarin 5 mg daily developed a gastrointestinal "
"hemorrhage and was hospitalized. Warfarin was discontinued; the patient "
"recovered."
)
# 1) Extract drug spans (Pharmaceutical category) on-device.
drugs = openmed.analyze_text(
narrative,
model_name="pharma_detection_superclinical",
output_format="dict",
)["entities"]
# 2) Extract condition / reaction spans (Disease category).
conditions = openmed.analyze_text(
narrative,
model_name="disease_detection_superclinical",
output_format="dict",
)["entities"]
# 3) Assemble an E2B(R3)-shaped ICSR skeleton (reaction PTs filled later via MedDRA).
icsr = {
"patient": {"age": None, "sex": None}, # from de-identified demographics
"drugs": [
{
"name": e["text"],
"drugcharacterization": 1, # 1=suspect 2=concomitant 3=interacting
"action": None, # e.g. drug withdrawn / dose reduced
}
for e in drugs
],
"reactions": [
{
"verbatim": e["text"], # narrative term, pre-MedDRA
"meddra_pt": None, # coded with user's MedDRA dict
"outcome": None, # E2B reaction outcome code
}
for e in conditions
],
"seriousness": {
"serious": None, "death": False, "lifeThreatening": False,
"hospitalization": True, "disability": False, "congenitalAnomaly": False,
"otherMedicallyImportant": False,
},
}
E2B(R3) seriousness and outcome value sets
Seriousness is a set of boolean criteria (E2B E.i.3.2). A case is serious if
any criterion is true:
| Criterion |
E2B element |
FAERS field |
| Death |
E.i.3.2a |
seriousnessdeath |
| Life-threatening |
E.i.3.2b |
seriousnesslifethreatening |
| Hospitalization / prolonged |
E.i.3.2c |
seriousnesshospitalization |
| Disability / incapacity |
E.i.3.2d |
seriousnessdisabling |
| Congenital anomaly |
E.i.3.2e |
seriousnesscongenitalanomali |
| Other medically important |
E.i.3.2f |
seriousnessother |
Reaction outcome (E2B E.i.7) is a coded value: 1 recovered/resolved,
2 recovering/resolving, 3 not recovered/not resolved, 4 recovered with
sequelae, 5 fatal, 6 unknown.
Drug characterization (E2B G.k.1): 1 suspect, 2 concomitant, 3 interacting.
Workflow
- De-identify first. Run
openmed.deidentify(narrative, policy=...) and
work from result.deidentified_text. Patient name, MRN, and dates must be
removed/shifted before the case leaves your environment.
- Extract drugs and reactions with the two
analyze_text calls above.
Keep each entity's start/end offsets for traceability.
- Characterize each drug as suspect (
1), concomitant (2), or
interacting (3). The drug that temporally precedes the reaction and was
acted upon (withdrawn/reduced) is usually the suspect.
- Code reactions to MedDRA. Map each verbatim reaction term to a MedDRA
Preferred Term (PT) and its System Organ Class using the user's licensed
MedDRA dictionary (see "Edge cases"). Never invent PTs.
- Determine seriousness. Scan the narrative for the six criteria; set
serious=True if any is met. "Hospitalized", "admitted", "ICU" → C.1.7c.
- Assign reaction outcome from the value set above.
- Hand the structured draft to a qualified safety reviewer for causality
(e.g. WHO-UMC or Naranjo), expectedness, and final submission.
Hand-off to / from OpenMed
OpenMed's analyze_text returns a dict; result["entities"] is a list whose
items carry text, label, confidence, start, end. Consume them:
- From
extracting-clinical-entities: Pharmaceutical entities →
icsr["drugs"]; Disease entities → icsr["reactions"]. Keep offsets so each
E2B field is traceable to the source span.
- From
normalizing-rxnorm: optionally attach an RxCUI to each suspect drug
for product identification (E2B G.k.2.2) before coding.
- De-identify with
deidentifying-clinical-text (openmed.deidentify)
before the case is exported or transmitted to any safety database.
- To
detecting-pv-signals: aggregated, coded cases feed disproportionality
analysis. To querying-openfda-labels: confirm the reaction is/ isn't a
labeled event (expectedness).
Edge cases & gotchas
- MedDRA is licensed — never bundle it. MedDRA is distributed by the MSSO
under subscription; OpenMed ships none of it. Load PTs/LLTs from the user's own
MedDRA release (the version is itself a reportable field, E2B C.1.x). Verbatim
reaction text stays in the case until a coder maps it.
- One reaction term ≠ one PT. "GI bleed" maps to the PT Gastrointestinal
haemorrhage; keep the verbatim term alongside the coded PT for the audit
trail. Multi-word reactions span several OpenMed tokens — reassemble by offset.
- Suspect vs concomitant matters. Disproportionality and labeling decisions
hinge on
drugcharacterization. Do not default every drug to suspect.
- Seriousness is OR, not a severity scale. A mild rash that caused
hospitalization is serious; a severe headache that resolved at home may not
be. Classify by the six regulatory criteria, not by clinical severity words.
- Causality is out of scope here. This skill structures the case; it does not
assert the drug caused the event. Leave causality to the reviewer.
- Local-first. NER and de-identification run on-device. Only de-identified,
structured case data should reach an external safety database, and only under
the appropriate regulatory agreement.
Standards & references
1---2name: reporting-adverse-events3description: Structures adverse-event mentions that OpenMed extracts into FAERS / ICH E2B(R3) reportable fields — suspect drug, reaction (MedDRA PT), seriousness criteria, and outcome. Use when the user needs to build an individual case safety report (ICSR), populate a FAERS submission, map a narrative to E2B(R3) data elements, classify seriousness (death, life-threatening, hospitalization, disability, congenital anomaly), or assign reaction outcomes. Trigger keywords: adverse event, ADR, ICSR, FAERS, E2B, E2B(R3), suspect drug, seriousness, MedDRA, reaction outcome, pharmacovigilance case. Pairs after OpenMed NER: consume Pharmaceutical/Chemical and Disease entities from openmed.analyze_text. MedDRA is licensed and user-supplied — never bundled. De-identify the narrative with openmed.deidentify before any external submission.4license: Apache-2.05---67# Reporting adverse events into FAERS / ICH E2B(R3)89A pharmacovigilance case starts as free-text narrative ("68 yo on warfarin10developed GI bleed, hospitalized"). To make it reportable you must structure it11into the **ICH E2B(R3)** data elements that the FDA's **FAERS** (and EMA's12EudraVigilance) expect: a **suspect drug**, one or more **reactions** coded to13**MedDRA** Preferred Terms, **seriousness** criteria, and a **reaction outcome**.1415OpenMed extracts the drug and condition spans on-device; this skill turns those16spans plus the narrative into the E2B(R3) skeleton. The reaction coding step17needs **MedDRA**, which is **licensed by the MSSO and user-supplied** — it is18never bundled with OpenMed and must be loaded from the user's own subscription.1920## When to use2122- A narrative names a drug and an adverse reaction and you need an ICSR23 (Individual Case Safety Report) shell with the right E2B(R3) fields.24- You must classify **seriousness** (E2B sections C.1.7 / E.i.3) — death,25 life-threatening, hospitalization/prolongation, disability, congenital26 anomaly, or "other medically important condition".27- You need to characterize each drug as **suspect / concomitant / interacting**28 (the `drugcharacterization` axis FAERS uses).29- You are pre-filling a 3500A / FAERS electronic submission or staging cases for30 a safety database.3132This skill produces a **structured draft for human safety review** — it does not33file reports or perform causality assessment autonomously.3435## Quick start3637```python38import openmed3940narrative = (41 "68-year-old patient on warfarin 5 mg daily developed a gastrointestinal "42 "hemorrhage and was hospitalized. Warfarin was discontinued; the patient "43 "recovered."44)4546# 1) Extract drug spans (Pharmaceutical category) on-device.47drugs = openmed.analyze_text(48 narrative,49 model_name="pharma_detection_superclinical",50 output_format="dict",51)["entities"]5253# 2) Extract condition / reaction spans (Disease category).54conditions = openmed.analyze_text(55 narrative,56 model_name="disease_detection_superclinical",57 output_format="dict",58)["entities"]5960# 3) Assemble an E2B(R3)-shaped ICSR skeleton (reaction PTs filled later via MedDRA).61icsr = {62 "patient": {"age": None, "sex": None}, # from de-identified demographics63 "drugs": [64 {65 "name": e["text"],66 "drugcharacterization": 1, # 1=suspect 2=concomitant 3=interacting67 "action": None, # e.g. drug withdrawn / dose reduced68 }69 for e in drugs70 ],71 "reactions": [72 {73 "verbatim": e["text"], # narrative term, pre-MedDRA74 "meddra_pt": None, # coded with user's MedDRA dict75 "outcome": None, # E2B reaction outcome code76 }77 for e in conditions78 ],79 "seriousness": {80 "serious": None, "death": False, "lifeThreatening": False,81 "hospitalization": True, "disability": False, "congenitalAnomaly": False,82 "otherMedicallyImportant": False,83 },84}85```8687## E2B(R3) seriousness and outcome value sets8889Seriousness is a set of boolean criteria (E2B E.i.3.2). A case is **serious** if90*any* criterion is true:9192| Criterion | E2B element | FAERS field |93| --- | --- | --- |94| Death | E.i.3.2a | `seriousnessdeath` |95| Life-threatening | E.i.3.2b | `seriousnesslifethreatening` |96| Hospitalization / prolonged | E.i.3.2c | `seriousnesshospitalization` |97| Disability / incapacity | E.i.3.2d | `seriousnessdisabling` |98| Congenital anomaly | E.i.3.2e | `seriousnesscongenitalanomali` |99| Other medically important | E.i.3.2f | `seriousnessother` |100101Reaction outcome (E2B E.i.7) is a coded value: `1` recovered/resolved,102`2` recovering/resolving, `3` not recovered/not resolved, `4` recovered with103sequelae, `5` fatal, `6` unknown.104105Drug characterization (E2B G.k.1): `1` suspect, `2` concomitant, `3` interacting.106107## Workflow1081091. **De-identify first.** Run `openmed.deidentify(narrative, policy=...)` and110 work from `result.deidentified_text`. Patient name, MRN, and dates must be111 removed/shifted before the case leaves your environment.1122. **Extract drugs and reactions** with the two `analyze_text` calls above.113 Keep each entity's `start`/`end` offsets for traceability.1143. **Characterize each drug** as suspect (`1`), concomitant (`2`), or115 interacting (`3`). The drug that temporally precedes the reaction and was116 acted upon (withdrawn/reduced) is usually the suspect.1174. **Code reactions to MedDRA.** Map each verbatim reaction term to a MedDRA118 **Preferred Term (PT)** and its System Organ Class using the user's licensed119 MedDRA dictionary (see "Edge cases"). Never invent PTs.1205. **Determine seriousness.** Scan the narrative for the six criteria; set121 `serious=True` if any is met. "Hospitalized", "admitted", "ICU" → C.1.7c.1226. **Assign reaction outcome** from the value set above.1237. **Hand the structured draft to a qualified safety reviewer** for causality124 (e.g. WHO-UMC or Naranjo), expectedness, and final submission.125126## Hand-off to / from OpenMed127128OpenMed's `analyze_text` returns a `dict`; `result["entities"]` is a list whose129items carry `text`, `label`, `confidence`, `start`, `end`. Consume them:130131- **From** `extracting-clinical-entities`: Pharmaceutical entities →132 `icsr["drugs"]`; Disease entities → `icsr["reactions"]`. Keep offsets so each133 E2B field is traceable to the source span.134- **From** `normalizing-rxnorm`: optionally attach an RxCUI to each suspect drug135 for product identification (E2B G.k.2.2) before coding.136- **De-identify** with `deidentifying-clinical-text` (`openmed.deidentify`)137 **before** the case is exported or transmitted to any safety database.138- **To** `detecting-pv-signals`: aggregated, coded cases feed disproportionality139 analysis. **To** `querying-openfda-labels`: confirm the reaction is/ isn't a140 labeled event (expectedness).141142## Edge cases & gotchas143144- **MedDRA is licensed — never bundle it.** MedDRA is distributed by the MSSO145 under subscription; OpenMed ships none of it. Load PTs/LLTs from the user's own146 MedDRA release (the version is itself a reportable field, E2B C.1.x). Verbatim147 reaction text stays in the case until a coder maps it.148- **One reaction term ≠ one PT.** "GI bleed" maps to the PT *Gastrointestinal149 haemorrhage*; keep the verbatim term alongside the coded PT for the audit150 trail. Multi-word reactions span several OpenMed tokens — reassemble by offset.151- **Suspect vs concomitant matters.** Disproportionality and labeling decisions152 hinge on `drugcharacterization`. Do not default every drug to suspect.153- **Seriousness is OR, not a severity scale.** A mild rash that caused154 hospitalization is *serious*; a severe headache that resolved at home may not155 be. Classify by the six regulatory criteria, not by clinical severity words.156- **Causality is out of scope here.** This skill structures the case; it does not157 assert the drug caused the event. Leave causality to the reviewer.158- **Local-first.** NER and de-identification run on-device. Only de-identified,159 structured case data should reach an external safety database, and only under160 the appropriate regulatory agreement.161162## Standards & references163164- FDA FAERS overview: https://www.fda.gov/drugs/surveillance/fda-adverse-event-reporting-system-faers165- ICH E2B(R3) ICSR implementation guide: https://www.ich.org/page/efficacy-guidelines (E2B(R3))166- FDA E2B(R3) regional implementation: https://www.fda.gov/industry/fda-data-standards-advisory-board/ich-e2br3-individual-case-safety-report-icsr167- MedDRA (licensed, user-supplied): https://www.meddra.org/168- FDA MedWatch 3500A reporting: https://www.fda.gov/safety/medical-product-safety-information/medwatch-fda-safety-information-and-adverse-event-reporting-program