Api / Extract Concepts
/v1/extract/concepts
Extract clinical phrases from free text and resolve each one to ranked SNOMED concept candidates using embeddings and pgvector cosine search.
/v1/extract/conceptsUnlike /v1/normalize, which matches a single phrase you already isolated, extract/concepts takes a whole clinical note. It detects candidate spans (NER), embeds each one with a multilingual sentence-transformer, and resolves it against SNOMED descriptions via pgvector cosine similarity. Each span gets a status derived from the top cosine score and the margin to the second candidate, so you can decide which results are safe to auto-accept versus which need review.
Request body
Parameters
textstringrequiredThe clinical text to analyze. After trimming, must be at least 2 characters; otherwise the request returns400 INVALID_INPUT.language"en" | "fr" | "auto"optionaldefault:autoLanguage hint for span detection.autolets the service infer it.
Response
{
"concepts": [
{
"span": "fibrillation auriculaire",
"candidates": [
{ "code": "49436004", "display": "Atrial fibrillation", "cosine": 0.91 },
{ "code": "40593004", "display": "Fibrillation", "cosine": 0.78 }
],
"code": "49436004",
"cosine": 0.91,
"margin": 0.13,
"concept_confidence": 0.91,
"status": "resolved"
}
]
}Concept shape
spanstringoptionalThe exact text span detected in the note.candidatesobject[]optionalTop SNOMED candidates, each withcode(SCTID),display, andcosinesimilarity.codestring | nulloptionalThe chosen SCTID, ornullwhen the span isunresolved.cosinenumberoptionalCosine similarity of the top candidate.marginnumberoptionalGap between the top and second candidate cosine. A small margin means the match is ambiguous.concept_confidencenumberoptionalConvenience score equal to the top cosine.status"resolved" | "flag" | "unresolved"optionalresolved: high cosine and margin;flag: matched but low confidence or margin, review recommended;unresolved: no candidate cleared the floor.
Examples
curl -X POST https://api.obscyro.com/v1/extract/concepts \
-H "Authorization: Bearer $OBS_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "Patient suivi pour une fibrillation auriculaire sous anticoagulant.",
"language": "fr"
}'Tips
- Treat
resolvedspans as safe to map automatically; routeflagandunresolvedspans to human review. - Feed the returned spans and codes into
/v1/extract/contextsto learn whether each concept is negated, historical, or about a family member. - The service uses a multilingual embedding model, so French and English notes both work without a separate model.
Errors
| Status | Code | When |
|---|---|---|
| VALIDATION_ERROR | Body did not pass schema validation (missing text, bad language). | |
| INVALID_INPUT | text was shorter than 2 characters after trimming. | |
| INVALID_API_KEY | Missing or invalid bearer token. | |
| RATE_LIMITED | Per-minute rate limit exceeded for this key. | |
| NLP_UPSTREAM_ERROR | The extraction service returned an error. | |
| NLP_UNAVAILABLE | The extraction service is not configured or unreachable. |
- VALIDATION_ERROR
Body did not pass schema validation (missing
text, badlanguage). - INVALID_INPUT
textwas shorter than 2 characters after trimming. - INVALID_API_KEY
Missing or invalid bearer token.
- RATE_LIMITED
Per-minute rate limit exceeded for this key.
- NLP_UPSTREAM_ERROR
The extraction service returned an error.
- NLP_UNAVAILABLE
The extraction service is not configured or unreachable.