Docs
pharmacopeia is a JSON-over-HTTP API. Every response is generated and validated by the same Zod schemas used internally, so this page is the schema.
API version v0.2.0-scale · last updated 2026-06-12
No authentication is required in v0. Rate limits apply.
// Fetch a drug by slug
const res = await fetch("https://pharmacopeia.dev/api/v1/drug/metformin");
const drug = await res.json();
console.log(drug.mechanism.summary);- Slugs over IDs. Every entity is keyed by a stable, human-readable slug (e.g.
metformin). Slugs never change. - Versioned URLs. All routes live under
/api/v1. Breaking changes will ship as/api/v2. - Provenance everywhere. Every record carries a
provenanceobject with the canonical source URL, hash, extractor, and confidence. - JSON in, JSON out. Bodies are
application/json. Responses areapplication/json; charset=utf-8. - Cache-friendly.
GETresponses ship withCache-Control: public, s-maxage=3600and a strongETag. Send the previous tag back inIf-None-Matchand you'll get a304 Not Modifiedwith no body. - OpenAPI + try-it. Every endpoint is described in the live OpenAPI 3.1 document at
/api/v1/openapi.jsonand rendered as an interactive reference at/reference. - LLM-friendly. A short
/llms.txtindex and a long-form/llms-full.txtfollow the llmstxt.org convention.
A single q parameter searches across drug names, brand names, synonyms, ingredient names, and class names.
// Search across drugs, ingredients, and classes
fetch("https://pharmacopeia.dev/api/v1/search?q=blood+thinner")
.then((r) => r.json())
.then(({ results }) => console.log(results));Send 2–20 drug slugs and get back every known pairwise interaction with severity, mechanism, and recommendation. The response includes a summary count per severity bucket.
// Check pairwise interactions
const res = await fetch(
"https://pharmacopeia.dev/api/v1/interactions/check",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ drugs: ["lisinopril", "ibuprofen"] }),
},
);
const { pairs, summary } = await res.json();Paste a SMILES and rank every drug in the dataset by 2D Tanimoto similarity, using the same OpenChemLib 512-bit fingerprint family that backs each drug's structural-analogs list. Use limit to cap the result count and threshold (0–1) to drop weak matches. Try it interactively at /structure-search. Structural proximity only — never therapeutic equivalence.
// Paste a SMILES, get the structurally closest drugs
const res = await fetch(
"https://pharmacopeia.dev/api/v1/structure-search",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
smiles: "CC(=O)NC1=CC=C(C=C1)O",
limit: 10,
threshold: 0.4,
}),
},
);
const { results } = await res.json();Every drug record is chunked into small, citable passages — mechanism, dosing, label sections, and more. q is matched by meaning (cosine similarity over precomputed embeddings) when the embedding store is available, with a lexical fallback over the same passages otherwise. The method field in the response reports which path answered; the shape never changes.
// Ask what you mean, not what you can spell
const res = await fetch(
"https://pharmacopeia.dev/api/v1/semantic-search?" +
new URLSearchParams({
q: "beta blocker safe in asthma",
sections: "mechanism,warnings-and-precautions",
}),
);
const { method, results } = await res.json();
// method: "embedding" | "lexical" — same shape either wayPOST /api/v1/grounded is the key-gated tier built for LLM consumers: the same retrieval, plus a citation for every passage and a character-span grounding map, so a model can attach a verifiable reference — source URL, content hash, extraction timestamp, confidence — to every token it quotes.
// Key-gated tier: passages + per-span citations with provenance
const res = await fetch("https://pharmacopeia.dev/api/v1/grounded", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.PHARMACOPEIA_API_KEY}`,
},
body: JSON.stringify({ query: "metformin renal dosing", limit: 8 }),
});
const { passages, citations } = await res.json();
// every passage.grounding span maps to a citation with
// sourceUrl, sourceHash, extractedAt, and confidenceKey-gated endpoints are rate limited per key: a requests-per-minute window reported via X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers, plus a daily quota reported via X-Quota-Limit / X-Quota-Remaining (resets at UTC midnight). Exceeding either returns 429 with a Retry-After header and error code rate_limited.
Register an HTTPS endpoint and receive signed POSTs when drug records change (drug.created, drug.updated, drug.deleted, dataset.refreshed) instead of polling the change feed. Deliveries carry an X-Pharmacopeia-Signature: t=<ts>,v1=<hex> header — HMAC-SHA256 of <ts>.<body>with your endpoint's secret. Endpoints auto-disable after 25 consecutive failed deliveries.
// Register an endpoint; verify deliveries with the whsec_... secret
const res = await fetch("https://pharmacopeia.dev/api/v1/webhooks", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.PHARMACOPEIA_API_KEY}`,
},
body: JSON.stringify({
url: "https://example.com/hooks/pharmacopeia",
events: ["drug.updated", "dataset.refreshed"],
}),
});
const { id, secret } = await res.json(); // secret shown exactly onceA thin GraphQL layer over the same repository. Pick exactly the fields and relations you need in one query — a drug, its mechanism, its interactions, and its structural analogs in a single round-trip. Open /api/graphql in a browser for the GraphiQL IDE with a worked example.
// Field-selected query — one round-trip, exactly the shape you want
const res = await fetch("https://pharmacopeia.dev/api/graphql", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
query: `
query Metformin {
drug(slug: "metformin") {
name
mechanism { summary targets }
similar { slug name score }
interactions { drugB severity description }
}
}
`,
}),
});
const { data } = await res.json();- GET
/api/v1/healthLiveness probe + dataset snapshot version. Tiny envelope for monitors and load balancers.
- GET
/api/v1/statsTop-level counts for the entire dataset and current version.
- GET
/api/v1/drugsList drug summaries. Supports ?limit, ?offset, ?q=<text>, ?class=<slug>, ?ingredient=<slug>, and ?jurisdiction=<agency>.
- GET
/api/v1/drug/{slug}Full drug record: mechanism + targets, indications, contraindications, FDA label sections (boxed warning, dosage, adverse reactions, warnings, special populations, overdosage), PK, approval history, and identifiers. Supports ?fields=<csv> sparse fieldsets to omit heavy sections.
- POST
/api/v1/drugs/batchResolve up to 100 drug slugs in a single round-trip. Body: { slugs: string[] }. Returns the found records plus the slugs that did not resolve.
- GET
/api/v1/drug/{slug}/interactionsAll interactions involving the given drug.
- GET
/api/v1/drug/{slug}/similarStructurally similar drugs, ranked by 2D fingerprint (Tanimoto) similarity over PubChem structures.
- GET
/api/v1/drug/{slug}/historyDataset time-travel: the drug's current-snapshot provenance plus its change-event timeline (newest first). Pin ?asOf= to trim to a past instant. The drug endpoint also accepts ?asOf= to gate by extraction time.
- GET
/api/v1/drug/{slug}/shortagesFDA shortage entries (active, resolved, discontinuation) for a drug. Reference statistics only.
- GET
/api/v1/shortagesEvery FDA shortage entry across the dataset, ordered by drug then presentation.
- GET
/api/v1/drug/{slug}/adverse-eventsAggregate FAERS report counts — top reactions by reporting volume. NOT incidence rates, signals, or causality.
- GET
/api/v1/drug/{slug}/literatureCurated PubMed references, pinned to MeSH major topic at ingest time.
- GET
/api/v1/drug/{slug}/trialsClinicalTrials.gov registrations naming the drug as an intervention. Registration is NOT evidence of efficacy or safety.
- GET
/api/v1/drug/{slug}/pharmacogenomicsCPIC-curated drug–gene pairs with evidence levels and guideline links. Evidence metadata only — never testing or dosing guidance.
- GET
/api/v1/reactionsBrowse MedDRA Preferred Terms reported to FAERS across the dataset (paginated, filterable with ?q=).
- GET
/api/v1/reaction/{slug}One reaction with per-drug counts/shares plus related reactions by Jaccard similarity. Alias slugs 301-redirect to canonical.
- GET
/api/v1/brandsBrand → generic crosswalk for every brand name in the dataset.
- GET
/api/v1/classesList pharmacological classes (ATC, EPC, MoA, MeSH). Filterable with ?q=.
- GET
/api/v1/class/{slug}Class detail with the list of drugs it contains.
- GET
/api/v1/atcFull WHO ATC hierarchy as a nested tree (levels 1–5) with intermediate group names.
- GET
/api/v1/mechanisms/graphMechanism-of-action network: drugs, MoA classes, and molecular targets as nodes and links.
- GET
/api/v1/ingredientsList active ingredients with chemistry identifiers. Filterable with ?q=.
- GET
/api/v1/ingredient/{slug}Ingredient detail (RxCUI, UNII, SMILES, InChIKey, formula).
- GET
/api/v1/searchSearch drugs, ingredients, classes by name or synonym.
- POST
/api/v1/interactions/checkPairwise interaction check. Body: { drugs: string[] }. Returns severity-graded pairs.
- POST
/api/v1/structure-searchPaste a SMILES and rank drugs in the dataset by 2D Tanimoto similarity. Body: { smiles, limit?, threshold? }. Structural proximity only.
- GET
/api/v1/semantic-searchMeaning-based retrieval over drug-record passages. Supports ?q, ?limit, ?sections=<csv>. Embedding-backed when available; lexical fallback otherwise — the response `method` field reports which.
- POST
/api/v1/groundedKey-gated retrieval tier for LLM consumers: passages with per-span citations carrying full provenance. Body: { query, limit?, sections? }. Requires Authorization: Bearer <key>.
- GET
/api/v1/webhooksList webhook endpoints registered by the calling API key. Requires Authorization: Bearer <key>.
- POST
/api/v1/webhooksRegister an HTTPS webhook endpoint for drug.created / drug.updated / drug.deleted / dataset.refreshed events. Returns the HMAC signing secret exactly once.
- DELETE
/api/v1/webhooks/{id}Delete a webhook endpoint owned by the calling API key.
- POST
/api/graphqlField-selected GraphQL surface over the same repository. GET the endpoint in a browser to open GraphiQL.
- GET
/api/v1/changelogRecent record-level changes (typed mirror of /feed.xml and /feed.json). Supports ?limit and ?since=<ISO-8601>.
A public “what’s new” feed of recent record changes — new drugs, new endpoints, new ingestion batches — so consumers and curators can watch the dataset evolve without scraping. Same entries served over RSS 2.0 and JSON Feed 1.1. Browse the same entries at /changelog.
- GET
/feed.xmlRSS 2.0 feed. Drop into Feedly, NetNewsWire, or any reader.
- GET
/feed.jsonJSON Feed 1.1. Each item carries the structured
_pharmacopeiaextension (kind, action, entity slug, sources) for automation.
Thin, fully-typed clients so consumers don’t hand-roll fetch wrappers. Types are generated from the same Zod schemas the API uses, so request and response shapes can never silently drift from the server. Tagged releases on GitHub publish both packages automatically.
@pharmacopeia/client
npmnpm install @pharmacopeia/clientpharmacopeia
PyPIpip install pharmacopeiaThe full machine-readable contract — every endpoint, every schema — lives at /api/v1/openapi.json if you’d rather generate your own client.
Every field on every page is tagged with the pipeline that produced it. The badges below tell you at a glance how much trust to extend before you act on a sentence. Hover or focus any live badge to see the underlying extractor, confidence, and source URL.
- AI-extractedAI-extracted. An LLM produced or rewrote this content. Read critically and cross-check against the linked source. Used for any extractor starting with
llm-,claude-,gpt-,gemini-, ormistral-. - Sourced from openFDAAuto-sourced. A script fetched this directly from a structured, authoritative source — humans wrote the words, our pipeline just shipped them. Used for
openfda,dailymed,rxnav,drugbank-open,atc-who, and anyingest-script@*. - no badgeCurated. A maintainer typed this by hand. No badge is rendered — default trust — but the underlying
provenanceis still in the JSON payload.
pharmacopeia is for educational and informational use only. Nothing in the API or this site is medical advice, a diagnosis, a treatment recommendation, or a substitute for consultation with a qualified clinician. Always verify against the canonical provenance.sourceUrl before acting on any field.