# Phenoml Console > Phenoml is a healthcare AI developer platform offering configurable, healthcare-compliant APIs for providers, biopharma, healthtech, and payers. This is the Phenoml developer console. The console app requires sign-in and isn't represented here; the links below cover the publicly documented APIs. Complete Phenoml API reference with every endpoint inlined for language-model ingestion. # Construe Extract medical codes from natural language clinical text. Supports SNOMED CT, ICD-10, RxNorm, LOINC, and more. ## Construe / Code Systems Manage custom medical code systems used by the extractor. ### GET /construe/codes/systems **List available code systems** Returns the terminology server's catalog of available code systems, including both built-in standard terminologies and custom uploaded systems. **Operation ID:** `construe_list` #### Responses **200** - List of available code systems Content-Type: `application/json` ```json { "type": "object", "required": [ "systems" ], "properties": { "systems": { "type": "array", "items": { "type": "object", "required": [ "name", "version", "code_count", "builtin" ], "properties": { "name": { "type": "string", "description": "Code system name", "example": "ICD-10-CM" }, "version": { "type": "string", "description": "Code system version", "example": "2025" }, "code_count": { "type": "integer", "description": "Total number of codes in the system", "example": 72750 }, "builtin": { "type": "boolean", "description": "Whether this is a built-in system (vs custom uploaded)", "example": true } } } } } } ``` **Example:** ```json { "systems": [ { "name": "ICD-10-CM", "version": "2025", "code_count": 97584, "builtin": true }, { "name": "SNOMED_CT_US_LITE", "version": "20240901", "code_count": 102837, "builtin": true }, { "name": "RXNORM", "version": "11042024", "code_count": 257619, "builtin": true }, { "name": "LOINC", "version": "2.78", "code_count": 98123, "builtin": true }, { "name": "HPO", "version": "2025", "code_count": 19542, "builtin": true }, { "name": "CPT", "version": "2025", "code_count": 10192, "builtin": true }, { "name": "ICD-10-PCS", "version": "2025", "code_count": 78717, "builtin": true } ] } ``` **401** - Unauthorized **500** - Server error --- ### GET /construe/codes/systems/{codesystem} **Get code system detail** Returns full metadata for a single code system, including timestamps and builtin status. **Operation ID:** `construe_find` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `codesystem` | path | string | Yes | Code system name (e.g., "ICD-10-CM", "SNOMED_CT_US_LITE") | | `version` | query | string | No | Specific version of the code system. Required if multiple versions exist. | #### Responses **200** - Code system detail Content-Type: `application/json` ```json { "type": "object", "required": [ "name", "version", "code_count", "builtin", "status", "created_at", "updated_at" ], "properties": { "name": { "type": "string", "description": "Code system name", "example": "ICD-10-CM" }, "version": { "type": "string", "description": "Code system version", "example": "2025" }, "code_count": { "type": "integer", "description": "Total number of codes in the system", "example": 72750 }, "builtin": { "type": "boolean", "description": "Whether this is a built-in system (vs custom uploaded)", "example": true }, "status": { "type": "string", "enum": [ "processing", "ready", "failed" ], "description": "Processing status of the code system.\n- \"processing\": embeddings are being generated\n- \"ready\": code system is ready for use\n- \"failed\": processing failed (re-upload with replace=true to retry)\n", "example": "ready" }, "created_at": { "type": "string", "format": "date-time", "description": "When the code system was created" }, "updated_at": { "type": "string", "format": "date-time", "description": "When the code system was last updated" } } } ``` **Example:** ```json { "name": "ICD-10-CM", "version": "2025", "code_count": 97584, "builtin": true, "status": "ready", "created_at": "2026-02-10T18:33:23Z", "updated_at": "2026-02-10T18:33:23Z" } ``` **400** - Invalid parameters or multiple versions exist without version specified **401** - Unauthorized **404** - Code system not found **500** - Server error --- ### DELETE /construe/codes/systems/{codesystem} **Delete custom code system** Deletes a custom (non-builtin) code system and all its codes. Builtin systems cannot be deleted. Only available on dedicated instances. Large systems may take up to a minute to delete. **Operation ID:** `construe_delete` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `codesystem` | path | string | Yes | Code system name | | `version` | query | string | No | Specific version of the code system. Required if multiple versions exist. | #### Responses **200** - Code system deleted successfully Content-Type: `application/json` ```json { "type": "object", "required": [ "message" ], "properties": { "message": { "type": "string", "description": "Confirmation message", "example": "code system deleted successfully" } } } ``` **Example:** ```json { "message": "code system deleted successfully" } ``` **400** - Invalid parameters or multiple versions exist without version specified **401** - Unauthorized **403** - Cannot delete builtin code systems or not on a dedicated instance **404** - Code system not found **500** - Server error --- ### GET /construe/codes/systems/{codesystem}/export **Export custom code system** Exports a custom (non-builtin) code system as a JSON file compatible with the upload format. The exported file can be re-uploaded directly via POST /construe/upload with format "json". Only available on dedicated instances. Builtin systems cannot be exported. **Operation ID:** `construe_export` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `codesystem` | path | string | Yes | Code system name | | `version` | query | string | No | Specific version of the code system. Required if multiple versions exist. | #### Responses **200** - Exported code system as JSON file Content-Type: `application/json` ```json { "type": "object", "required": [ "name", "version", "format", "codes" ], "properties": { "name": { "type": "string", "description": "Code system name", "example": "CUSTOM_CODES" }, "version": { "type": "string", "description": "Code system version", "example": "1.0" }, "format": { "type": "string", "enum": [ "json" ], "description": "Upload format (always \"json\")" }, "codes": { "type": "array", "description": "All codes in the system", "items": { "type": "object", "required": [ "code", "description" ], "properties": { "code": { "type": "string", "description": "The code identifier", "example": "E11.65" }, "description": { "type": "string", "description": "Short description of the code", "example": "Type 2 diabetes mellitus with hyperglycemia" }, "definition": { "type": "string", "nullable": true, "description": "Extended definition of the code (if available)" } } } } } } ``` **Example:** ```json { "name": "CUSTOM_CODES", "version": "1.0", "format": "json", "codes": [ { "code": "X001", "description": "Example custom code 1" }, { "code": "X002", "description": "Example custom code 2" } ] } ``` **400** - Invalid parameters or multiple versions exist without version specified **401** - Unauthorized **403** - Cannot export builtin code systems or not on a dedicated instance **404** - Code system not found **409** - Code system is still processing **424** - Code system processing failed **500** - Server error --- ### POST /construe/upload **Upload custom code system** Upload a custom medical code system with codes and descriptions for use in code extraction. Requires a paid plan. Returns 202 immediately; embedding generation runs asynchronously. Poll GET /construe/codes/systems/{codesystem}?version={version} to check when status transitions from "processing" to "ready" or "failed". **Operation ID:** `construe_upload` #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "description": "Upload a custom code system. The `format` field determines which additional fields are required:\n- **csv**: requires `file`, `code_col`, `desc_col`\n- **json**: requires either `file` (base64-encoded JSON array) or `codes` (direct JSON array)\n", "required": [ "name", "version", "format" ], "properties": { "name": { "type": "string", "description": "Name of the code system. Names are case-insensitive and stored uppercase.\nBuiltin system names (e.g. ICD-10-CM, SNOMED_CT_US_LITE, LOINC, CPT, etc.) are\nreserved and cannot be used for custom uploads; attempts return HTTP 403 Forbidden.\n", "example": "CUSTOM_CODES" }, "version": { "type": "string", "description": "Version of the code system", "example": "1.0" }, "revision": { "type": "number", "description": "Optional revision number", "example": 1 }, "format": { "type": "string", "enum": [ "csv", "json" ], "description": "Upload format" }, "file": { "type": "string", "format": "byte", "description": "The file contents as a base64-encoded string.\nFor CSV format, this is the CSV file contents.\nFor JSON format, this is a base64-encoded JSON array; prefer using 'codes' instead.\n" }, "code_col": { "type": "string", "description": "Column name containing codes (required for CSV format)", "example": "code" }, "desc_col": { "type": "string", "description": "Column name containing descriptions (required for CSV format)", "example": "description" }, "defn_col": { "type": "string", "description": "Optional column name containing long definitions (for CSV format)", "example": "definition" }, "codes": { "type": "array", "items": { "type": "object", "required": [ "code", "description" ], "properties": { "code": { "type": "string", "description": "The code identifier", "example": "E11.65" }, "description": { "type": "string", "description": "Short description of the code", "example": "Type 2 diabetes mellitus with hyperglycemia" }, "definition": { "type": "string", "nullable": true, "description": "Extended definition of the code (if available)" } } }, "description": "The codes to upload as a JSON array (JSON format only).\nThis is the preferred way to upload JSON codes, as it avoids unnecessary base64 encoding.\nIf both 'codes' and 'file' are provided, 'codes' takes precedence.\n" }, "replace": { "type": "boolean", "default": false, "description": "If true, replaces an existing code system with the same name and version.\nBuiltin systems cannot be replaced; attempts to do so return HTTP 403 Forbidden.\nWhen false (default), uploading a duplicate returns 409 Conflict.\n" } } } ``` **Example:** ```json { "name": "CUSTOM_CODES", "version": "1.0", "format": "json", "codes": [ { "code": "X001", "description": "Example custom code 1" }, { "code": "X002", "description": "Example custom code 2" } ] } ``` #### Responses **202** - Upload accepted for asynchronous processing Content-Type: `application/json` ```json { "type": "object", "properties": { "status": { "type": "string", "example": "processing" }, "name": { "type": "string", "example": "CUSTOM_CODES" }, "version": { "type": "string", "example": "1.0" } } } ``` **Example:** ```json { "status": "processing", "name": "CUSTOM_CODES", "version": "1.0" } ``` **400** - Invalid request format or parameters **401** - Unauthorized **403** - Forbidden (not on a dedicated instance, or replace=true on a builtin system) **409** - Code system version already exists (when replace=false) **424** - Failed dependency (error processing or storing the code system) **500** - Server error --- ## Construe / Codes Extract and search codes within a code system. ### GET /construe/codes/{codesystem} **List codes in a code system** Returns a paginated list of all codes in the specified code system from the terminology server. Usage of CPT is subject to AMA requirements: see PhenoML Terms of Service. **Operation ID:** `construe_listCodes` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `codesystem` | path | string | Yes | Code system name (e.g., "ICD-10-CM", "SNOMED_CT_US_LITE") | | `version` | query | string | No | Specific version of the code system. Required if multiple versions exist. | | `cursor` | query | string | No | Pagination cursor from previous response | | `limit` | query | integer | No | Maximum number of codes to return (default 20) | #### Responses **200** - Paginated list of codes Content-Type: `application/json` ```json { "type": "object", "required": [ "system", "codes", "has_more" ], "properties": { "system": { "type": "object", "required": [ "name", "version" ], "properties": { "name": { "type": "string", "description": "Code system name", "example": "ICD-10-CM" }, "version": { "type": "string", "description": "Code system version", "example": "2025" } } }, "codes": { "type": "array", "items": { "type": "object", "required": [ "code", "description" ], "properties": { "code": { "type": "string", "description": "The code identifier", "example": "E11.65" }, "description": { "type": "string", "description": "Short description of the code", "example": "Type 2 diabetes mellitus with hyperglycemia" }, "definition": { "type": "string", "nullable": true, "description": "Extended definition of the code (if available)" } } } }, "next_cursor": { "type": "string", "nullable": true, "description": "Cursor for fetching the next page (null if no more results)" }, "has_more": { "type": "boolean", "description": "Whether there are more results available" } } } ``` **Example:** ```json { "system": { "name": "ICD-10-CM", "version": "2025" }, "codes": [ { "code": "A00", "description": "Cholera" }, { "code": "A000", "description": "Cholera due to Vibrio cholerae 01, biovar cholerae" }, { "code": "A001", "description": "Cholera due to Vibrio cholerae 01, biovar eltor" }, { "code": "A009", "description": "Cholera, unspecified" }, { "code": "A01", "description": "Typhoid and paratyphoid fevers" } ], "next_cursor": "QTAx", "has_more": true } ``` **400** - Invalid parameters or multiple versions exist without version specified **401** - Unauthorized **404** - Code system not found **500** - Server error --- ### GET /construe/codes/{codesystem}/{codeID} **Get a specific code** Looks up a specific code in the terminology server and returns its details. Usage of CPT is subject to AMA requirements: see PhenoML Terms of Service. **Operation ID:** `construe_lookup` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `codesystem` | path | string | Yes | Code system name | | `codeID` | path | string | Yes | The code identifier. ICD-10-CM codes are stored without their cosmetic dot (use "E1165", not "E11.65"). | | `version` | query | string | No | Specific version of the code system | #### Responses **200** - Code details Content-Type: `application/json` ```json { "type": "object", "required": [ "system", "code", "description" ], "properties": { "system": { "type": "object", "required": [ "name", "version" ], "properties": { "name": { "type": "string", "description": "Code system name", "example": "ICD-10-CM" }, "version": { "type": "string", "description": "Code system version", "example": "2025" } } }, "code": { "type": "string", "description": "The code identifier", "example": "E11.65" }, "description": { "type": "string", "description": "Short description of the code", "example": "Type 2 diabetes mellitus with hyperglycemia" }, "definition": { "type": "string", "nullable": true, "description": "Extended definition of the code (if available)" } } } ``` **Example:** ```json { "system": { "name": "ICD-10-CM", "version": "2025" }, "code": "E1165", "description": "Type 2 diabetes mellitus with hyperglycemia" } ``` **400** - Invalid code ID or parameters **401** - Unauthorized **404** - Code or code system not found **500** - Server error --- ### GET /construe/codes/{codesystem}/search/semantic **Semantic search (embedding-based)** Performs semantic similarity search using vector embeddings. **Availability**: This endpoint works for both **built-in and custom** code systems. **When to use**: Best for natural language queries where you want to find conceptually related codes, even when different terminology is used. The search understands meaning, not just keywords. **Examples**: - Query "trouble breathing at night" finds codes like "Sleep apnea", "Orthopnea", "Nocturnal dyspnea" — semantically related but no exact keyword matches - Query "heart problems" finds "Myocardial infarction", "Cardiac arrest", "Arrhythmia" **Trade-offs**: Slower than text search (requires embedding generation), but finds conceptually similar results that keyword search would miss. See also: `/search/text` for faster keyword-based lookup with typo tolerance. Usage of CPT is subject to AMA requirements: see PhenoML Terms of Service. **Operation ID:** `construe_searchSemantic` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `codesystem` | path | string | Yes | Code system name | | `text` | query | string | Yes | Natural language text to find semantically similar codes for | | `version` | query | string | No | Specific version of the code system | | `limit` | query | integer | No | Maximum number of results (default 10, max 50) | #### Responses **200** - Semantic search results ordered by similarity Content-Type: `application/json` ```json { "type": "object", "required": [ "system", "results" ], "properties": { "system": { "type": "object", "required": [ "name", "version" ], "properties": { "name": { "type": "string", "description": "Code system name", "example": "ICD-10-CM" }, "version": { "type": "string", "description": "Code system version", "example": "2025" } } }, "results": { "type": "array", "description": "Codes ordered by semantic similarity (most similar first)", "items": { "type": "object", "required": [ "code", "description" ], "properties": { "code": { "type": "string", "example": "E11.65" }, "description": { "type": "string", "example": "Type 2 diabetes mellitus with hyperglycemia" } } } } } } ``` **Example:** ```json { "system": { "name": "ICD-10-CM", "version": "2025" }, "results": [ { "code": "R06.00", "description": "Dyspnea, unspecified" }, { "code": "R06.01", "description": "Orthopnea" }, { "code": "G47.33", "description": "Obstructive sleep apnea" }, { "code": "R06.83", "description": "Snoring" }, { "code": "J45.20", "description": "Mild intermittent asthma, uncomplicated" } ] } ``` **400** - Invalid parameters or missing search text **401** - Unauthorized **404** - Code system not found **500** - Server error --- ### GET /construe/codes/{codesystem}/search/text **Text search (keyword-based)** Performs fast full-text search over code IDs and descriptions. **Availability**: This endpoint is only available for **built-in code systems**. Custom code systems uploaded via `/construe/upload` are not indexed for full-text search and will return empty results. Use `/search/semantic` to search custom code systems. **When to use**: Best for autocomplete UIs, code lookup, or when users know part of the code ID or specific keywords. Fast response times suitable for typeahead interfaces. **Features**: - Substring matching on code IDs (e.g., "11.65" finds "E11.65") - Typo tolerance on descriptions (not on code IDs) - Fast response times (~10-50ms) **Examples**: - Query "E11" finds all codes starting with E11 (diabetes codes) - Query "diabtes" (typo) still finds "diabetes" codes **Trade-offs**: Faster than semantic search, but only matches keywords/substrings. Won't find conceptually related codes with different terminology. See also: `/search/semantic` for finding conceptually similar codes. Usage of CPT is subject to AMA requirements: see PhenoML Terms of Service. **Operation ID:** `construe_searchText` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `codesystem` | path | string | Yes | Code system name | | `q` | query | string | Yes | Search query (searches code IDs and descriptions) | | `version` | query | string | No | Specific version of the code system | | `limit` | query | integer | No | Maximum number of results (default 20, max 100) | #### Responses **200** - Text search results Content-Type: `application/json` ```json { "type": "object", "required": [ "system", "results", "found" ], "properties": { "system": { "type": "object", "required": [ "name", "version" ], "properties": { "name": { "type": "string", "description": "Code system name", "example": "ICD-10-CM" }, "version": { "type": "string", "description": "Code system version", "example": "2025" } } }, "results": { "type": "array", "description": "Codes matching the search query", "items": { "type": "object", "required": [ "code", "description" ], "properties": { "code": { "type": "string", "example": "E11.65" }, "description": { "type": "string", "example": "Type 2 diabetes mellitus with hyperglycemia" } } } }, "found": { "type": "integer", "description": "Total number of matching results (may exceed results array due to pagination)", "example": 150 } } } ``` **Example:** ```json { "system": { "name": "ICD-10-CM", "version": "2025" }, "results": [ { "code": "E11.65", "description": "Type 2 diabetes mellitus with hyperglycemia" }, { "code": "E11.649", "description": "Type 2 diabetes mellitus with hypoglycemia without coma" }, { "code": "E11.69", "description": "Type 2 diabetes mellitus with other specified complication" } ], "found": 3 } ``` **400** - Invalid parameters or missing query **401** - Unauthorized **404** - Code system not found **500** - Server error **501** - Text search not configured --- ### POST /construe/extract **Extract medical codes from text** Converts natural language text into structured medical codes. Usage of CPT is subject to AMA requirements: see PhenoML Terms of Service. **Operation ID:** `construe_extract` #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "text" ], "properties": { "text": { "type": "string", "description": "Natural language text to extract codes from", "example": "Patient is a 14-year-old female, previously healthy, who is here for evaluation of abnormal renal ultrasound with atrophic right kidney" }, "system": { "type": "object", "properties": { "name": { "type": "string", "description": "Code system name. Can be a built-in system or a custom system name.\n\nBuilt-in systems:\n* SNOMED_CT_US_LITE - version 20240901\n* RXNORM - version 11042024\n* ICD-10-CM - version 2025\n* ICD-10-PCS - version 2025\n* LOINC - version 2.78\n* HPO - version 2025\n* CPT - version 2025\n\nCustom systems:\n* Any valid system name uploaded via /construe/upload. Requires a paid plan.\n\nUsage of CPT is subject to AMA requirements: see PhenoML Terms of Service.\n", "example": "SNOMED_CT_US_LITE" }, "version": { "type": "string", "description": "Code system version. Must match the version available in your environment.", "example": "20240901" } } }, "config": { "type": "object", "properties": { "chunking_method": { "type": "string", "enum": [ "none", "sentences", "paragraphs", "topics", "soap_note", "clinical_ner_extract", "fasthpocr" ], "default": "sentences", "description": "Method for splitting input text into chunks before code extraction.\n* none - Treat the full input as a single chunk.\n* sentences - Split on sentence boundaries (supports citations).\n* paragraphs / topics / soap_note - LLM-based chunking.\n* clinical_ner_extract - Extract clinical concepts (problems, tests,\n treatments) and use each as a chunk (supports citations).\n* fasthpocr - Extract HPO concepts directly with category\n annotations (supports citations). Requires `system: HPO`;\n other systems are rejected. Causes most other config options\n to be ignored.\n" }, "max_codes_per_chunk": { "type": "integer", "minimum": 1, "example": 5, "description": "Maximum number of codes to extract per chunk. If not specified, uses system-specific defaults:\n* SNOMED: 10\n* LOINC, HPO, RXNORM: 20\n* All other systems: 5\n" }, "code_similarity_filter": { "type": "number", "format": "float", "minimum": 0, "maximum": 1, "default": 0.9, "example": 0.9, "description": "Threshold for filtering similar codes (0.0-1.0)" }, "validation_method": { "type": "string", "enum": [ "none", "simple", "medication_search", "chunk_code_jaccard_similarity" ], "default": "simple", "description": "Method for validating extracted codes:\n* none - No validation, returns all candidate codes\n* simple - LLM-based validation\n* medication_search - LLM-based validation tailored for medication concepts\n* chunk_code_jaccard_similarity - Token-level Jaccard similarity between source text chunk and code description\n" }, "chunk_code_jaccard_similarity_filtering_threshold": { "type": "number", "format": "float", "minimum": 0, "maximum": 1, "default": 0.2, "description": "Minimum Jaccard similarity (0.0-1.0) for a code to be considered valid\nwhen using the \"chunk_code_jaccard_similarity\" validation method. Ignored by other methods.\n" }, "include_rationale": { "type": "boolean", "default": true, "description": "Whether to include explanations for why each code was extracted" }, "include_ancestors": { "type": "boolean", "default": false, "description": "Whether to include ancestor/parent codes in the results" }, "include_invalid": { "type": "boolean", "default": false, "description": "Whether to include codes that failed validation in the results" }, "include_citations": { "type": "boolean", "default": false, "description": "Whether to include source text citations for each extracted code.\nCitations show the exact text spans (with character offsets) that led to each code.\nSupported when chunking_method is \"sentences\", \"clinical_ner_extract\", or \"fasthpocr\".\n" }, "extraction_context": { "type": "string", "maxLength": 1000, "description": "Optional context describing the goal of the extraction.\nRequired when min_context_relevance is greater than 0.\n", "example": "extract billing codes for an outpatient visit" }, "min_context_relevance": { "type": "number", "format": "double", "minimum": 0, "maximum": 1, "default": 0, "description": "Minimum relevance score (0.0–1.0) a chunk must reach to proceed to code extraction.\nChunks are scored by an LLM against the extraction_context goal. Chunks below this\nthreshold are dropped, reducing noise and extraction cost.\nSet to 0 (the default) to disable relevance filtering and extract from all chunks.\nRequires the \"extraction_context\" field when set above 0.\n" }, "consistency_effort": { "type": "string", "enum": [ "none", "low", "medium", "high" ], "default": "none", "description": "How much effort to spend ensuring consistent results across repeated requests.\nHigher levels apply stricter filtering to remove borderline results that may\nvary between calls, improving determinism at the cost of additional latency.\n\nWhen validation_method is set to a value other than \"none\", consistency is\napplied to the validation step: codes must be unanimously validated across\nmultiple rounds to be included.\n\nWhen validation_method is \"none\" and min_context_relevance is set above 0,\nconsistency is applied to the relevance ranking step instead: chunks must\npass the relevance threshold in every round to be included.\n" } } } } } ``` **Example:** ```json { "text": "Patient is a 14-year-old female, previously healthy, who is here for evaluation of abnormal renal ultrasound with atrophic right kidney.", "system": { "name": "ICD-10-CM", "version": "2025" } } ``` #### Responses **200** - Successfully extracted codes Content-Type: `application/json` ```json { "type": "object", "required": [ "system", "codes" ], "properties": { "system": { "type": "object", "properties": { "name": { "type": "string", "description": "Code system name. Can be a built-in system or a custom system name.\n\nBuilt-in systems:\n* SNOMED_CT_US_LITE - version 20240901\n* RXNORM - version 11042024\n* ICD-10-CM - version 2025\n* ICD-10-PCS - version 2025\n* LOINC - version 2.78\n* HPO - version 2025\n* CPT - version 2025\n\nCustom systems:\n* Any valid system name uploaded via /construe/upload. Requires a paid plan.\n\nUsage of CPT is subject to AMA requirements: see PhenoML Terms of Service.\n", "example": "SNOMED_CT_US_LITE" }, "version": { "type": "string", "description": "Code system version. Must match the version available in your environment.", "example": "20240901" } } }, "codes": { "type": "array", "items": { "type": "object", "required": [ "code", "description", "valid" ], "properties": { "code": { "type": "string", "description": "The extracted code", "example": "195967001" }, "description": { "type": "string", "description": "Short description of the code", "example": "Asthma" }, "valid": { "type": "boolean", "description": "Whether the code passed validation. Always true unless include_invalid is set to true, in which case invalid codes will have this set to false.", "example": true }, "reason": { "type": "string", "description": "Explanation for why this code was extracted (if include_rationale is true)" }, "is_ancestor": { "type": "boolean", "nullable": true, "description": "Whether this code is an ancestor (parent) of an extracted code rather than directly extracted.\nOnly present when include_ancestors is true.\n" }, "citations": { "type": "array", "nullable": true, "description": "Source text references showing where this code was found in the input.\nOnly present when include_citations is true and chunking method supports it.\nAncestor codes do not receive citations.\n", "items": { "type": "object", "required": [ "text", "begin_offset", "end_offset" ], "description": "A reference to source text that led to a code extraction", "properties": { "text": { "type": "string", "description": "The exact text span containing evidence for the code", "example": "Patient has type 2 diabetes" }, "begin_offset": { "type": "integer", "description": "Starting byte offset in the original input text (0-indexed)", "example": 0 }, "end_offset": { "type": "integer", "description": "Ending byte offset (exclusive), such that input[begin_offset:end_offset] == text", "example": 27 } } } }, "categories": { "type": "array", "nullable": true, "description": "Higher-level groupings the extracted code belongs to (e.g. HPO category terms).\nOnly populated by full-extraction chunking methods such as \"fasthpocr\".\n", "items": { "type": "object", "required": [ "uri", "label" ], "description": "A higher-level grouping (e.g. HPO category) for an extracted code.", "properties": { "uri": { "type": "string", "description": "Identifier for the category term (e.g. an HPO URI).", "example": "HP:0025142" }, "label": { "type": "string", "description": "Human-readable label for the category term.", "example": "Constitutional symptom" } } } } } } } } } ``` **Example:** ```json { "system": { "name": "ICD-10-CM", "version": "2025" }, "codes": [ { "code": "Q60.3", "description": "Renal hypoplasia, unspecified", "valid": true }, { "code": "R93.42", "description": "Abnormal findings on diagnostic imaging of kidney", "valid": true }, { "code": "N28.1", "description": "Cyst of kidney, acquired", "valid": true } ] } ``` **400** - Invalid request **401** - Unauthorized **404** - Code system not found **500** - Server error **503** - Service temporarily unavailable **504** - Request timed out --- ## Untagged ### POST /construe/feedback **Submit feedback on extraction results** Submits user feedback on results from the Construe extraction endpoint. Feedback includes the full extraction result received and the result the user expected. **Operation ID:** `construe_submitFeedback` #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "text", "received_result", "expected_result" ], "properties": { "text": { "type": "string", "description": "The natural language text that was used for code extraction", "example": "Patient has type 2 diabetes with hyperglycemia" }, "received_result": { "type": "object", "required": [ "system", "codes" ], "properties": { "system": { "type": "object", "properties": { "name": { "type": "string", "description": "Code system name. Can be a built-in system or a custom system name.\n\nBuilt-in systems:\n* SNOMED_CT_US_LITE - version 20240901\n* RXNORM - version 11042024\n* ICD-10-CM - version 2025\n* ICD-10-PCS - version 2025\n* LOINC - version 2.78\n* HPO - version 2025\n* CPT - version 2025\n\nCustom systems:\n* Any valid system name uploaded via /construe/upload. Requires a paid plan.\n\nUsage of CPT is subject to AMA requirements: see PhenoML Terms of Service.\n", "example": "SNOMED_CT_US_LITE" }, "version": { "type": "string", "description": "Code system version. Must match the version available in your environment.", "example": "20240901" } } }, "codes": { "type": "array", "items": { "type": "object", "required": [ "code", "description", "valid" ], "properties": { "code": { "type": "string", "description": "The extracted code", "example": "195967001" }, "description": { "type": "string", "description": "Short description of the code", "example": "Asthma" }, "valid": { "type": "boolean", "description": "Whether the code passed validation. Always true unless include_invalid is set to true, in which case invalid codes will have this set to false.", "example": true }, "reason": { "type": "string", "description": "Explanation for why this code was extracted (if include_rationale is true)" }, "is_ancestor": { "type": "boolean", "nullable": true, "description": "Whether this code is an ancestor (parent) of an extracted code rather than directly extracted.\nOnly present when include_ancestors is true.\n" }, "citations": { "type": "array", "nullable": true, "description": "Source text references showing where this code was found in the input.\nOnly present when include_citations is true and chunking method supports it.\nAncestor codes do not receive citations.\n", "items": { "type": "object", "required": [ "text", "begin_offset", "end_offset" ], "description": "A reference to source text that led to a code extraction", "properties": { "text": { "type": "string", "description": "The exact text span containing evidence for the code", "example": "Patient has type 2 diabetes" }, "begin_offset": { "type": "integer", "description": "Starting byte offset in the original input text (0-indexed)", "example": 0 }, "end_offset": { "type": "integer", "description": "Ending byte offset (exclusive), such that input[begin_offset:end_offset] == text", "example": 27 } } } }, "categories": { "type": "array", "nullable": true, "description": "Higher-level groupings the extracted code belongs to (e.g. HPO category terms).\nOnly populated by full-extraction chunking methods such as \"fasthpocr\".\n", "items": { "type": "object", "required": [ "uri", "label" ], "description": "A higher-level grouping (e.g. HPO category) for an extracted code.", "properties": { "uri": { "type": "string", "description": "Identifier for the category term (e.g. an HPO URI).", "example": "HP:0025142" }, "label": { "type": "string", "description": "Human-readable label for the category term.", "example": "Constitutional symptom" } } } } } } } } }, "expected_result": { "type": "object", "required": [ "system", "codes" ], "properties": { "system": { "type": "object", "properties": { "name": { "type": "string", "description": "Code system name. Can be a built-in system or a custom system name.\n\nBuilt-in systems:\n* SNOMED_CT_US_LITE - version 20240901\n* RXNORM - version 11042024\n* ICD-10-CM - version 2025\n* ICD-10-PCS - version 2025\n* LOINC - version 2.78\n* HPO - version 2025\n* CPT - version 2025\n\nCustom systems:\n* Any valid system name uploaded via /construe/upload. Requires a paid plan.\n\nUsage of CPT is subject to AMA requirements: see PhenoML Terms of Service.\n", "example": "SNOMED_CT_US_LITE" }, "version": { "type": "string", "description": "Code system version. Must match the version available in your environment.", "example": "20240901" } } }, "codes": { "type": "array", "items": { "type": "object", "required": [ "code", "description", "valid" ], "properties": { "code": { "type": "string", "description": "The extracted code", "example": "195967001" }, "description": { "type": "string", "description": "Short description of the code", "example": "Asthma" }, "valid": { "type": "boolean", "description": "Whether the code passed validation. Always true unless include_invalid is set to true, in which case invalid codes will have this set to false.", "example": true }, "reason": { "type": "string", "description": "Explanation for why this code was extracted (if include_rationale is true)" }, "is_ancestor": { "type": "boolean", "nullable": true, "description": "Whether this code is an ancestor (parent) of an extracted code rather than directly extracted.\nOnly present when include_ancestors is true.\n" }, "citations": { "type": "array", "nullable": true, "description": "Source text references showing where this code was found in the input.\nOnly present when include_citations is true and chunking method supports it.\nAncestor codes do not receive citations.\n", "items": { "type": "object", "required": [ "text", "begin_offset", "end_offset" ], "description": "A reference to source text that led to a code extraction", "properties": { "text": { "type": "string", "description": "The exact text span containing evidence for the code", "example": "Patient has type 2 diabetes" }, "begin_offset": { "type": "integer", "description": "Starting byte offset in the original input text (0-indexed)", "example": 0 }, "end_offset": { "type": "integer", "description": "Ending byte offset (exclusive), such that input[begin_offset:end_offset] == text", "example": 27 } } } }, "categories": { "type": "array", "nullable": true, "description": "Higher-level groupings the extracted code belongs to (e.g. HPO category terms).\nOnly populated by full-extraction chunking methods such as \"fasthpocr\".\n", "items": { "type": "object", "required": [ "uri", "label" ], "description": "A higher-level grouping (e.g. HPO category) for an extracted code.", "properties": { "uri": { "type": "string", "description": "Identifier for the category term (e.g. an HPO URI).", "example": "HP:0025142" }, "label": { "type": "string", "description": "Human-readable label for the category term.", "example": "Constitutional symptom" } } } } } } } } }, "detail": { "type": "string", "description": "Optional details explaining the feedback", "example": "Expected code X instead because ..." } } } ``` **Example:** ```json { "text": "Patient has type 2 diabetes with hyperglycemia", "received_result": { "system": { "name": "ICD-10-CM", "version": "2025" }, "codes": [ { "code": "E11.9", "description": "Type 2 diabetes mellitus without complications", "valid": true } ] }, "expected_result": { "system": { "name": "ICD-10-CM", "version": "2025" }, "codes": [ { "code": "E11.65", "description": "Type 2 diabetes mellitus with hyperglycemia", "valid": true } ] }, "detail": "Expected code E11.65 because the text mentions hyperglycemia" } ``` #### Responses **201** - Feedback saved successfully Content-Type: `application/json` ```json { "type": "object", "required": [ "id" ], "properties": { "id": { "type": "string", "description": "The ID of the saved feedback", "example": "abc123def456" } } } ``` **Example:** ```json { "id": "abc123def456" } ``` **400** - Invalid request (missing required fields or malformed JSON) **401** - Unauthorized **500** - Server error **503** - Database unavailable --- # Lang2FHIR Convert natural language clinical text into structured FHIR resources including Patient, Condition, MedicationRequest, and more. ## Endpoints ### POST /cohort **Analyze text for patient cohort criteria** Converts natural language text into structured FHIR search queries for patient cohort analysis **Operation ID:** `cohort_analyze` #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "text" ], "properties": { "text": { "type": "string", "description": "Natural language text describing patient cohort criteria", "example": "female patients over 65 with diabetes but not hypertension" } } } ``` **Example:** ```json { "text": "female patients over 65 with diabetes but not hypertension" } ``` #### Responses **200** - Successfully analyzed cohort criteria Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether the cohort analysis was successful", "example": true }, "message": { "type": "string", "description": "Human-readable message about the analysis result", "example": "Cohort analysis completed successfully. Generated 3 search queries from 3 concepts." }, "queries": { "type": "array", "description": "Array of search concepts converted to FHIR search queries", "items": { "type": "object", "properties": { "resource_type": { "type": "string", "description": "The FHIR resource type for this search concept", "example": "Patient" }, "search_params": { "type": "string", "description": "FHIR search parameters in standard format", "example": "gender=female&birthdate=le1959-01-01" }, "concept": { "type": "string", "description": "The original concept description", "example": "female patients over 65" }, "exclude": { "type": "boolean", "description": "Whether this concept should be excluded from the search", "example": false } } } } } } ``` **Example:** ```json { "success": true, "message": "Cohort analysis completed successfully. Generated 3 search queries from 3 concepts.", "queries": [ { "resource_type": "Patient", "search_params": "gender=female&birthdate=le1959-01-01", "concept": "female patients over 65", "exclude": false }, { "resource_type": "Condition", "search_params": "code=44054006", "concept": "diabetes", "exclude": false }, { "resource_type": "Condition", "search_params": "code=38341003", "concept": "hypertension", "exclude": true } ] } ``` **400** - Invalid request **401** - Unauthorized **500** - Server error --- ### POST /lang2fhir/create **Create FHIR resource from text** Converts natural language text into a structured FHIR resource. **Patient identifier handling.** When generating a `patient` (or `patient-canvas`) resource, US Core requires `Patient.identifier` (a business identifier such as an MRN). When the source text contains an identifier, it is extracted with an appropriate URI system. When the source text does not contain a detectable identifier, a synthetic one is generated with `system: "urn:phenoml:lang2fhir-generated-id"` and a UUID `value` so the resource remains FHIR-valid and US Core conformant. Callers who need a tenant-specific namespace should rewrite the synthetic system after extraction. **Operation ID:** `lang2fhir_create` #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "version", "resource", "text" ], "properties": { "version": { "type": "string", "description": "FHIR version to use", "example": "R4", "default": "R4" }, "resource": { "type": "string", "description": "Type of FHIR resource to create. Use 'auto' for automatic resource type detection, or specify a supported US Core profile. Recommended to use the supported US Core Profiles for validated results but you can also use any custom profile you've uploaded (if you're a develop or launch customer) \n", "example": "condition-encounter-diagnosis", "enum": [ "auto", "appointment", "condition-encounter-diagnosis", "medicationrequest", "careplan", "condition-problems-health-concerns", "coverage", "encounter", "observation-clinical-result", "observation-lab", "patient", "procedure", "questionnaire", "questionnaireresponse", "servicerequest", "simple-observation", "vital-signs" ] }, "text": { "type": "string", "description": "Natural language text to convert", "example": "Patient has severe asthma with acute exacerbation" } } } ``` **Example:** ```json { "text": "Patient has severe persistent asthma with acute exacerbation", "version": "R4", "resource": "condition-encounter-diagnosis" } ``` #### Responses **200** - Successfully created FHIR resource Content-Type: `application/json` ```json { "type": "object", "description": "A FHIR resource (schema depends on resource type)" } ``` **Example:** ```json { "resourceType": "Condition", "clinicalStatus": { "coding": [ { "system": "http://terminology.hl7.org/CodeSystem/condition-clinical", "code": "active" } ] }, "code": { "coding": [ { "system": "http://snomed.info/sct", "code": "195967001", "display": "Asthma" } ], "text": "Severe persistent asthma with acute exacerbation" }, "severity": { "coding": [ { "system": "http://snomed.info/sct", "code": "24484000", "display": "Severe" } ] } } ``` **400** - Invalid request **401** - Unauthorized **404** - Profile not found **422** - Generated FHIR resource failed validation **500** - Server error --- ### POST /lang2fhir/create/multi **Extract multiple FHIR resources from text** Analyzes natural language text and extracts multiple FHIR resources, returning them as a transaction Bundle. Automatically detects Patient, Condition, MedicationRequest, Observation, and other resource types from the text. Resources are linked with proper references (e.g., Conditions reference the Patient). **Patient identifier handling.** US Core requires `Patient.identifier` (a business identifier such as an MRN). When the source text contains an identifier, it is extracted with an appropriate URI system. When the source text does not contain a detectable identifier, a synthetic one is generated with `system: "urn:phenoml:lang2fhir-generated-id"` and a UUID `value` so the bundle remains FHIR-valid and US Core conformant. Callers who need a tenant-specific namespace should rewrite the synthetic system after extraction. **Operation ID:** `lang2fhir_createMulti` #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "text" ], "properties": { "text": { "type": "string", "description": "Natural language text containing multiple clinical concepts to extract", "example": "John Smith, male born on 1980-03-12, diagnosed with Type 2 Diabetes. Prescribed Metformin 500mg twice daily." }, "version": { "type": "string", "description": "FHIR version to use", "example": "R4", "default": "R4" }, "provider": { "type": "string", "description": "Optional FHIR provider name for provider-specific profiles", "example": "canvas" }, "implementation_guide": { "type": "string", "description": "Custom Implementation Guide name. When specified, profiles from this IG are included alongside US Core profiles during resource detection. US Core is always the base layer; custom IG profiles are additive.\n", "example": "acme-cardiology" }, "detection_effort": { "type": "string", "description": "Detection effort. 'standard' runs detection once, 'deep' runs detection multiple times for higher recall.", "enum": [ "standard", "deep" ], "default": "standard" }, "validation_method": { "type": "string", "description": "FHIR validation method to apply to the generated bundle. 'none' skips validation (default). 'check' runs the bundle through a FHIR structure validator and includes the results in the response. 'fix' runs validation and attempts to auto-correct errors using an LLM (up to 3 validation passes). The response includes results from each pass. Warning: 'fix' can significantly increase latency due to multiple LLM and validation round-trips.\n", "enum": [ "none", "check", "fix" ], "default": "none" } } } ``` **Example:** ```json { "text": "John Smith, 45-year-old male, diagnosed with Type 2 Diabetes. Prescribed Metformin 500mg twice daily. Blood pressure 140/90.", "version": "R4" } ``` #### Responses **200** - Successfully extracted FHIR resources Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether extraction was successful", "example": true }, "message": { "type": "string", "description": "Status message", "example": "Successfully extracted 3 resources" }, "bundle": { "type": "object", "description": "FHIR transaction Bundle containing all extracted resources", "properties": { "resourceType": { "type": "string", "example": "Bundle" }, "type": { "type": "string", "example": "transaction" }, "entry": { "type": "array", "items": { "type": "object", "properties": { "fullUrl": { "type": "string", "example": "urn:uuid:a842c4bc-f6cb-4555-9741-ac3aec4ef0b8" }, "resource": { "type": "object" }, "request": { "type": "object", "properties": { "method": { "type": "string", "example": "POST" }, "url": { "type": "string", "example": "Patient" } } } } } } } }, "resources": { "type": "array", "description": "Summary of extracted resources", "items": { "type": "object", "properties": { "tempId": { "type": "string", "description": "Temporary UUID for the resource", "example": "urn:uuid:a842c4bc-f6cb-4555-9741-ac3aec4ef0b8" }, "resourceType": { "type": "string", "description": "FHIR resource type", "example": "Patient" }, "description": { "type": "string", "description": "Context-enriched rewritten text excerpt for this resource", "example": "John Smith (DOB 1980-05-12) was diagnosed with Type 2 Diabetes during office visit on 2025-03-01 with Dr. Chen" }, "originalText": { "type": "string", "description": "Verbatim text excerpt from the original clinical document", "example": "diagnosed with Type 2 Diabetes" } } } }, "validation": { "type": "object", "nullable": true, "description": "FHIR validation results. Present when validation_method is 'check' or 'fix'. Contains results from each validation pass. For 'check', there is one pass. For 'fix', there may be up to 3 passes as the system attempts auto-correction.\n", "properties": { "passes": { "type": "array", "description": "Results from each validation pass, in chronological order", "items": { "type": "object", "properties": { "issues": { "type": "array", "description": "Validation issues found in this pass", "items": { "type": "object", "properties": { "severity": { "type": "string", "description": "Issue severity level", "enum": [ "fatal", "error", "warning", "information" ] }, "code": { "type": "string", "description": "Issue type code" }, "diagnostics": { "type": "string", "description": "Human-readable description of the issue" }, "expression": { "type": "array", "items": { "type": "string" }, "description": "FHIRPath expression(s) pointing to the issue location" }, "source": { "type": "string", "description": "Validation phase that generated this issue" } } } }, "stats": { "type": "object", "nullable": true, "description": "Validation statistics for this pass", "properties": { "resource_type": { "type": "string" }, "profile_url": { "type": "string" }, "is_custom_profile": { "type": "boolean" }, "duration_ms": { "type": "number", "description": "Validation duration in milliseconds" } } } } } }, "fixed": { "type": "boolean", "description": "Whether validation errors were successfully fixed by the LLM. Always false for 'check' mode. For 'fix' mode, true if errors were resolved and the returned bundle is the corrected version.\n" }, "attempts": { "type": "integer", "description": "Total number of validation passes run (1 for check, 1-3 for fix)" }, "summary": { "type": "string", "description": "Human-readable summary of the validation outcome" } } } } } ``` **Example:** ```json { "success": true, "message": "Successfully extracted 3 resources", "bundle": { "resourceType": "Bundle", "type": "transaction", "entry": [ { "fullUrl": "urn:uuid:patient-001", "resource": { "resourceType": "Patient", "name": [ { "given": [ "John" ], "family": "Smith" } ], "gender": "male" }, "request": { "method": "POST", "url": "Patient" } }, { "fullUrl": "urn:uuid:condition-001", "resource": { "resourceType": "Condition", "code": { "text": "Type 2 Diabetes" } }, "request": { "method": "POST", "url": "Condition" } }, { "fullUrl": "urn:uuid:medication-001", "resource": { "resourceType": "MedicationRequest", "medicationCodeableConcept": { "text": "Metformin 500mg" } }, "request": { "method": "POST", "url": "MedicationRequest" } } ] } } ``` **400** - Invalid request **401** - Unauthorized **404** - Profile not found **422** - Generated FHIR resource failed validation **500** - Server error --- ### POST /lang2fhir/document **Convert document to FHIR resource** Extracts text from a document (PDF or image) and converts it into a structured FHIR resource. **Patient identifier handling.** When generating a `patient` (or `patient-canvas`) resource, US Core requires `Patient.identifier` (a business identifier such as an MRN). When the source text contains an identifier, it is extracted with an appropriate URI system. When the source text does not contain a detectable identifier, a synthetic one is generated with `system: "urn:phenoml:lang2fhir-generated-id"` and a UUID `value` so the resource remains FHIR-valid and US Core conformant. Callers who need a tenant-specific namespace should rewrite the synthetic system after extraction. **Operation ID:** `lang2fhir_document` #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "version", "resource", "content" ], "properties": { "version": { "type": "string", "description": "FHIR version to use", "example": "R4" }, "resource": { "type": "string", "description": "Type of FHIR resource to create. Accepts any FHIR resource type or US Core profile name.", "example": "questionnaire" }, "content": { "type": "string", "description": "Base64 encoded file content.\nSupported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg).\nFile type is auto-detected from content magic bytes.\n" }, "config": { "type": "object", "description": "Optional processing configuration shared across document endpoints.", "properties": { "page_filter": { "type": "object", "description": "Configures per-page pre-extraction filtering. When set, each page of text extracted from the document is classified by an LLM, and pages classified as irrelevant to the supplied context are dropped before FHIR extraction.\n", "required": [ "context" ], "properties": { "context": { "type": "string", "description": "Natural-language description of what IS relevant to the extraction goal. Pages that do not match are dropped from downstream FHIR extraction.\n", "example": "clinical notes, diagnoses, medications — not sample collection instructions or insurance forms" } } } } } } } ``` **Example:** ```json { "version": "R4", "resource": "questionnaire", "content": "JVBERi0xLjQKJeLjz9MK...(base64-encoded PDF or image bytes)" } ``` #### Responses **200** - Successfully created FHIR resource from document Content-Type: `application/json` ```json { "type": "object", "description": "A FHIR resource (schema depends on resource type)" } ``` **Example:** ```json { "resourceType": "Questionnaire", "status": "active", "title": "Patient Intake Form", "item": [ { "linkId": "1", "text": "What is your name?", "type": "string" }, { "linkId": "2", "text": "What is your date of birth?", "type": "date" } ] } ``` **400** - Invalid request **401** - Unauthorized **404** - Profile not found **422** - Document could not be processed or generated resource failed validation **499** - Client closed request before response was ready **500** - Server error **504** - Request timed out --- ### POST /lang2fhir/document/multi **Extract multiple FHIR resources from a document** Extracts text from a document (PDF or image) and converts it into multiple FHIR resources, returned as a transaction Bundle. Combines document text extraction with multi-resource detection. Automatically detects Patient, Condition, MedicationRequest, Observation, and other resource types. Resources are linked with proper references (e.g., Conditions reference the Patient). **Patient identifier handling.** US Core requires `Patient.identifier` (a business identifier such as an MRN). When the source text contains an identifier, it is extracted with an appropriate URI system. When the source text does not contain a detectable identifier, a synthetic one is generated with `system: "urn:phenoml:lang2fhir-generated-id"` and a UUID `value` so the bundle remains FHIR-valid and US Core conformant. Callers who need a tenant-specific namespace should rewrite the synthetic system after extraction. **Operation ID:** `lang2fhir_documentMulti` #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "version", "content" ], "properties": { "version": { "type": "string", "description": "FHIR version to use", "example": "R4" }, "content": { "type": "string", "description": "Base64 encoded file content.\nSupported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg).\nFile type is auto-detected from content magic bytes.\n" }, "provider": { "type": "string", "description": "Optional FHIR provider name for provider-specific profiles", "example": "canvas" }, "implementation_guide": { "type": "string", "description": "Custom Implementation Guide name. When specified, profiles from this IG are included alongside US Core profiles during resource detection. US Core is always the base layer; custom IG profiles are additive.\n", "example": "acme-cardiology" }, "detection_effort": { "type": "string", "description": "Detection effort. 'standard' runs detection once, 'deep' runs detection multiple times for higher recall.", "enum": [ "standard", "deep" ], "default": "standard" }, "validation_method": { "type": "string", "description": "FHIR validation method to apply to the generated bundle. 'none' skips validation (default). 'check' runs the bundle through a FHIR structure validator and includes the results in the response. 'fix' runs validation and attempts to auto-correct errors using an LLM (up to 3 validation passes). The response includes results from each pass. Warning: 'fix' can significantly increase latency due to multiple LLM and validation round-trips.\n", "enum": [ "none", "check", "fix" ], "default": "none" }, "config": { "type": "object", "description": "Optional processing configuration shared across document endpoints.", "properties": { "page_filter": { "type": "object", "description": "Configures per-page pre-extraction filtering. When set, each page of text extracted from the document is classified by an LLM, and pages classified as irrelevant to the supplied context are dropped before FHIR extraction.\n", "required": [ "context" ], "properties": { "context": { "type": "string", "description": "Natural-language description of what IS relevant to the extraction goal. Pages that do not match are dropped from downstream FHIR extraction.\n", "example": "clinical notes, diagnoses, medications — not sample collection instructions or insurance forms" } } } } } } } ``` **Example:** ```json { "version": "R4", "content": "JVBERi0xLjQKJeLjz9MK...(base64-encoded PDF or image bytes)", "provider": "medplum" } ``` #### Responses **200** - Successfully extracted FHIR resources from document Content-Type: `application/json` ```json { "allOf": [ { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether extraction was successful", "example": true }, "message": { "type": "string", "description": "Status message", "example": "Successfully extracted 3 resources" }, "bundle": { "type": "object", "description": "FHIR transaction Bundle containing all extracted resources", "properties": { "resourceType": { "type": "string", "example": "Bundle" }, "type": { "type": "string", "example": "transaction" }, "entry": { "type": "array", "items": { "type": "object", "properties": { "fullUrl": { "type": "string", "example": "urn:uuid:a842c4bc-f6cb-4555-9741-ac3aec4ef0b8" }, "resource": { "type": "object" }, "request": { "type": "object", "properties": { "method": { "type": "string", "example": "POST" }, "url": { "type": "string", "example": "Patient" } } } } } } } }, "resources": { "type": "array", "description": "Summary of extracted resources", "items": { "type": "object", "properties": { "tempId": { "type": "string", "description": "Temporary UUID for the resource", "example": "urn:uuid:a842c4bc-f6cb-4555-9741-ac3aec4ef0b8" }, "resourceType": { "type": "string", "description": "FHIR resource type", "example": "Patient" }, "description": { "type": "string", "description": "Context-enriched rewritten text excerpt for this resource", "example": "John Smith (DOB 1980-05-12) was diagnosed with Type 2 Diabetes during office visit on 2025-03-01 with Dr. Chen" }, "originalText": { "type": "string", "description": "Verbatim text excerpt from the original clinical document", "example": "diagnosed with Type 2 Diabetes" } } } }, "validation": { "type": "object", "nullable": true, "description": "FHIR validation results. Present when validation_method is 'check' or 'fix'. Contains results from each validation pass. For 'check', there is one pass. For 'fix', there may be up to 3 passes as the system attempts auto-correction.\n", "properties": { "passes": { "type": "array", "description": "Results from each validation pass, in chronological order", "items": { "type": "object", "properties": { "issues": { "type": "array", "description": "Validation issues found in this pass", "items": { "type": "object", "properties": { "severity": { "type": "string", "description": "Issue severity level", "enum": [ "fatal", "error", "warning", "information" ] }, "code": { "type": "string", "description": "Issue type code" }, "diagnostics": { "type": "string", "description": "Human-readable description of the issue" }, "expression": { "type": "array", "items": { "type": "string" }, "description": "FHIRPath expression(s) pointing to the issue location" }, "source": { "type": "string", "description": "Validation phase that generated this issue" } } } }, "stats": { "type": "object", "nullable": true, "description": "Validation statistics for this pass", "properties": { "resource_type": { "type": "string" }, "profile_url": { "type": "string" }, "is_custom_profile": { "type": "boolean" }, "duration_ms": { "type": "number", "description": "Validation duration in milliseconds" } } } } } }, "fixed": { "type": "boolean", "description": "Whether validation errors were successfully fixed by the LLM. Always false for 'check' mode. For 'fix' mode, true if errors were resolved and the returned bundle is the corrected version.\n" }, "attempts": { "type": "integer", "description": "Total number of validation passes run (1 for check, 1-3 for fix)" }, "summary": { "type": "string", "description": "Human-readable summary of the validation outcome" } } } } }, { "type": "object", "properties": { "page_classifications": { "type": "array", "description": "Per-page classifier decisions. Populated only when a page_filter was supplied in the request. Contains one entry per input page, including both kept and dropped pages.\n", "items": { "type": "object", "description": "The classifier's decision for a single page of the input document.", "properties": { "page_number": { "type": "integer", "description": "1-indexed page number.", "example": 1 }, "include": { "type": "boolean", "description": "Whether the page was kept (true) or dropped (false) from FHIR extraction.", "example": true }, "reason": { "type": "string", "description": "Short LLM-generated explanation of the decision.", "example": "clinical notes with diagnoses" } } } } } } ] } ``` **Example:** ```json { "success": true, "message": "Successfully extracted 3 resources", "bundle": { "resourceType": "Bundle", "type": "transaction", "entry": [ { "fullUrl": "urn:uuid:patient-001", "resource": { "resourceType": "Patient", "name": [ { "given": [ "John" ], "family": "Doe" } ], "gender": "male", "birthDate": "1979-03-15" }, "request": { "method": "POST", "url": "Patient" } }, { "fullUrl": "urn:uuid:condition-001", "resource": { "resourceType": "Condition", "code": { "text": "Type 2 Diabetes Mellitus" }, "subject": { "reference": "urn:uuid:patient-001" } }, "request": { "method": "POST", "url": "Condition" } }, { "fullUrl": "urn:uuid:medication-001", "resource": { "resourceType": "MedicationRequest", "medicationCodeableConcept": { "text": "Metformin 500mg" }, "subject": { "reference": "urn:uuid:patient-001" } }, "request": { "method": "POST", "url": "MedicationRequest" } } ] }, "resources": [ { "tempId": "urn:uuid:patient-001", "resourceType": "Patient", "description": "John Doe, born 1979-03-15", "originalText": "John Doe, DOB 1979-03-15" }, { "tempId": "urn:uuid:condition-001", "resourceType": "Condition", "description": "Type 2 Diabetes Mellitus diagnosis", "originalText": "diagnosed with Type 2 Diabetes" }, { "tempId": "urn:uuid:medication-001", "resourceType": "MedicationRequest", "description": "Metformin 500mg prescription", "originalText": "Prescribed Metformin 500mg" } ] } ``` **400** - Invalid request **401** - Unauthorized **404** - Profile not found **422** - Document could not be processed or generated resource failed validation **499** - Client closed request before response was ready **500** - Server error **504** - Request timed out --- ### POST /lang2fhir/profile/upload **Upload custom FHIR profile** Upload a custom FHIR StructureDefinition profile for use with the lang2fhir service. All metadata is derived from the StructureDefinition JSON itself. The lowercase `id` field from the StructureDefinition is used as the profile's unique identifier and lookup key. To use the uploaded profile with `/lang2fhir/create`, pass this id as the `resource` parameter. Uploads will be rejected if: - A built-in US Core or R4 base profile already exists with the same id - A custom profile with the same id has already been uploaded - A custom profile with the same url has already been uploaded **Operation ID:** `lang2fhir_uploadProfile` #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "profile" ], "properties": { "profile": { "type": "string", "description": "Base64 encoded JSON string of a FHIR StructureDefinition. The profile must include id, url, type, and a snapshot with elements. All metadata (version, resource type, identifier) is derived from the StructureDefinition itself. The lowercase id from the StructureDefinition becomes the profile's lookup key.\n", "example": "(base64 encoded FHIR StructureDefinition JSON)" }, "implementation_guide": { "type": "string", "description": "Implementation Guide name to group this profile under. Defaults to \"custom\" if omitted. Cannot be \"us_core\" (reserved). Use this to organize custom profiles into named IGs that can be referenced when calling create/multi or document/multi endpoints.\n", "example": "acme-cardiology" }, "profile_context": { "type": "string", "maxLength": 2000, "description": "Natural language context that helps the LLM select the right profiles from this implementation guide during resource detection. For example, \"When the text mentions phenotypic features or abnormalities, prefer the hpo-observation profile over Condition.\" This is stored as IG-level metadata and injected into the LLM prompt. Max 2000 characters. Providing this field on any upload will update the context for the entire IG (last write wins).\n", "example": "When clinical text describes phenotypic features, abnormalities, or findings that map to HPO terms, use the hpo-phenotype-observation profile instead of Condition." } } } ``` **Example:** ```json { "profile": "eyJyZXNvdXJjZVR5cGUiOiJTdHJ1Y3R1cmVEZWZpbml0aW9uIiwiaWQiOiJjdXN0b20tcGF0aWVudCIsInVybCI6Imh0dHA6Ly9waGVub21sLmNvbS9maGlyL1N0cnVjdHVyZURlZmluaXRpb24vY3VzdG9tLXBhdGllbnQiLCJuYW1lIjoiQ3VzdG9tUGF0aWVudCIsInN0YXR1cyI6ImFjdGl2ZSIsImZoaXJWZXJzaW9uIjoiNC4wLjEiLCJraW5kIjoicmVzb3VyY2UiLCJhYnN0cmFjdCI6ZmFsc2UsInR5cGUiOiJQYXRpZW50IiwiYmFzZURlZmluaXRpb24iOiJodHRwOi8vaGw3Lm9yZy9maGlyL1N0cnVjdHVyZURlZmluaXRpb24vUGF0aWVudCIsImRlcml2YXRpb24iOiJjb25zdHJhaW50Iiwic25hcHNob3QiOnsiZWxlbWVudCI6W3siaWQiOiJQYXRpZW50IiwicGF0aCI6IlBhdGllbnQiLCJtaW4iOjAsIm1heCI6IioifSx7ImlkIjoiUGF0aWVudC5uYW1lIiwicGF0aCI6IlBhdGllbnQubmFtZSIsIm1pbiI6MSwibWF4IjoiKiJ9XX19Cg==", "implementation_guide": "acme-cardiology", "profile_context": "When clinical text describes cardiology-specific findings, prefer this profile over the generic US Core Condition." } ``` #### Responses **201** - Profile successfully uploaded Content-Type: `application/json` ```json { "type": "object", "properties": { "message": { "type": "string", "example": "Profile uploaded successfully" }, "id": { "type": "string", "description": "The lowercase StructureDefinition id, used as the profile's unique identifier and lookup key. Pass this value as the `resource` parameter to `/lang2fhir/create` or `/lang2fhir/profile/json/:version/:resource` to use this profile.\n", "example": "custom-patient" }, "type": { "type": "string", "description": "The FHIR resource type from the StructureDefinition", "example": "Patient" }, "url": { "type": "string", "description": "The canonical URL from the StructureDefinition", "example": "http://phenoml.com/fhir/StructureDefinition/custom-patient" } } } ``` **Example:** ```json { "message": "Profile uploaded successfully", "id": "custom-patient", "type": "Patient", "url": "http://phenoml.com/fhir/StructureDefinition/custom-patient" } ``` **400** - Invalid request or profile validation failed. Possible reasons: - Missing or invalid StructureDefinition JSON - Missing required fields (id, url, type, snapshot with elements) - A built-in US Core or R4 base profile exists with the same id - A custom profile with the same id or url already exists **401** - Unauthorized **403** - Forbidden - profile upload is only available on dedicated instances **500** - Server error --- ### POST /lang2fhir/search **Generate FHIR search parameters from text** Converts natural language text into FHIR search parameters. Automatically identifies the appropriate FHIR resource type and generates valid search query parameters. Supported resource types include: AllergyIntolerance, Appointment, CarePlan, CareTeam, Condition, Coverage, Device, DiagnosticReport, DocumentReference, Encounter, Goal, Immunization, Location, Medication, MedicationRequest, Observation, Organization, Patient, PlanDefinition, Practitioner, PractitionerRole, Procedure, Provenance, Questionnaire, QuestionnaireResponse, RelatedPerson, Schedule, ServiceRequest, Slot, and Specimen. **Operation ID:** `lang2fhir_search` #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "text" ], "properties": { "text": { "type": "string", "description": "Natural language text to convert into FHIR search parameters.\nThe system will automatically identify the appropriate resource type and generate valid search parameters.\n\nExamples:\n- \"Appointments between March 2-9, 2025\" → Appointment search with date range\n- \"Patients with diabetes\" → Condition search with code parameter\n- \"Active medication requests for metformin\" → MedicationRequest search\n- \"Lab results for creatinine\" → DiagnosticReport search\n- \"Dr. Smith's schedule\" → Practitioner or Schedule search\n", "example": "Appointments between March 2-9, 2025" } } } ``` **Example:** ```json { "text": "Appointments between March 2-9, 2025" } ``` #### Responses **200** - Successfully generated FHIR search parameters Content-Type: `application/json` ```json { "type": "object", "properties": { "resource_type": { "type": "string", "description": "The FHIR resource type identified for the search", "enum": [ "AllergyIntolerance", "Appointment", "CarePlan", "CareTeam", "Condition", "Coverage", "Device", "DiagnosticReport", "DocumentReference", "Encounter", "Goal", "Immunization", "Location", "Medication", "MedicationRequest", "Observation", "Organization", "Patient", "PlanDefinition", "Practitioner", "PractitionerRole", "Procedure", "Provenance", "Questionnaire", "QuestionnaireResponse", "RelatedPerson", "Schedule", "ServiceRequest", "Slot", "Specimen" ], "example": "Appointment" }, "search_params": { "type": "string", "description": "FHIR search parameters in standard query string format.\nParameters are formatted according to the FHIR specification with appropriate operators.\nCode parameters are resolved to standard terminology codes (SNOMED CT, LOINC, RxNorm, ICD-10-CM).\n", "example": "date=ge2025-03-02&date=le2025-03-09" } } } ``` **Example:** ```json { "resource_type": "Appointment", "search_params": "date=ge2025-03-02&date=le2025-03-09" } ``` **400** - Invalid request **401** - Unauthorized **500** - Server error --- # Summary Generate clinical summaries from FHIR resources. Supports narrative templates, flattening for RAG, and IPS generation. ## Summary / Templates Reusable summary templates that drive FHIR-to-text generation. ### POST /fhir2summary/template **Create a new summary template** Creates a summary template from an example using LLM function calling **Operation ID:** `summary_createTemplate` #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "name", "example_summary", "target_resources", "mode" ], "properties": { "name": { "type": "string", "description": "Name of the template" }, "description": { "type": "string", "description": "Description of the template" }, "example_summary": { "type": "string", "description": "Example summary note to generate template from", "example": "Patient John Doe, age 45, presents with hypertension diagnosed on 2024-01-15." }, "target_resources": { "type": "array", "items": { "type": "string" }, "description": "List of target FHIR resources", "example": [ "Patient", "Condition", "Observation" ] }, "example_fhir_data": { "type": "object", "description": "Optional example FHIR data that corresponds to the example summary", "additionalProperties": true }, "mode": { "type": "string", "description": "Template mode (stored with the template)" } } } ``` **Example:** ```json { "name": "Discharge Summary", "example_summary": "Patient John Doe, age 45, was admitted on 2024-01-10 with Type 2 Diabetes. Discharged on 2024-01-15 with Metformin 500mg BID.", "target_resources": [ "Patient", "Condition", "MedicationRequest" ], "mode": "narrative" } ``` #### Responses **200** - Template created successfully Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean" }, "message": { "type": "string" }, "template_id": { "type": "string", "format": "uuid" }, "template": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "description": { "type": "string" }, "template": { "type": "string", "description": "Template with {{resource.field}} placeholders" }, "target_resources": { "type": "array", "items": { "type": "string" }, "description": "List of FHIR resource types/profiles" }, "mode": { "type": "string", "description": "Template mode (stored value)" }, "metadata": { "type": "object", "additionalProperties": true }, "created_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" } } } } } ``` **Example:** ```json { "success": true, "message": "Template created successfully", "template_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "template": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "name": "Discharge Summary", "template": "Patient <>, age <>, was admitted on <> with <>. Discharged on <> with <> <>.", "target_resources": [ "Patient", "Condition", "MedicationRequest" ], "mode": "narrative", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" } } ``` **400** - Bad request - invalid input **401** - Unauthorized **500** - Internal server error --- ### GET /fhir2summary/template/{id} **Get a summary template by ID** Retrieves a specific summary template **Operation ID:** `summary_get` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `id` | path | string | Yes | Template ID | #### Responses **200** - Template retrieved successfully Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean" }, "template": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "description": { "type": "string" }, "template": { "type": "string", "description": "Template with {{resource.field}} placeholders" }, "target_resources": { "type": "array", "items": { "type": "string" }, "description": "List of FHIR resource types/profiles" }, "mode": { "type": "string", "description": "Template mode (stored value)" }, "metadata": { "type": "object", "additionalProperties": true }, "created_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" } } } } } ``` **Example:** ```json { "success": true, "template": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "name": "Discharge Summary", "template": "Patient <>, age <>, was admitted on <> with <>.", "target_resources": [ "Patient", "Condition", "MedicationRequest" ], "mode": "narrative", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" } } ``` **401** - Unauthorized **403** - Access denied **404** - Template not found **500** - Internal server error --- ### PUT /fhir2summary/template/{id} **Update a summary template** Updates an existing summary template **Operation ID:** `summary_update` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `id` | path | string | Yes | Template ID | #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "name", "template", "target_resources", "mode" ], "properties": { "name": { "type": "string" }, "description": { "type": "string" }, "template": { "type": "string", "description": "Updated template with placeholders" }, "target_resources": { "type": "array", "items": { "type": "string" } }, "mode": { "type": "string", "description": "Template mode" } } } ``` **Example:** ```json { "name": "Discharge Summary", "template": "Patient {{Patient.name[0].text}} was discharged on {{Encounter[0].period.end}} with {{MedicationRequest[0].medicationCodeableConcept.coding[0].display}} {{MedicationRequest[0].dosageInstruction[0].text}}.", "target_resources": [ "Patient", "Encounter", "MedicationRequest" ], "mode": "narrative" } ``` #### Responses **200** - Template updated successfully Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean" }, "message": { "type": "string" }, "template": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "description": { "type": "string" }, "template": { "type": "string", "description": "Template with {{resource.field}} placeholders" }, "target_resources": { "type": "array", "items": { "type": "string" }, "description": "List of FHIR resource types/profiles" }, "mode": { "type": "string", "description": "Template mode (stored value)" }, "metadata": { "type": "object", "additionalProperties": true }, "created_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" } } } } } ``` **Example:** ```json { "success": true, "message": "Template updated successfully", "template": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "name": "Discharge Summary", "template": "Patient <> was discharged on <> with <> <>.", "target_resources": [ "Patient", "Encounter", "MedicationRequest" ], "mode": "narrative", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-02-20T11:00:00Z" } } ``` **400** - Bad request - invalid input **401** - Unauthorized **403** - Access denied **404** - Template not found **500** - Internal server error --- ### DELETE /fhir2summary/template/{id} **Delete a summary template** Deletes a summary template **Operation ID:** `summary_delete` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `id` | path | string | Yes | Template ID | #### Responses **200** - Template deleted successfully Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean" }, "message": { "type": "string" } } } ``` **Example:** ```json { "success": true, "message": "Template deleted successfully" } ``` **401** - Unauthorized **403** - Access denied **404** - Template not found **500** - Internal server error --- ### GET /fhir2summary/templates **List all summary templates** Retrieves all summary templates for the authenticated user **Operation ID:** `summary_list` #### Responses **200** - Templates retrieved successfully Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean" }, "templates": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "description": { "type": "string" }, "template": { "type": "string", "description": "Template with {{resource.field}} placeholders" }, "target_resources": { "type": "array", "items": { "type": "string" }, "description": "List of FHIR resource types/profiles" }, "mode": { "type": "string", "description": "Template mode (stored value)" }, "metadata": { "type": "object", "additionalProperties": true }, "created_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" } } } } } } ``` **Example:** ```json { "success": true, "templates": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "name": "Discharge Summary", "template": "Patient <>, age <>, was admitted on <> with <>.", "target_resources": [ "Patient", "Condition", "MedicationRequest" ], "mode": "narrative", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" } ] } ``` **401** - Unauthorized **500** - Internal server error --- ## Untagged ### POST /fhir2summary/create **Generate a summary from FHIR resources** Creates a summary from FHIR resources using one of three modes: - **narrative**: Uses a template to substitute FHIR data into placeholders (requires template_id) - **flatten**: Flattens FHIR resources into a searchable format for RAG/search (no template needed) - **ips**: Generates an International Patient Summary (IPS) narrative per ISO 27269/HL7 FHIR IPS IG. Requires a Bundle with exactly one Patient resource (returns 400 error if no Patient or multiple Patients are present). Automatically filters resources to those referencing the patient and generates sections for allergies, medications, problems, immunizations, procedures, and vital signs. **Operation ID:** `summary_create` #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "fhir_resources" ], "properties": { "mode": { "type": "string", "enum": [ "narrative", "flatten", "ips" ], "default": "narrative", "description": "Summary generation mode:\n- narrative: Substitute FHIR data into a template (requires template_id)\n- flatten: Flatten FHIR resources for RAG/search (no template needed)\n- ips: Generate International Patient Summary (IPS) narrative per ISO 27269/HL7 FHIR IPS IG\n" }, "template_id": { "type": "string", "format": "uuid", "description": "ID of the template to use (required for narrative mode)" }, "fhir_resources": { "type": "object", "additionalProperties": true, "description": "FHIR resources (single resource or Bundle).\nFor IPS mode, must be a Bundle containing exactly one Patient resource with at least one\nidentifier (id, fullUrl, or identifier field). Returns an error if no Patient is found,\nif multiple Patients are present, or if the Patient has no identifiers. Resources are\nautomatically filtered to only include those referencing the patient.\n" } } } ``` **Example:** ```json { "mode": "narrative", "template_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "fhir_resources": { "resourceType": "Bundle", "type": "collection", "entry": [ { "resource": { "resourceType": "Patient", "name": [ { "given": [ "John" ], "family": "Doe" } ], "gender": "male", "birthDate": "1979-03-15" } }, { "resource": { "resourceType": "Condition", "code": { "text": "Type 2 Diabetes Mellitus" }, "onsetDateTime": "2024-01-15" } } ] } } ``` #### Responses **200** - Summary generated successfully Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean" }, "message": { "type": "string" }, "summary": { "type": "string", "description": "Generated summary text" }, "warnings": { "type": "array", "items": { "type": "string" }, "description": "Unresolved placeholders or issues (narrative mode only)" } } } ``` **Example:** ```json { "success": true, "summary": "Patient John Doe is a 45-year-old male diagnosed with Type 2 Diabetes Mellitus on January 15, 2024. Current treatment plan includes lifestyle modifications and medication management.", "warnings": [] } ``` **400** - Bad request - invalid input. Possible reasons: - Invalid or unsupported mode value - Missing template_id (required for narrative mode) - No Patient resource found in bundle (IPS mode) - Multiple Patient resources found in bundle - IPS requires exactly one (IPS mode) - Patient resource has no identifiers for reference matching (IPS mode) Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean" }, "message": { "type": "string" }, "summary": { "type": "string", "description": "Generated summary text" }, "warnings": { "type": "array", "items": { "type": "string" }, "description": "Unresolved placeholders or issues (narrative mode only)" } } } ``` **401** - Unauthorized **403** - Access denied - template belongs to another user **404** - Template not found (narrative mode with invalid template_id) **500** - Internal server error --- # FHIR2OMOP Map FHIR R4 resources and bundles into OMOP Common Data Model (CDM v5.4) tables. ### POST /fhir2omop/create **Map FHIR resources to OMOP CDM v5.4** Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows (person, visit_occurrence, condition_occurrence, drug_exposure, procedure_occurrence, measurement, observation). Resource support is intentionally limited to the OMOP tables returned by this endpoint: - `Patient` -> `person` - `Encounter` -> `visit_occurrence` - `Condition` -> `condition_occurrence` - `Procedure` -> `procedure_occurrence` - `MedicationRequest`, `MedicationStatement`, and `MedicationAdministration` -> `drug_exposure` - `Immunization` -> `drug_exposure` - `Observation` with a numeric `valueQuantity`, `valueInteger`, or numeric-looking `valueString` (for example `"<2"`) -> `measurement` - non-numeric `Observation` -> `observation` - `AllergyIntolerance` -> `observation` `Medication` is supported only as reference data for medication resources; it is not emitted as its own row because OMOP CDM has no Medication table. Other reference/admin resources such as `Practitioner`, `Organization`, `Location`, `Coverage`, and `Claim`, and clinical workflow/document resources such as `DiagnosticReport`, `ServiceRequest`, `CarePlan`, `DocumentReference`, `Composition`, `Specimen`, and `DeviceUseStatement`, are currently accepted in a Bundle but are not shaped into OMOP rows. Unsupported resource types are ignored rather than listed under `dropped`; `dropped` is reserved for supported resource types that were missing the subject/patient, code, or medication reference data needed to produce a valid row. Each resource's primary clinical coding is resolved to a standard OMOP `concept_id`. Alongside the OMOP rows grouped by table (`tables`), the response carries `mappings` (how each source coding resolved, linked back to the row it produced), `dropped` (resources that could not be shaped into a row), `vocab_version` (the OMOP vocabulary release codes were resolved against), and a small `summary` of the resolution outcomes. A `concept_id` of `0` is reported, not omitted (OMOP "no matching concept" semantics): it covers both a coding with no standard match (`UNMAPPED`) and an unverified suggestion for a text-only resource (`UNCHECKED`). Only the primary clinical coding is resolved, so `gender`/`race`/`ethnicity`/`visit`/`value`/`unit` `concept_id`s are always `0`; the one populated non-resolved concept is measurement `operator_concept_id`, set from a value comparator (`<`, `<=`, `>`, `>=`) rather than the resolver. Each `*_source_value` carries the verbatim FHIR coding (`system#code`), and `*_type_concept_id` is set to `32817` (EHR). Medication codes are resolved whether they appear inline (`medicationCodeableConcept`) or via a `medicationReference` to a contained, relative (`Type/id`), or bundle-entry (`urn:uuid`) `Medication` resource. Resources that cannot be shaped into a row — a medication with no usable code, resolvable reference, or display, or any clinical resource whose subject/patient reference cannot be tied to a person — are reported under `dropped` rather than emitted as blank rows. The bundle must contain at least one Patient resource. **Operation ID:** `fhir2omop_create` #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "fhir_resources" ], "properties": { "fhir_resources": { "type": "object", "additionalProperties": true, "description": "FHIR resources (single resource or Bundle). Must contain at least one\nPatient resource. Supported row-producing resources are Patient,\nEncounter, Condition, Procedure, MedicationRequest,\nMedicationStatement, MedicationAdministration, Immunization,\nObservation, and AllergyIntolerance. Standalone Medication resources\nare consumed by medication references rather than mapped to their own\ntable. Other resource types are accepted but ignored.\n" } } } ``` **Example:** ```json { "fhir_resources": { "resourceType": "Bundle", "type": "collection", "entry": [ { "resource": { "resourceType": "Patient", "id": "patient-1", "gender": "female", "birthDate": "1985-07-22" } }, { "resource": { "resourceType": "Condition", "id": "condition-1", "subject": { "reference": "Patient/patient-1" }, "code": { "coding": [ { "system": "http://snomed.info/sct", "code": "44054006", "display": "Type 2 diabetes mellitus" } ] }, "onsetDateTime": "2024-01-15" } }, { "resource": { "resourceType": "MedicationRequest", "id": "medreq-1", "status": "active", "subject": { "reference": "Patient/patient-1" }, "medicationReference": { "reference": "#med0" }, "authoredOn": "2024-01-16", "contained": [ { "resourceType": "Medication", "id": "med0", "code": { "coding": [ { "system": "http://www.nlm.nih.gov/research/umls/rxnorm", "code": "860975", "display": "metformin hydrochloride 500 MG" } ] } } ] } } ] } } ``` #### Responses **200** - FHIR resources mapped to OMOP CDM v5.4 Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean" }, "message": { "type": "string" }, "tables": { "type": "object", "description": "OMOP CDM v5.4 rows grouped by destination table.", "properties": { "location": { "type": "array", "items": { "type": "object", "properties": { "location_id": { "type": "integer", "format": "int64" }, "address_1": { "type": "string" }, "address_2": { "type": "string" }, "city": { "type": "string" }, "state": { "type": "string" }, "zip": { "type": "string" }, "county": { "type": "string" }, "location_source_value": { "type": "string" }, "country_concept_id": { "type": "integer", "format": "int64" }, "country_source_value": { "type": "string" }, "latitude": { "type": "number", "format": "double" }, "longitude": { "type": "number", "format": "double" } } } }, "care_site": { "type": "array", "items": { "type": "object", "properties": { "care_site_id": { "type": "integer", "format": "int64" }, "care_site_name": { "type": "string" }, "place_of_service_concept_id": { "type": "integer", "format": "int64" }, "location_id": { "type": "integer", "format": "int64" }, "care_site_source_value": { "type": "string" }, "place_of_service_source_value": { "type": "string" } } } }, "provider": { "type": "array", "items": { "type": "object", "properties": { "provider_id": { "type": "integer", "format": "int64" }, "provider_name": { "type": "string" }, "npi": { "type": "string" }, "dea": { "type": "string" }, "specialty_concept_id": { "type": "integer", "format": "int64" }, "care_site_id": { "type": "integer", "format": "int64" }, "year_of_birth": { "type": "integer" }, "gender_concept_id": { "type": "integer", "format": "int64" }, "provider_source_value": { "type": "string" }, "specialty_source_value": { "type": "string" }, "specialty_source_concept_id": { "type": "integer", "format": "int64" }, "gender_source_value": { "type": "string" }, "gender_source_concept_id": { "type": "integer", "format": "int64" } } } }, "person": { "type": "array", "items": { "type": "object", "properties": { "person_id": { "type": "integer", "format": "int64" }, "gender_concept_id": { "type": "integer", "format": "int64" }, "year_of_birth": { "type": "integer" }, "month_of_birth": { "type": "integer" }, "day_of_birth": { "type": "integer" }, "birth_datetime": { "type": "string" }, "race_concept_id": { "type": "integer", "format": "int64" }, "ethnicity_concept_id": { "type": "integer", "format": "int64" }, "location_id": { "type": "integer", "format": "int64" }, "person_source_value": { "type": "string" }, "gender_source_value": { "type": "string" }, "race_source_value": { "type": "string" }, "ethnicity_source_value": { "type": "string" } } } }, "death": { "type": "array", "items": { "type": "object", "properties": { "person_id": { "type": "integer", "format": "int64" }, "death_date": { "type": "string" }, "death_datetime": { "type": "string" }, "death_type_concept_id": { "type": "integer", "format": "int64" }, "cause_concept_id": { "type": "integer", "format": "int64" }, "cause_source_value": { "type": "string" }, "cause_source_concept_id": { "type": "integer", "format": "int64" } } } }, "observation_period": { "type": "array", "items": { "type": "object", "properties": { "observation_period_id": { "type": "integer", "format": "int64" }, "person_id": { "type": "integer", "format": "int64" }, "observation_period_start_date": { "type": "string" }, "observation_period_end_date": { "type": "string" }, "period_type_concept_id": { "type": "integer", "format": "int64" } } } }, "visit_occurrence": { "type": "array", "items": { "type": "object", "properties": { "visit_occurrence_id": { "type": "integer", "format": "int64" }, "person_id": { "type": "integer", "format": "int64" }, "visit_concept_id": { "type": "integer", "format": "int64" }, "visit_start_date": { "type": "string" }, "visit_start_datetime": { "type": "string" }, "visit_end_date": { "type": "string" }, "visit_end_datetime": { "type": "string" }, "visit_type_concept_id": { "type": "integer", "format": "int64" }, "provider_id": { "type": "integer", "format": "int64" }, "care_site_id": { "type": "integer", "format": "int64" }, "visit_source_value": { "type": "string" } } } }, "condition_occurrence": { "type": "array", "items": { "type": "object", "properties": { "condition_occurrence_id": { "type": "integer", "format": "int64" }, "person_id": { "type": "integer", "format": "int64" }, "condition_concept_id": { "type": "integer", "format": "int64" }, "condition_start_date": { "type": "string" }, "condition_start_datetime": { "type": "string" }, "condition_end_date": { "type": "string" }, "condition_type_concept_id": { "type": "integer", "format": "int64" }, "visit_occurrence_id": { "type": "integer", "format": "int64" }, "provider_id": { "type": "integer", "format": "int64" }, "condition_source_value": { "type": "string" }, "condition_source_concept_id": { "type": "integer", "format": "int64" }, "condition_status_source_value": { "type": "string" } } } }, "drug_exposure": { "type": "array", "items": { "type": "object", "properties": { "drug_exposure_id": { "type": "integer", "format": "int64" }, "person_id": { "type": "integer", "format": "int64" }, "drug_concept_id": { "type": "integer", "format": "int64" }, "drug_exposure_start_date": { "type": "string" }, "drug_exposure_start_datetime": { "type": "string" }, "drug_exposure_end_date": { "type": "string" }, "drug_type_concept_id": { "type": "integer", "format": "int64" }, "stop_reason": { "type": "string" }, "sig": { "type": "string" }, "visit_occurrence_id": { "type": "integer", "format": "int64" }, "provider_id": { "type": "integer", "format": "int64" }, "drug_source_value": { "type": "string" }, "drug_source_concept_id": { "type": "integer", "format": "int64" } } } }, "procedure_occurrence": { "type": "array", "items": { "type": "object", "properties": { "procedure_occurrence_id": { "type": "integer", "format": "int64" }, "person_id": { "type": "integer", "format": "int64" }, "procedure_concept_id": { "type": "integer", "format": "int64" }, "procedure_date": { "type": "string" }, "procedure_datetime": { "type": "string" }, "procedure_type_concept_id": { "type": "integer", "format": "int64" }, "visit_occurrence_id": { "type": "integer", "format": "int64" }, "provider_id": { "type": "integer", "format": "int64" }, "procedure_source_value": { "type": "string" }, "procedure_source_concept_id": { "type": "integer", "format": "int64" } } } }, "measurement": { "type": "array", "items": { "type": "object", "properties": { "measurement_id": { "type": "integer", "format": "int64" }, "person_id": { "type": "integer", "format": "int64" }, "measurement_concept_id": { "type": "integer", "format": "int64" }, "measurement_date": { "type": "string" }, "measurement_datetime": { "type": "string" }, "measurement_type_concept_id": { "type": "integer", "format": "int64" }, "value_as_number": { "type": "number", "format": "double" }, "operator_concept_id": { "type": "integer", "format": "int64", "description": "OMOP \"Meas Value Operator\" standard concept qualifying value_as_number (<, <=, >, >=), parsed from a numeric-string value or a FHIR valueQuantity.comparator. 0 when no operator (a bare number)." }, "value_as_concept_id": { "type": "integer", "format": "int64" }, "unit_concept_id": { "type": "integer", "format": "int64" }, "range_low": { "type": "number", "format": "double" }, "range_high": { "type": "number", "format": "double" }, "visit_occurrence_id": { "type": "integer", "format": "int64" }, "provider_id": { "type": "integer", "format": "int64" }, "measurement_source_value": { "type": "string" }, "measurement_source_concept_id": { "type": "integer", "format": "int64" }, "unit_source_value": { "type": "string" }, "value_source_value": { "type": "string" } } } }, "observation": { "type": "array", "items": { "type": "object", "properties": { "observation_id": { "type": "integer", "format": "int64" }, "person_id": { "type": "integer", "format": "int64" }, "observation_concept_id": { "type": "integer", "format": "int64" }, "observation_date": { "type": "string" }, "observation_datetime": { "type": "string" }, "observation_type_concept_id": { "type": "integer", "format": "int64" }, "value_as_number": { "type": "number", "format": "double" }, "value_as_string": { "type": "string" }, "value_as_concept_id": { "type": "integer", "format": "int64" }, "unit_concept_id": { "type": "integer", "format": "int64" }, "visit_occurrence_id": { "type": "integer", "format": "int64" }, "provider_id": { "type": "integer", "format": "int64" }, "observation_source_value": { "type": "string" }, "observation_source_concept_id": { "type": "integer", "format": "int64" }, "unit_source_value": { "type": "string" }, "value_source_value": { "type": "string" } } } } } }, "mappings": { "type": "array", "description": "One entry per source coding (or one entry for a text-only resource with no coding), describing how it resolved and linking back to the row it produced.", "items": { "type": "object", "description": "How one source coding (or a text-only resource's free text) resolved to an OMOP standard concept.", "properties": { "resource_type": { "type": "string" }, "resource_id": { "type": "string" }, "omop_table": { "type": "string" }, "omop_id": { "type": "integer", "format": "int64", "description": "The id of the OMOP row this coding produced (e.g. `condition_occurrence_id`),\nwithin `omop_table`. A resource with multiple codings yields one entry\nper coding, all sharing this id.\n" }, "source_system": { "type": "string" }, "source_code": { "type": "string" }, "source_name": { "type": "string" }, "target_vocabulary": { "type": "string" }, "target_code": { "type": "string", "description": "The standard concept's own code: the source code itself for an\nALREADY_STANDARD row, the standard concept's code for a MAPPED row,\nor the suggested code for an UNCHECKED row. Omitted for UNMAPPED\nrows.\n" }, "target_name": { "type": "string" }, "mapping_status": { "type": "string", "description": "ALREADY_STANDARD (source coding is already a standard OMOP concept),\nMAPPED (source coding was mapped to a standard concept), UNCHECKED (a\nstandard code was suggested — e.g. for a text-only resource — but not\nverified against the OMOP vocabulary, so `concept_id` stays `0`), or\nUNMAPPED (no standard concept found).\n" }, "note": { "type": "string" } } } }, "dropped": { "type": "array", "description": "Supported resource instances that could not be shaped into an OMOP\nrow because required subject/patient, code, or medication reference\ndata was missing. Unsupported resource types are ignored and do not\nappear here.\n", "items": { "type": "object", "properties": { "resource_type": { "type": "string" }, "resource_id": { "type": "string" }, "reason": { "type": "string" } } } }, "vocab_version": { "type": "string", "description": "The OMOP vocabulary release the clinical codes were resolved against\n(e.g. \"v20240229\"), for reproducibility. Present when at least one\ncoded concept was resolved.\n" }, "summary": { "type": "object", "description": "The request's data-quality headline: how the coded concepts split across\nresolution outcomes, and the share that was not already in a target\nstandard vocabulary. Each coded resource is counted once (per resolved\nconcept), even when it carried several codings — unlike `mappings`, which\nhas one entry per coding.\n", "properties": { "codes_already_standard": { "type": "integer", "description": "Coded concepts already a standard OMOP concept (ALREADY_STANDARD)." }, "codes_normalized": { "type": "integer", "description": "Coded concepts mapped or suggested to a standard concept (MAPPED or UNCHECKED)." }, "codes_unmapped": { "type": "integer", "description": "Coded concepts with no standard concept found (UNMAPPED)." }, "off_vocab_rate": { "type": "number", "format": "double", "description": "Share of coded concepts not already standard ((normalized + unmapped) / total)." } } } } } ``` **Example:** ```json { "success": true, "message": "FHIR resources mapped to OMOP CDM v5.4", "tables": { "person": [ { "person_id": 1, "gender_concept_id": 0, "year_of_birth": 1985, "month_of_birth": 7, "day_of_birth": 22, "birth_datetime": "1985-07-22", "race_concept_id": 0, "ethnicity_concept_id": 0, "person_source_value": "patient-1", "gender_source_value": "female" } ], "condition_occurrence": [ { "condition_occurrence_id": 1, "person_id": 1, "condition_concept_id": 201826, "condition_start_date": "2024-01-15", "condition_start_datetime": "2024-01-15", "condition_type_concept_id": 32817, "condition_source_value": "http://snomed.info/sct#44054006", "condition_source_concept_id": 201826 } ], "drug_exposure": [ { "drug_exposure_id": 1, "person_id": 1, "drug_concept_id": 40163924, "drug_exposure_start_date": "2024-01-16", "drug_exposure_start_datetime": "2024-01-16", "drug_type_concept_id": 32817, "drug_source_value": "http://www.nlm.nih.gov/research/umls/rxnorm#860975", "drug_source_concept_id": 40163924 } ] }, "mappings": [ { "resource_type": "Condition", "resource_id": "condition-1", "omop_table": "condition_occurrence", "omop_id": 1, "source_system": "http://snomed.info/sct", "source_code": "44054006", "source_name": "Type 2 diabetes mellitus", "target_vocabulary": "SNOMED", "target_code": "44054006", "target_name": "Type 2 diabetes mellitus", "mapping_status": "ALREADY_STANDARD" }, { "resource_type": "MedicationRequest", "resource_id": "medreq-1", "omop_table": "drug_exposure", "omop_id": 1, "source_system": "http://www.nlm.nih.gov/research/umls/rxnorm", "source_code": "860975", "source_name": "metformin hydrochloride 500 MG", "target_vocabulary": "RXNORM", "target_code": "860975", "target_name": "metformin hydrochloride 500 MG", "mapping_status": "ALREADY_STANDARD" } ], "vocab_version": "v20240229", "summary": { "codes_already_standard": 2, "codes_normalized": 0, "codes_unmapped": 0, "off_vocab_rate": 0 } } ``` **400** - Bad request - invalid input. Possible reasons: - Missing or malformed request body (no `fhir_resources`) - Invalid FHIR input (non-Bundle/non-resource payload) - No Patient resource found (OMOP requires at least one person) Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean" }, "message": { "type": "string" }, "tables": { "type": "object", "description": "OMOP CDM v5.4 rows grouped by destination table.", "properties": { "location": { "type": "array", "items": { "type": "object", "properties": { "location_id": { "type": "integer", "format": "int64" }, "address_1": { "type": "string" }, "address_2": { "type": "string" }, "city": { "type": "string" }, "state": { "type": "string" }, "zip": { "type": "string" }, "county": { "type": "string" }, "location_source_value": { "type": "string" }, "country_concept_id": { "type": "integer", "format": "int64" }, "country_source_value": { "type": "string" }, "latitude": { "type": "number", "format": "double" }, "longitude": { "type": "number", "format": "double" } } } }, "care_site": { "type": "array", "items": { "type": "object", "properties": { "care_site_id": { "type": "integer", "format": "int64" }, "care_site_name": { "type": "string" }, "place_of_service_concept_id": { "type": "integer", "format": "int64" }, "location_id": { "type": "integer", "format": "int64" }, "care_site_source_value": { "type": "string" }, "place_of_service_source_value": { "type": "string" } } } }, "provider": { "type": "array", "items": { "type": "object", "properties": { "provider_id": { "type": "integer", "format": "int64" }, "provider_name": { "type": "string" }, "npi": { "type": "string" }, "dea": { "type": "string" }, "specialty_concept_id": { "type": "integer", "format": "int64" }, "care_site_id": { "type": "integer", "format": "int64" }, "year_of_birth": { "type": "integer" }, "gender_concept_id": { "type": "integer", "format": "int64" }, "provider_source_value": { "type": "string" }, "specialty_source_value": { "type": "string" }, "specialty_source_concept_id": { "type": "integer", "format": "int64" }, "gender_source_value": { "type": "string" }, "gender_source_concept_id": { "type": "integer", "format": "int64" } } } }, "person": { "type": "array", "items": { "type": "object", "properties": { "person_id": { "type": "integer", "format": "int64" }, "gender_concept_id": { "type": "integer", "format": "int64" }, "year_of_birth": { "type": "integer" }, "month_of_birth": { "type": "integer" }, "day_of_birth": { "type": "integer" }, "birth_datetime": { "type": "string" }, "race_concept_id": { "type": "integer", "format": "int64" }, "ethnicity_concept_id": { "type": "integer", "format": "int64" }, "location_id": { "type": "integer", "format": "int64" }, "person_source_value": { "type": "string" }, "gender_source_value": { "type": "string" }, "race_source_value": { "type": "string" }, "ethnicity_source_value": { "type": "string" } } } }, "death": { "type": "array", "items": { "type": "object", "properties": { "person_id": { "type": "integer", "format": "int64" }, "death_date": { "type": "string" }, "death_datetime": { "type": "string" }, "death_type_concept_id": { "type": "integer", "format": "int64" }, "cause_concept_id": { "type": "integer", "format": "int64" }, "cause_source_value": { "type": "string" }, "cause_source_concept_id": { "type": "integer", "format": "int64" } } } }, "observation_period": { "type": "array", "items": { "type": "object", "properties": { "observation_period_id": { "type": "integer", "format": "int64" }, "person_id": { "type": "integer", "format": "int64" }, "observation_period_start_date": { "type": "string" }, "observation_period_end_date": { "type": "string" }, "period_type_concept_id": { "type": "integer", "format": "int64" } } } }, "visit_occurrence": { "type": "array", "items": { "type": "object", "properties": { "visit_occurrence_id": { "type": "integer", "format": "int64" }, "person_id": { "type": "integer", "format": "int64" }, "visit_concept_id": { "type": "integer", "format": "int64" }, "visit_start_date": { "type": "string" }, "visit_start_datetime": { "type": "string" }, "visit_end_date": { "type": "string" }, "visit_end_datetime": { "type": "string" }, "visit_type_concept_id": { "type": "integer", "format": "int64" }, "provider_id": { "type": "integer", "format": "int64" }, "care_site_id": { "type": "integer", "format": "int64" }, "visit_source_value": { "type": "string" } } } }, "condition_occurrence": { "type": "array", "items": { "type": "object", "properties": { "condition_occurrence_id": { "type": "integer", "format": "int64" }, "person_id": { "type": "integer", "format": "int64" }, "condition_concept_id": { "type": "integer", "format": "int64" }, "condition_start_date": { "type": "string" }, "condition_start_datetime": { "type": "string" }, "condition_end_date": { "type": "string" }, "condition_type_concept_id": { "type": "integer", "format": "int64" }, "visit_occurrence_id": { "type": "integer", "format": "int64" }, "provider_id": { "type": "integer", "format": "int64" }, "condition_source_value": { "type": "string" }, "condition_source_concept_id": { "type": "integer", "format": "int64" }, "condition_status_source_value": { "type": "string" } } } }, "drug_exposure": { "type": "array", "items": { "type": "object", "properties": { "drug_exposure_id": { "type": "integer", "format": "int64" }, "person_id": { "type": "integer", "format": "int64" }, "drug_concept_id": { "type": "integer", "format": "int64" }, "drug_exposure_start_date": { "type": "string" }, "drug_exposure_start_datetime": { "type": "string" }, "drug_exposure_end_date": { "type": "string" }, "drug_type_concept_id": { "type": "integer", "format": "int64" }, "stop_reason": { "type": "string" }, "sig": { "type": "string" }, "visit_occurrence_id": { "type": "integer", "format": "int64" }, "provider_id": { "type": "integer", "format": "int64" }, "drug_source_value": { "type": "string" }, "drug_source_concept_id": { "type": "integer", "format": "int64" } } } }, "procedure_occurrence": { "type": "array", "items": { "type": "object", "properties": { "procedure_occurrence_id": { "type": "integer", "format": "int64" }, "person_id": { "type": "integer", "format": "int64" }, "procedure_concept_id": { "type": "integer", "format": "int64" }, "procedure_date": { "type": "string" }, "procedure_datetime": { "type": "string" }, "procedure_type_concept_id": { "type": "integer", "format": "int64" }, "visit_occurrence_id": { "type": "integer", "format": "int64" }, "provider_id": { "type": "integer", "format": "int64" }, "procedure_source_value": { "type": "string" }, "procedure_source_concept_id": { "type": "integer", "format": "int64" } } } }, "measurement": { "type": "array", "items": { "type": "object", "properties": { "measurement_id": { "type": "integer", "format": "int64" }, "person_id": { "type": "integer", "format": "int64" }, "measurement_concept_id": { "type": "integer", "format": "int64" }, "measurement_date": { "type": "string" }, "measurement_datetime": { "type": "string" }, "measurement_type_concept_id": { "type": "integer", "format": "int64" }, "value_as_number": { "type": "number", "format": "double" }, "operator_concept_id": { "type": "integer", "format": "int64", "description": "OMOP \"Meas Value Operator\" standard concept qualifying value_as_number (<, <=, >, >=), parsed from a numeric-string value or a FHIR valueQuantity.comparator. 0 when no operator (a bare number)." }, "value_as_concept_id": { "type": "integer", "format": "int64" }, "unit_concept_id": { "type": "integer", "format": "int64" }, "range_low": { "type": "number", "format": "double" }, "range_high": { "type": "number", "format": "double" }, "visit_occurrence_id": { "type": "integer", "format": "int64" }, "provider_id": { "type": "integer", "format": "int64" }, "measurement_source_value": { "type": "string" }, "measurement_source_concept_id": { "type": "integer", "format": "int64" }, "unit_source_value": { "type": "string" }, "value_source_value": { "type": "string" } } } }, "observation": { "type": "array", "items": { "type": "object", "properties": { "observation_id": { "type": "integer", "format": "int64" }, "person_id": { "type": "integer", "format": "int64" }, "observation_concept_id": { "type": "integer", "format": "int64" }, "observation_date": { "type": "string" }, "observation_datetime": { "type": "string" }, "observation_type_concept_id": { "type": "integer", "format": "int64" }, "value_as_number": { "type": "number", "format": "double" }, "value_as_string": { "type": "string" }, "value_as_concept_id": { "type": "integer", "format": "int64" }, "unit_concept_id": { "type": "integer", "format": "int64" }, "visit_occurrence_id": { "type": "integer", "format": "int64" }, "provider_id": { "type": "integer", "format": "int64" }, "observation_source_value": { "type": "string" }, "observation_source_concept_id": { "type": "integer", "format": "int64" }, "unit_source_value": { "type": "string" }, "value_source_value": { "type": "string" } } } } } }, "mappings": { "type": "array", "description": "One entry per source coding (or one entry for a text-only resource with no coding), describing how it resolved and linking back to the row it produced.", "items": { "type": "object", "description": "How one source coding (or a text-only resource's free text) resolved to an OMOP standard concept.", "properties": { "resource_type": { "type": "string" }, "resource_id": { "type": "string" }, "omop_table": { "type": "string" }, "omop_id": { "type": "integer", "format": "int64", "description": "The id of the OMOP row this coding produced (e.g. `condition_occurrence_id`),\nwithin `omop_table`. A resource with multiple codings yields one entry\nper coding, all sharing this id.\n" }, "source_system": { "type": "string" }, "source_code": { "type": "string" }, "source_name": { "type": "string" }, "target_vocabulary": { "type": "string" }, "target_code": { "type": "string", "description": "The standard concept's own code: the source code itself for an\nALREADY_STANDARD row, the standard concept's code for a MAPPED row,\nor the suggested code for an UNCHECKED row. Omitted for UNMAPPED\nrows.\n" }, "target_name": { "type": "string" }, "mapping_status": { "type": "string", "description": "ALREADY_STANDARD (source coding is already a standard OMOP concept),\nMAPPED (source coding was mapped to a standard concept), UNCHECKED (a\nstandard code was suggested — e.g. for a text-only resource — but not\nverified against the OMOP vocabulary, so `concept_id` stays `0`), or\nUNMAPPED (no standard concept found).\n" }, "note": { "type": "string" } } } }, "dropped": { "type": "array", "description": "Supported resource instances that could not be shaped into an OMOP\nrow because required subject/patient, code, or medication reference\ndata was missing. Unsupported resource types are ignored and do not\nappear here.\n", "items": { "type": "object", "properties": { "resource_type": { "type": "string" }, "resource_id": { "type": "string" }, "reason": { "type": "string" } } } }, "vocab_version": { "type": "string", "description": "The OMOP vocabulary release the clinical codes were resolved against\n(e.g. \"v20240229\"), for reproducibility. Present when at least one\ncoded concept was resolved.\n" }, "summary": { "type": "object", "description": "The request's data-quality headline: how the coded concepts split across\nresolution outcomes, and the share that was not already in a target\nstandard vocabulary. Each coded resource is counted once (per resolved\nconcept), even when it carried several codings — unlike `mappings`, which\nhas one entry per coding.\n", "properties": { "codes_already_standard": { "type": "integer", "description": "Coded concepts already a standard OMOP concept (ALREADY_STANDARD)." }, "codes_normalized": { "type": "integer", "description": "Coded concepts mapped or suggested to a standard concept (MAPPED or UNCHECKED)." }, "codes_unmapped": { "type": "integer", "description": "Coded concepts with no standard concept found (UNMAPPED)." }, "off_vocab_rate": { "type": "number", "format": "double", "description": "Share of coded concepts not already standard ((normalized + unmapped) / total)." } } } } } ``` **401** - Unauthorized **500** - Internal server error **503** - Service unavailable due to a server configuration error. No rows are returned. Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean" }, "message": { "type": "string" }, "tables": { "type": "object", "description": "OMOP CDM v5.4 rows grouped by destination table.", "properties": { "location": { "type": "array", "items": { "type": "object", "properties": { "location_id": { "type": "integer", "format": "int64" }, "address_1": { "type": "string" }, "address_2": { "type": "string" }, "city": { "type": "string" }, "state": { "type": "string" }, "zip": { "type": "string" }, "county": { "type": "string" }, "location_source_value": { "type": "string" }, "country_concept_id": { "type": "integer", "format": "int64" }, "country_source_value": { "type": "string" }, "latitude": { "type": "number", "format": "double" }, "longitude": { "type": "number", "format": "double" } } } }, "care_site": { "type": "array", "items": { "type": "object", "properties": { "care_site_id": { "type": "integer", "format": "int64" }, "care_site_name": { "type": "string" }, "place_of_service_concept_id": { "type": "integer", "format": "int64" }, "location_id": { "type": "integer", "format": "int64" }, "care_site_source_value": { "type": "string" }, "place_of_service_source_value": { "type": "string" } } } }, "provider": { "type": "array", "items": { "type": "object", "properties": { "provider_id": { "type": "integer", "format": "int64" }, "provider_name": { "type": "string" }, "npi": { "type": "string" }, "dea": { "type": "string" }, "specialty_concept_id": { "type": "integer", "format": "int64" }, "care_site_id": { "type": "integer", "format": "int64" }, "year_of_birth": { "type": "integer" }, "gender_concept_id": { "type": "integer", "format": "int64" }, "provider_source_value": { "type": "string" }, "specialty_source_value": { "type": "string" }, "specialty_source_concept_id": { "type": "integer", "format": "int64" }, "gender_source_value": { "type": "string" }, "gender_source_concept_id": { "type": "integer", "format": "int64" } } } }, "person": { "type": "array", "items": { "type": "object", "properties": { "person_id": { "type": "integer", "format": "int64" }, "gender_concept_id": { "type": "integer", "format": "int64" }, "year_of_birth": { "type": "integer" }, "month_of_birth": { "type": "integer" }, "day_of_birth": { "type": "integer" }, "birth_datetime": { "type": "string" }, "race_concept_id": { "type": "integer", "format": "int64" }, "ethnicity_concept_id": { "type": "integer", "format": "int64" }, "location_id": { "type": "integer", "format": "int64" }, "person_source_value": { "type": "string" }, "gender_source_value": { "type": "string" }, "race_source_value": { "type": "string" }, "ethnicity_source_value": { "type": "string" } } } }, "death": { "type": "array", "items": { "type": "object", "properties": { "person_id": { "type": "integer", "format": "int64" }, "death_date": { "type": "string" }, "death_datetime": { "type": "string" }, "death_type_concept_id": { "type": "integer", "format": "int64" }, "cause_concept_id": { "type": "integer", "format": "int64" }, "cause_source_value": { "type": "string" }, "cause_source_concept_id": { "type": "integer", "format": "int64" } } } }, "observation_period": { "type": "array", "items": { "type": "object", "properties": { "observation_period_id": { "type": "integer", "format": "int64" }, "person_id": { "type": "integer", "format": "int64" }, "observation_period_start_date": { "type": "string" }, "observation_period_end_date": { "type": "string" }, "period_type_concept_id": { "type": "integer", "format": "int64" } } } }, "visit_occurrence": { "type": "array", "items": { "type": "object", "properties": { "visit_occurrence_id": { "type": "integer", "format": "int64" }, "person_id": { "type": "integer", "format": "int64" }, "visit_concept_id": { "type": "integer", "format": "int64" }, "visit_start_date": { "type": "string" }, "visit_start_datetime": { "type": "string" }, "visit_end_date": { "type": "string" }, "visit_end_datetime": { "type": "string" }, "visit_type_concept_id": { "type": "integer", "format": "int64" }, "provider_id": { "type": "integer", "format": "int64" }, "care_site_id": { "type": "integer", "format": "int64" }, "visit_source_value": { "type": "string" } } } }, "condition_occurrence": { "type": "array", "items": { "type": "object", "properties": { "condition_occurrence_id": { "type": "integer", "format": "int64" }, "person_id": { "type": "integer", "format": "int64" }, "condition_concept_id": { "type": "integer", "format": "int64" }, "condition_start_date": { "type": "string" }, "condition_start_datetime": { "type": "string" }, "condition_end_date": { "type": "string" }, "condition_type_concept_id": { "type": "integer", "format": "int64" }, "visit_occurrence_id": { "type": "integer", "format": "int64" }, "provider_id": { "type": "integer", "format": "int64" }, "condition_source_value": { "type": "string" }, "condition_source_concept_id": { "type": "integer", "format": "int64" }, "condition_status_source_value": { "type": "string" } } } }, "drug_exposure": { "type": "array", "items": { "type": "object", "properties": { "drug_exposure_id": { "type": "integer", "format": "int64" }, "person_id": { "type": "integer", "format": "int64" }, "drug_concept_id": { "type": "integer", "format": "int64" }, "drug_exposure_start_date": { "type": "string" }, "drug_exposure_start_datetime": { "type": "string" }, "drug_exposure_end_date": { "type": "string" }, "drug_type_concept_id": { "type": "integer", "format": "int64" }, "stop_reason": { "type": "string" }, "sig": { "type": "string" }, "visit_occurrence_id": { "type": "integer", "format": "int64" }, "provider_id": { "type": "integer", "format": "int64" }, "drug_source_value": { "type": "string" }, "drug_source_concept_id": { "type": "integer", "format": "int64" } } } }, "procedure_occurrence": { "type": "array", "items": { "type": "object", "properties": { "procedure_occurrence_id": { "type": "integer", "format": "int64" }, "person_id": { "type": "integer", "format": "int64" }, "procedure_concept_id": { "type": "integer", "format": "int64" }, "procedure_date": { "type": "string" }, "procedure_datetime": { "type": "string" }, "procedure_type_concept_id": { "type": "integer", "format": "int64" }, "visit_occurrence_id": { "type": "integer", "format": "int64" }, "provider_id": { "type": "integer", "format": "int64" }, "procedure_source_value": { "type": "string" }, "procedure_source_concept_id": { "type": "integer", "format": "int64" } } } }, "measurement": { "type": "array", "items": { "type": "object", "properties": { "measurement_id": { "type": "integer", "format": "int64" }, "person_id": { "type": "integer", "format": "int64" }, "measurement_concept_id": { "type": "integer", "format": "int64" }, "measurement_date": { "type": "string" }, "measurement_datetime": { "type": "string" }, "measurement_type_concept_id": { "type": "integer", "format": "int64" }, "value_as_number": { "type": "number", "format": "double" }, "operator_concept_id": { "type": "integer", "format": "int64", "description": "OMOP \"Meas Value Operator\" standard concept qualifying value_as_number (<, <=, >, >=), parsed from a numeric-string value or a FHIR valueQuantity.comparator. 0 when no operator (a bare number)." }, "value_as_concept_id": { "type": "integer", "format": "int64" }, "unit_concept_id": { "type": "integer", "format": "int64" }, "range_low": { "type": "number", "format": "double" }, "range_high": { "type": "number", "format": "double" }, "visit_occurrence_id": { "type": "integer", "format": "int64" }, "provider_id": { "type": "integer", "format": "int64" }, "measurement_source_value": { "type": "string" }, "measurement_source_concept_id": { "type": "integer", "format": "int64" }, "unit_source_value": { "type": "string" }, "value_source_value": { "type": "string" } } } }, "observation": { "type": "array", "items": { "type": "object", "properties": { "observation_id": { "type": "integer", "format": "int64" }, "person_id": { "type": "integer", "format": "int64" }, "observation_concept_id": { "type": "integer", "format": "int64" }, "observation_date": { "type": "string" }, "observation_datetime": { "type": "string" }, "observation_type_concept_id": { "type": "integer", "format": "int64" }, "value_as_number": { "type": "number", "format": "double" }, "value_as_string": { "type": "string" }, "value_as_concept_id": { "type": "integer", "format": "int64" }, "unit_concept_id": { "type": "integer", "format": "int64" }, "visit_occurrence_id": { "type": "integer", "format": "int64" }, "provider_id": { "type": "integer", "format": "int64" }, "observation_source_value": { "type": "string" }, "observation_source_concept_id": { "type": "integer", "format": "int64" }, "unit_source_value": { "type": "string" }, "value_source_value": { "type": "string" } } } } } }, "mappings": { "type": "array", "description": "One entry per source coding (or one entry for a text-only resource with no coding), describing how it resolved and linking back to the row it produced.", "items": { "type": "object", "description": "How one source coding (or a text-only resource's free text) resolved to an OMOP standard concept.", "properties": { "resource_type": { "type": "string" }, "resource_id": { "type": "string" }, "omop_table": { "type": "string" }, "omop_id": { "type": "integer", "format": "int64", "description": "The id of the OMOP row this coding produced (e.g. `condition_occurrence_id`),\nwithin `omop_table`. A resource with multiple codings yields one entry\nper coding, all sharing this id.\n" }, "source_system": { "type": "string" }, "source_code": { "type": "string" }, "source_name": { "type": "string" }, "target_vocabulary": { "type": "string" }, "target_code": { "type": "string", "description": "The standard concept's own code: the source code itself for an\nALREADY_STANDARD row, the standard concept's code for a MAPPED row,\nor the suggested code for an UNCHECKED row. Omitted for UNMAPPED\nrows.\n" }, "target_name": { "type": "string" }, "mapping_status": { "type": "string", "description": "ALREADY_STANDARD (source coding is already a standard OMOP concept),\nMAPPED (source coding was mapped to a standard concept), UNCHECKED (a\nstandard code was suggested — e.g. for a text-only resource — but not\nverified against the OMOP vocabulary, so `concept_id` stays `0`), or\nUNMAPPED (no standard concept found).\n" }, "note": { "type": "string" } } } }, "dropped": { "type": "array", "description": "Supported resource instances that could not be shaped into an OMOP\nrow because required subject/patient, code, or medication reference\ndata was missing. Unsupported resource types are ignored and do not\nappear here.\n", "items": { "type": "object", "properties": { "resource_type": { "type": "string" }, "resource_id": { "type": "string" }, "reason": { "type": "string" } } } }, "vocab_version": { "type": "string", "description": "The OMOP vocabulary release the clinical codes were resolved against\n(e.g. \"v20240229\"), for reproducibility. Present when at least one\ncoded concept was resolved.\n" }, "summary": { "type": "object", "description": "The request's data-quality headline: how the coded concepts split across\nresolution outcomes, and the share that was not already in a target\nstandard vocabulary. Each coded resource is counted once (per resolved\nconcept), even when it carried several codings — unlike `mappings`, which\nhas one entry per coding.\n", "properties": { "codes_already_standard": { "type": "integer", "description": "Coded concepts already a standard OMOP concept (ALREADY_STANDARD)." }, "codes_normalized": { "type": "integer", "description": "Coded concepts mapped or suggested to a standard concept (MAPPED or UNCHECKED)." }, "codes_unmapped": { "type": "integer", "description": "Coded concepts with no standard concept found (UNMAPPED)." }, "off_vocab_rate": { "type": "number", "format": "double", "description": "Share of coded concepts not already standard ((normalized + unmapped) / total)." } } } } } ``` --- # Agent Create AI agents that can query and interact with electronic health records using natural language. ## Agent / Chat Conversational sessions with an agent. ### POST /agent/chat **Chat with agent** Send a message to an agent and receive a JSON response. **Operation ID:** `agent_send` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `X-Phenoml-On-Behalf-Of` | header | string | No | Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity. Must be in the format: Patient/{uuid} or Practitioner/{uuid} | | `X-Phenoml-Fhir-Provider` | header | string | No | Optional header for FHIR provider authentication. Contains credentials in the format {fhir_provider_id}:{oauth2_token}. Multiple FHIR provider integrations can be provided as comma-separated values. | #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "message", "agent_id" ], "properties": { "message": { "type": "string", "description": "The message to send to the agent", "example": "What is the patient's current condition?" }, "context": { "type": "string", "description": "Optional context for the conversation", "example": "Respond concisely and with clear rationale" }, "session_id": { "type": "string", "description": "Optional session ID for conversation continuity. Only one request may be active for a session at a time; overlapping turns for the same session return 409 Conflict.", "example": "session-abc123" }, "agent_id": { "type": "string", "description": "The ID of the agent to chat with", "example": "agent-123" }, "enhanced_reasoning": { "type": "boolean", "description": "Enable enhanced reasoning capabilities. Increases latency but improves response quality and reliability.", "default": false, "example": false } } } ``` **Example:** ```json { "message": "What is the patient's current condition?", "agent_id": "agent-123", "session_id": "session-abc123" } ``` #### Responses **200** - Chat response received successfully Content-Type: `application/json` ```json { "type": "object", "properties": { "response": { "type": "string", "description": "Agent's response", "example": "I'll create a patient record for John Doe with diabetes. Let me process that information..." }, "success": { "type": "boolean", "example": true }, "message": { "type": "string", "description": "Status message", "example": "Chat response generated successfully" }, "session_id": { "type": "string", "description": "Chat session ID", "example": "session_123" } } } ``` **Example:** ```json { "success": true, "message": "Response generated successfully", "response": "Based on the patient records, they have been diagnosed with Type 2 Diabetes Mellitus (ICD-10: E11.65) and Essential Hypertension (ICD-10: I10). Current medications include Metformin 500mg BID and Lisinopril 10mg daily. Most recent HbA1c was 7.2% on 2024-12-15.", "session_id": "session-abc123" } ``` **400** - Invalid request **401** - Unauthorized **403** - Forbidden - access denied to the requested resource **404** - Agent or session not found **409** - Chat session already has an active request. Retry after the in-flight turn completes. **500** - Server error **504** - Request timed out --- ### GET /agent/chat/messages **Get chat messages** Retrieves a list of chat messages for a given chat session **Operation ID:** `agent_listMessages` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `chat_session_id` | query | string | Yes | Chat session ID | | `num_messages` | query | integer | No | Number of messages to return | | `role` | query | string | No | Filter by one or more message roles. Multiple roles can be specified as a comma-separated string. If not specified, messages with all roles are returned. **Available roles:** - `user` - Messages from the user - `assistant` - Text responses from the AI assistant - `model` - Function/tool call requests from the model - `function` - Function/tool call results | | `order` | query | string | No | Order of messages | #### Responses **200** - Chat messages retrieved successfully Content-Type: `application/json` ```json { "type": "object", "properties": { "messages": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Chat message ID", "example": "message_123" }, "session_id": { "type": "string", "description": "Chat session ID", "example": "session_123" }, "role": { "type": "string", "description": "Message role indicating the source/type of the message:\n- `user` - Messages from the user\n- `assistant` - Text responses from the AI assistant\n- `model` - Function/tool call requests to the model\n- `function` - Function/tool call results\n", "enum": [ "user", "assistant", "model", "function" ], "example": "user" }, "content": { "type": "string", "description": "Message content", "example": "Hello, how are you?" }, "created": { "type": "string", "description": "Message created time", "example": "2021-01-01T00:00:00Z" }, "updated": { "type": "string", "description": "Message updated time", "example": "2021-01-01T00:00:00Z" }, "function_name": { "type": "string", "description": "Function name", "example": "get_patient_info" }, "function_args": { "type": "object", "description": "Function arguments", "example": { "patient_id": "123" } }, "function_result": { "type": "object", "description": "Function result", "example": { "name": "John Doe" } }, "message_order": { "type": "integer", "description": "Message order", "example": 1 } } } }, "total": { "type": "integer", "example": 10 }, "session_id": { "type": "string", "example": "session_123" } } } ``` **Example:** ```json { "session_id": "session_123", "total": 2, "messages": [ { "id": "message_001", "session_id": "session_123", "role": "user", "content": "What is the patient's current condition?", "created": "2025-03-01T14:00:00Z", "updated": "2025-03-01T14:00:00Z", "message_order": 1 }, { "id": "message_002", "session_id": "session_123", "role": "assistant", "content": "Based on the patient records, they have been diagnosed with Type 2 Diabetes Mellitus (ICD-10: E11.65).", "created": "2025-03-01T14:00:02Z", "updated": "2025-03-01T14:00:02Z", "message_order": 2 } ] } ``` **401** - Unauthorized **403** - Forbidden - access denied to the requested resource **404** - Chat session not found **500** - Server error **504** - Request timed out --- ### POST /agent/stream-chat **Chat with agent (streaming)** Send a message to an agent and receive the response as a Server-Sent Events (SSE) stream. Events include message_start, content_delta, tool_use, tool_result, message_end, and error. **Operation ID:** `agent_stream` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `X-Phenoml-On-Behalf-Of` | header | string | No | Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity. Must be in the format: Patient/{uuid} or Practitioner/{uuid} | | `X-Phenoml-Fhir-Provider` | header | string | No | Optional header for FHIR provider authentication. Contains credentials in the format {fhir_provider_id}:{oauth2_token}. Multiple FHIR provider integrations can be provided as comma-separated values. | #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "description": "Request body for the streaming chat endpoint.", "required": [ "message", "agent_id" ], "properties": { "message": { "type": "string", "description": "The message to send to the agent", "example": "What is the patient's current condition?" }, "context": { "type": "string", "description": "Optional context for the conversation", "example": "Respond concisely and with clear rationale" }, "session_id": { "type": "string", "description": "Optional session ID for conversation continuity. Only one request may be active for a session at a time; overlapping turns for the same session return 409 Conflict.", "example": "session-abc123" }, "agent_id": { "type": "string", "description": "The ID of the agent to chat with", "example": "agent-123" }, "enhanced_reasoning": { "type": "boolean", "description": "Enable enhanced reasoning capabilities. Increases latency but improves response quality and reliability.", "default": false, "example": false } } } ``` **Example:** ```json { "message": "What is the patient's current condition?", "agent_id": "agent-123", "session_id": "session-abc123" } ``` #### Responses **200** - Streaming chat response. Each frame is a standard SSE record (`event:` line + `data:` JSON line). The example shows a single `content_delta` payload — multiple frames stream until `message_end`. Content-Type: `text/event-stream` ```json { "type": "object", "description": "JSON payload sent in the `data:` line of a Server-Sent Event (SSE) frame for streaming chat responses.\nEach SSE frame uses the standard `event:` and `data:` lines; this schema describes the JSON object\nin the `data:` line. The event type is encoded in the top-level `type` property.\nEvent types: message_start, content_delta, tool_use, tool_result, message_end, error.\n", "properties": { "type": { "type": "string", "description": "The event type", "enum": [ "message_start", "content_delta", "tool_use", "tool_result", "message_end", "error" ], "example": "content_delta" }, "session_id": { "type": "string", "description": "Chat session ID", "example": "session_123" }, "content": { "type": "string", "description": "Incremental text content (present in content_delta events)", "example": "I'll create a patient record..." }, "success": { "type": "boolean", "description": "Whether the operation was successful", "example": true }, "message": { "type": "string", "description": "Status message", "example": "Response generated successfully" }, "function_name": { "type": "string", "description": "Tool/function name (present in tool_use and tool_result events)", "example": "lang2fhir_search" }, "function_args": { "type": "object", "description": "Tool arguments (present in tool_use events)", "additionalProperties": true }, "function_result": { "type": "object", "description": "Tool execution result (present in tool_result events)", "additionalProperties": true } } } ``` **Example:** ```json { "type": "content_delta", "session_id": "session-abc123", "content": "Based on the patient records, " } ``` **400** - Invalid request **401** - Unauthorized **403** - Forbidden - access denied to the requested resource **404** - Agent or session not found **409** - Chat session already has an active request. Retry after the in-flight turn completes. **500** - Server error **504** - Request timed out --- ## Agent / Prompts Reusable prompt templates that agents can attach to chats. ### POST /agent/prompts **Create agent prompt** Creates a new agent prompt **Operation ID:** `agent_createPrompt` #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "name", "content" ], "properties": { "name": { "type": "string", "description": "Prompt name", "example": "Medical Assistant System Prompt" }, "description": { "type": "string", "description": "Prompt description", "example": "System prompt for medical assistant agent" }, "content": { "type": "string", "description": "Prompt content", "example": "You are a helpful medical assistant specialized in FHIR data processing..." }, "is_default": { "type": "boolean", "description": "Whether this is a default prompt", "example": false }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Tags for categorizing the prompt", "example": [ "medical", "system" ] } } } ``` **Example:** ```json { "name": "Medical Assistant System Prompt", "description": "System prompt for medical assistant agent", "content": "You are a helpful medical assistant specialized in FHIR data processing.", "is_default": false, "tags": [ "medical", "system" ] } ``` #### Responses **201** - Prompt created successfully Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string" }, "data": { "type": "object", "properties": { "id": { "type": "string", "description": "Prompt ID", "example": "prompt_123" }, "name": { "type": "string", "description": "Prompt name", "example": "Medical Assistant System Prompt" }, "description": { "type": "string", "description": "Prompt description", "example": "System prompt for medical assistant agent" }, "content": { "type": "string", "description": "Prompt content", "example": "You are a helpful medical assistant..." }, "is_default": { "type": "boolean", "description": "Whether this is a default prompt", "example": false }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Tags for categorizing the prompt", "example": [ "medical", "system" ] } } } } } ``` **Example:** ```json { "success": true, "message": "Prompt created successfully", "data": { "id": "prompt_123", "name": "Medical Assistant System Prompt", "description": "System prompt for medical assistant agent", "content": "You are a helpful medical assistant...", "is_default": false, "tags": [ "medical", "system" ] } } ``` **400** - Invalid request **401** - Unauthorized **403** - Forbidden - access denied to the requested resource **500** - Server error --- ### GET /agent/prompts/{id} **Get prompt by ID** Retrieves a specific prompt by its ID **Operation ID:** `agent_getPrompt` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `id` | path | string | Yes | Prompt ID | #### Responses **200** - Prompt retrieved successfully Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string" }, "data": { "type": "object", "properties": { "id": { "type": "string", "description": "Prompt ID", "example": "prompt_123" }, "name": { "type": "string", "description": "Prompt name", "example": "Medical Assistant System Prompt" }, "description": { "type": "string", "description": "Prompt description", "example": "System prompt for medical assistant agent" }, "content": { "type": "string", "description": "Prompt content", "example": "You are a helpful medical assistant..." }, "is_default": { "type": "boolean", "description": "Whether this is a default prompt", "example": false }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Tags for categorizing the prompt", "example": [ "medical", "system" ] } } } } } ``` **Example:** ```json { "success": true, "message": "Prompt retrieved successfully", "data": { "id": "prompt_123", "name": "Medical Assistant System Prompt", "description": "System prompt for medical assistant agent", "content": "You are a helpful medical assistant...", "is_default": false, "tags": [ "medical", "system" ] } } ``` **401** - Unauthorized **403** - Forbidden - access denied to the requested resource **404** - Prompt not found **500** - Server error --- ### PUT /agent/prompts/{id} **Update prompt** Updates an existing prompt **Operation ID:** `agent_updatePrompt` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `id` | path | string | Yes | Prompt ID | #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "properties": { "name": { "type": "string", "description": "Prompt name", "example": "Medical Assistant System Prompt" }, "description": { "type": "string", "description": "Prompt description", "example": "System prompt for medical assistant agent" }, "content": { "type": "string", "description": "Prompt content", "example": "You are a helpful medical assistant specialized in FHIR data processing..." }, "is_default": { "type": "boolean", "description": "Whether this is a default prompt", "example": false }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Tags for categorizing the prompt", "example": [ "medical", "system" ] } } } ``` **Example:** ```json { "name": "Medical Assistant System Prompt", "description": "Updated system prompt", "content": "You are a helpful medical assistant. Always cite ICD-10 codes when discussing diagnoses.", "is_default": false, "tags": [ "medical", "system", "updated" ] } ``` #### Responses **200** - Prompt updated successfully Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string" }, "data": { "type": "object", "properties": { "id": { "type": "string", "description": "Prompt ID", "example": "prompt_123" }, "name": { "type": "string", "description": "Prompt name", "example": "Medical Assistant System Prompt" }, "description": { "type": "string", "description": "Prompt description", "example": "System prompt for medical assistant agent" }, "content": { "type": "string", "description": "Prompt content", "example": "You are a helpful medical assistant..." }, "is_default": { "type": "boolean", "description": "Whether this is a default prompt", "example": false }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Tags for categorizing the prompt", "example": [ "medical", "system" ] } } } } } ``` **Example:** ```json { "success": true, "message": "Prompt updated successfully", "data": { "id": "prompt_123", "name": "Medical Assistant System Prompt", "description": "System prompt for medical assistant agent", "content": "You are a helpful medical assistant...", "is_default": false, "tags": [ "medical", "system" ] } } ``` **400** - Invalid request **401** - Unauthorized **403** - Forbidden - access denied to the requested resource **404** - Prompt not found **500** - Server error --- ### DELETE /agent/prompts/{id} **Delete prompt** Deletes a prompt **Operation ID:** `agent_deletePrompt` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `id` | path | string | Yes | Prompt ID | #### Responses **200** - Prompt deleted successfully Content-Type: `application/json` ```json { "type": "object", "title": "PromptsDeleteResponse", "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string", "example": "Prompt deleted successfully" } } } ``` **Example:** ```json { "success": true, "message": "Prompt deleted successfully" } ``` **401** - Unauthorized **403** - Forbidden - access denied to the requested resource **404** - Prompt not found **500** - Server error --- ### PATCH /agent/prompts/{id} **Patch prompt** Patches an existing prompt **Operation ID:** `agent_patchPrompt` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `id` | path | string | Yes | Agent Prompt ID | #### Request Body **Required:** Yes **Content-Type:** `application/json+patch` ```json { "type": "array", "description": "RFC 6902 JSON Patch document", "items": { "type": "object", "required": [ "op", "path" ], "properties": { "op": { "type": "string", "enum": [ "add", "remove", "replace", "move", "copy", "test" ], "description": "The operation to be performed", "example": "replace" }, "path": { "type": "string", "description": "A JSON Pointer string specifying a location within the target document", "example": "/name" }, "value": { "description": "The value to be used within the operations", "example": "New Agent Name" }, "from": { "type": "string", "description": "A JSON Pointer string specifying the location in the target document to move the value from (used with move and copy operations)", "example": "/oldName" } } }, "example": [ { "op": "replace", "path": "/name", "value": "Updated Agent Name" }, { "op": "add", "path": "/tags/-", "value": "new-tag" }, { "op": "remove", "path": "/description" } ] } ``` **Example:** ```json [ { "op": "replace", "path": "/content", "value": "Updated prompt content." } ] ``` #### Responses **200** - Prompt patched successfully Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string" }, "data": { "type": "object", "properties": { "id": { "type": "string", "description": "Prompt ID", "example": "prompt_123" }, "name": { "type": "string", "description": "Prompt name", "example": "Medical Assistant System Prompt" }, "description": { "type": "string", "description": "Prompt description", "example": "System prompt for medical assistant agent" }, "content": { "type": "string", "description": "Prompt content", "example": "You are a helpful medical assistant..." }, "is_default": { "type": "boolean", "description": "Whether this is a default prompt", "example": false }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Tags for categorizing the prompt", "example": [ "medical", "system" ] } } } } } ``` **Example:** ```json { "success": true, "message": "Prompt patched successfully", "data": { "id": "prompt_123", "name": "Medical Assistant System Prompt", "description": "System prompt for medical assistant agent", "content": "You are a helpful medical assistant...", "is_default": false, "tags": [ "medical", "system" ] } } ``` **400** - Failed to apply JSON patch. **401** - Unauthorized **403** - Forbidden - access denied to the requested resource **404** - Prompt not found **500** - Internal Server Error --- ### GET /agent/prompts/list **List agent prompts** Retrieves a list of agent prompts belonging to the authenticated user **Operation ID:** `agent_listPrompts` #### Responses **200** - Prompts retrieved successfully Content-Type: `application/json` ```json { "type": "object", "title": "PromptsListResponse", "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string", "example": "Prompts retrieved successfully" }, "prompts": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Prompt ID", "example": "prompt_123" }, "name": { "type": "string", "description": "Prompt name", "example": "Medical Assistant System Prompt" }, "description": { "type": "string", "description": "Prompt description", "example": "System prompt for medical assistant agent" }, "content": { "type": "string", "description": "Prompt content", "example": "You are a helpful medical assistant..." }, "is_default": { "type": "boolean", "description": "Whether this is a default prompt", "example": false }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Tags for categorizing the prompt", "example": [ "medical", "system" ] } } } } } } ``` **Example:** ```json { "success": true, "message": "Prompts retrieved successfully", "prompts": [ { "id": "prompt_123", "name": "Medical Assistant System Prompt", "description": "System prompt for medical assistant agent", "content": "You are a helpful medical assistant...", "is_default": false, "tags": [ "medical", "system" ] }, { "id": "prompt_456", "name": "Clinical Coding Prompt", "description": "Prompt for ICD-10 / SNOMED coding tasks", "content": "You assist with mapping clinical text to standard codes...", "is_default": false, "tags": [ "coding" ] } ] } ``` **401** - Unauthorized **403** - Forbidden - access denied to the requested resource **500** - Server error --- ## Untagged ### GET /agent/{id} **Get agent by ID** Retrieves a specific agent by its ID **Operation ID:** `agent_get` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `id` | path | string | Yes | Agent ID | #### Responses **200** - Agent retrieved successfully Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string" }, "data": { "type": "object", "properties": { "id": { "type": "string", "description": "Agent ID", "example": "agent_123" }, "name": { "type": "string", "description": "Agent name", "example": "Medical Assistant" }, "description": { "type": "string", "description": "Agent description", "example": "An AI assistant for medical information processing" }, "prompts": { "type": "array", "items": { "type": "string" }, "description": "Array of prompt IDs used by this agent", "example": [ "prompt_123", "prompt_456" ] }, "tools": { "type": "array", "items": { "type": "string" }, "description": "Array of MCP server tool IDs used by this agent", "example": [ "mcp_server_123", "mcp_server_456" ] }, "workflows": { "type": "array", "items": { "type": "string" }, "description": "Array of workflow IDs exposed as tools by this agent", "example": [ "workflow_123", "workflow_456" ] }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Tags for categorizing the agent", "example": [ "medical", "fhir" ] }, "provider": { "oneOf": [ { "type": "string", "format": "uuid", "description": "Single FHIR provider ID" }, { "type": "array", "items": { "type": "string", "format": "uuid" }, "description": "Array of FHIR provider IDs" } ], "description": "FHIR provider ID(s) - must be valid UUIDs from existing FHIR providers", "example": "7002b0b4-8d09-445a-bf65-0fafdaf26c35" } } } } } ``` **Example:** ```json { "success": true, "message": "Agent retrieved successfully", "data": { "id": "agent_123", "name": "Medical Assistant", "description": "An AI assistant for medical information processing", "prompts": [ "prompt_123", "prompt_456" ], "tools": [ "mcp_server_123", "mcp_server_456" ], "workflows": [ "workflow_123", "workflow_456" ], "tags": [ "medical", "fhir" ], "provider": "7002b0b4-8d09-445a-bf65-0fafdaf26c35" } } ``` **401** - Unauthorized **403** - Forbidden - access denied to the requested resource **404** - Agent not found **500** - Server error --- ### PUT /agent/{id} **Update agent** Updates an existing agent's configuration **Operation ID:** `agent_update` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `id` | path | string | Yes | Agent ID | #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "name", "prompts", "provider" ], "properties": { "name": { "type": "string", "description": "Agent name" }, "description": { "type": "string", "description": "Agent description", "example": "An AI assistant for medical information processing" }, "prompts": { "type": "array", "items": { "type": "string" }, "description": "Array of prompt IDs to use for this agent", "example": [ "prompt_123", "prompt_456" ] }, "tools": { "type": "array", "items": { "type": "string" }, "description": "Array of MCP server tool IDs to use for this agent", "example": [ "mcp_server_123", "mcp_server_456" ] }, "workflows": { "type": "array", "items": { "type": "string" }, "description": "Array of workflow IDs to expose as tools for this agent", "example": [ "workflow_123", "workflow_456" ] }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Tags for categorizing the agent", "example": [ "medical", "fhir" ] }, "provider": { "oneOf": [ { "type": "string", "format": "uuid", "description": "Single FHIR provider ID" }, { "type": "array", "items": { "type": "string", "format": "uuid" }, "description": "Array of FHIR provider IDs" } ], "description": "FHIR provider ID(s) for this agent. Required.\nIn shared/experiment environments, the default sandbox provider is used if a different provider is not explicitly specified.\n", "example": "7002b0b4-8d09-445a-bf65-0fafdaf26c35" } } } ``` **Example:** ```json { "name": "Medical Assistant", "description": "Updated description for the medical assistant", "prompts": [ "prompt_123" ], "provider": "7002b0b4-8d09-445a-bf65-0fafdaf26c35", "tags": [ "medical", "fhir", "updated" ] } ``` #### Responses **200** - Agent updated successfully Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string" }, "data": { "type": "object", "properties": { "id": { "type": "string", "description": "Agent ID", "example": "agent_123" }, "name": { "type": "string", "description": "Agent name", "example": "Medical Assistant" }, "description": { "type": "string", "description": "Agent description", "example": "An AI assistant for medical information processing" }, "prompts": { "type": "array", "items": { "type": "string" }, "description": "Array of prompt IDs used by this agent", "example": [ "prompt_123", "prompt_456" ] }, "tools": { "type": "array", "items": { "type": "string" }, "description": "Array of MCP server tool IDs used by this agent", "example": [ "mcp_server_123", "mcp_server_456" ] }, "workflows": { "type": "array", "items": { "type": "string" }, "description": "Array of workflow IDs exposed as tools by this agent", "example": [ "workflow_123", "workflow_456" ] }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Tags for categorizing the agent", "example": [ "medical", "fhir" ] }, "provider": { "oneOf": [ { "type": "string", "format": "uuid", "description": "Single FHIR provider ID" }, { "type": "array", "items": { "type": "string", "format": "uuid" }, "description": "Array of FHIR provider IDs" } ], "description": "FHIR provider ID(s) - must be valid UUIDs from existing FHIR providers", "example": "7002b0b4-8d09-445a-bf65-0fafdaf26c35" } } } } } ``` **Example:** ```json { "success": true, "message": "Agent updated successfully", "data": { "id": "agent_123", "name": "Medical Assistant", "description": "An AI assistant for medical information processing", "prompts": [ "prompt_123", "prompt_456" ], "tools": [ "mcp_server_123", "mcp_server_456" ], "workflows": [ "workflow_123", "workflow_456" ], "tags": [ "medical", "fhir" ], "provider": "7002b0b4-8d09-445a-bf65-0fafdaf26c35" } } ``` **400** - Invalid request **401** - Unauthorized **403** - Forbidden - access denied to the requested resource **404** - Agent not found **500** - Server error --- ### DELETE /agent/{id} **Delete agent** Deletes an existing agent **Operation ID:** `agent_delete` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `id` | path | string | Yes | Agent ID | #### Responses **200** - Agent deleted successfully Content-Type: `application/json` ```json { "type": "object", "title": "DeleteResponse", "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string", "example": "Agent deleted successfully" } } } ``` **Example:** ```json { "success": true, "message": "Agent deleted successfully" } ``` **401** - Unauthorized **403** - Forbidden - access denied to the requested resource **404** - Agent not found **500** - Server error --- ### PATCH /agent/{id} **Patch agent** Patches an existing agent's configuration **Operation ID:** `agent_patch` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `id` | path | string | Yes | Agent ID | #### Request Body **Required:** Yes **Content-Type:** `application/json+patch` ```json { "type": "array", "description": "RFC 6902 JSON Patch document", "items": { "type": "object", "required": [ "op", "path" ], "properties": { "op": { "type": "string", "enum": [ "add", "remove", "replace", "move", "copy", "test" ], "description": "The operation to be performed", "example": "replace" }, "path": { "type": "string", "description": "A JSON Pointer string specifying a location within the target document", "example": "/name" }, "value": { "description": "The value to be used within the operations", "example": "New Agent Name" }, "from": { "type": "string", "description": "A JSON Pointer string specifying the location in the target document to move the value from (used with move and copy operations)", "example": "/oldName" } } }, "example": [ { "op": "replace", "path": "/name", "value": "Updated Agent Name" }, { "op": "add", "path": "/tags/-", "value": "new-tag" }, { "op": "remove", "path": "/description" } ] } ``` **Example:** ```json [ { "op": "replace", "path": "/description", "value": "patched description" }, { "op": "add", "path": "/tags/-", "value": "updated" } ] ``` #### Responses **200** - Agent patched successfully Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string" }, "data": { "type": "object", "properties": { "id": { "type": "string", "description": "Agent ID", "example": "agent_123" }, "name": { "type": "string", "description": "Agent name", "example": "Medical Assistant" }, "description": { "type": "string", "description": "Agent description", "example": "An AI assistant for medical information processing" }, "prompts": { "type": "array", "items": { "type": "string" }, "description": "Array of prompt IDs used by this agent", "example": [ "prompt_123", "prompt_456" ] }, "tools": { "type": "array", "items": { "type": "string" }, "description": "Array of MCP server tool IDs used by this agent", "example": [ "mcp_server_123", "mcp_server_456" ] }, "workflows": { "type": "array", "items": { "type": "string" }, "description": "Array of workflow IDs exposed as tools by this agent", "example": [ "workflow_123", "workflow_456" ] }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Tags for categorizing the agent", "example": [ "medical", "fhir" ] }, "provider": { "oneOf": [ { "type": "string", "format": "uuid", "description": "Single FHIR provider ID" }, { "type": "array", "items": { "type": "string", "format": "uuid" }, "description": "Array of FHIR provider IDs" } ], "description": "FHIR provider ID(s) - must be valid UUIDs from existing FHIR providers", "example": "7002b0b4-8d09-445a-bf65-0fafdaf26c35" } } } } } ``` **Example:** ```json { "success": true, "message": "Agent patched successfully", "data": { "id": "agent_123", "name": "Medical Assistant", "description": "An AI assistant for medical information processing", "prompts": [ "prompt_123", "prompt_456" ], "tools": [ "mcp_server_123", "mcp_server_456" ], "workflows": [ "workflow_123", "workflow_456" ], "tags": [ "medical", "fhir" ], "provider": "7002b0b4-8d09-445a-bf65-0fafdaf26c35" } } ``` **400** - Failed to apply JSON patch. **401** - Unauthorized **403** - Forbidden - access denied to the requested resource **404** - Agent not found **500** - Internal Server Error --- ### POST /agent/create **Create a new agent** Creates a new PhenoAgent with specified configuration **Operation ID:** `agent_create` #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "name", "prompts", "provider" ], "properties": { "name": { "type": "string", "description": "Agent name" }, "description": { "type": "string", "description": "Agent description", "example": "An AI assistant for medical information processing" }, "prompts": { "type": "array", "items": { "type": "string" }, "description": "Array of prompt IDs to use for this agent", "example": [ "prompt_123", "prompt_456" ] }, "tools": { "type": "array", "items": { "type": "string" }, "description": "Array of MCP server tool IDs to use for this agent", "example": [ "mcp_server_123", "mcp_server_456" ] }, "workflows": { "type": "array", "items": { "type": "string" }, "description": "Array of workflow IDs to expose as tools for this agent", "example": [ "workflow_123", "workflow_456" ] }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Tags for categorizing the agent", "example": [ "medical", "fhir" ] }, "provider": { "oneOf": [ { "type": "string", "format": "uuid", "description": "Single FHIR provider ID" }, { "type": "array", "items": { "type": "string", "format": "uuid" }, "description": "Array of FHIR provider IDs" } ], "description": "FHIR provider ID(s) for this agent. Required.\nIn shared/experiment environments, the default sandbox provider is used if a different provider is not explicitly specified.\n", "example": "7002b0b4-8d09-445a-bf65-0fafdaf26c35" } } } ``` **Example:** ```json { "name": "Medical Assistant", "description": "An AI assistant for medical information processing", "prompts": [ "prompt_123" ], "provider": "7002b0b4-8d09-445a-bf65-0fafdaf26c35", "tags": [ "medical", "fhir" ] } ``` #### Responses **201** - Agent created successfully Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string" }, "data": { "type": "object", "properties": { "id": { "type": "string", "description": "Agent ID", "example": "agent_123" }, "name": { "type": "string", "description": "Agent name", "example": "Medical Assistant" }, "description": { "type": "string", "description": "Agent description", "example": "An AI assistant for medical information processing" }, "prompts": { "type": "array", "items": { "type": "string" }, "description": "Array of prompt IDs used by this agent", "example": [ "prompt_123", "prompt_456" ] }, "tools": { "type": "array", "items": { "type": "string" }, "description": "Array of MCP server tool IDs used by this agent", "example": [ "mcp_server_123", "mcp_server_456" ] }, "workflows": { "type": "array", "items": { "type": "string" }, "description": "Array of workflow IDs exposed as tools by this agent", "example": [ "workflow_123", "workflow_456" ] }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Tags for categorizing the agent", "example": [ "medical", "fhir" ] }, "provider": { "oneOf": [ { "type": "string", "format": "uuid", "description": "Single FHIR provider ID" }, { "type": "array", "items": { "type": "string", "format": "uuid" }, "description": "Array of FHIR provider IDs" } ], "description": "FHIR provider ID(s) - must be valid UUIDs from existing FHIR providers", "example": "7002b0b4-8d09-445a-bf65-0fafdaf26c35" } } } } } ``` **Example:** ```json { "success": true, "message": "Agent created successfully", "data": { "id": "agent_123", "name": "Medical Assistant", "description": "An AI assistant for medical information processing", "prompts": [ "prompt_123", "prompt_456" ], "tools": [ "mcp_server_123", "mcp_server_456" ], "workflows": [ "workflow_123", "workflow_456" ], "tags": [ "medical", "fhir" ], "provider": "7002b0b4-8d09-445a-bf65-0fafdaf26c35" } } ``` **400** - Invalid request **401** - Unauthorized **403** - Forbidden - access denied to the requested resource **500** - Server error --- ### GET /agent/list **List agents** Retrieves a list of PhenoAgents belonging to the authenticated user **Operation ID:** `agent_list` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `tags` | query | string | No | Filter by tags | #### Responses **200** - Agents retrieved successfully Content-Type: `application/json` ```json { "type": "object", "title": "ListResponse", "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string", "example": "Agents retrieved successfully" }, "agents": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Agent ID", "example": "agent_123" }, "name": { "type": "string", "description": "Agent name", "example": "Medical Assistant" }, "description": { "type": "string", "description": "Agent description", "example": "An AI assistant for medical information processing" }, "prompts": { "type": "array", "items": { "type": "string" }, "description": "Array of prompt IDs used by this agent", "example": [ "prompt_123", "prompt_456" ] }, "tools": { "type": "array", "items": { "type": "string" }, "description": "Array of MCP server tool IDs used by this agent", "example": [ "mcp_server_123", "mcp_server_456" ] }, "workflows": { "type": "array", "items": { "type": "string" }, "description": "Array of workflow IDs exposed as tools by this agent", "example": [ "workflow_123", "workflow_456" ] }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Tags for categorizing the agent", "example": [ "medical", "fhir" ] }, "provider": { "oneOf": [ { "type": "string", "format": "uuid", "description": "Single FHIR provider ID" }, { "type": "array", "items": { "type": "string", "format": "uuid" }, "description": "Array of FHIR provider IDs" } ], "description": "FHIR provider ID(s) - must be valid UUIDs from existing FHIR providers", "example": "7002b0b4-8d09-445a-bf65-0fafdaf26c35" } } } } } } ``` **Example:** ```json { "success": true, "message": "Agents retrieved successfully", "agents": [ { "id": "agent_123", "name": "Medical Assistant", "description": "An AI assistant for medical information processing", "prompts": [ "prompt_123" ], "tags": [ "medical", "fhir" ], "provider": [ "7002b0b4-8d09-445a-bf65-0fafdaf26c35" ] }, { "id": "agent_456", "name": "Clinical Coding Assistant", "description": "Helps with ICD-10 and SNOMED coding", "prompts": [ "prompt_456" ], "tags": [ "coding" ], "provider": [ "7002b0b4-8d09-445a-bf65-0fafdaf26c35" ] } ] } ``` **401** - Unauthorized **403** - Forbidden - access denied to the requested resource **500** - Server error --- # Workflow Create and execute clinical workflows. Define workflow logic and test execution with sample data. ## Endpoints ### GET /workflows **List all workflows** Retrieves all workflow definitions for the authenticated user **Operation ID:** `workflows_list` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `verbose` | query | boolean | No | If true, includes full workflow implementation details in workflow_details field | #### Responses **200** - Successfully retrieved workflows Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether the workflow list was retrieved successfully", "example": true }, "message": { "type": "string", "description": "Status message", "example": "Workflows retrieved successfully" }, "workflows": { "type": "array", "items": { "type": "object", "description": "Simplified workflow representation without implementation details", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier for the workflow", "example": "550e8400-e29b-41d4-a716-446655440001" }, "name": { "type": "string", "description": "Human-readable name for the workflow", "example": "Patient Data Mapping Workflow" }, "workflow_instructions": { "type": "string", "description": "Natural language instructions that define the workflow logic", "example": "Given diagnosis data, find the patient and create condition record" }, "sample_data": { "type": "object", "additionalProperties": true, "description": "Sample data used for workflow graph generation", "example": { "diagnosis_code": "I10", "diagnosis_date": "2025-01-01", "patient_first_name": "Clay", "patient_last_name": "Rippin" } }, "config": { "type": "object", "properties": { "fhir_provider_ids": { "type": "array", "items": { "type": "string", "format": "uuid" }, "description": "FHIR provider IDs for executing workflow steps", "example": [ "550e8400-e29b-41d4-a716-446655440000" ] }, "dynamic_generation": { "type": "boolean", "description": "Whether to use dynamic lang2fhir generation instead of pre-populated templates", "example": false } } }, "graph": { "type": "object", "properties": { "steps": { "type": "array", "items": { "type": "object", "description": "Simplified workflow step without implementation details", "properties": { "id": { "type": "string", "description": "Unique identifier for the step", "example": "step_1_id" }, "name": { "type": "string", "description": "Human-readable name for the step", "example": "Find Patient" }, "description": { "type": "string", "description": "Detailed description of what the step does", "example": "Search for an existing patient by first name and last name" }, "type": { "type": "string", "enum": [ "search", "create", "workflow", "decision_node" ], "description": "Type of operation this step performs", "example": "search" }, "provider_id": { "type": "string", "format": "uuid", "description": "Selected FHIR provider ID for this step", "example": "550e8400-e29b-41d4-a716-446655440000" } } }, "description": "Simplified list of workflow steps without operation details" } } }, "created_at": { "type": "string", "format": "date-time", "description": "Timestamp when the workflow was created", "example": "2024-01-15T10:30:00Z" }, "updated_at": { "type": "string", "format": "date-time", "description": "Timestamp when the workflow was last updated", "example": "2024-01-15T15:45:00Z" } } }, "description": "Array of simplified workflow responses for the authenticated user" }, "workflow_details": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier for the workflow", "example": "550e8400-e29b-41d4-a716-446655440001" }, "name": { "type": "string", "description": "Human-readable name for the workflow", "example": "Patient Data Mapping Workflow" }, "workflow_instructions": { "type": "string", "description": "Natural language instructions that define the workflow logic", "example": "Given diagnosis data, find the patient and create condition record" }, "sample_data": { "type": "object", "additionalProperties": true, "description": "Sample data used for workflow graph generation", "example": { "diagnosis_code": "I10", "diagnosis_date": "2025-01-01", "patient_first_name": "Clay", "patient_last_name": "Rippin" } }, "config": { "type": "object", "properties": { "fhir_provider_ids": { "type": "array", "items": { "type": "string", "format": "uuid" }, "description": "FHIR provider IDs for executing workflow steps", "example": [ "550e8400-e29b-41d4-a716-446655440000" ] }, "dynamic_generation": { "type": "boolean", "description": "Whether to use dynamic lang2fhir generation instead of pre-populated templates", "example": false } } }, "graph": { "type": "object", "properties": { "steps": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier for the step", "example": "1" }, "name": { "type": "string", "description": "Human-readable name for the step", "example": "Create Patient Resource" }, "description": { "type": "string", "description": "Detailed description of what the step does", "example": "Create a FHIR Patient resource from input data" }, "type": { "type": "string", "enum": [ "search", "create", "workflow", "decision_node" ], "description": "Type of operation this step performs", "example": "create" }, "operation": { "type": "object", "properties": { "search_definition": { "type": "object", "properties": { "original_query": { "type": "string", "description": "Original natural language query", "example": "find patient {{patient_first_name}} {{patient_last_name}} by first name and last name" }, "resource_type": { "type": "string", "description": "FHIR resource type to search", "example": "Patient" }, "search_parameters": { "type": "object", "additionalProperties": true, "description": "Prepared FHIR search parameters", "example": { "family": "{{patient_last_name}}", "given": "{{patient_first_name}}" } }, "required_fields": { "type": "array", "items": { "type": "string" }, "description": "Fields needed from search results", "example": [ "id", "name", "identifier" ] }, "runtime_placeholders": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Maps placeholder tokens to their input data paths", "example": { "{{patient_first_name}}": "input.patient_first_name", "{{patient_last_name}}": "input.patient_last_name" } } } }, "create_definition": { "type": "object", "properties": { "original_description": { "type": "string", "description": "Original natural language description", "example": "create condition with diagnosis code {{diagnosis_code}} and diagnosis date 2025-01-01" }, "resource_type": { "type": "string", "description": "FHIR resource type to create", "example": "Condition" }, "resource_template": { "type": "object", "additionalProperties": true, "description": "Prepared FHIR resource template", "example": { "resourceType": "Condition", "code": { "coding": [ { "code": "{{diagnosis_code}}", "system": "http://hl7.org/fhir/sid/icd-10" } ] }, "subject": { "reference": "Patient/{{step_1_id}}" } } }, "runtime_placeholders": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Maps placeholder tokens to their input data paths", "example": { "{{diagnosis_code}}": "input.diagnosis_code", "{{diagnosis_date}}": "input.diagnosis_date" } } } }, "workflow_definition": { "type": "object", "properties": { "workflow_id": { "type": "string", "format": "uuid", "description": "ID of the workflow to execute as a sub-workflow", "example": "550e8400-e29b-41d4-a716-446655440002" }, "input": { "type": "object", "additionalProperties": true, "description": "Input data to pass to the sub-workflow", "example": { "patient_id": "{{step_1_id}}", "additional_context": "laboratory_results" } }, "runtime_placeholders": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Maps placeholder tokens to their input data paths for sub-workflow", "example": { "{{step_1_id}}": "step_1.result.id", "{{patient_data}}": "input.patient_data" } } } }, "decision_definition": { "type": "object", "properties": { "expression": { "type": "string", "description": "Simple equality expression for decision logic", "example": "input.patient_age >= 18" }, "paths": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Maps decision outcomes to next step IDs", "example": { "true": "step_adult_workflow", "false": "step_pediatric_workflow", "default": "step_error_handler" } }, "runtime_placeholders": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Maps placeholder tokens to their input data paths for decision evaluation", "example": { "{{patient_age}}": "input.patient_age", "{{diagnosis_type}}": "step_2.result.diagnosis_category" } } } } } }, "provider_id": { "type": "string", "format": "uuid", "description": "Selected FHIR provider ID for this step", "example": "550e8400-e29b-41d4-a716-446655440000" }, "dependencies": { "type": "array", "items": { "type": "string" }, "description": "IDs of steps this step depends on", "example": [] }, "dynamic_generation": { "type": "boolean", "description": "Whether to use dynamic lang2fhir generation for this step", "example": false } } }, "description": "Ordered list of workflow execution steps" } } }, "created_at": { "type": "string", "format": "date-time", "description": "Timestamp when the workflow was created", "example": "2024-01-15T10:30:00Z" }, "updated_at": { "type": "string", "format": "date-time", "description": "Timestamp when the workflow was last updated", "example": "2024-01-15T15:45:00Z" } } }, "description": "Only included when verbose=true - contains full implementation details for all workflows" } } } ``` **Example:** ```json { "success": true, "message": "Workflows retrieved successfully", "workflows": [ { "id": "7a8b9c0d-1234-5678-abcd-ef9876543210", "name": "Patient Data Mapping Workflow", "workflow_instructions": "Given diagnosis data, find the patient and create a condition record", "sample_data": { "patient_last_name": "Rippin", "patient_first_name": "Clay", "diagnosis_code": "I10", "encounter_date": "2024-01-15" }, "config": { "fhir_provider_ids": [ "550e8400-e29b-41d4-a716-446655440000" ], "dynamic_generation": false }, "graph": { "steps": [ { "id": "step_1_id", "name": "Find Patient", "description": "Search for an existing patient by first name and last name", "type": "search", "provider_id": "550e8400-e29b-41d4-a716-446655440000" }, { "id": "step_2_id", "name": "Create Condition", "description": "Create a FHIR Condition resource for the patient", "type": "create", "provider_id": "550e8400-e29b-41d4-a716-446655440000" } ] }, "created_at": "2024-01-15T09:30:00Z", "updated_at": "2024-01-15T09:30:00Z" } ] } ``` **401** - Unauthorized **403** - Forbidden - access denied to the requested workflow **500** - Server error --- ### POST /workflows **Create new workflow** Creates a new workflow definition with graph generation from workflow instructions **Operation ID:** `workflows_create` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `verbose` | query | boolean | No | If true, includes full workflow implementation details in workflow_details field | #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "name", "workflow_instructions", "sample_data", "fhir_provider_id" ], "properties": { "name": { "type": "string", "description": "Human-readable name for the workflow", "example": "Patient Data Mapping Workflow" }, "workflow_instructions": { "type": "string", "description": "Natural language instructions that define the workflow logic", "example": "Given diagnosis data, find the patient and create condition record" }, "sample_data": { "type": "object", "additionalProperties": true, "description": "Sample data to use for workflow graph generation", "example": { "patient_last_name": "Rippin", "patient_first_name": "Clay", "diagnosis_code": "I10" } }, "fhir_provider_id": { "oneOf": [ { "type": "string", "format": "uuid", "description": "Single FHIR provider ID", "example": "550e8400-e29b-41d4-a716-446655440000" }, { "type": "array", "items": { "type": "string", "format": "uuid" }, "description": "Multiple FHIR provider IDs", "example": [ "550e8400-e29b-41d4-a716-446655440000", "550e8400-e29b-41d4-a716-446655440001" ] } ], "description": "FHIR provider ID(s) - must be valid UUID(s) from existing FHIR providers" }, "dynamic_generation": { "type": "boolean", "description": "Enable dynamic lang2fhir calls instead of pre-populated templates", "example": false } } } ``` **Example:** ```json { "name": "Patient Data Mapping Workflow", "workflow_instructions": "Given diagnosis data, find the patient and create a condition record linked to their encounter", "sample_data": { "patient_last_name": "Rippin", "patient_first_name": "Clay", "diagnosis_code": "I10", "encounter_date": "2024-01-15" }, "fhir_provider_id": "550e8400-e29b-41d4-a716-446655440000" } ``` #### Responses **200** - Successfully created workflow Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether the workflow was created successfully", "example": true }, "message": { "type": "string", "description": "Status message", "example": "Workflow created successfully" }, "workflow_id": { "type": "string", "format": "uuid", "description": "ID of the created workflow", "example": "550e8400-e29b-41d4-a716-446655440001" }, "workflow": { "type": "object", "description": "Simplified workflow representation without implementation details", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier for the workflow", "example": "550e8400-e29b-41d4-a716-446655440001" }, "name": { "type": "string", "description": "Human-readable name for the workflow", "example": "Patient Data Mapping Workflow" }, "workflow_instructions": { "type": "string", "description": "Natural language instructions that define the workflow logic", "example": "Given diagnosis data, find the patient and create condition record" }, "sample_data": { "type": "object", "additionalProperties": true, "description": "Sample data used for workflow graph generation", "example": { "diagnosis_code": "I10", "diagnosis_date": "2025-01-01", "patient_first_name": "Clay", "patient_last_name": "Rippin" } }, "config": { "type": "object", "properties": { "fhir_provider_ids": { "type": "array", "items": { "type": "string", "format": "uuid" }, "description": "FHIR provider IDs for executing workflow steps", "example": [ "550e8400-e29b-41d4-a716-446655440000" ] }, "dynamic_generation": { "type": "boolean", "description": "Whether to use dynamic lang2fhir generation instead of pre-populated templates", "example": false } } }, "graph": { "type": "object", "properties": { "steps": { "type": "array", "items": { "type": "object", "description": "Simplified workflow step without implementation details", "properties": { "id": { "type": "string", "description": "Unique identifier for the step", "example": "step_1_id" }, "name": { "type": "string", "description": "Human-readable name for the step", "example": "Find Patient" }, "description": { "type": "string", "description": "Detailed description of what the step does", "example": "Search for an existing patient by first name and last name" }, "type": { "type": "string", "enum": [ "search", "create", "workflow", "decision_node" ], "description": "Type of operation this step performs", "example": "search" }, "provider_id": { "type": "string", "format": "uuid", "description": "Selected FHIR provider ID for this step", "example": "550e8400-e29b-41d4-a716-446655440000" } } }, "description": "Simplified list of workflow steps without operation details" } } }, "created_at": { "type": "string", "format": "date-time", "description": "Timestamp when the workflow was created", "example": "2024-01-15T10:30:00Z" }, "updated_at": { "type": "string", "format": "date-time", "description": "Timestamp when the workflow was last updated", "example": "2024-01-15T15:45:00Z" } } }, "workflow_details": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier for the workflow", "example": "550e8400-e29b-41d4-a716-446655440001" }, "name": { "type": "string", "description": "Human-readable name for the workflow", "example": "Patient Data Mapping Workflow" }, "workflow_instructions": { "type": "string", "description": "Natural language instructions that define the workflow logic", "example": "Given diagnosis data, find the patient and create condition record" }, "sample_data": { "type": "object", "additionalProperties": true, "description": "Sample data used for workflow graph generation", "example": { "diagnosis_code": "I10", "diagnosis_date": "2025-01-01", "patient_first_name": "Clay", "patient_last_name": "Rippin" } }, "config": { "type": "object", "properties": { "fhir_provider_ids": { "type": "array", "items": { "type": "string", "format": "uuid" }, "description": "FHIR provider IDs for executing workflow steps", "example": [ "550e8400-e29b-41d4-a716-446655440000" ] }, "dynamic_generation": { "type": "boolean", "description": "Whether to use dynamic lang2fhir generation instead of pre-populated templates", "example": false } } }, "graph": { "type": "object", "properties": { "steps": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier for the step", "example": "1" }, "name": { "type": "string", "description": "Human-readable name for the step", "example": "Create Patient Resource" }, "description": { "type": "string", "description": "Detailed description of what the step does", "example": "Create a FHIR Patient resource from input data" }, "type": { "type": "string", "enum": [ "search", "create", "workflow", "decision_node" ], "description": "Type of operation this step performs", "example": "create" }, "operation": { "type": "object", "properties": { "search_definition": { "type": "object", "properties": { "original_query": { "type": "string", "description": "Original natural language query", "example": "find patient {{patient_first_name}} {{patient_last_name}} by first name and last name" }, "resource_type": { "type": "string", "description": "FHIR resource type to search", "example": "Patient" }, "search_parameters": { "type": "object", "additionalProperties": true, "description": "Prepared FHIR search parameters", "example": { "family": "{{patient_last_name}}", "given": "{{patient_first_name}}" } }, "required_fields": { "type": "array", "items": { "type": "string" }, "description": "Fields needed from search results", "example": [ "id", "name", "identifier" ] }, "runtime_placeholders": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Maps placeholder tokens to their input data paths", "example": { "{{patient_first_name}}": "input.patient_first_name", "{{patient_last_name}}": "input.patient_last_name" } } } }, "create_definition": { "type": "object", "properties": { "original_description": { "type": "string", "description": "Original natural language description", "example": "create condition with diagnosis code {{diagnosis_code}} and diagnosis date 2025-01-01" }, "resource_type": { "type": "string", "description": "FHIR resource type to create", "example": "Condition" }, "resource_template": { "type": "object", "additionalProperties": true, "description": "Prepared FHIR resource template", "example": { "resourceType": "Condition", "code": { "coding": [ { "code": "{{diagnosis_code}}", "system": "http://hl7.org/fhir/sid/icd-10" } ] }, "subject": { "reference": "Patient/{{step_1_id}}" } } }, "runtime_placeholders": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Maps placeholder tokens to their input data paths", "example": { "{{diagnosis_code}}": "input.diagnosis_code", "{{diagnosis_date}}": "input.diagnosis_date" } } } }, "workflow_definition": { "type": "object", "properties": { "workflow_id": { "type": "string", "format": "uuid", "description": "ID of the workflow to execute as a sub-workflow", "example": "550e8400-e29b-41d4-a716-446655440002" }, "input": { "type": "object", "additionalProperties": true, "description": "Input data to pass to the sub-workflow", "example": { "patient_id": "{{step_1_id}}", "additional_context": "laboratory_results" } }, "runtime_placeholders": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Maps placeholder tokens to their input data paths for sub-workflow", "example": { "{{step_1_id}}": "step_1.result.id", "{{patient_data}}": "input.patient_data" } } } }, "decision_definition": { "type": "object", "properties": { "expression": { "type": "string", "description": "Simple equality expression for decision logic", "example": "input.patient_age >= 18" }, "paths": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Maps decision outcomes to next step IDs", "example": { "true": "step_adult_workflow", "false": "step_pediatric_workflow", "default": "step_error_handler" } }, "runtime_placeholders": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Maps placeholder tokens to their input data paths for decision evaluation", "example": { "{{patient_age}}": "input.patient_age", "{{diagnosis_type}}": "step_2.result.diagnosis_category" } } } } } }, "provider_id": { "type": "string", "format": "uuid", "description": "Selected FHIR provider ID for this step", "example": "550e8400-e29b-41d4-a716-446655440000" }, "dependencies": { "type": "array", "items": { "type": "string" }, "description": "IDs of steps this step depends on", "example": [] }, "dynamic_generation": { "type": "boolean", "description": "Whether to use dynamic lang2fhir generation for this step", "example": false } } }, "description": "Ordered list of workflow execution steps" } } }, "created_at": { "type": "string", "format": "date-time", "description": "Timestamp when the workflow was created", "example": "2024-01-15T10:30:00Z" }, "updated_at": { "type": "string", "format": "date-time", "description": "Timestamp when the workflow was last updated", "example": "2024-01-15T15:45:00Z" } }, "description": "Only included when verbose=true - contains full implementation details including operation definitions and placeholders" } } } ``` **Example:** ```json { "success": true, "message": "Workflow created successfully", "workflow_id": "7a8b9c0d-1234-5678-abcd-ef9876543210", "workflow": { "id": "7a8b9c0d-1234-5678-abcd-ef9876543210", "name": "Patient Data Mapping Workflow", "workflow_instructions": "Given diagnosis data, find the patient and create a condition record linked to their encounter", "sample_data": { "patient_last_name": "Rippin", "patient_first_name": "Clay", "diagnosis_code": "I10", "encounter_date": "2024-01-15" }, "created_at": "2024-01-15T09:30:00Z", "updated_at": "2024-01-15T09:30:00Z" } } ``` **400** - Invalid request **401** - Unauthorized **403** - Forbidden - access denied to the requested workflow **500** - Server error --- ### GET /workflows/{id} **Get workflow by ID** Retrieves a workflow definition by its ID **Operation ID:** `workflows_get` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `id` | path | string (uuid) | Yes | ID of the workflow to retrieve | | `verbose` | query | boolean | No | If true, includes full workflow implementation details in workflow_details field | #### Responses **200** - Successfully retrieved workflow Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "example": true }, "workflow": { "type": "object", "description": "Simplified workflow representation without implementation details", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier for the workflow", "example": "550e8400-e29b-41d4-a716-446655440001" }, "name": { "type": "string", "description": "Human-readable name for the workflow", "example": "Patient Data Mapping Workflow" }, "workflow_instructions": { "type": "string", "description": "Natural language instructions that define the workflow logic", "example": "Given diagnosis data, find the patient and create condition record" }, "sample_data": { "type": "object", "additionalProperties": true, "description": "Sample data used for workflow graph generation", "example": { "diagnosis_code": "I10", "diagnosis_date": "2025-01-01", "patient_first_name": "Clay", "patient_last_name": "Rippin" } }, "config": { "type": "object", "properties": { "fhir_provider_ids": { "type": "array", "items": { "type": "string", "format": "uuid" }, "description": "FHIR provider IDs for executing workflow steps", "example": [ "550e8400-e29b-41d4-a716-446655440000" ] }, "dynamic_generation": { "type": "boolean", "description": "Whether to use dynamic lang2fhir generation instead of pre-populated templates", "example": false } } }, "graph": { "type": "object", "properties": { "steps": { "type": "array", "items": { "type": "object", "description": "Simplified workflow step without implementation details", "properties": { "id": { "type": "string", "description": "Unique identifier for the step", "example": "step_1_id" }, "name": { "type": "string", "description": "Human-readable name for the step", "example": "Find Patient" }, "description": { "type": "string", "description": "Detailed description of what the step does", "example": "Search for an existing patient by first name and last name" }, "type": { "type": "string", "enum": [ "search", "create", "workflow", "decision_node" ], "description": "Type of operation this step performs", "example": "search" }, "provider_id": { "type": "string", "format": "uuid", "description": "Selected FHIR provider ID for this step", "example": "550e8400-e29b-41d4-a716-446655440000" } } }, "description": "Simplified list of workflow steps without operation details" } } }, "created_at": { "type": "string", "format": "date-time", "description": "Timestamp when the workflow was created", "example": "2024-01-15T10:30:00Z" }, "updated_at": { "type": "string", "format": "date-time", "description": "Timestamp when the workflow was last updated", "example": "2024-01-15T15:45:00Z" } } }, "workflow_details": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier for the workflow", "example": "550e8400-e29b-41d4-a716-446655440001" }, "name": { "type": "string", "description": "Human-readable name for the workflow", "example": "Patient Data Mapping Workflow" }, "workflow_instructions": { "type": "string", "description": "Natural language instructions that define the workflow logic", "example": "Given diagnosis data, find the patient and create condition record" }, "sample_data": { "type": "object", "additionalProperties": true, "description": "Sample data used for workflow graph generation", "example": { "diagnosis_code": "I10", "diagnosis_date": "2025-01-01", "patient_first_name": "Clay", "patient_last_name": "Rippin" } }, "config": { "type": "object", "properties": { "fhir_provider_ids": { "type": "array", "items": { "type": "string", "format": "uuid" }, "description": "FHIR provider IDs for executing workflow steps", "example": [ "550e8400-e29b-41d4-a716-446655440000" ] }, "dynamic_generation": { "type": "boolean", "description": "Whether to use dynamic lang2fhir generation instead of pre-populated templates", "example": false } } }, "graph": { "type": "object", "properties": { "steps": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier for the step", "example": "1" }, "name": { "type": "string", "description": "Human-readable name for the step", "example": "Create Patient Resource" }, "description": { "type": "string", "description": "Detailed description of what the step does", "example": "Create a FHIR Patient resource from input data" }, "type": { "type": "string", "enum": [ "search", "create", "workflow", "decision_node" ], "description": "Type of operation this step performs", "example": "create" }, "operation": { "type": "object", "properties": { "search_definition": { "type": "object", "properties": { "original_query": { "type": "string", "description": "Original natural language query", "example": "find patient {{patient_first_name}} {{patient_last_name}} by first name and last name" }, "resource_type": { "type": "string", "description": "FHIR resource type to search", "example": "Patient" }, "search_parameters": { "type": "object", "additionalProperties": true, "description": "Prepared FHIR search parameters", "example": { "family": "{{patient_last_name}}", "given": "{{patient_first_name}}" } }, "required_fields": { "type": "array", "items": { "type": "string" }, "description": "Fields needed from search results", "example": [ "id", "name", "identifier" ] }, "runtime_placeholders": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Maps placeholder tokens to their input data paths", "example": { "{{patient_first_name}}": "input.patient_first_name", "{{patient_last_name}}": "input.patient_last_name" } } } }, "create_definition": { "type": "object", "properties": { "original_description": { "type": "string", "description": "Original natural language description", "example": "create condition with diagnosis code {{diagnosis_code}} and diagnosis date 2025-01-01" }, "resource_type": { "type": "string", "description": "FHIR resource type to create", "example": "Condition" }, "resource_template": { "type": "object", "additionalProperties": true, "description": "Prepared FHIR resource template", "example": { "resourceType": "Condition", "code": { "coding": [ { "code": "{{diagnosis_code}}", "system": "http://hl7.org/fhir/sid/icd-10" } ] }, "subject": { "reference": "Patient/{{step_1_id}}" } } }, "runtime_placeholders": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Maps placeholder tokens to their input data paths", "example": { "{{diagnosis_code}}": "input.diagnosis_code", "{{diagnosis_date}}": "input.diagnosis_date" } } } }, "workflow_definition": { "type": "object", "properties": { "workflow_id": { "type": "string", "format": "uuid", "description": "ID of the workflow to execute as a sub-workflow", "example": "550e8400-e29b-41d4-a716-446655440002" }, "input": { "type": "object", "additionalProperties": true, "description": "Input data to pass to the sub-workflow", "example": { "patient_id": "{{step_1_id}}", "additional_context": "laboratory_results" } }, "runtime_placeholders": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Maps placeholder tokens to their input data paths for sub-workflow", "example": { "{{step_1_id}}": "step_1.result.id", "{{patient_data}}": "input.patient_data" } } } }, "decision_definition": { "type": "object", "properties": { "expression": { "type": "string", "description": "Simple equality expression for decision logic", "example": "input.patient_age >= 18" }, "paths": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Maps decision outcomes to next step IDs", "example": { "true": "step_adult_workflow", "false": "step_pediatric_workflow", "default": "step_error_handler" } }, "runtime_placeholders": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Maps placeholder tokens to their input data paths for decision evaluation", "example": { "{{patient_age}}": "input.patient_age", "{{diagnosis_type}}": "step_2.result.diagnosis_category" } } } } } }, "provider_id": { "type": "string", "format": "uuid", "description": "Selected FHIR provider ID for this step", "example": "550e8400-e29b-41d4-a716-446655440000" }, "dependencies": { "type": "array", "items": { "type": "string" }, "description": "IDs of steps this step depends on", "example": [] }, "dynamic_generation": { "type": "boolean", "description": "Whether to use dynamic lang2fhir generation for this step", "example": false } } }, "description": "Ordered list of workflow execution steps" } } }, "created_at": { "type": "string", "format": "date-time", "description": "Timestamp when the workflow was created", "example": "2024-01-15T10:30:00Z" }, "updated_at": { "type": "string", "format": "date-time", "description": "Timestamp when the workflow was last updated", "example": "2024-01-15T15:45:00Z" } }, "description": "Only included when verbose=true - contains full implementation details" } } } ``` **Example:** ```json { "success": true, "workflow": { "id": "7a8b9c0d-1234-5678-abcd-ef9876543210", "name": "Patient Data Mapping Workflow", "workflow_instructions": "Given diagnosis data, find the patient and create a condition record", "sample_data": { "patient_last_name": "Rippin", "patient_first_name": "Clay", "diagnosis_code": "I10", "encounter_date": "2024-01-15" }, "config": { "fhir_provider_ids": [ "550e8400-e29b-41d4-a716-446655440000" ], "dynamic_generation": false }, "graph": { "steps": [ { "id": "step_1_id", "name": "Find Patient", "description": "Search for an existing patient by first name and last name", "type": "search", "provider_id": "550e8400-e29b-41d4-a716-446655440000" }, { "id": "step_2_id", "name": "Create Condition", "description": "Create a FHIR Condition resource for the patient", "type": "create", "provider_id": "550e8400-e29b-41d4-a716-446655440000" } ] }, "created_at": "2024-01-15T09:30:00Z", "updated_at": "2024-01-15T09:30:00Z" } } ``` **401** - Unauthorized **403** - Forbidden - access denied to the requested workflow **404** - Workflow not found **500** - Server error **504** - Request timed out --- ### PUT /workflows/{id} **Update workflow** Updates an existing workflow definition **Operation ID:** `workflows_update` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `id` | path | string (uuid) | Yes | ID of the workflow to update | | `verbose` | query | boolean | No | If true, includes full workflow implementation details in workflow_details field | #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "name", "workflow_instructions", "sample_data", "fhir_provider_id" ], "properties": { "name": { "type": "string", "description": "Human-readable name for the workflow", "example": "Updated Patient Data Mapping Workflow" }, "workflow_instructions": { "type": "string", "description": "Natural language instructions that define the workflow logic", "example": "Given diagnosis data, find the patient and create condition record" }, "sample_data": { "type": "object", "additionalProperties": true, "description": "Sample data to use for workflow graph generation", "example": { "patient_last_name": "Smith", "patient_first_name": "John", "diagnosis_code": "E11" } }, "fhir_provider_id": { "oneOf": [ { "type": "string", "format": "uuid", "description": "Single FHIR provider ID", "example": "550e8400-e29b-41d4-a716-446655440000" }, { "type": "array", "items": { "type": "string", "format": "uuid" }, "description": "Multiple FHIR provider IDs", "example": [ "550e8400-e29b-41d4-a716-446655440000", "550e8400-e29b-41d4-a716-446655440001" ] } ], "description": "FHIR provider ID(s) - must be valid UUID(s) from existing FHIR providers" }, "dynamic_generation": { "type": "boolean", "description": "Enable dynamic lang2fhir calls instead of pre-populated templates", "example": false } } } ``` **Example:** ```json { "name": "Patient Data Mapping Workflow (v2)", "workflow_instructions": "Given diagnosis data, find the patient and create a condition record linked to their encounter", "sample_data": { "patient_last_name": "Rippin", "patient_first_name": "Clay", "diagnosis_code": "I10", "encounter_date": "2024-01-15" }, "fhir_provider_id": "550e8400-e29b-41d4-a716-446655440000" } ``` #### Responses **200** - Successfully updated workflow Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string", "example": "Workflow updated successfully" }, "workflow": { "type": "object", "description": "Simplified workflow representation without implementation details", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier for the workflow", "example": "550e8400-e29b-41d4-a716-446655440001" }, "name": { "type": "string", "description": "Human-readable name for the workflow", "example": "Patient Data Mapping Workflow" }, "workflow_instructions": { "type": "string", "description": "Natural language instructions that define the workflow logic", "example": "Given diagnosis data, find the patient and create condition record" }, "sample_data": { "type": "object", "additionalProperties": true, "description": "Sample data used for workflow graph generation", "example": { "diagnosis_code": "I10", "diagnosis_date": "2025-01-01", "patient_first_name": "Clay", "patient_last_name": "Rippin" } }, "config": { "type": "object", "properties": { "fhir_provider_ids": { "type": "array", "items": { "type": "string", "format": "uuid" }, "description": "FHIR provider IDs for executing workflow steps", "example": [ "550e8400-e29b-41d4-a716-446655440000" ] }, "dynamic_generation": { "type": "boolean", "description": "Whether to use dynamic lang2fhir generation instead of pre-populated templates", "example": false } } }, "graph": { "type": "object", "properties": { "steps": { "type": "array", "items": { "type": "object", "description": "Simplified workflow step without implementation details", "properties": { "id": { "type": "string", "description": "Unique identifier for the step", "example": "step_1_id" }, "name": { "type": "string", "description": "Human-readable name for the step", "example": "Find Patient" }, "description": { "type": "string", "description": "Detailed description of what the step does", "example": "Search for an existing patient by first name and last name" }, "type": { "type": "string", "enum": [ "search", "create", "workflow", "decision_node" ], "description": "Type of operation this step performs", "example": "search" }, "provider_id": { "type": "string", "format": "uuid", "description": "Selected FHIR provider ID for this step", "example": "550e8400-e29b-41d4-a716-446655440000" } } }, "description": "Simplified list of workflow steps without operation details" } } }, "created_at": { "type": "string", "format": "date-time", "description": "Timestamp when the workflow was created", "example": "2024-01-15T10:30:00Z" }, "updated_at": { "type": "string", "format": "date-time", "description": "Timestamp when the workflow was last updated", "example": "2024-01-15T15:45:00Z" } } }, "workflow_details": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier for the workflow", "example": "550e8400-e29b-41d4-a716-446655440001" }, "name": { "type": "string", "description": "Human-readable name for the workflow", "example": "Patient Data Mapping Workflow" }, "workflow_instructions": { "type": "string", "description": "Natural language instructions that define the workflow logic", "example": "Given diagnosis data, find the patient and create condition record" }, "sample_data": { "type": "object", "additionalProperties": true, "description": "Sample data used for workflow graph generation", "example": { "diagnosis_code": "I10", "diagnosis_date": "2025-01-01", "patient_first_name": "Clay", "patient_last_name": "Rippin" } }, "config": { "type": "object", "properties": { "fhir_provider_ids": { "type": "array", "items": { "type": "string", "format": "uuid" }, "description": "FHIR provider IDs for executing workflow steps", "example": [ "550e8400-e29b-41d4-a716-446655440000" ] }, "dynamic_generation": { "type": "boolean", "description": "Whether to use dynamic lang2fhir generation instead of pre-populated templates", "example": false } } }, "graph": { "type": "object", "properties": { "steps": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier for the step", "example": "1" }, "name": { "type": "string", "description": "Human-readable name for the step", "example": "Create Patient Resource" }, "description": { "type": "string", "description": "Detailed description of what the step does", "example": "Create a FHIR Patient resource from input data" }, "type": { "type": "string", "enum": [ "search", "create", "workflow", "decision_node" ], "description": "Type of operation this step performs", "example": "create" }, "operation": { "type": "object", "properties": { "search_definition": { "type": "object", "properties": { "original_query": { "type": "string", "description": "Original natural language query", "example": "find patient {{patient_first_name}} {{patient_last_name}} by first name and last name" }, "resource_type": { "type": "string", "description": "FHIR resource type to search", "example": "Patient" }, "search_parameters": { "type": "object", "additionalProperties": true, "description": "Prepared FHIR search parameters", "example": { "family": "{{patient_last_name}}", "given": "{{patient_first_name}}" } }, "required_fields": { "type": "array", "items": { "type": "string" }, "description": "Fields needed from search results", "example": [ "id", "name", "identifier" ] }, "runtime_placeholders": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Maps placeholder tokens to their input data paths", "example": { "{{patient_first_name}}": "input.patient_first_name", "{{patient_last_name}}": "input.patient_last_name" } } } }, "create_definition": { "type": "object", "properties": { "original_description": { "type": "string", "description": "Original natural language description", "example": "create condition with diagnosis code {{diagnosis_code}} and diagnosis date 2025-01-01" }, "resource_type": { "type": "string", "description": "FHIR resource type to create", "example": "Condition" }, "resource_template": { "type": "object", "additionalProperties": true, "description": "Prepared FHIR resource template", "example": { "resourceType": "Condition", "code": { "coding": [ { "code": "{{diagnosis_code}}", "system": "http://hl7.org/fhir/sid/icd-10" } ] }, "subject": { "reference": "Patient/{{step_1_id}}" } } }, "runtime_placeholders": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Maps placeholder tokens to their input data paths", "example": { "{{diagnosis_code}}": "input.diagnosis_code", "{{diagnosis_date}}": "input.diagnosis_date" } } } }, "workflow_definition": { "type": "object", "properties": { "workflow_id": { "type": "string", "format": "uuid", "description": "ID of the workflow to execute as a sub-workflow", "example": "550e8400-e29b-41d4-a716-446655440002" }, "input": { "type": "object", "additionalProperties": true, "description": "Input data to pass to the sub-workflow", "example": { "patient_id": "{{step_1_id}}", "additional_context": "laboratory_results" } }, "runtime_placeholders": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Maps placeholder tokens to their input data paths for sub-workflow", "example": { "{{step_1_id}}": "step_1.result.id", "{{patient_data}}": "input.patient_data" } } } }, "decision_definition": { "type": "object", "properties": { "expression": { "type": "string", "description": "Simple equality expression for decision logic", "example": "input.patient_age >= 18" }, "paths": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Maps decision outcomes to next step IDs", "example": { "true": "step_adult_workflow", "false": "step_pediatric_workflow", "default": "step_error_handler" } }, "runtime_placeholders": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Maps placeholder tokens to their input data paths for decision evaluation", "example": { "{{patient_age}}": "input.patient_age", "{{diagnosis_type}}": "step_2.result.diagnosis_category" } } } } } }, "provider_id": { "type": "string", "format": "uuid", "description": "Selected FHIR provider ID for this step", "example": "550e8400-e29b-41d4-a716-446655440000" }, "dependencies": { "type": "array", "items": { "type": "string" }, "description": "IDs of steps this step depends on", "example": [] }, "dynamic_generation": { "type": "boolean", "description": "Whether to use dynamic lang2fhir generation for this step", "example": false } } }, "description": "Ordered list of workflow execution steps" } } }, "created_at": { "type": "string", "format": "date-time", "description": "Timestamp when the workflow was created", "example": "2024-01-15T10:30:00Z" }, "updated_at": { "type": "string", "format": "date-time", "description": "Timestamp when the workflow was last updated", "example": "2024-01-15T15:45:00Z" } }, "description": "Only included when verbose=true - contains full implementation details" } } } ``` **Example:** ```json { "success": true, "message": "Workflow updated successfully", "workflow": { "id": "7a8b9c0d-1234-5678-abcd-ef9876543210", "name": "Patient Data Mapping Workflow (v2)", "workflow_instructions": "Given diagnosis data, find the patient and create a condition record linked to their encounter", "sample_data": { "patient_last_name": "Rippin", "patient_first_name": "Clay", "diagnosis_code": "I10", "encounter_date": "2024-01-15" }, "config": { "fhir_provider_ids": [ "550e8400-e29b-41d4-a716-446655440000" ], "dynamic_generation": false }, "graph": { "steps": [ { "id": "step_1_id", "name": "Find Patient", "description": "Search for an existing patient by first name and last name", "type": "search", "provider_id": "550e8400-e29b-41d4-a716-446655440000" } ] }, "created_at": "2024-01-15T09:30:00Z", "updated_at": "2024-02-20T11:00:00Z" } } ``` **400** - Invalid request **401** - Unauthorized **403** - Forbidden - access denied to the requested workflow **404** - Workflow not found **500** - Server error **504** - Request timed out --- ### DELETE /workflows/{id} **Delete workflow** Deletes a workflow definition by its ID **Operation ID:** `workflows_delete` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `id` | path | string (uuid) | Yes | ID of the workflow to delete | #### Responses **200** - Successfully deleted workflow Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string", "example": "Workflow deleted successfully" } } } ``` **Example:** ```json { "success": true, "message": "Workflow deleted successfully" } ``` **401** - Unauthorized **403** - Forbidden - access denied to the requested workflow **404** - Workflow not found **500** - Server error **504** - Request timed out --- ### POST /workflows/{id}/execute **Execute workflow** Executes a workflow with provided input data and returns results **Operation ID:** `workflows_execute` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `id` | path | string (uuid) | Yes | ID of the workflow to execute | #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "input_data" ], "properties": { "input_data": { "type": "object", "additionalProperties": true, "description": "Input data for workflow execution", "example": { "patient_last_name": "Johnson", "patient_first_name": "Mary", "diagnosis_code": "M79.3", "encounter_date": "2024-01-15" } }, "preview": { "type": "boolean", "description": "If true, create operations return mock resources instead of persisting to the FHIR server", "default": false, "example": false } } } ``` **Example:** ```json { "input_data": { "patient_last_name": "Johnson", "patient_first_name": "Mary", "diagnosis_code": "M79.3", "encounter_date": "2024-03-20" } } ``` #### Responses **200** - Successfully executed workflow Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether the workflow execution was successful", "example": true }, "message": { "type": "string", "description": "Status message with execution details", "example": "Workflow executed successfully" }, "results": { "type": "object", "properties": { "steps": { "type": "object", "additionalProperties": true, "description": "Results for each executed workflow step, keyed by step ID" } } }, "preview": { "type": "boolean", "description": "Whether the workflow was executed in preview mode", "example": false } } } ``` **Example:** ```json { "success": true, "message": "Workflow executed successfully", "results": { "steps": { "step_1_id": { "type": "search_result", "original_query": "find patient by first name Mary and last name Johnson", "resource_type": "Patient", "search_params": { "family": "Johnson", "given": "Mary" }, "results": [ { "resourceType": "Patient", "id": "patient-123", "name": [ { "family": "Johnson", "given": [ "Mary" ], "use": "usual" } ], "gender": "female", "birthDate": "1961-01-01" } ] }, "step_2_id": { "type": "create_result", "id": "condition-456", "resource_type": "Condition", "original_desc": "create condition with diagnosis code M79.3 for the patient from step_1_id", "preview": false, "created_resource": { "resourceType": "Condition", "id": "condition-456", "clinicalStatus": { "coding": [ { "system": "http://terminology.hl7.org/CodeSystem/condition-clinical", "code": "active" } ] }, "code": { "coding": [ { "system": "http://hl7.org/fhir/sid/icd-10", "code": "M79.3", "display": "Panniculitis, unspecified" } ] }, "subject": { "reference": "Patient/patient-123" } } } } }, "preview": false } ``` **400** - Invalid request **401** - Unauthorized **403** - Forbidden - access denied to the requested workflow **404** - Workflow not found **500** - Server error **504** - Workflow execution exceeded the server-side time budget --- # Authentication Manage API credentials, generate authentication tokens, and handle authorization. ## Endpoints ### POST /auth/token **Generate authentication token** Generates a JWT token using Basic Authentication with API credential client ID and secret. **Operation ID:** `authtoken_getLegacyToken` #### Responses **200** - Successfully generated token Content-Type: `application/json` ```json { "type": "object", "properties": { "token": { "type": "string", "description": "JWT token to be used for subsequent authenticated requests" } }, "required": [ "token" ] } ``` **401** - Unauthorized - Invalid credentials Content-Type: `application/json` ```json { "type": "object", "properties": { "code": { "type": "integer", "example": 401 }, "message": { "type": "string", "example": "Invalid credentials" }, "data": { "type": "object", "nullable": true } } } ``` --- ### POST /v2/auth/token **Request an access token** OAuth 2.0 client credentials token endpoint (RFC 6749 §4.4). Accepts client_id and client_secret in the request body (JSON or form-encoded) or via Basic Auth header (RFC 6749 §2.3.1), and returns an access token with expiration information. **Operation ID:** `authtoken_getToken` #### Request Body **Required:** No **Content-Type:** `application/json` ```json { "type": "object", "description": "When using body credentials, both client_id and client_secret are required. When using Basic Auth, the body may contain only grant_type.\n", "properties": { "grant_type": { "type": "string", "description": "Must be \"client_credentials\" if provided", "example": "client_credentials" }, "client_id": { "type": "string", "description": "The client ID (credential username)" }, "client_secret": { "type": "string", "description": "The client secret (credential password)" } } } ``` **Example:** ```json { "client_id": "your_client_id", "client_secret": "your_client_secret" } ``` **Content-Type:** `application/x-www-form-urlencoded` ```json { "type": "object", "description": "When using body credentials, both client_id and client_secret are required. When using Basic Auth, the body may contain only grant_type.\n", "properties": { "grant_type": { "type": "string", "description": "Must be \"client_credentials\" if provided", "example": "client_credentials" }, "client_id": { "type": "string", "description": "The client ID (credential username)" }, "client_secret": { "type": "string", "description": "The client secret (credential password)" } } } ``` #### Responses **200** - Successfully generated token Content-Type: `application/json` ```json { "type": "object", "properties": { "access_token": { "type": "string", "description": "JWT access token for subsequent authenticated requests" }, "token_type": { "type": "string", "description": "Token type (always \"Bearer\")", "example": "Bearer" }, "expires_in": { "type": "integer", "description": "Token lifetime in seconds", "example": 172800 } }, "required": [ "access_token", "token_type", "expires_in" ] } ``` **Example:** ```json { "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "Bearer", "expires_in": 172800 } ``` **400** - Bad Request - Missing client credentials or unsupported grant type Content-Type: `application/json` ```json { "type": "object", "description": "OAuth 2.0 error response (RFC 6749 §5.2)", "properties": { "error": { "type": "string", "description": "Error code", "enum": [ "invalid_request", "invalid_client", "unsupported_grant_type", "server_error" ] }, "error_description": { "type": "string", "description": "Human-readable error description" } }, "required": [ "error" ] } ``` **401** - Unauthorized - Invalid client credentials Content-Type: `application/json` ```json { "type": "object", "description": "OAuth 2.0 error response (RFC 6749 §5.2)", "properties": { "error": { "type": "string", "description": "Error code", "enum": [ "invalid_request", "invalid_client", "unsupported_grant_type", "server_error" ] }, "error_description": { "type": "string", "description": "Human-readable error description" } }, "required": [ "error" ] } ``` **500** - Internal Server Error - Authentication service unavailable Content-Type: `application/json` ```json { "type": "object", "description": "OAuth 2.0 error response (RFC 6749 §5.2)", "properties": { "error": { "type": "string", "description": "Error code", "enum": [ "invalid_request", "invalid_client", "unsupported_grant_type", "server_error" ] }, "error_description": { "type": "string", "description": "Human-readable error description" } }, "required": [ "error" ] } ``` --- # Tools LLM tools that combine lang2fhir with FHIR server operations. ## Tools / MCP Servers Register and manage MCP servers exposed as agent tools. ### GET /tools/mcp-server/{mcp_server_id} **Get MCP server by ID** Gets a MCP server by ID **Operation ID:** `tools_get` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `mcp_server_id` | path | string | Yes | ID of the MCP server to retrieve | #### Responses **200** - Successfully retrieved MCP server Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether the operation succeeded", "example": true }, "message": { "type": "string", "description": "Status message" }, "data": { "description": "Single MCP server (returned by GET /tools/mcp-server/{mcp_server_id}).", "type": "object", "properties": { "id": { "type": "string", "description": "ID of the MCP server", "example": "123" }, "name": { "type": "string", "description": "Name of the MCP server", "example": "My MCP Server" }, "description": { "type": "string", "description": "Description of the MCP server", "example": "My MCP Server is a server that provides MCP services" }, "mcp_server_url": { "type": "string", "description": "URL of the MCP server", "example": "https://mcp.example.com" } } }, "mcp_servers": { "type": "array", "description": "List of MCP servers. Returned by /tools/mcp-server/create (the\nnewly created server) and /tools/mcp-server/list (all servers).\n", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "ID of the MCP server", "example": "123" }, "name": { "type": "string", "description": "Name of the MCP server", "example": "My MCP Server" }, "description": { "type": "string", "description": "Description of the MCP server", "example": "My MCP Server is a server that provides MCP services" }, "mcp_server_url": { "type": "string", "description": "URL of the MCP server", "example": "https://mcp.example.com" } } } }, "mcp_server_tools": { "type": "array", "description": "Tools loaded from the MCP server. Returned by /tools/mcp-server/create\nalongside the server record, since tool discovery happens at create time.\n", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "ID of the MCP server tool", "example": "123" }, "name": { "type": "string", "description": "Name of the MCP server tool", "example": "My MCP Server Tool" }, "description": { "type": "string", "description": "Description of the MCP server tool", "example": "My MCP Server Tool is a tool that provides MCP services" }, "input_schema": { "type": "object", "description": "Input schema of the MCP server tool", "example": { "name": "string", "age": "number" } }, "mcp_server_id": { "type": "string", "description": "ID of the MCP server that the tool belongs to", "example": "123" }, "mcp_server_url": { "type": "string", "description": "URL of the MCP server", "example": "https://mcp.example.com" } } } } } } ``` **Example:** ```json { "success": true, "message": "MCP Server retrieved successfully", "data": { "id": "123", "name": "My MCP Server", "description": "My MCP Server is a server that provides MCP services", "mcp_server_url": "https://mcp.example.com" } } ``` **401** - Unauthorized **403** - Forbidden - MCP server endpoints require a dedicated instance, or access denied to this resource **404** - MCP server not found **500** - Server error --- ### DELETE /tools/mcp-server/{mcp_server_id} **Delete MCP server by ID** Deletes a MCP server by ID **Operation ID:** `tools_delete` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `mcp_server_id` | path | string | Yes | ID of the MCP server to delete | #### Responses **200** - Successfully deleted MCP server Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether the operation succeeded", "example": true }, "message": { "type": "string", "description": "Status message" }, "data": { "description": "Single MCP server (returned by GET /tools/mcp-server/{mcp_server_id}).", "type": "object", "properties": { "id": { "type": "string", "description": "ID of the MCP server", "example": "123" }, "name": { "type": "string", "description": "Name of the MCP server", "example": "My MCP Server" }, "description": { "type": "string", "description": "Description of the MCP server", "example": "My MCP Server is a server that provides MCP services" }, "mcp_server_url": { "type": "string", "description": "URL of the MCP server", "example": "https://mcp.example.com" } } }, "mcp_servers": { "type": "array", "description": "List of MCP servers. Returned by /tools/mcp-server/create (the\nnewly created server) and /tools/mcp-server/list (all servers).\n", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "ID of the MCP server", "example": "123" }, "name": { "type": "string", "description": "Name of the MCP server", "example": "My MCP Server" }, "description": { "type": "string", "description": "Description of the MCP server", "example": "My MCP Server is a server that provides MCP services" }, "mcp_server_url": { "type": "string", "description": "URL of the MCP server", "example": "https://mcp.example.com" } } } }, "mcp_server_tools": { "type": "array", "description": "Tools loaded from the MCP server. Returned by /tools/mcp-server/create\nalongside the server record, since tool discovery happens at create time.\n", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "ID of the MCP server tool", "example": "123" }, "name": { "type": "string", "description": "Name of the MCP server tool", "example": "My MCP Server Tool" }, "description": { "type": "string", "description": "Description of the MCP server tool", "example": "My MCP Server Tool is a tool that provides MCP services" }, "input_schema": { "type": "object", "description": "Input schema of the MCP server tool", "example": { "name": "string", "age": "number" } }, "mcp_server_id": { "type": "string", "description": "ID of the MCP server that the tool belongs to", "example": "123" }, "mcp_server_url": { "type": "string", "description": "URL of the MCP server", "example": "https://mcp.example.com" } } } } } } ``` **Example:** ```json { "success": true, "message": "MCP Server Configuration and Tools deleted successfully" } ``` **401** - Unauthorized **403** - Forbidden - MCP server endpoints require a dedicated instance, or access denied to this resource **404** - MCP server not found **500** - Server error --- ### POST /tools/mcp-server/create **Create MCP server** Creates a new MCP server **Operation ID:** `tools_create` #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "name", "mcp_server_url" ], "properties": { "name": { "type": "string", "description": "Name of the MCP server", "example": "My MCP Server" }, "mcp_server_url": { "type": "string", "description": "URL of the MCP server", "example": "https://mcp.example.com" } } } ``` **Example:** ```json { "name": "My MCP Server", "mcp_server_url": "https://mcp.example.com" } ``` #### Responses **200** - Successfully created MCP server Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether the operation succeeded", "example": true }, "message": { "type": "string", "description": "Status message" }, "data": { "description": "Single MCP server (returned by GET /tools/mcp-server/{mcp_server_id}).", "type": "object", "properties": { "id": { "type": "string", "description": "ID of the MCP server", "example": "123" }, "name": { "type": "string", "description": "Name of the MCP server", "example": "My MCP Server" }, "description": { "type": "string", "description": "Description of the MCP server", "example": "My MCP Server is a server that provides MCP services" }, "mcp_server_url": { "type": "string", "description": "URL of the MCP server", "example": "https://mcp.example.com" } } }, "mcp_servers": { "type": "array", "description": "List of MCP servers. Returned by /tools/mcp-server/create (the\nnewly created server) and /tools/mcp-server/list (all servers).\n", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "ID of the MCP server", "example": "123" }, "name": { "type": "string", "description": "Name of the MCP server", "example": "My MCP Server" }, "description": { "type": "string", "description": "Description of the MCP server", "example": "My MCP Server is a server that provides MCP services" }, "mcp_server_url": { "type": "string", "description": "URL of the MCP server", "example": "https://mcp.example.com" } } } }, "mcp_server_tools": { "type": "array", "description": "Tools loaded from the MCP server. Returned by /tools/mcp-server/create\nalongside the server record, since tool discovery happens at create time.\n", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "ID of the MCP server tool", "example": "123" }, "name": { "type": "string", "description": "Name of the MCP server tool", "example": "My MCP Server Tool" }, "description": { "type": "string", "description": "Description of the MCP server tool", "example": "My MCP Server Tool is a tool that provides MCP services" }, "input_schema": { "type": "object", "description": "Input schema of the MCP server tool", "example": { "name": "string", "age": "number" } }, "mcp_server_id": { "type": "string", "description": "ID of the MCP server that the tool belongs to", "example": "123" }, "mcp_server_url": { "type": "string", "description": "URL of the MCP server", "example": "https://mcp.example.com" } } } } } } ``` **Example:** ```json { "success": true, "message": "MCP Server and Tools created successfully", "mcp_servers": [ { "id": "123", "name": "My MCP Server", "description": "My MCP Server is a server that provides MCP services", "mcp_server_url": "https://mcp.example.com" } ], "mcp_server_tools": [ { "id": "tool-001", "name": "search_endpoints", "description": "Search across the documented endpoints", "input_schema": { "query": "string" }, "mcp_server_id": "123", "mcp_server_url": "https://mcp.example.com" }, { "id": "tool-002", "name": "get_endpoint", "description": "Fetch a single endpoint by ID", "input_schema": { "endpoint_id": "string" }, "mcp_server_id": "123", "mcp_server_url": "https://mcp.example.com" } ] } ``` **400** - Invalid request **401** - Unauthorized **403** - Forbidden - MCP server endpoints require a dedicated instance, or access denied to this resource **500** - Server error --- ### GET /tools/mcp-server/list **List MCP servers** Lists all MCP servers for a specific user **Operation ID:** `tools_list` #### Responses **200** - Successfully listed MCP servers Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether the operation succeeded", "example": true }, "message": { "type": "string", "description": "Status message" }, "data": { "description": "Single MCP server (returned by GET /tools/mcp-server/{mcp_server_id}).", "type": "object", "properties": { "id": { "type": "string", "description": "ID of the MCP server", "example": "123" }, "name": { "type": "string", "description": "Name of the MCP server", "example": "My MCP Server" }, "description": { "type": "string", "description": "Description of the MCP server", "example": "My MCP Server is a server that provides MCP services" }, "mcp_server_url": { "type": "string", "description": "URL of the MCP server", "example": "https://mcp.example.com" } } }, "mcp_servers": { "type": "array", "description": "List of MCP servers. Returned by /tools/mcp-server/create (the\nnewly created server) and /tools/mcp-server/list (all servers).\n", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "ID of the MCP server", "example": "123" }, "name": { "type": "string", "description": "Name of the MCP server", "example": "My MCP Server" }, "description": { "type": "string", "description": "Description of the MCP server", "example": "My MCP Server is a server that provides MCP services" }, "mcp_server_url": { "type": "string", "description": "URL of the MCP server", "example": "https://mcp.example.com" } } } }, "mcp_server_tools": { "type": "array", "description": "Tools loaded from the MCP server. Returned by /tools/mcp-server/create\nalongside the server record, since tool discovery happens at create time.\n", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "ID of the MCP server tool", "example": "123" }, "name": { "type": "string", "description": "Name of the MCP server tool", "example": "My MCP Server Tool" }, "description": { "type": "string", "description": "Description of the MCP server tool", "example": "My MCP Server Tool is a tool that provides MCP services" }, "input_schema": { "type": "object", "description": "Input schema of the MCP server tool", "example": { "name": "string", "age": "number" } }, "mcp_server_id": { "type": "string", "description": "ID of the MCP server that the tool belongs to", "example": "123" }, "mcp_server_url": { "type": "string", "description": "URL of the MCP server", "example": "https://mcp.example.com" } } } } } } ``` **Example:** ```json { "success": true, "message": "MCP Servers retrieved successfully", "mcp_servers": [ { "id": "123", "name": "My MCP Server", "description": "My MCP Server is a server that provides MCP services", "mcp_server_url": "https://mcp.example.com" }, { "id": "456", "name": "Another MCP Server", "description": "A second MCP server", "mcp_server_url": "https://other.mcp.example.com" } ] } ``` **401** - Unauthorized **403** - Forbidden - MCP server endpoints require a dedicated instance, or access denied to this resource **500** - Server error --- ## Tools / MCP Tools List and manage individual tools exposed by an MCP server. ### GET /tools/mcp-server/{mcp_server_id}/list **List MCP server tools** Lists all MCP server tools for a specific MCP server **Operation ID:** `tools_listTools` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `mcp_server_id` | path | string | Yes | ID of the MCP server to list tools for | #### Responses **200** - Successfully listed MCP server tools Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether the operation succeeded", "example": true }, "message": { "type": "string", "description": "Status message" }, "data": { "type": "object", "properties": { "id": { "type": "string", "description": "ID of the MCP server tool", "example": "123" }, "name": { "type": "string", "description": "Name of the MCP server tool", "example": "My MCP Server Tool" }, "description": { "type": "string", "description": "Description of the MCP server tool", "example": "My MCP Server Tool is a tool that provides MCP services" }, "input_schema": { "type": "object", "description": "Input schema of the MCP server tool", "example": { "name": "string", "age": "number" } }, "mcp_server_id": { "type": "string", "description": "ID of the MCP server that the tool belongs to", "example": "123" }, "mcp_server_url": { "type": "string", "description": "URL of the MCP server", "example": "https://mcp.example.com" } }, "description": "Single MCP server tool (returned by GET /tools/mcp-server/tool/{mcp_server_tool_id})." }, "mcp_server_tools": { "type": "array", "description": "List of MCP server tools. Returned by\n/tools/mcp-server/{mcp_server_id}/list.\n", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "ID of the MCP server tool", "example": "123" }, "name": { "type": "string", "description": "Name of the MCP server tool", "example": "My MCP Server Tool" }, "description": { "type": "string", "description": "Description of the MCP server tool", "example": "My MCP Server Tool is a tool that provides MCP services" }, "input_schema": { "type": "object", "description": "Input schema of the MCP server tool", "example": { "name": "string", "age": "number" } }, "mcp_server_id": { "type": "string", "description": "ID of the MCP server that the tool belongs to", "example": "123" }, "mcp_server_url": { "type": "string", "description": "URL of the MCP server", "example": "https://mcp.example.com" } } } } } } ``` **Example:** ```json { "success": true, "message": "MCP Server tools retrieved successfully", "mcp_server_tools": [ { "id": "tool-001", "name": "search_endpoints", "description": "Search across the documented endpoints", "input_schema": { "query": "string" }, "mcp_server_id": "123", "mcp_server_url": "https://mcp.example.com" }, { "id": "tool-002", "name": "get_endpoint", "description": "Fetch a single endpoint by ID", "input_schema": { "endpoint_id": "string" }, "mcp_server_id": "123", "mcp_server_url": "https://mcp.example.com" } ] } ``` **401** - Unauthorized **403** - Forbidden - MCP server endpoints require a dedicated instance, or access denied to this resource **500** - Server error --- ### GET /tools/mcp-server/tool/{mcp_server_tool_id} **Get MCP server tool by ID** Gets a MCP server tool by ID **Operation ID:** `tools_getTool` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `mcp_server_tool_id` | path | string | Yes | ID of the MCP server tool to retrieve | #### Responses **200** - Successfully retrieved MCP server tool Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether the operation succeeded", "example": true }, "message": { "type": "string", "description": "Status message" }, "data": { "type": "object", "properties": { "id": { "type": "string", "description": "ID of the MCP server tool", "example": "123" }, "name": { "type": "string", "description": "Name of the MCP server tool", "example": "My MCP Server Tool" }, "description": { "type": "string", "description": "Description of the MCP server tool", "example": "My MCP Server Tool is a tool that provides MCP services" }, "input_schema": { "type": "object", "description": "Input schema of the MCP server tool", "example": { "name": "string", "age": "number" } }, "mcp_server_id": { "type": "string", "description": "ID of the MCP server that the tool belongs to", "example": "123" }, "mcp_server_url": { "type": "string", "description": "URL of the MCP server", "example": "https://mcp.example.com" } }, "description": "Single MCP server tool (returned by GET /tools/mcp-server/tool/{mcp_server_tool_id})." }, "mcp_server_tools": { "type": "array", "description": "List of MCP server tools. Returned by\n/tools/mcp-server/{mcp_server_id}/list.\n", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "ID of the MCP server tool", "example": "123" }, "name": { "type": "string", "description": "Name of the MCP server tool", "example": "My MCP Server Tool" }, "description": { "type": "string", "description": "Description of the MCP server tool", "example": "My MCP Server Tool is a tool that provides MCP services" }, "input_schema": { "type": "object", "description": "Input schema of the MCP server tool", "example": { "name": "string", "age": "number" } }, "mcp_server_id": { "type": "string", "description": "ID of the MCP server that the tool belongs to", "example": "123" }, "mcp_server_url": { "type": "string", "description": "URL of the MCP server", "example": "https://mcp.example.com" } } } } } } ``` **Example:** ```json { "success": true, "message": "MCP Server tool retrieved successfully", "data": { "id": "123", "name": "My MCP Server Tool", "description": "My MCP Server Tool is a tool that provides MCP services", "input_schema": { "name": "string", "age": "number" }, "mcp_server_id": "123", "mcp_server_url": "https://mcp.example.com" } } ``` **401** - Unauthorized **403** - Forbidden - MCP server endpoints require a dedicated instance, or access denied to this resource **404** - MCP server tool not found **500** - Server error --- ### DELETE /tools/mcp-server/tool/{mcp_server_tool_id} **Delete MCP server tool by ID** Deletes a MCP server tool by ID **Operation ID:** `tools_deleteTool` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `mcp_server_tool_id` | path | string | Yes | ID of the MCP server tool to delete | #### Responses **200** - Successfully deleted MCP server tool Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether the operation succeeded", "example": true }, "message": { "type": "string", "description": "Status message" }, "data": { "type": "object", "properties": { "id": { "type": "string", "description": "ID of the MCP server tool", "example": "123" }, "name": { "type": "string", "description": "Name of the MCP server tool", "example": "My MCP Server Tool" }, "description": { "type": "string", "description": "Description of the MCP server tool", "example": "My MCP Server Tool is a tool that provides MCP services" }, "input_schema": { "type": "object", "description": "Input schema of the MCP server tool", "example": { "name": "string", "age": "number" } }, "mcp_server_id": { "type": "string", "description": "ID of the MCP server that the tool belongs to", "example": "123" }, "mcp_server_url": { "type": "string", "description": "URL of the MCP server", "example": "https://mcp.example.com" } }, "description": "Single MCP server tool (returned by GET /tools/mcp-server/tool/{mcp_server_tool_id})." }, "mcp_server_tools": { "type": "array", "description": "List of MCP server tools. Returned by\n/tools/mcp-server/{mcp_server_id}/list.\n", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "ID of the MCP server tool", "example": "123" }, "name": { "type": "string", "description": "Name of the MCP server tool", "example": "My MCP Server Tool" }, "description": { "type": "string", "description": "Description of the MCP server tool", "example": "My MCP Server Tool is a tool that provides MCP services" }, "input_schema": { "type": "object", "description": "Input schema of the MCP server tool", "example": { "name": "string", "age": "number" } }, "mcp_server_id": { "type": "string", "description": "ID of the MCP server that the tool belongs to", "example": "123" }, "mcp_server_url": { "type": "string", "description": "URL of the MCP server", "example": "https://mcp.example.com" } } } } } } ``` **Example:** ```json { "success": true, "message": "MCP Server tool deleted successfully" } ``` **401** - Unauthorized **403** - Forbidden - MCP server endpoints require a dedicated instance, or access denied to this resource **404** - MCP server tool not found **500** - Server error --- ## Untagged ### POST /tools/cohort **Analyze patient cohorts** Uses LLM to extract search concepts from natural language and builds patient cohorts with inclusion/exclusion criteria **Operation ID:** `tools_analyzeCohort` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `X-Phenoml-On-Behalf-Of` | header | string | No | Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity. Must be in the format: Patient/{uuid} or Practitioner/{uuid} | | `X-Phenoml-Fhir-Provider` | header | string | No | Optional header for FHIR provider authentication. Contains credentials in the format {fhir_provider_id}:{oauth2_token}. Multiple FHIR provider integrations can be provided as comma-separated values. | #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "text", "provider" ], "properties": { "text": { "type": "string", "description": "Natural language text describing the patient cohort criteria", "example": "female patients over 20 with diabetes but not hypertension" }, "provider": { "type": "string", "format": "uuid", "description": "FHIR provider ID - must be a valid UUID from existing FHIR providers. also supports provider by name (e.g. medplum)", "example": "550e8400-e29b-41d4-a716-446655440000" } } } ``` **Example:** ```json { "text": "female patients over 20 with diabetes but not hypertension", "provider": "550e8400-e29b-41d4-a716-446655440000" } ``` #### Responses **200** - Successfully analyzed cohort and retrieved patient list Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether the cohort analysis was successful", "example": true }, "message": { "type": "string", "description": "Status message with details about the analysis", "example": "Cohort analysis completed successfully. Found 33 patients from 2 search concepts." }, "patientIds": { "type": "array", "items": { "type": "string" }, "description": "Array of patient IDs that match the cohort criteria", "example": [ "patient-123", "patient-456", "patient-789" ] }, "patientCount": { "type": "integer", "description": "Total number of patients in the cohort", "example": 33 }, "queries": { "type": "array", "items": { "type": "object", "description": "A single search concept detected in cohort mode", "properties": { "resource_type": { "type": "string", "description": "The FHIR resource type identified for this concept", "example": "Condition" }, "search_params": { "type": "string", "description": "FHIR search parameters for this concept", "example": "code=55822004" }, "concept": { "type": "string", "description": "Description of what this search represents", "example": "hyperlipidemia" }, "exclude": { "type": "boolean", "description": "Whether this is an exclusion criteria", "example": false } } }, "description": "Individual search concepts that were identified and executed", "example": [ { "resource_type": "Patient", "search_params": "gender=female&birthdate=le2004-01-01", "concept": "female patients over 20", "exclude": false }, { "resource_type": "Condition", "search_params": "code=55822004", "concept": "hyperlipidemia", "exclude": false } ] } } } ``` **Example:** ```json { "success": true, "message": "Cohort analysis completed successfully. Found 33 patients from 2 search concepts.", "patientIds": [ "patient-123", "patient-456", "patient-789" ], "patientCount": 33, "queries": [ { "resource_type": "Patient", "search_params": "gender=female&birthdate=le2004-01-01", "concept": "female patients over 20", "exclude": false }, { "resource_type": "Condition", "search_params": "code=44054006", "concept": "diabetes", "exclude": false }, { "resource_type": "Condition", "search_params": "code=38341003", "concept": "hypertension", "exclude": true } ] } ``` **400** - Invalid request **401** - Unauthorized **403** - Forbidden - access denied to the requested resource **500** - Server error --- ### POST /tools/lang2fhir-and-create **Create FHIR resource from text and store it** Converts natural language to FHIR resource and optionally stores it in a FHIR server **Operation ID:** `tools_createFhirResource` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `X-Phenoml-On-Behalf-Of` | header | string | No | Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity. Must be in the format: Patient/{uuid} or Practitioner/{uuid} | | `X-Phenoml-Fhir-Provider` | header | string | No | Optional header for FHIR provider authentication. Contains credentials in the format {fhir_provider_id}:{oauth2_token}. Multiple FHIR provider integrations can be provided as comma-separated values. | #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "resource", "text" ], "properties": { "resource": { "type": "string", "description": "Type of FHIR resource to create. Use 'auto' for automatic resource type detection, or specify a supported US Core profile.\n", "example": "condition-encounter-diagnosis", "enum": [ "auto", "appointment", "condition-encounter-diagnosis", "medicationrequest", "careplan", "condition-problems-health-concerns", "coverage", "encounter", "observation-clinical-result", "observation-lab", "patient", "procedure", "questionnaire", "questionnaireresponse", "servicerequest", "simple-observation", "vital-signs" ] }, "text": { "type": "string", "description": "Natural language text to convert to FHIR resource", "example": "Patient John Doe has severe asthma with acute exacerbation" }, "provider": { "type": "string", "format": "uuid", "description": "FHIR provider ID - must be a valid UUID from existing FHIR providers. also supports provider by name (e.g. medplum)", "example": "550e8400-e29b-41d4-a716-446655440000" } } } ``` **Example:** ```json { "resource": "condition-encounter-diagnosis", "text": "Patient has severe persistent asthma with acute exacerbation", "provider": "550e8400-e29b-41d4-a716-446655440000" } ``` #### Responses **200** - Successfully created FHIR resource Content-Type: `application/json` ```json { "type": "object", "properties": { "fhir_resource": { "type": "object", "description": "The created FHIR resource", "additionalProperties": true, "example": { "resourceType": "Condition", "id": "condition-123", "code": { "coding": [ { "system": "http://snomed.info/sct", "code": "195967001", "display": "Asthma" } ] }, "subject": { "reference": "Patient/patient-123", "display": "John Doe" } } }, "fhir_id": { "type": "string", "description": "ID of the resource in the FHIR server (if successfully stored)", "example": "condition-123" }, "success": { "type": "boolean", "example": true }, "message": { "type": "string", "description": "Status message", "example": "FHIR resource created and stored in FHIR server successfully" } } } ``` **Example:** ```json { "success": true, "message": "FHIR resource created successfully", "fhir_id": "condition-123", "fhir_resource": { "resourceType": "Condition", "id": "condition-123", "clinicalStatus": { "coding": [ { "system": "http://terminology.hl7.org/CodeSystem/condition-clinical", "code": "active" } ] }, "verificationStatus": { "coding": [ { "system": "http://terminology.hl7.org/CodeSystem/condition-ver-status", "code": "confirmed" } ] }, "category": [ { "coding": [ { "system": "http://terminology.hl7.org/CodeSystem/condition-category", "code": "encounter-diagnosis" } ] } ], "code": { "coding": [ { "system": "http://snomed.info/sct", "code": "195967001", "display": "Asthma" } ], "text": "Severe persistent asthma with acute exacerbation" }, "subject": { "reference": "Patient/patient-123" } } } ``` **400** - Invalid request **401** - Unauthorized **403** - Forbidden - access denied to the requested resource **500** - Server error --- ### POST /tools/lang2fhir-and-create-multi **Extract and store multiple FHIR resources** Extracts multiple FHIR resources from natural language text and stores them in a FHIR server. Automatically detects Patient, Condition, MedicationRequest, Observation, and other resource types. Resources are linked with proper references and submitted as a transaction bundle. For FHIR servers that don't auto-resolve urn:uuid references, this endpoint will automatically resolve them via PUT requests after the initial bundle creation. **Operation ID:** `tools_createFhirResourcesMulti` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `X-Phenoml-On-Behalf-Of` | header | string | No | Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity. Must be in the format: Patient/{uuid} or Practitioner/{uuid} | | `X-Phenoml-Fhir-Provider` | header | string | No | Optional header for FHIR provider authentication. Contains credentials in the format {fhir_provider_id}:{oauth2_token}. Multiple FHIR provider integrations can be provided as comma-separated values. | #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "text", "provider" ], "properties": { "text": { "type": "string", "description": "Natural language text containing multiple clinical concepts to extract", "example": "John Smith, 45-year-old male, diagnosed with Type 2 Diabetes. Prescribed Metformin 500mg twice daily." }, "version": { "type": "string", "description": "FHIR version to use", "example": "R4", "default": "R4" }, "provider": { "type": "string", "description": "FHIR provider ID or name", "example": "medplum" } } } ``` **Example:** ```json { "text": "John Smith, 45-year-old male, diagnosed with Type 2 Diabetes. Prescribed Metformin 500mg twice daily.", "version": "R4", "provider": "medplum" } ``` #### Responses **200** - Successfully created FHIR resources Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether the resources were created successfully", "example": true }, "message": { "type": "string", "description": "Status message", "example": "Created 3 resources" }, "response_bundle": { "type": "object", "description": "FHIR transaction-response Bundle from the server with resolved resource IDs", "properties": { "resourceType": { "type": "string", "example": "Bundle" }, "type": { "type": "string", "example": "transaction-response" }, "entry": { "type": "array", "items": { "type": "object" } } } }, "resource_info": { "type": "array", "description": "Metadata about created resources (temp IDs, types, descriptions)", "items": { "type": "object", "properties": { "tempId": { "type": "string", "description": "Original temporary UUID", "example": "urn:uuid:patient-abc123" }, "resourceType": { "type": "string", "description": "FHIR resource type", "example": "Patient" }, "description": { "type": "string", "description": "Text excerpt this resource was extracted from", "example": "John Smith, 45-year-old male" } } } } } } ``` **Example:** ```json { "success": true, "message": "Created 3 resources", "response_bundle": { "resourceType": "Bundle", "type": "transaction-response", "entry": [ { "response": { "status": "201 Created", "location": "Patient/patient-001" } }, { "response": { "status": "201 Created", "location": "Condition/condition-001" } }, { "response": { "status": "201 Created", "location": "MedicationRequest/medication-001" } } ] }, "resource_info": [ { "tempId": "urn:uuid:patient-abc123", "resourceType": "Patient", "description": "John Smith, 45-year-old male" }, { "tempId": "urn:uuid:condition-abc123", "resourceType": "Condition", "description": "Type 2 Diabetes diagnosis" }, { "tempId": "urn:uuid:medication-abc123", "resourceType": "MedicationRequest", "description": "Metformin 500mg twice daily" } ] } ``` **400** - Invalid request **401** - Unauthorized **403** - Forbidden - access denied to the requested resource **500** - Server error --- ### POST /tools/lang2fhir-and-search **Search FHIR resources from natural language** Converts natural language to FHIR search parameters and executes search in FHIR server **Operation ID:** `tools_searchFhirResources` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `X-Phenoml-On-Behalf-Of` | header | string | No | Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity. Must be in the format: Patient/{uuid} or Practitioner/{uuid} | | `X-Phenoml-Fhir-Provider` | header | string | No | Optional header for FHIR provider authentication. Contains credentials in the format {fhir_provider_id}:{oauth2_token}. Multiple FHIR provider integrations can be provided as comma-separated values. | #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "text" ], "properties": { "text": { "type": "string", "description": "Natural language text to convert to FHIR search parameters", "example": "Find all appointments for patient John Doe next week" }, "patient_id": { "type": "string", "description": "Patient ID to filter results", "example": "patient-123" }, "count": { "type": "integer", "description": "Maximum number of results to return", "example": 10, "minimum": 1, "maximum": 100 }, "provider": { "type": "string", "format": "uuid", "description": "FHIR provider ID - must be a valid UUID from existing FHIR providers. also supports provider by name (e.g. medplum)", "example": "550e8400-e29b-41d4-a716-446655440000" } } } ``` **Example:** ```json { "text": "Find all appointments for patient John Doe next week", "count": 10, "provider": "550e8400-e29b-41d4-a716-446655440000" } ``` #### Responses **200** - Successfully generated search and retrieved results Content-Type: `application/json` ```json { "type": "object", "properties": { "resource_type": { "type": "string", "description": "The FHIR resource type identified for the search", "example": "Appointment" }, "search_params": { "type": "string", "description": "FHIR search parameters in standard format", "example": "patient=Patient/patient-123&date=ge2024-01-15&date=le2024-01-22" }, "fhir_results": { "type": "array", "items": { "type": "object", "additionalProperties": true }, "description": "Array of FHIR resources returned from the search", "example": [ { "resourceType": "Appointment", "id": "appointment-123", "status": "booked", "start": "2024-01-16T10:00:00Z", "end": "2024-01-16T11:00:00Z", "participant": [ { "actor": { "reference": "Patient/patient-123", "display": "John Doe" } } ] } ] }, "success": { "type": "boolean", "example": true }, "message": { "type": "string", "description": "Status message", "example": "Search query generated and executed in FHIR server successfully. Found 1 results." } } } ``` **Example:** ```json { "success": true, "message": "Search query generated and executed in FHIR server successfully. Found 1 results.", "resource_type": "Appointment", "search_params": "patient=Patient/patient-123&date=ge2024-01-15&date=le2024-01-22", "fhir_results": [ { "resourceType": "Appointment", "id": "appointment-123", "status": "booked", "start": "2024-01-16T10:00:00Z", "end": "2024-01-16T11:00:00Z", "participant": [ { "actor": { "reference": "Patient/patient-123", "display": "John Doe" } } ] } ] } ``` **400** - Invalid request **401** - Unauthorized **403** - Forbidden - access denied to the requested resource **500** - Server error --- # FHIR FHIR server operations including resource CRUD, search, and batch operations. ## FHIR / Auth Config Manage authentication configurations attached to a FHIR provider. ### PATCH /fhir-provider/{fhir_provider_id}/add-auth-config **Add authentication configuration** Adds a new authentication configuration to an existing FHIR provider. This enables key rotation and multiple auth configurations per provider. Note: Sandbox providers cannot be modified. **Operation ID:** `fhir_provider_add` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `fhir_provider_id` | path | string | Yes | ID of the FHIR provider to add auth config to | #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "oneOf": [ { "type": "object", "required": [ "auth_method", "client_id" ], "properties": { "auth_method": { "type": "string", "enum": [ "jwt" ] }, "client_id": { "type": "string", "description": "OAuth client ID", "example": "your-client-id" }, "credential_expiry": { "type": "string", "format": "date-time", "description": "Expiry time for JWT credentials. If omitted, a default expiry is used.", "example": "2024-12-31T23:59:59Z" }, "role": { "type": "string", "description": "Predefined access level that maps to provider-specific OAuth scopes.\nCannot be specified together with `scopes`. Only applicable to\n`client_secret`, `jwt`, and `on_behalf_of` auth methods.\n\nRoles apply across **all FHIR resource types** (e.g., Patient, Observation,\nCondition, etc.) — they are not limited to a single resource. The server\nresolves each role to the appropriate system-level scopes for the provider:\n- `admin`: Full CRUD access (create, read, update, delete, search) on all resources\n- `read`: Read and search access on all resources\n- `write`: Create, update, and delete access on all resources (no read)\n\n**The exact scopes generated depend on the provider**, because each EHR uses a\ndifferent SMART on FHIR version or scope format:\n- **Epic**: SMART v2 scopes (e.g., `system/*.cruds` for admin)\n- **Cerner**: Cerner-specific SMART v2 scopes with per-resource grants for the\n subset of resources Cerner supports\n- **Athenahealth**: USCDI SMART v2 scopes with explicit per-resource grants\n (e.g., `system/Patient.rs`, `system/Observation.rs`, etc.)\n- **Elation**: SMART v1 scopes (e.g., `system/*.read` for read)\n- **Medplum, Phenostore**: SMART v2 scopes\n\nIf neither `role` nor `scopes` is specified, the provider-specific default\nrole is used (typically `read`; `admin` for Medplum/sandbox).\n\nIf the generated scopes don't match what your EHR expects, use the `scopes`\nfield to specify exact scopes instead.\n\nCanvas does not support system-level roles — use `scopes` directly.\nGoogle Healthcare, HAPI, Meditech, and `none`/`token_passthrough`\nauth methods do not use scopes at all.\n", "enum": [ "admin", "read", "write" ], "example": "read" }, "scopes": { "type": "string", "description": "OAuth scopes to request. Cannot be specified with role. If neither role nor scopes are specified, the provider-specific default role will be used.", "example": "system/Patient.read system/Observation.read" } } }, { "type": "object", "required": [ "auth_method", "client_id", "client_secret" ], "properties": { "auth_method": { "type": "string", "enum": [ "client_secret" ] }, "client_id": { "type": "string", "description": "OAuth client ID", "example": "your-client-id" }, "client_secret": { "type": "string", "description": "OAuth client secret", "example": "your-client-secret" }, "role": { "type": "string", "description": "Predefined access level that maps to provider-specific OAuth scopes.\nCannot be specified together with `scopes`. Only applicable to\n`client_secret`, `jwt`, and `on_behalf_of` auth methods.\n\nRoles apply across **all FHIR resource types** (e.g., Patient, Observation,\nCondition, etc.) — they are not limited to a single resource. The server\nresolves each role to the appropriate system-level scopes for the provider:\n- `admin`: Full CRUD access (create, read, update, delete, search) on all resources\n- `read`: Read and search access on all resources\n- `write`: Create, update, and delete access on all resources (no read)\n\n**The exact scopes generated depend on the provider**, because each EHR uses a\ndifferent SMART on FHIR version or scope format:\n- **Epic**: SMART v2 scopes (e.g., `system/*.cruds` for admin)\n- **Cerner**: Cerner-specific SMART v2 scopes with per-resource grants for the\n subset of resources Cerner supports\n- **Athenahealth**: USCDI SMART v2 scopes with explicit per-resource grants\n (e.g., `system/Patient.rs`, `system/Observation.rs`, etc.)\n- **Elation**: SMART v1 scopes (e.g., `system/*.read` for read)\n- **Medplum, Phenostore**: SMART v2 scopes\n\nIf neither `role` nor `scopes` is specified, the provider-specific default\nrole is used (typically `read`; `admin` for Medplum/sandbox).\n\nIf the generated scopes don't match what your EHR expects, use the `scopes`\nfield to specify exact scopes instead.\n\nCanvas does not support system-level roles — use `scopes` directly.\nGoogle Healthcare, HAPI, Meditech, and `none`/`token_passthrough`\nauth methods do not use scopes at all.\n", "enum": [ "admin", "read", "write" ], "example": "read" }, "scopes": { "type": "string", "description": "OAuth scopes to request. Cannot be specified with role. If neither role nor scopes are specified, the provider-specific default role will be used.", "example": "system/Patient.read system/Observation.read" } } }, { "type": "object", "required": [ "auth_method", "client_id", "client_secret" ], "properties": { "auth_method": { "type": "string", "enum": [ "on_behalf_of" ] }, "client_id": { "type": "string", "description": "OAuth client ID", "example": "your-client-id" }, "client_secret": { "type": "string", "description": "OAuth client secret", "example": "your-client-secret" }, "role": { "type": "string", "description": "Predefined access level that maps to provider-specific OAuth scopes.\nCannot be specified together with `scopes`. Only applicable to\n`client_secret`, `jwt`, and `on_behalf_of` auth methods.\n\nRoles apply across **all FHIR resource types** (e.g., Patient, Observation,\nCondition, etc.) — they are not limited to a single resource. The server\nresolves each role to the appropriate system-level scopes for the provider:\n- `admin`: Full CRUD access (create, read, update, delete, search) on all resources\n- `read`: Read and search access on all resources\n- `write`: Create, update, and delete access on all resources (no read)\n\n**The exact scopes generated depend on the provider**, because each EHR uses a\ndifferent SMART on FHIR version or scope format:\n- **Epic**: SMART v2 scopes (e.g., `system/*.cruds` for admin)\n- **Cerner**: Cerner-specific SMART v2 scopes with per-resource grants for the\n subset of resources Cerner supports\n- **Athenahealth**: USCDI SMART v2 scopes with explicit per-resource grants\n (e.g., `system/Patient.rs`, `system/Observation.rs`, etc.)\n- **Elation**: SMART v1 scopes (e.g., `system/*.read` for read)\n- **Medplum, Phenostore**: SMART v2 scopes\n\nIf neither `role` nor `scopes` is specified, the provider-specific default\nrole is used (typically `read`; `admin` for Medplum/sandbox).\n\nIf the generated scopes don't match what your EHR expects, use the `scopes`\nfield to specify exact scopes instead.\n\nCanvas does not support system-level roles — use `scopes` directly.\nGoogle Healthcare, HAPI, Meditech, and `none`/`token_passthrough`\nauth methods do not use scopes at all.\n", "enum": [ "admin", "read", "write" ], "example": "read" }, "scopes": { "type": "string", "description": "OAuth scopes to request. Cannot be specified with role. If neither role nor scopes are specified, the provider-specific default role will be used.", "example": "system/Patient.read system/Observation.read" } } }, { "type": "object", "required": [ "auth_method", "service_account_key" ], "properties": { "auth_method": { "type": "string", "enum": [ "google_healthcare" ] }, "service_account_key": { "type": "object", "description": "Google Cloud Service Account key (required for google_healthcare auth method)", "required": [ "type", "project_id", "private_key_id", "private_key", "client_email", "client_id", "auth_uri", "token_uri", "auth_provider_x509_cert_url", "client_x509_cert_url", "universe_domain" ], "properties": { "type": { "type": "string", "example": "service_account" }, "project_id": { "type": "string", "example": "my-gcp-project" }, "private_key_id": { "type": "string", "example": "key-id-123" }, "private_key": { "type": "string", "example": "-----BEGIN PRIVATE KEY-----\n..." }, "client_email": { "type": "string", "format": "email", "example": "service-account@my-gcp-project.iam.gserviceaccount.com" }, "client_id": { "type": "string", "example": "123456789012345678901" }, "auth_uri": { "type": "string", "format": "uri", "example": "https://accounts.google.com/o/oauth2/auth" }, "token_uri": { "type": "string", "format": "uri", "example": "https://oauth2.googleapis.com/token" }, "auth_provider_x509_cert_url": { "type": "string", "format": "uri", "example": "https://www.googleapis.com/oauth2/v1/certs" }, "client_x509_cert_url": { "type": "string", "format": "uri", "example": "https://www.googleapis.com/robot/v1/metadata/x509/service-account%40my-gcp-project.iam.gserviceaccount.com" }, "universe_domain": { "type": "string", "example": "googleapis.com" } } } } }, { "type": "object", "required": [ "auth_method" ], "properties": { "auth_method": { "type": "string", "enum": [ "token_passthrough" ] } } }, { "type": "object", "required": [ "auth_method" ], "properties": { "auth_method": { "type": "string", "enum": [ "none" ] } } } ], "discriminator": { "propertyName": "auth_method", "mapping": { "jwt": "#/components/schemas/fhir_provider_JwtAuth", "client_secret": "#/components/schemas/fhir_provider_ClientSecretAuth", "on_behalf_of": "#/components/schemas/fhir_provider_OnBehalfOfAuth", "google_healthcare": "#/components/schemas/fhir_provider_GoogleHealthcareAuth", "token_passthrough": "#/components/schemas/fhir_provider_TokenPassthroughAuth", "none": "#/components/schemas/fhir_provider_NoAuth" } } } ``` **Example:** ```json { "auth_method": "client_secret", "client_id": "your-other-client-id", "client_secret": "your-other-client-secret", "role": "read" } ``` #### Responses **200** - Auth configuration added successfully Content-Type: `application/json` ```json { "type": "object", "description": "Response payload for a single FHIR Provider operation.", "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string" }, "data": { "oneOf": [ { "type": "object", "description": "Full FHIR provider configuration returned for non-sandbox providers.\n`auth_configs` and `last_updated` are always populated, which is how\nlist responses distinguish this shape from `FhirProviderSandboxInfo`.\n", "required": [ "id", "name", "provider", "auth_configs", "last_updated" ], "properties": { "id": { "type": "string", "description": "Unique identifier for the FHIR provider", "example": "1716d214-de93-43a4-aa6b-a878d864e2ad" }, "name": { "type": "string", "description": "Display name for the FHIR provider", "example": "Epic Sandbox" }, "description": { "type": "string", "description": "Optional description of the FHIR provider", "example": "Epic sandbox environment for testing" }, "provider": { "type": "string", "description": "Type of FHIR server provider.\n\nThe \"sandbox\" provider type is managed internally and cannot be created via API.\nIt is used on shared instances.\n", "enum": [ "aidbox", "athenahealth", "canvas", "cerner", "elation", "epic", "google_healthcare", "hapi", "meditech", "medplum", "phenostore", "sandbox" ], "example": "epic" }, "base_url": { "type": "string", "format": "uri", "description": "Base URL of the FHIR server", "example": "https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4" }, "client_id": { "type": "string", "deprecated": true, "description": "OAuth client ID. Deprecated: use client_id on FhirProviderAuthConfig instead. Retained for backward compatibility with existing providers.", "example": "your-client-id" }, "auth_configs": { "type": "object", "description": "Map of authentication configurations (key is auth_config_id)", "additionalProperties": { "type": "object", "description": "Authentication configuration for a FHIR provider (sensitive fields are hidden from JSON responses)", "properties": { "auth_config_id": { "type": "string", "description": "Unique identifier for this auth configuration", "example": "auth-config-123" }, "auth_method": { "type": "string", "description": "Authentication method for the FHIR provider. Only one authentication method can be used at a time,\nbut these can be rotated on the FHIR Provider as needed.\n\n**Scope behavior by auth method:**\n- `client_secret`, `jwt`, `on_behalf_of`: Scopes are included in the OAuth token request.\n They can be configured using the `role` or `scopes` field. If neither is specified, provider-specific\n default scopes derived from a default role are used. Roles grant access across all FHIR resource\n types, but the exact scope format varies by EHR — see the `Role` schema for details.\n- `google_healthcare`: Uses a fixed Google Cloud Healthcare scope. Specifying `role` or `scopes` will\n return an error.\n- `token_passthrough`: The caller provides their own bearer token via the X-Phenoml-Fhir-Provider header\n as one or more comma-separated {fhir_provider_id}:{oauth2_token} pairs. Specifying `role` or `scopes`\n will return an error. This is the recommended mode for providers like Meditech where the bearer token\n is typically obtained outside PhenoML.\n- `none`: No authentication is performed. Specifying `role` or `scopes` will return an error.\n\nFor the `on_behalf_of` authentication method, you must also provide the Patient or Practitioner reference\nin the X-Phenoml-On-Behalf-Of header in the format Patient/{uuid} or Practitioner/{uuid}. This only works\nfor the medplum provider currently.\n\nMore on the authentication headers and how to structure them can be found in the FHIR Proxy, Tools and\nAgent documentation.\n", "enum": [ "client_secret", "google_healthcare", "jwt", "on_behalf_of", "token_passthrough", "none" ], "example": "jwt" }, "is_active_auth_config": { "type": "boolean", "description": "Whether this auth configuration is currently active", "example": true }, "created_at": { "type": "string", "format": "date-time", "description": "Timestamp when this auth configuration was created", "example": "2024-01-15T10:30:00Z" }, "updated_at": { "type": "string", "format": "date-time", "description": "Timestamp when this auth configuration was last updated", "example": "2024-01-15T14:45:00Z" }, "public_key_cert_pem": { "type": "string", "description": "Public key certificate in PEM format (visible for JWT auth)", "example": "-----BEGIN CERTIFICATE-----\n..." }, "json_web_key": { "type": "object", "description": "JSON Web Key structure for RSA keys used in JWT authentication. Keys are automatically generated using RSA-2048 with RS384 signing algorithm. The Key ID (kid) is derived from a SHA256 hash of the public key PEM format.", "properties": { "kty": { "type": "string", "description": "Key Type", "example": "RSA" }, "use": { "type": "string", "description": "Usage (sig for signature)", "example": "sig" }, "kid": { "type": "string", "description": "Key ID - SHA256 hash of the public key PEM (including headers) encoded as base64url. Generated by taking the public key in PEM format, hashing with SHA256, then base64url encoding (replacing + with -, / with _, and removing padding).", "example": "FHIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0vx7agoeb" }, "alg": { "type": "string", "description": "Algorithm used for JWT signing (RSA with SHA-384)", "example": "RS384" }, "n": { "type": "string", "description": "RSA Modulus (base64url encoded)", "example": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbIS" }, "e": { "type": "string", "description": "RSA Exponent (base64url encoded)", "example": "AQAB" } } }, "credential_expiry": { "type": "string", "format": "date-time", "description": "Expiry time for credentials (JWT auth only)", "example": "2024-12-31T23:59:59Z" }, "smart_configuration": { "type": "object", "description": "SMART on FHIR configuration for OAuth-based providers", "properties": { "authorization_endpoint": { "type": "string", "format": "uri", "description": "OAuth2 authorization endpoint", "example": "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/authorize" }, "token_endpoint": { "type": "string", "format": "uri", "description": "OAuth2 token endpoint", "example": "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token" }, "issuer": { "type": "string", "format": "uri", "description": "OIDC issuer URL", "example": "https://fhir.epic.com/interconnect-fhir-oauth" }, "jwks_uri": { "type": "string", "format": "uri", "description": "JSON Web Key Set URI", "example": "https://fhir.epic.com/interconnect-fhir-oauth/.well-known/jwks" }, "scopes_supported": { "type": "array", "description": "List of supported scopes", "items": { "type": "string" }, "example": [ "patient/*.read", "system/*.read" ] } } }, "service_account_metadata": { "type": "object", "description": "Non-sensitive metadata from a Google Cloud Service Account, exposed in API responses to help identify auth configurations without revealing sensitive credentials.", "properties": { "type": { "type": "string", "description": "Account type (always \"service_account\")", "example": "service_account" }, "project_id": { "type": "string", "description": "Google Cloud project ID", "example": "my-gcp-project" }, "client_email": { "type": "string", "format": "email", "description": "Service account email address", "example": "service-account@my-gcp-project.iam.gserviceaccount.com" }, "client_id": { "type": "string", "description": "Service account client ID", "example": "123456789012345678901" } } }, "scopes": { "type": "string", "description": "OAuth scopes", "example": "system/Patient.read system/Observation.read" }, "client_id": { "type": "string", "description": "OAuth client ID for this auth configuration. When set, takes precedence over the provider-level client_id.", "example": "your-client-id" } } } }, "last_updated": { "type": "string", "format": "date-time", "description": "Timestamp when the provider was last updated", "example": "2024-01-15T10:30:00Z" } } }, { "type": "object", "description": "Limited information returned for sandbox FHIR providers. Sandbox\nresponses omit `auth_configs` and `last_updated`, which is what\ndistinguishes this shape from `FhirProviderTemplate` in `oneOf`.\n", "required": [ "id", "name", "provider" ], "properties": { "id": { "type": "string", "description": "Unique identifier for the FHIR provider", "example": "1716d214-de93-43a4-aa6b-a878d864e2ad" }, "name": { "type": "string", "description": "Display name for the FHIR provider", "example": "PhenoML Sandbox" }, "description": { "type": "string", "description": "Optional description of the FHIR provider", "example": "Shared sandbox environment for experimentation" }, "provider": { "type": "string", "enum": [ "sandbox" ], "description": "Provider type (always \"sandbox\" for this schema)", "example": "sandbox" } } } ], "description": "Provider details. Sandbox providers return FhirProviderSandboxInfo.\n" } } } ``` **Example:** ```json { "success": true, "message": "Fhir provider auth config added successfully", "data": { "id": "1716d214-de93-43a4-aa6b-a878d864e2ad", "name": "Epic Sandbox", "description": "Epic sandbox environment for testing", "provider": "epic", "base_url": "https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4", "auth_configs": { "auth-config-123": { "auth_config_id": "auth-config-123", "auth_method": "jwt", "is_active_auth_config": true, "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T14:45:00Z", "scopes": "system/Patient.read system/Observation.read", "client_id": "your-client-id" }, "auth-config-456": { "auth_config_id": "auth-config-456", "auth_method": "client_secret", "is_active_auth_config": false, "created_at": "2024-02-20T09:00:00Z", "updated_at": "2024-02-20T09:00:00Z", "scopes": "system/Patient.read", "client_id": "your-other-client-id" } }, "last_updated": "2024-02-20T09:00:00Z" } } ``` **400** - Invalid request - missing required fields or invalid values **401** - Unauthorized **403** - Forbidden - dedicated instance required, or sandbox provider cannot be modified **404** - FHIR provider not found **500** - Server error --- ### PATCH /fhir-provider/{fhir_provider_id}/remove-auth-config **Remove authentication configuration** Removes an authentication configuration from a FHIR provider. Cannot remove the currently active auth configuration. Note: Sandbox providers cannot be modified. **Operation ID:** `fhir_provider_remove` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `fhir_provider_id` | path | string | Yes | ID of the FHIR provider | #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "auth_config_id" ], "properties": { "auth_config_id": { "type": "string", "description": "ID of the auth configuration to remove", "example": "auth-config-123" } } } ``` **Example:** ```json { "auth_config_id": "auth-config-456" } ``` #### Responses **200** - Auth configuration removed successfully Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string" }, "data": { "type": "object", "description": "Full FHIR provider configuration returned for non-sandbox providers.\n`auth_configs` and `last_updated` are always populated, which is how\nlist responses distinguish this shape from `FhirProviderSandboxInfo`.\n", "required": [ "id", "name", "provider", "auth_configs", "last_updated" ], "properties": { "id": { "type": "string", "description": "Unique identifier for the FHIR provider", "example": "1716d214-de93-43a4-aa6b-a878d864e2ad" }, "name": { "type": "string", "description": "Display name for the FHIR provider", "example": "Epic Sandbox" }, "description": { "type": "string", "description": "Optional description of the FHIR provider", "example": "Epic sandbox environment for testing" }, "provider": { "type": "string", "description": "Type of FHIR server provider.\n\nThe \"sandbox\" provider type is managed internally and cannot be created via API.\nIt is used on shared instances.\n", "enum": [ "aidbox", "athenahealth", "canvas", "cerner", "elation", "epic", "google_healthcare", "hapi", "meditech", "medplum", "phenostore", "sandbox" ], "example": "epic" }, "base_url": { "type": "string", "format": "uri", "description": "Base URL of the FHIR server", "example": "https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4" }, "client_id": { "type": "string", "deprecated": true, "description": "OAuth client ID. Deprecated: use client_id on FhirProviderAuthConfig instead. Retained for backward compatibility with existing providers.", "example": "your-client-id" }, "auth_configs": { "type": "object", "description": "Map of authentication configurations (key is auth_config_id)", "additionalProperties": { "type": "object", "description": "Authentication configuration for a FHIR provider (sensitive fields are hidden from JSON responses)", "properties": { "auth_config_id": { "type": "string", "description": "Unique identifier for this auth configuration", "example": "auth-config-123" }, "auth_method": { "type": "string", "description": "Authentication method for the FHIR provider. Only one authentication method can be used at a time,\nbut these can be rotated on the FHIR Provider as needed.\n\n**Scope behavior by auth method:**\n- `client_secret`, `jwt`, `on_behalf_of`: Scopes are included in the OAuth token request.\n They can be configured using the `role` or `scopes` field. If neither is specified, provider-specific\n default scopes derived from a default role are used. Roles grant access across all FHIR resource\n types, but the exact scope format varies by EHR — see the `Role` schema for details.\n- `google_healthcare`: Uses a fixed Google Cloud Healthcare scope. Specifying `role` or `scopes` will\n return an error.\n- `token_passthrough`: The caller provides their own bearer token via the X-Phenoml-Fhir-Provider header\n as one or more comma-separated {fhir_provider_id}:{oauth2_token} pairs. Specifying `role` or `scopes`\n will return an error. This is the recommended mode for providers like Meditech where the bearer token\n is typically obtained outside PhenoML.\n- `none`: No authentication is performed. Specifying `role` or `scopes` will return an error.\n\nFor the `on_behalf_of` authentication method, you must also provide the Patient or Practitioner reference\nin the X-Phenoml-On-Behalf-Of header in the format Patient/{uuid} or Practitioner/{uuid}. This only works\nfor the medplum provider currently.\n\nMore on the authentication headers and how to structure them can be found in the FHIR Proxy, Tools and\nAgent documentation.\n", "enum": [ "client_secret", "google_healthcare", "jwt", "on_behalf_of", "token_passthrough", "none" ], "example": "jwt" }, "is_active_auth_config": { "type": "boolean", "description": "Whether this auth configuration is currently active", "example": true }, "created_at": { "type": "string", "format": "date-time", "description": "Timestamp when this auth configuration was created", "example": "2024-01-15T10:30:00Z" }, "updated_at": { "type": "string", "format": "date-time", "description": "Timestamp when this auth configuration was last updated", "example": "2024-01-15T14:45:00Z" }, "public_key_cert_pem": { "type": "string", "description": "Public key certificate in PEM format (visible for JWT auth)", "example": "-----BEGIN CERTIFICATE-----\n..." }, "json_web_key": { "type": "object", "description": "JSON Web Key structure for RSA keys used in JWT authentication. Keys are automatically generated using RSA-2048 with RS384 signing algorithm. The Key ID (kid) is derived from a SHA256 hash of the public key PEM format.", "properties": { "kty": { "type": "string", "description": "Key Type", "example": "RSA" }, "use": { "type": "string", "description": "Usage (sig for signature)", "example": "sig" }, "kid": { "type": "string", "description": "Key ID - SHA256 hash of the public key PEM (including headers) encoded as base64url. Generated by taking the public key in PEM format, hashing with SHA256, then base64url encoding (replacing + with -, / with _, and removing padding).", "example": "FHIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0vx7agoeb" }, "alg": { "type": "string", "description": "Algorithm used for JWT signing (RSA with SHA-384)", "example": "RS384" }, "n": { "type": "string", "description": "RSA Modulus (base64url encoded)", "example": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbIS" }, "e": { "type": "string", "description": "RSA Exponent (base64url encoded)", "example": "AQAB" } } }, "credential_expiry": { "type": "string", "format": "date-time", "description": "Expiry time for credentials (JWT auth only)", "example": "2024-12-31T23:59:59Z" }, "smart_configuration": { "type": "object", "description": "SMART on FHIR configuration for OAuth-based providers", "properties": { "authorization_endpoint": { "type": "string", "format": "uri", "description": "OAuth2 authorization endpoint", "example": "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/authorize" }, "token_endpoint": { "type": "string", "format": "uri", "description": "OAuth2 token endpoint", "example": "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token" }, "issuer": { "type": "string", "format": "uri", "description": "OIDC issuer URL", "example": "https://fhir.epic.com/interconnect-fhir-oauth" }, "jwks_uri": { "type": "string", "format": "uri", "description": "JSON Web Key Set URI", "example": "https://fhir.epic.com/interconnect-fhir-oauth/.well-known/jwks" }, "scopes_supported": { "type": "array", "description": "List of supported scopes", "items": { "type": "string" }, "example": [ "patient/*.read", "system/*.read" ] } } }, "service_account_metadata": { "type": "object", "description": "Non-sensitive metadata from a Google Cloud Service Account, exposed in API responses to help identify auth configurations without revealing sensitive credentials.", "properties": { "type": { "type": "string", "description": "Account type (always \"service_account\")", "example": "service_account" }, "project_id": { "type": "string", "description": "Google Cloud project ID", "example": "my-gcp-project" }, "client_email": { "type": "string", "format": "email", "description": "Service account email address", "example": "service-account@my-gcp-project.iam.gserviceaccount.com" }, "client_id": { "type": "string", "description": "Service account client ID", "example": "123456789012345678901" } } }, "scopes": { "type": "string", "description": "OAuth scopes", "example": "system/Patient.read system/Observation.read" }, "client_id": { "type": "string", "description": "OAuth client ID for this auth configuration. When set, takes precedence over the provider-level client_id.", "example": "your-client-id" } } } }, "last_updated": { "type": "string", "format": "date-time", "description": "Timestamp when the provider was last updated", "example": "2024-01-15T10:30:00Z" } } } } } ``` **Example:** ```json { "success": true, "message": "Fhir provider auth config deleted successfully", "data": { "id": "1716d214-de93-43a4-aa6b-a878d864e2ad", "name": "Epic Sandbox", "description": "Epic sandbox environment for testing", "provider": "epic", "base_url": "https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4", "auth_configs": { "auth-config-123": { "auth_config_id": "auth-config-123", "auth_method": "jwt", "is_active_auth_config": true, "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z", "scopes": "system/Patient.read system/Observation.read", "client_id": "your-client-id" } }, "last_updated": "2024-02-20T11:30:00Z" } } ``` **400** - Invalid request - cannot remove active auth configuration **401** - Unauthorized **403** - Forbidden - dedicated instance required, or sandbox provider cannot be modified **404** - FHIR provider or auth config not found **500** - Server error --- ### PATCH /fhir-provider/{fhir_provider_id}/set-active-auth-config **Set active authentication configuration** Sets which authentication configuration should be active for a FHIR provider. Only one auth config can be active at a time. If the specified auth config is already active, the request succeeds without making any changes and returns a message indicating the config is already active. Note: Sandbox providers cannot be modified. **Operation ID:** `fhir_provider_setActive` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `fhir_provider_id` | path | string | Yes | ID of the FHIR provider | #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "auth_config_id" ], "properties": { "auth_config_id": { "type": "string", "description": "ID of the auth configuration to set as active", "example": "auth-config-123" } } } ``` **Example:** ```json { "auth_config_id": "auth-config-456" } ``` #### Responses **200** - Active auth configuration set successfully, or the config was already active. Check the message field to determine which case occurred. Content-Type: `application/json` ```json { "type": "object", "description": "Response payload for a single FHIR Provider operation.", "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string" }, "data": { "oneOf": [ { "type": "object", "description": "Full FHIR provider configuration returned for non-sandbox providers.\n`auth_configs` and `last_updated` are always populated, which is how\nlist responses distinguish this shape from `FhirProviderSandboxInfo`.\n", "required": [ "id", "name", "provider", "auth_configs", "last_updated" ], "properties": { "id": { "type": "string", "description": "Unique identifier for the FHIR provider", "example": "1716d214-de93-43a4-aa6b-a878d864e2ad" }, "name": { "type": "string", "description": "Display name for the FHIR provider", "example": "Epic Sandbox" }, "description": { "type": "string", "description": "Optional description of the FHIR provider", "example": "Epic sandbox environment for testing" }, "provider": { "type": "string", "description": "Type of FHIR server provider.\n\nThe \"sandbox\" provider type is managed internally and cannot be created via API.\nIt is used on shared instances.\n", "enum": [ "aidbox", "athenahealth", "canvas", "cerner", "elation", "epic", "google_healthcare", "hapi", "meditech", "medplum", "phenostore", "sandbox" ], "example": "epic" }, "base_url": { "type": "string", "format": "uri", "description": "Base URL of the FHIR server", "example": "https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4" }, "client_id": { "type": "string", "deprecated": true, "description": "OAuth client ID. Deprecated: use client_id on FhirProviderAuthConfig instead. Retained for backward compatibility with existing providers.", "example": "your-client-id" }, "auth_configs": { "type": "object", "description": "Map of authentication configurations (key is auth_config_id)", "additionalProperties": { "type": "object", "description": "Authentication configuration for a FHIR provider (sensitive fields are hidden from JSON responses)", "properties": { "auth_config_id": { "type": "string", "description": "Unique identifier for this auth configuration", "example": "auth-config-123" }, "auth_method": { "type": "string", "description": "Authentication method for the FHIR provider. Only one authentication method can be used at a time,\nbut these can be rotated on the FHIR Provider as needed.\n\n**Scope behavior by auth method:**\n- `client_secret`, `jwt`, `on_behalf_of`: Scopes are included in the OAuth token request.\n They can be configured using the `role` or `scopes` field. If neither is specified, provider-specific\n default scopes derived from a default role are used. Roles grant access across all FHIR resource\n types, but the exact scope format varies by EHR — see the `Role` schema for details.\n- `google_healthcare`: Uses a fixed Google Cloud Healthcare scope. Specifying `role` or `scopes` will\n return an error.\n- `token_passthrough`: The caller provides their own bearer token via the X-Phenoml-Fhir-Provider header\n as one or more comma-separated {fhir_provider_id}:{oauth2_token} pairs. Specifying `role` or `scopes`\n will return an error. This is the recommended mode for providers like Meditech where the bearer token\n is typically obtained outside PhenoML.\n- `none`: No authentication is performed. Specifying `role` or `scopes` will return an error.\n\nFor the `on_behalf_of` authentication method, you must also provide the Patient or Practitioner reference\nin the X-Phenoml-On-Behalf-Of header in the format Patient/{uuid} or Practitioner/{uuid}. This only works\nfor the medplum provider currently.\n\nMore on the authentication headers and how to structure them can be found in the FHIR Proxy, Tools and\nAgent documentation.\n", "enum": [ "client_secret", "google_healthcare", "jwt", "on_behalf_of", "token_passthrough", "none" ], "example": "jwt" }, "is_active_auth_config": { "type": "boolean", "description": "Whether this auth configuration is currently active", "example": true }, "created_at": { "type": "string", "format": "date-time", "description": "Timestamp when this auth configuration was created", "example": "2024-01-15T10:30:00Z" }, "updated_at": { "type": "string", "format": "date-time", "description": "Timestamp when this auth configuration was last updated", "example": "2024-01-15T14:45:00Z" }, "public_key_cert_pem": { "type": "string", "description": "Public key certificate in PEM format (visible for JWT auth)", "example": "-----BEGIN CERTIFICATE-----\n..." }, "json_web_key": { "type": "object", "description": "JSON Web Key structure for RSA keys used in JWT authentication. Keys are automatically generated using RSA-2048 with RS384 signing algorithm. The Key ID (kid) is derived from a SHA256 hash of the public key PEM format.", "properties": { "kty": { "type": "string", "description": "Key Type", "example": "RSA" }, "use": { "type": "string", "description": "Usage (sig for signature)", "example": "sig" }, "kid": { "type": "string", "description": "Key ID - SHA256 hash of the public key PEM (including headers) encoded as base64url. Generated by taking the public key in PEM format, hashing with SHA256, then base64url encoding (replacing + with -, / with _, and removing padding).", "example": "FHIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0vx7agoeb" }, "alg": { "type": "string", "description": "Algorithm used for JWT signing (RSA with SHA-384)", "example": "RS384" }, "n": { "type": "string", "description": "RSA Modulus (base64url encoded)", "example": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbIS" }, "e": { "type": "string", "description": "RSA Exponent (base64url encoded)", "example": "AQAB" } } }, "credential_expiry": { "type": "string", "format": "date-time", "description": "Expiry time for credentials (JWT auth only)", "example": "2024-12-31T23:59:59Z" }, "smart_configuration": { "type": "object", "description": "SMART on FHIR configuration for OAuth-based providers", "properties": { "authorization_endpoint": { "type": "string", "format": "uri", "description": "OAuth2 authorization endpoint", "example": "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/authorize" }, "token_endpoint": { "type": "string", "format": "uri", "description": "OAuth2 token endpoint", "example": "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token" }, "issuer": { "type": "string", "format": "uri", "description": "OIDC issuer URL", "example": "https://fhir.epic.com/interconnect-fhir-oauth" }, "jwks_uri": { "type": "string", "format": "uri", "description": "JSON Web Key Set URI", "example": "https://fhir.epic.com/interconnect-fhir-oauth/.well-known/jwks" }, "scopes_supported": { "type": "array", "description": "List of supported scopes", "items": { "type": "string" }, "example": [ "patient/*.read", "system/*.read" ] } } }, "service_account_metadata": { "type": "object", "description": "Non-sensitive metadata from a Google Cloud Service Account, exposed in API responses to help identify auth configurations without revealing sensitive credentials.", "properties": { "type": { "type": "string", "description": "Account type (always \"service_account\")", "example": "service_account" }, "project_id": { "type": "string", "description": "Google Cloud project ID", "example": "my-gcp-project" }, "client_email": { "type": "string", "format": "email", "description": "Service account email address", "example": "service-account@my-gcp-project.iam.gserviceaccount.com" }, "client_id": { "type": "string", "description": "Service account client ID", "example": "123456789012345678901" } } }, "scopes": { "type": "string", "description": "OAuth scopes", "example": "system/Patient.read system/Observation.read" }, "client_id": { "type": "string", "description": "OAuth client ID for this auth configuration. When set, takes precedence over the provider-level client_id.", "example": "your-client-id" } } } }, "last_updated": { "type": "string", "format": "date-time", "description": "Timestamp when the provider was last updated", "example": "2024-01-15T10:30:00Z" } } }, { "type": "object", "description": "Limited information returned for sandbox FHIR providers. Sandbox\nresponses omit `auth_configs` and `last_updated`, which is what\ndistinguishes this shape from `FhirProviderTemplate` in `oneOf`.\n", "required": [ "id", "name", "provider" ], "properties": { "id": { "type": "string", "description": "Unique identifier for the FHIR provider", "example": "1716d214-de93-43a4-aa6b-a878d864e2ad" }, "name": { "type": "string", "description": "Display name for the FHIR provider", "example": "PhenoML Sandbox" }, "description": { "type": "string", "description": "Optional description of the FHIR provider", "example": "Shared sandbox environment for experimentation" }, "provider": { "type": "string", "enum": [ "sandbox" ], "description": "Provider type (always \"sandbox\" for this schema)", "example": "sandbox" } } } ], "description": "Provider details. Sandbox providers return FhirProviderSandboxInfo.\n" } } } ``` **Example:** ```json { "success": true, "message": "FHIR provider auth config set as active successfully", "data": { "id": "1716d214-de93-43a4-aa6b-a878d864e2ad", "name": "Epic Sandbox", "description": "Epic sandbox environment for testing", "provider": "epic", "base_url": "https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4", "auth_configs": { "auth-config-123": { "auth_config_id": "auth-config-123", "auth_method": "jwt", "is_active_auth_config": false, "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-02-20T11:00:00Z", "scopes": "system/Patient.read system/Observation.read", "client_id": "your-client-id" }, "auth-config-456": { "auth_config_id": "auth-config-456", "auth_method": "client_secret", "is_active_auth_config": true, "created_at": "2024-02-20T09:00:00Z", "updated_at": "2024-02-20T11:00:00Z", "scopes": "system/Patient.read", "client_id": "your-other-client-id" } }, "last_updated": "2024-02-20T11:00:00Z" } } ``` **400** - Invalid request **401** - Unauthorized **403** - Forbidden - dedicated instance required, or sandbox provider cannot be modified **404** - FHIR provider or auth config not found **500** - Server error --- ## Untagged ### POST /fhir-provider **Create FHIR provider** Creates a new FHIR provider configuration with authentication credentials. Note: The "sandbox" provider type cannot be created via this API - it is managed internally. **Operation ID:** `fhir_provider_create` #### Request Body **Required:** Yes **Content-Type:** `application/json` ```json { "type": "object", "required": [ "name", "provider", "base_url", "auth" ], "properties": { "name": { "type": "string", "description": "Display name for the FHIR provider", "example": "Epic Sandbox", "minLength": 1 }, "description": { "type": "string", "description": "Optional description of the FHIR provider", "example": "Epic sandbox environment for testing" }, "provider": { "type": "string", "description": "Type of FHIR server provider.\n\nThe \"sandbox\" provider type is managed internally and cannot be created via API.\nIt is used on shared instances.\n", "enum": [ "aidbox", "athenahealth", "canvas", "cerner", "elation", "epic", "google_healthcare", "hapi", "meditech", "medplum", "phenostore", "sandbox" ], "example": "epic" }, "base_url": { "type": "string", "format": "uri", "description": "Base URL of the FHIR server", "example": "https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4" }, "auth": { "oneOf": [ { "type": "object", "required": [ "auth_method", "client_id" ], "properties": { "auth_method": { "type": "string", "enum": [ "jwt" ] }, "client_id": { "type": "string", "description": "OAuth client ID", "example": "your-client-id" }, "credential_expiry": { "type": "string", "format": "date-time", "description": "Expiry time for JWT credentials. If omitted, a default expiry is used.", "example": "2024-12-31T23:59:59Z" }, "role": { "type": "string", "description": "Predefined access level that maps to provider-specific OAuth scopes.\nCannot be specified together with `scopes`. Only applicable to\n`client_secret`, `jwt`, and `on_behalf_of` auth methods.\n\nRoles apply across **all FHIR resource types** (e.g., Patient, Observation,\nCondition, etc.) — they are not limited to a single resource. The server\nresolves each role to the appropriate system-level scopes for the provider:\n- `admin`: Full CRUD access (create, read, update, delete, search) on all resources\n- `read`: Read and search access on all resources\n- `write`: Create, update, and delete access on all resources (no read)\n\n**The exact scopes generated depend on the provider**, because each EHR uses a\ndifferent SMART on FHIR version or scope format:\n- **Epic**: SMART v2 scopes (e.g., `system/*.cruds` for admin)\n- **Cerner**: Cerner-specific SMART v2 scopes with per-resource grants for the\n subset of resources Cerner supports\n- **Athenahealth**: USCDI SMART v2 scopes with explicit per-resource grants\n (e.g., `system/Patient.rs`, `system/Observation.rs`, etc.)\n- **Elation**: SMART v1 scopes (e.g., `system/*.read` for read)\n- **Medplum, Phenostore**: SMART v2 scopes\n\nIf neither `role` nor `scopes` is specified, the provider-specific default\nrole is used (typically `read`; `admin` for Medplum/sandbox).\n\nIf the generated scopes don't match what your EHR expects, use the `scopes`\nfield to specify exact scopes instead.\n\nCanvas does not support system-level roles — use `scopes` directly.\nGoogle Healthcare, HAPI, Meditech, and `none`/`token_passthrough`\nauth methods do not use scopes at all.\n", "enum": [ "admin", "read", "write" ], "example": "read" }, "scopes": { "type": "string", "description": "OAuth scopes to request. Cannot be specified with role. If neither role nor scopes are specified, the provider-specific default role will be used.", "example": "system/Patient.read system/Observation.read" } } }, { "type": "object", "required": [ "auth_method", "client_id", "client_secret" ], "properties": { "auth_method": { "type": "string", "enum": [ "client_secret" ] }, "client_id": { "type": "string", "description": "OAuth client ID", "example": "your-client-id" }, "client_secret": { "type": "string", "description": "OAuth client secret", "example": "your-client-secret" }, "role": { "type": "string", "description": "Predefined access level that maps to provider-specific OAuth scopes.\nCannot be specified together with `scopes`. Only applicable to\n`client_secret`, `jwt`, and `on_behalf_of` auth methods.\n\nRoles apply across **all FHIR resource types** (e.g., Patient, Observation,\nCondition, etc.) — they are not limited to a single resource. The server\nresolves each role to the appropriate system-level scopes for the provider:\n- `admin`: Full CRUD access (create, read, update, delete, search) on all resources\n- `read`: Read and search access on all resources\n- `write`: Create, update, and delete access on all resources (no read)\n\n**The exact scopes generated depend on the provider**, because each EHR uses a\ndifferent SMART on FHIR version or scope format:\n- **Epic**: SMART v2 scopes (e.g., `system/*.cruds` for admin)\n- **Cerner**: Cerner-specific SMART v2 scopes with per-resource grants for the\n subset of resources Cerner supports\n- **Athenahealth**: USCDI SMART v2 scopes with explicit per-resource grants\n (e.g., `system/Patient.rs`, `system/Observation.rs`, etc.)\n- **Elation**: SMART v1 scopes (e.g., `system/*.read` for read)\n- **Medplum, Phenostore**: SMART v2 scopes\n\nIf neither `role` nor `scopes` is specified, the provider-specific default\nrole is used (typically `read`; `admin` for Medplum/sandbox).\n\nIf the generated scopes don't match what your EHR expects, use the `scopes`\nfield to specify exact scopes instead.\n\nCanvas does not support system-level roles — use `scopes` directly.\nGoogle Healthcare, HAPI, Meditech, and `none`/`token_passthrough`\nauth methods do not use scopes at all.\n", "enum": [ "admin", "read", "write" ], "example": "read" }, "scopes": { "type": "string", "description": "OAuth scopes to request. Cannot be specified with role. If neither role nor scopes are specified, the provider-specific default role will be used.", "example": "system/Patient.read system/Observation.read" } } }, { "type": "object", "required": [ "auth_method", "client_id", "client_secret" ], "properties": { "auth_method": { "type": "string", "enum": [ "on_behalf_of" ] }, "client_id": { "type": "string", "description": "OAuth client ID", "example": "your-client-id" }, "client_secret": { "type": "string", "description": "OAuth client secret", "example": "your-client-secret" }, "role": { "type": "string", "description": "Predefined access level that maps to provider-specific OAuth scopes.\nCannot be specified together with `scopes`. Only applicable to\n`client_secret`, `jwt`, and `on_behalf_of` auth methods.\n\nRoles apply across **all FHIR resource types** (e.g., Patient, Observation,\nCondition, etc.) — they are not limited to a single resource. The server\nresolves each role to the appropriate system-level scopes for the provider:\n- `admin`: Full CRUD access (create, read, update, delete, search) on all resources\n- `read`: Read and search access on all resources\n- `write`: Create, update, and delete access on all resources (no read)\n\n**The exact scopes generated depend on the provider**, because each EHR uses a\ndifferent SMART on FHIR version or scope format:\n- **Epic**: SMART v2 scopes (e.g., `system/*.cruds` for admin)\n- **Cerner**: Cerner-specific SMART v2 scopes with per-resource grants for the\n subset of resources Cerner supports\n- **Athenahealth**: USCDI SMART v2 scopes with explicit per-resource grants\n (e.g., `system/Patient.rs`, `system/Observation.rs`, etc.)\n- **Elation**: SMART v1 scopes (e.g., `system/*.read` for read)\n- **Medplum, Phenostore**: SMART v2 scopes\n\nIf neither `role` nor `scopes` is specified, the provider-specific default\nrole is used (typically `read`; `admin` for Medplum/sandbox).\n\nIf the generated scopes don't match what your EHR expects, use the `scopes`\nfield to specify exact scopes instead.\n\nCanvas does not support system-level roles — use `scopes` directly.\nGoogle Healthcare, HAPI, Meditech, and `none`/`token_passthrough`\nauth methods do not use scopes at all.\n", "enum": [ "admin", "read", "write" ], "example": "read" }, "scopes": { "type": "string", "description": "OAuth scopes to request. Cannot be specified with role. If neither role nor scopes are specified, the provider-specific default role will be used.", "example": "system/Patient.read system/Observation.read" } } }, { "type": "object", "required": [ "auth_method", "service_account_key" ], "properties": { "auth_method": { "type": "string", "enum": [ "google_healthcare" ] }, "service_account_key": { "type": "object", "description": "Google Cloud Service Account key (required for google_healthcare auth method)", "required": [ "type", "project_id", "private_key_id", "private_key", "client_email", "client_id", "auth_uri", "token_uri", "auth_provider_x509_cert_url", "client_x509_cert_url", "universe_domain" ], "properties": { "type": { "type": "string", "example": "service_account" }, "project_id": { "type": "string", "example": "my-gcp-project" }, "private_key_id": { "type": "string", "example": "key-id-123" }, "private_key": { "type": "string", "example": "-----BEGIN PRIVATE KEY-----\n..." }, "client_email": { "type": "string", "format": "email", "example": "service-account@my-gcp-project.iam.gserviceaccount.com" }, "client_id": { "type": "string", "example": "123456789012345678901" }, "auth_uri": { "type": "string", "format": "uri", "example": "https://accounts.google.com/o/oauth2/auth" }, "token_uri": { "type": "string", "format": "uri", "example": "https://oauth2.googleapis.com/token" }, "auth_provider_x509_cert_url": { "type": "string", "format": "uri", "example": "https://www.googleapis.com/oauth2/v1/certs" }, "client_x509_cert_url": { "type": "string", "format": "uri", "example": "https://www.googleapis.com/robot/v1/metadata/x509/service-account%40my-gcp-project.iam.gserviceaccount.com" }, "universe_domain": { "type": "string", "example": "googleapis.com" } } } } }, { "type": "object", "required": [ "auth_method" ], "properties": { "auth_method": { "type": "string", "enum": [ "token_passthrough" ] } } }, { "type": "object", "required": [ "auth_method" ], "properties": { "auth_method": { "type": "string", "enum": [ "none" ] } } } ], "discriminator": { "propertyName": "auth_method", "mapping": { "jwt": "#/components/schemas/fhir_provider_JwtAuth", "client_secret": "#/components/schemas/fhir_provider_ClientSecretAuth", "on_behalf_of": "#/components/schemas/fhir_provider_OnBehalfOfAuth", "google_healthcare": "#/components/schemas/fhir_provider_GoogleHealthcareAuth", "token_passthrough": "#/components/schemas/fhir_provider_TokenPassthroughAuth", "none": "#/components/schemas/fhir_provider_NoAuth" } } } } } ``` **Example:** ```json { "name": "Epic Sandbox", "description": "Epic sandbox environment for testing", "provider": "epic", "base_url": "https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4", "auth": { "auth_method": "client_secret", "client_id": "your-client-id", "client_secret": "your-client-secret", "role": "read" } } ``` #### Responses **201** - FHIR provider created successfully Content-Type: `application/json` ```json { "type": "object", "description": "Response payload for a single FHIR Provider operation.", "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string" }, "data": { "oneOf": [ { "type": "object", "description": "Full FHIR provider configuration returned for non-sandbox providers.\n`auth_configs` and `last_updated` are always populated, which is how\nlist responses distinguish this shape from `FhirProviderSandboxInfo`.\n", "required": [ "id", "name", "provider", "auth_configs", "last_updated" ], "properties": { "id": { "type": "string", "description": "Unique identifier for the FHIR provider", "example": "1716d214-de93-43a4-aa6b-a878d864e2ad" }, "name": { "type": "string", "description": "Display name for the FHIR provider", "example": "Epic Sandbox" }, "description": { "type": "string", "description": "Optional description of the FHIR provider", "example": "Epic sandbox environment for testing" }, "provider": { "type": "string", "description": "Type of FHIR server provider.\n\nThe \"sandbox\" provider type is managed internally and cannot be created via API.\nIt is used on shared instances.\n", "enum": [ "aidbox", "athenahealth", "canvas", "cerner", "elation", "epic", "google_healthcare", "hapi", "meditech", "medplum", "phenostore", "sandbox" ], "example": "epic" }, "base_url": { "type": "string", "format": "uri", "description": "Base URL of the FHIR server", "example": "https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4" }, "client_id": { "type": "string", "deprecated": true, "description": "OAuth client ID. Deprecated: use client_id on FhirProviderAuthConfig instead. Retained for backward compatibility with existing providers.", "example": "your-client-id" }, "auth_configs": { "type": "object", "description": "Map of authentication configurations (key is auth_config_id)", "additionalProperties": { "type": "object", "description": "Authentication configuration for a FHIR provider (sensitive fields are hidden from JSON responses)", "properties": { "auth_config_id": { "type": "string", "description": "Unique identifier for this auth configuration", "example": "auth-config-123" }, "auth_method": { "type": "string", "description": "Authentication method for the FHIR provider. Only one authentication method can be used at a time,\nbut these can be rotated on the FHIR Provider as needed.\n\n**Scope behavior by auth method:**\n- `client_secret`, `jwt`, `on_behalf_of`: Scopes are included in the OAuth token request.\n They can be configured using the `role` or `scopes` field. If neither is specified, provider-specific\n default scopes derived from a default role are used. Roles grant access across all FHIR resource\n types, but the exact scope format varies by EHR — see the `Role` schema for details.\n- `google_healthcare`: Uses a fixed Google Cloud Healthcare scope. Specifying `role` or `scopes` will\n return an error.\n- `token_passthrough`: The caller provides their own bearer token via the X-Phenoml-Fhir-Provider header\n as one or more comma-separated {fhir_provider_id}:{oauth2_token} pairs. Specifying `role` or `scopes`\n will return an error. This is the recommended mode for providers like Meditech where the bearer token\n is typically obtained outside PhenoML.\n- `none`: No authentication is performed. Specifying `role` or `scopes` will return an error.\n\nFor the `on_behalf_of` authentication method, you must also provide the Patient or Practitioner reference\nin the X-Phenoml-On-Behalf-Of header in the format Patient/{uuid} or Practitioner/{uuid}. This only works\nfor the medplum provider currently.\n\nMore on the authentication headers and how to structure them can be found in the FHIR Proxy, Tools and\nAgent documentation.\n", "enum": [ "client_secret", "google_healthcare", "jwt", "on_behalf_of", "token_passthrough", "none" ], "example": "jwt" }, "is_active_auth_config": { "type": "boolean", "description": "Whether this auth configuration is currently active", "example": true }, "created_at": { "type": "string", "format": "date-time", "description": "Timestamp when this auth configuration was created", "example": "2024-01-15T10:30:00Z" }, "updated_at": { "type": "string", "format": "date-time", "description": "Timestamp when this auth configuration was last updated", "example": "2024-01-15T14:45:00Z" }, "public_key_cert_pem": { "type": "string", "description": "Public key certificate in PEM format (visible for JWT auth)", "example": "-----BEGIN CERTIFICATE-----\n..." }, "json_web_key": { "type": "object", "description": "JSON Web Key structure for RSA keys used in JWT authentication. Keys are automatically generated using RSA-2048 with RS384 signing algorithm. The Key ID (kid) is derived from a SHA256 hash of the public key PEM format.", "properties": { "kty": { "type": "string", "description": "Key Type", "example": "RSA" }, "use": { "type": "string", "description": "Usage (sig for signature)", "example": "sig" }, "kid": { "type": "string", "description": "Key ID - SHA256 hash of the public key PEM (including headers) encoded as base64url. Generated by taking the public key in PEM format, hashing with SHA256, then base64url encoding (replacing + with -, / with _, and removing padding).", "example": "FHIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0vx7agoeb" }, "alg": { "type": "string", "description": "Algorithm used for JWT signing (RSA with SHA-384)", "example": "RS384" }, "n": { "type": "string", "description": "RSA Modulus (base64url encoded)", "example": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbIS" }, "e": { "type": "string", "description": "RSA Exponent (base64url encoded)", "example": "AQAB" } } }, "credential_expiry": { "type": "string", "format": "date-time", "description": "Expiry time for credentials (JWT auth only)", "example": "2024-12-31T23:59:59Z" }, "smart_configuration": { "type": "object", "description": "SMART on FHIR configuration for OAuth-based providers", "properties": { "authorization_endpoint": { "type": "string", "format": "uri", "description": "OAuth2 authorization endpoint", "example": "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/authorize" }, "token_endpoint": { "type": "string", "format": "uri", "description": "OAuth2 token endpoint", "example": "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token" }, "issuer": { "type": "string", "format": "uri", "description": "OIDC issuer URL", "example": "https://fhir.epic.com/interconnect-fhir-oauth" }, "jwks_uri": { "type": "string", "format": "uri", "description": "JSON Web Key Set URI", "example": "https://fhir.epic.com/interconnect-fhir-oauth/.well-known/jwks" }, "scopes_supported": { "type": "array", "description": "List of supported scopes", "items": { "type": "string" }, "example": [ "patient/*.read", "system/*.read" ] } } }, "service_account_metadata": { "type": "object", "description": "Non-sensitive metadata from a Google Cloud Service Account, exposed in API responses to help identify auth configurations without revealing sensitive credentials.", "properties": { "type": { "type": "string", "description": "Account type (always \"service_account\")", "example": "service_account" }, "project_id": { "type": "string", "description": "Google Cloud project ID", "example": "my-gcp-project" }, "client_email": { "type": "string", "format": "email", "description": "Service account email address", "example": "service-account@my-gcp-project.iam.gserviceaccount.com" }, "client_id": { "type": "string", "description": "Service account client ID", "example": "123456789012345678901" } } }, "scopes": { "type": "string", "description": "OAuth scopes", "example": "system/Patient.read system/Observation.read" }, "client_id": { "type": "string", "description": "OAuth client ID for this auth configuration. When set, takes precedence over the provider-level client_id.", "example": "your-client-id" } } } }, "last_updated": { "type": "string", "format": "date-time", "description": "Timestamp when the provider was last updated", "example": "2024-01-15T10:30:00Z" } } }, { "type": "object", "description": "Limited information returned for sandbox FHIR providers. Sandbox\nresponses omit `auth_configs` and `last_updated`, which is what\ndistinguishes this shape from `FhirProviderTemplate` in `oneOf`.\n", "required": [ "id", "name", "provider" ], "properties": { "id": { "type": "string", "description": "Unique identifier for the FHIR provider", "example": "1716d214-de93-43a4-aa6b-a878d864e2ad" }, "name": { "type": "string", "description": "Display name for the FHIR provider", "example": "PhenoML Sandbox" }, "description": { "type": "string", "description": "Optional description of the FHIR provider", "example": "Shared sandbox environment for experimentation" }, "provider": { "type": "string", "enum": [ "sandbox" ], "description": "Provider type (always \"sandbox\" for this schema)", "example": "sandbox" } } } ], "description": "Provider details. Sandbox providers return FhirProviderSandboxInfo.\n" } } } ``` **Example:** ```json { "success": true, "message": "Fhir provider created successfully", "data": { "id": "1716d214-de93-43a4-aa6b-a878d864e2ad", "name": "Epic Sandbox", "description": "Epic sandbox environment for testing", "provider": "epic", "base_url": "https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4", "auth_configs": { "auth-config-123": { "auth_config_id": "auth-config-123", "auth_method": "client_secret", "is_active_auth_config": true, "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z", "scopes": "system/Patient.read system/Observation.read", "client_id": "your-client-id" } }, "last_updated": "2024-01-15T10:30:00Z" } } ``` **400** - Invalid request - missing required fields or invalid values **401** - Unauthorized **403** - Forbidden - only available on dedicated instances **500** - Server error --- ### GET /fhir-provider/{fhir_provider_id} **Get FHIR provider by ID** Retrieves a specific FHIR provider configuration by its ID. Sandbox providers return FhirProviderSandboxInfo. On shared instances, only sandbox providers can be accessed. **Operation ID:** `fhir_provider_get` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `fhir_provider_id` | path | string | Yes | ID of the FHIR provider to retrieve | #### Responses **200** - FHIR provider retrieved successfully Content-Type: `application/json` ```json { "type": "object", "description": "Response payload for a single FHIR Provider operation.", "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string" }, "data": { "oneOf": [ { "type": "object", "description": "Full FHIR provider configuration returned for non-sandbox providers.\n`auth_configs` and `last_updated` are always populated, which is how\nlist responses distinguish this shape from `FhirProviderSandboxInfo`.\n", "required": [ "id", "name", "provider", "auth_configs", "last_updated" ], "properties": { "id": { "type": "string", "description": "Unique identifier for the FHIR provider", "example": "1716d214-de93-43a4-aa6b-a878d864e2ad" }, "name": { "type": "string", "description": "Display name for the FHIR provider", "example": "Epic Sandbox" }, "description": { "type": "string", "description": "Optional description of the FHIR provider", "example": "Epic sandbox environment for testing" }, "provider": { "type": "string", "description": "Type of FHIR server provider.\n\nThe \"sandbox\" provider type is managed internally and cannot be created via API.\nIt is used on shared instances.\n", "enum": [ "aidbox", "athenahealth", "canvas", "cerner", "elation", "epic", "google_healthcare", "hapi", "meditech", "medplum", "phenostore", "sandbox" ], "example": "epic" }, "base_url": { "type": "string", "format": "uri", "description": "Base URL of the FHIR server", "example": "https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4" }, "client_id": { "type": "string", "deprecated": true, "description": "OAuth client ID. Deprecated: use client_id on FhirProviderAuthConfig instead. Retained for backward compatibility with existing providers.", "example": "your-client-id" }, "auth_configs": { "type": "object", "description": "Map of authentication configurations (key is auth_config_id)", "additionalProperties": { "type": "object", "description": "Authentication configuration for a FHIR provider (sensitive fields are hidden from JSON responses)", "properties": { "auth_config_id": { "type": "string", "description": "Unique identifier for this auth configuration", "example": "auth-config-123" }, "auth_method": { "type": "string", "description": "Authentication method for the FHIR provider. Only one authentication method can be used at a time,\nbut these can be rotated on the FHIR Provider as needed.\n\n**Scope behavior by auth method:**\n- `client_secret`, `jwt`, `on_behalf_of`: Scopes are included in the OAuth token request.\n They can be configured using the `role` or `scopes` field. If neither is specified, provider-specific\n default scopes derived from a default role are used. Roles grant access across all FHIR resource\n types, but the exact scope format varies by EHR — see the `Role` schema for details.\n- `google_healthcare`: Uses a fixed Google Cloud Healthcare scope. Specifying `role` or `scopes` will\n return an error.\n- `token_passthrough`: The caller provides their own bearer token via the X-Phenoml-Fhir-Provider header\n as one or more comma-separated {fhir_provider_id}:{oauth2_token} pairs. Specifying `role` or `scopes`\n will return an error. This is the recommended mode for providers like Meditech where the bearer token\n is typically obtained outside PhenoML.\n- `none`: No authentication is performed. Specifying `role` or `scopes` will return an error.\n\nFor the `on_behalf_of` authentication method, you must also provide the Patient or Practitioner reference\nin the X-Phenoml-On-Behalf-Of header in the format Patient/{uuid} or Practitioner/{uuid}. This only works\nfor the medplum provider currently.\n\nMore on the authentication headers and how to structure them can be found in the FHIR Proxy, Tools and\nAgent documentation.\n", "enum": [ "client_secret", "google_healthcare", "jwt", "on_behalf_of", "token_passthrough", "none" ], "example": "jwt" }, "is_active_auth_config": { "type": "boolean", "description": "Whether this auth configuration is currently active", "example": true }, "created_at": { "type": "string", "format": "date-time", "description": "Timestamp when this auth configuration was created", "example": "2024-01-15T10:30:00Z" }, "updated_at": { "type": "string", "format": "date-time", "description": "Timestamp when this auth configuration was last updated", "example": "2024-01-15T14:45:00Z" }, "public_key_cert_pem": { "type": "string", "description": "Public key certificate in PEM format (visible for JWT auth)", "example": "-----BEGIN CERTIFICATE-----\n..." }, "json_web_key": { "type": "object", "description": "JSON Web Key structure for RSA keys used in JWT authentication. Keys are automatically generated using RSA-2048 with RS384 signing algorithm. The Key ID (kid) is derived from a SHA256 hash of the public key PEM format.", "properties": { "kty": { "type": "string", "description": "Key Type", "example": "RSA" }, "use": { "type": "string", "description": "Usage (sig for signature)", "example": "sig" }, "kid": { "type": "string", "description": "Key ID - SHA256 hash of the public key PEM (including headers) encoded as base64url. Generated by taking the public key in PEM format, hashing with SHA256, then base64url encoding (replacing + with -, / with _, and removing padding).", "example": "FHIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0vx7agoeb" }, "alg": { "type": "string", "description": "Algorithm used for JWT signing (RSA with SHA-384)", "example": "RS384" }, "n": { "type": "string", "description": "RSA Modulus (base64url encoded)", "example": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbIS" }, "e": { "type": "string", "description": "RSA Exponent (base64url encoded)", "example": "AQAB" } } }, "credential_expiry": { "type": "string", "format": "date-time", "description": "Expiry time for credentials (JWT auth only)", "example": "2024-12-31T23:59:59Z" }, "smart_configuration": { "type": "object", "description": "SMART on FHIR configuration for OAuth-based providers", "properties": { "authorization_endpoint": { "type": "string", "format": "uri", "description": "OAuth2 authorization endpoint", "example": "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/authorize" }, "token_endpoint": { "type": "string", "format": "uri", "description": "OAuth2 token endpoint", "example": "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token" }, "issuer": { "type": "string", "format": "uri", "description": "OIDC issuer URL", "example": "https://fhir.epic.com/interconnect-fhir-oauth" }, "jwks_uri": { "type": "string", "format": "uri", "description": "JSON Web Key Set URI", "example": "https://fhir.epic.com/interconnect-fhir-oauth/.well-known/jwks" }, "scopes_supported": { "type": "array", "description": "List of supported scopes", "items": { "type": "string" }, "example": [ "patient/*.read", "system/*.read" ] } } }, "service_account_metadata": { "type": "object", "description": "Non-sensitive metadata from a Google Cloud Service Account, exposed in API responses to help identify auth configurations without revealing sensitive credentials.", "properties": { "type": { "type": "string", "description": "Account type (always \"service_account\")", "example": "service_account" }, "project_id": { "type": "string", "description": "Google Cloud project ID", "example": "my-gcp-project" }, "client_email": { "type": "string", "format": "email", "description": "Service account email address", "example": "service-account@my-gcp-project.iam.gserviceaccount.com" }, "client_id": { "type": "string", "description": "Service account client ID", "example": "123456789012345678901" } } }, "scopes": { "type": "string", "description": "OAuth scopes", "example": "system/Patient.read system/Observation.read" }, "client_id": { "type": "string", "description": "OAuth client ID for this auth configuration. When set, takes precedence over the provider-level client_id.", "example": "your-client-id" } } } }, "last_updated": { "type": "string", "format": "date-time", "description": "Timestamp when the provider was last updated", "example": "2024-01-15T10:30:00Z" } } }, { "type": "object", "description": "Limited information returned for sandbox FHIR providers. Sandbox\nresponses omit `auth_configs` and `last_updated`, which is what\ndistinguishes this shape from `FhirProviderTemplate` in `oneOf`.\n", "required": [ "id", "name", "provider" ], "properties": { "id": { "type": "string", "description": "Unique identifier for the FHIR provider", "example": "1716d214-de93-43a4-aa6b-a878d864e2ad" }, "name": { "type": "string", "description": "Display name for the FHIR provider", "example": "PhenoML Sandbox" }, "description": { "type": "string", "description": "Optional description of the FHIR provider", "example": "Shared sandbox environment for experimentation" }, "provider": { "type": "string", "enum": [ "sandbox" ], "description": "Provider type (always \"sandbox\" for this schema)", "example": "sandbox" } } } ], "description": "Provider details. Sandbox providers return FhirProviderSandboxInfo.\n" } } } ``` **Example:** ```json { "success": true, "message": "Fhir provider retrieved successfully", "data": { "id": "1716d214-de93-43a4-aa6b-a878d864e2ad", "name": "Epic Sandbox", "description": "Epic sandbox environment for testing", "provider": "epic", "base_url": "https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4", "auth_configs": { "auth-config-123": { "auth_config_id": "auth-config-123", "auth_method": "jwt", "is_active_auth_config": true, "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T14:45:00Z", "scopes": "system/Patient.read system/Observation.read", "client_id": "your-client-id" } }, "last_updated": "2024-01-15T14:45:00Z" } } ``` **401** - Unauthorized **404** - FHIR provider not found **500** - Server error --- ### DELETE /fhir-provider/{fhir_provider_id} **Delete FHIR provider** Deletes a FHIR provider. Note: Sandbox providers cannot be deleted. **Operation ID:** `fhir_provider_delete` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `fhir_provider_id` | path | string | Yes | ID of the FHIR provider to delete | #### Responses **200** - FHIR provider deleted successfully Content-Type: `application/json` ```json { "type": "object", "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string", "example": "Fhir provider deleted successfully" } } } ``` **Example:** ```json { "success": true, "message": "Fhir provider deleted successfully" } ``` **401** - Unauthorized **403** - Forbidden - dedicated instance required, or sandbox provider cannot be modified **404** - FHIR provider not found **500** - Server error --- ### POST /fhir-provider/{fhir_provider_id}/fhir **Execute FHIR bundle operation** Executes a FHIR Bundle transaction or batch operation on the specified provider. This allows multiple FHIR resources to be processed in a single request. The request body should contain a valid FHIR Bundle resource with transaction or batch type. The request is proxied to the configured FHIR server with appropriate authentication headers. **Operation ID:** `fhir_executeBundle` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `fhir_provider_id` | path | string | Yes | The ID of the FHIR provider to use. Can be either: - A UUID representing the provider ID - A provider name (legacy support - will just use the most recently updated provider with this name) | | `X-Phenoml-On-Behalf-Of` | header | string | No | Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity. Must be in the format: Patient/{uuid} or Practitioner/{uuid} | | `X-Phenoml-Fhir-Provider` | header | string | No | Optional header for FHIR provider authentication. Contains credentials in the format {fhir_provider_id}:{oauth2_token}. Multiple FHIR provider integrations can be provided as comma-separated values. | #### Request Body FHIR Bundle for transaction or batch processing **Required:** Yes **Content-Type:** `application/fhir+json` ```json {} ``` **Example:** ```json { "resourceType": "Bundle", "type": "transaction", "entry": [ { "request": { "method": "POST", "url": "Patient" }, "resource": { "resourceType": "Patient", "name": [ { "family": "Doe", "given": [ "John" ] } ] } }, { "request": { "method": "POST", "url": "Observation" }, "resource": { "resourceType": "Observation", "status": "final", "subject": { "reference": "Patient/123" } } } ] } ``` #### Responses **200** - Bundle executed successfully Content-Type: `application/json` ```json {} ``` **Example:** ```json { "resourceType": "Bundle", "type": "transaction-response", "entry": [ { "response": { "status": "201 Created", "location": "Patient/456" }, "resource": { "resourceType": "Patient", "id": "456" } } ] } ``` --- ### GET /fhir-provider/{fhir_provider_id}/fhir/{fhir_path} **Read or search FHIR resources** Retrieves FHIR resources from the specified provider. Supports both individual resource retrieval (e.g. `Patient/123` via the path) and search operations. FHIR search parameters are passed through to the upstream server verbatim as native query-string parameters; this proxy does not model, validate, or transform them. Append standard FHIR search parameters directly to the request URL. Supported parameters include: - Resource-specific search parameters (e.g. `name` for Patient, `status` for Observation) - Common search parameters (`_id`, `_lastUpdated`, `_tag`, `_profile`, `_security`, `_text`, `_content`, `_filter`) - Result parameters (`_count`, `_offset`, `_sort`, `_include`, `_revinclude`, `_summary`, `_elements`) - Search prefixes for dates, numbers, and quantities (`eq`, `ne`, `gt`, `ge`, `lt`, `le`, `sa`, `eb`, `ap`) Examples: - `Patient?name=John%20Doe&_count=10&_sort=family` - `Observation?patient=Patient/123&date=ge2023-01-01&category=vital-signs&_sort=-date` When using a generated SDK, supply these via the client's request-level query-parameter option (the SDK escape hatch) rather than a typed argument. The request is proxied to the configured FHIR server with appropriate authentication headers. **Operation ID:** `fhir_search` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `fhir_provider_id` | path | string | Yes | The ID of the FHIR provider to use. Can be either: - A UUID representing the provider ID - A provider name (legacy support - will just use the most recently updated provider with this name) | | `fhir_path` | path | string | Yes | The FHIR resource path to operate on. This follows FHIR RESTful API conventions. Examples: - "Patient" (for resource type operations) - "Patient/123" (for specific resource operations) - "Patient/123/_history" (for history operations) | | `X-Phenoml-On-Behalf-Of` | header | string | No | Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity. Must be in the format: Patient/{uuid} or Practitioner/{uuid} | | `X-Phenoml-Fhir-Provider` | header | string | No | Optional header for FHIR provider authentication. Contains credentials in the format {fhir_provider_id}:{oauth2_token}. Multiple FHIR provider integrations can be provided as comma-separated values. | #### Responses **200** - Successfully retrieved FHIR resource(s) Content-Type: `application/json` ```json {} ``` **Example:** ```json { "resourceType": "Bundle", "total": 2, "entry": [ { "resource": { "resourceType": "Patient", "id": "123", "name": [ { "family": "Doe", "given": [ "John" ] } ] } } ] } ``` --- ### PUT /fhir-provider/{fhir_provider_id}/fhir/{fhir_path} **Upsert FHIR resource** Creates or updates a FHIR resource on the specified provider. If the resource exists, it will be updated; otherwise, it will be created. The request is proxied to the configured FHIR server with appropriate authentication headers. **Operation ID:** `fhir_upsert` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `fhir_provider_id` | path | string | Yes | The ID of the FHIR provider to use. Can be either: - A UUID representing the provider ID - A provider name (legacy support - will just use the most recently updated provider with this name) | | `fhir_path` | path | string | Yes | The FHIR resource path to operate on. This follows FHIR RESTful API conventions. Examples: - "Patient" (for resource type operations) - "Patient/123" (for specific resource operations) - "Patient/123/_history" (for history operations) | | `X-Phenoml-On-Behalf-Of` | header | string | No | Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity. Must be in the format: Patient/{uuid} or Practitioner/{uuid} | | `X-Phenoml-Fhir-Provider` | header | string | No | Optional header for FHIR provider authentication. Contains credentials in the format {fhir_provider_id}:{oauth2_token}. Multiple FHIR provider integrations can be provided as comma-separated values. | #### Request Body FHIR resource to create or update **Required:** Yes **Content-Type:** `application/fhir+json` ```json {} ``` **Example:** ```json { "resourceType": "Patient", "id": "123" } ``` #### Responses **200** - Resource upserted successfully Content-Type: `application/json` ```json {} ``` **Example:** ```json { "resourceType": "Patient", "id": "123", "meta": { "versionId": "2", "lastUpdated": "2024-02-20T11:00:00Z" } } ``` --- ### POST /fhir-provider/{fhir_provider_id}/fhir/{fhir_path} **Create FHIR resource** Creates a new FHIR resource on the specified provider. The request body should contain a valid FHIR resource in JSON format. The request is proxied to the configured FHIR server with appropriate authentication headers. **Operation ID:** `fhir_create` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `fhir_provider_id` | path | string | Yes | The ID of the FHIR provider to use. Can be either: - A UUID representing the provider ID - A provider name (legacy support - will just use the most recently updated provider with this name) | | `fhir_path` | path | string | Yes | The FHIR resource path to operate on. This follows FHIR RESTful API conventions. Examples: - "Patient" (for resource type operations) - "Patient/123" (for specific resource operations) - "Patient/123/_history" (for history operations) | | `X-Phenoml-On-Behalf-Of` | header | string | No | Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity. Must be in the format: Patient/{uuid} or Practitioner/{uuid} | | `X-Phenoml-Fhir-Provider` | header | string | No | Optional header for FHIR provider authentication. Contains credentials in the format {fhir_provider_id}:{oauth2_token}. Multiple FHIR provider integrations can be provided as comma-separated values. | #### Request Body FHIR resource to create **Required:** Yes **Content-Type:** `application/fhir+json` ```json {} ``` **Example:** ```json { "resourceType": "Patient" } ``` #### Responses **200** - Resource created successfully Content-Type: `application/json` ```json {} ``` **Example:** ```json { "resourceType": "Patient", "id": "456", "meta": { "versionId": "1", "lastUpdated": "2024-01-15T10:30:00Z" } } ``` --- ### DELETE /fhir-provider/{fhir_provider_id}/fhir/{fhir_path} **Delete FHIR resource** Deletes a FHIR resource from the specified provider. The request is proxied to the configured FHIR server with appropriate authentication headers. **Operation ID:** `fhir_delete` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `fhir_provider_id` | path | string | Yes | The ID of the FHIR provider to use. Can be either: - A UUID representing the provider ID - A provider name (legacy support - will just use the most recently updated provider with this name) | | `fhir_path` | path | string | Yes | The FHIR resource path to operate on. This follows FHIR RESTful API conventions. Examples: - "Patient" (for resource type operations) - "Patient/123" (for specific resource operations) - "Patient/123/_history" (for history operations) | | `X-Phenoml-On-Behalf-Of` | header | string | No | Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity. Must be in the format: Patient/{uuid} or Practitioner/{uuid} | | `X-Phenoml-Fhir-Provider` | header | string | No | Optional header for FHIR provider authentication. Contains credentials in the format {fhir_provider_id}:{oauth2_token}. Multiple FHIR provider integrations can be provided as comma-separated values. | #### Responses **200** - Resource deleted successfully Content-Type: `application/json` ```json {} ``` **Example:** ```json { "resourceType": "OperationOutcome", "issue": [ { "severity": "information", "code": "informational", "details": { "text": "Resource deleted successfully" } } ] } ``` --- ### PATCH /fhir-provider/{fhir_provider_id}/fhir/{fhir_path} **Patch FHIR resource** Partially updates a FHIR resource on the specified provider. Two body formats are supported, selected by request content type: - `application/json-patch+json` — an array of JSON Patch operations as defined in RFC 6902. Each operation specifies: - `op`: The operation type (add, remove, replace, move, copy, test) - `path`: JSON Pointer to the target location in the resource - `value`: The value to use (required for add, replace, and test operations) - `application/fhir+json` — a partial FHIR resource for merge-patch semantics. **Note:** This proxy currently forwards the request body to the upstream FHIR server with `Content-Type: application/fhir+json` regardless of the declared request content type. JSON Patch (RFC 6902) therefore only succeeds against upstream servers that accept patch arrays under `application/fhir+json`; servers that strictly enforce patch media types may reject or misinterpret it. Support for either format ultimately depends on the upstream FHIR server. The request is proxied to the configured FHIR server with appropriate authentication headers. **Operation ID:** `fhir_patch` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `fhir_provider_id` | path | string | Yes | The ID of the FHIR provider to use. Can be either: - A UUID representing the provider ID - A provider name (legacy support - will just use the most recently updated provider with this name) | | `fhir_path` | path | string | Yes | The FHIR resource path to operate on. This follows FHIR RESTful API conventions. Examples: - "Patient" (for resource type operations) - "Patient/123" (for specific resource operations) - "Patient/123/_history" (for history operations) | | `X-Phenoml-On-Behalf-Of` | header | string | No | Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity. Must be in the format: Patient/{uuid} or Practitioner/{uuid} | | `X-Phenoml-Fhir-Provider` | header | string | No | Optional header for FHIR provider authentication. Contains credentials in the format {fhir_provider_id}:{oauth2_token}. Multiple FHIR provider integrations can be provided as comma-separated values. | #### Request Body JSON Patch operations to apply to the FHIR resource (RFC 6902) **Required:** Yes **Content-Type:** `application/json-patch+json` ```json { "type": "array", "description": "Array of JSON Patch operations following RFC 6902", "items": { "type": "object", "required": [ "op", "path" ], "properties": { "op": { "type": "string", "enum": [ "add", "remove", "replace", "move", "copy", "test" ], "description": "The operation to perform" }, "path": { "type": "string", "description": "JSON Pointer to the target location" }, "value": { "description": "The value to use (required for add, replace, test operations)" }, "from": { "type": "string", "description": "Source location for move and copy operations (JSON Pointer)" } } } } ``` **Example:** ```json [ { "op": "replace", "path": "/name/0/family", "value": "NewFamilyName" } ] ``` **Content-Type:** `application/fhir+json` ```json {} ``` **Example:** ```json { "name": [ { "family": "NewName", "given": [ "John" ] } ] } ``` #### Responses **200** - Resource patched successfully Content-Type: `application/json` ```json {} ``` **Example:** ```json { "resourceType": "Patient", "id": "123", "meta": { "versionId": "3", "lastUpdated": "2024-02-20T11:30:00Z" } } ``` --- ### GET /fhir-provider/list **List FHIR providers** Retrieves a list of all active FHIR providers for the authenticated user. On shared instances, only sandbox providers are returned. Sandbox providers return FhirProviderSandboxInfo. **Operation ID:** `fhir_provider_list` #### Responses **200** - FHIR providers retrieved successfully Content-Type: `application/json` ```json { "type": "object", "description": "Response payload for listing FHIR Providers.\nOn shared instances, only sandbox providers are returned (as FhirProviderSandboxInfo).\nOn dedicated instances, full provider details are returned (as FhirProviderTemplate).\n", "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string", "example": "Fhir providers retrieved successfully" }, "fhir_providers": { "type": "array", "description": "List of FHIR providers. Sandbox providers return FhirProviderSandboxInfo,\nother providers return FhirProviderTemplate.\n", "items": { "oneOf": [ { "type": "object", "description": "Full FHIR provider configuration returned for non-sandbox providers.\n`auth_configs` and `last_updated` are always populated, which is how\nlist responses distinguish this shape from `FhirProviderSandboxInfo`.\n", "required": [ "id", "name", "provider", "auth_configs", "last_updated" ], "properties": { "id": { "type": "string", "description": "Unique identifier for the FHIR provider", "example": "1716d214-de93-43a4-aa6b-a878d864e2ad" }, "name": { "type": "string", "description": "Display name for the FHIR provider", "example": "Epic Sandbox" }, "description": { "type": "string", "description": "Optional description of the FHIR provider", "example": "Epic sandbox environment for testing" }, "provider": { "type": "string", "description": "Type of FHIR server provider.\n\nThe \"sandbox\" provider type is managed internally and cannot be created via API.\nIt is used on shared instances.\n", "enum": [ "aidbox", "athenahealth", "canvas", "cerner", "elation", "epic", "google_healthcare", "hapi", "meditech", "medplum", "phenostore", "sandbox" ], "example": "epic" }, "base_url": { "type": "string", "format": "uri", "description": "Base URL of the FHIR server", "example": "https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4" }, "client_id": { "type": "string", "deprecated": true, "description": "OAuth client ID. Deprecated: use client_id on FhirProviderAuthConfig instead. Retained for backward compatibility with existing providers.", "example": "your-client-id" }, "auth_configs": { "type": "object", "description": "Map of authentication configurations (key is auth_config_id)", "additionalProperties": { "type": "object", "description": "Authentication configuration for a FHIR provider (sensitive fields are hidden from JSON responses)", "properties": { "auth_config_id": { "type": "string", "description": "Unique identifier for this auth configuration", "example": "auth-config-123" }, "auth_method": { "type": "string", "description": "Authentication method for the FHIR provider. Only one authentication method can be used at a time,\nbut these can be rotated on the FHIR Provider as needed.\n\n**Scope behavior by auth method:**\n- `client_secret`, `jwt`, `on_behalf_of`: Scopes are included in the OAuth token request.\n They can be configured using the `role` or `scopes` field. If neither is specified, provider-specific\n default scopes derived from a default role are used. Roles grant access across all FHIR resource\n types, but the exact scope format varies by EHR — see the `Role` schema for details.\n- `google_healthcare`: Uses a fixed Google Cloud Healthcare scope. Specifying `role` or `scopes` will\n return an error.\n- `token_passthrough`: The caller provides their own bearer token via the X-Phenoml-Fhir-Provider header\n as one or more comma-separated {fhir_provider_id}:{oauth2_token} pairs. Specifying `role` or `scopes`\n will return an error. This is the recommended mode for providers like Meditech where the bearer token\n is typically obtained outside PhenoML.\n- `none`: No authentication is performed. Specifying `role` or `scopes` will return an error.\n\nFor the `on_behalf_of` authentication method, you must also provide the Patient or Practitioner reference\nin the X-Phenoml-On-Behalf-Of header in the format Patient/{uuid} or Practitioner/{uuid}. This only works\nfor the medplum provider currently.\n\nMore on the authentication headers and how to structure them can be found in the FHIR Proxy, Tools and\nAgent documentation.\n", "enum": [ "client_secret", "google_healthcare", "jwt", "on_behalf_of", "token_passthrough", "none" ], "example": "jwt" }, "is_active_auth_config": { "type": "boolean", "description": "Whether this auth configuration is currently active", "example": true }, "created_at": { "type": "string", "format": "date-time", "description": "Timestamp when this auth configuration was created", "example": "2024-01-15T10:30:00Z" }, "updated_at": { "type": "string", "format": "date-time", "description": "Timestamp when this auth configuration was last updated", "example": "2024-01-15T14:45:00Z" }, "public_key_cert_pem": { "type": "string", "description": "Public key certificate in PEM format (visible for JWT auth)", "example": "-----BEGIN CERTIFICATE-----\n..." }, "json_web_key": { "type": "object", "description": "JSON Web Key structure for RSA keys used in JWT authentication. Keys are automatically generated using RSA-2048 with RS384 signing algorithm. The Key ID (kid) is derived from a SHA256 hash of the public key PEM format.", "properties": { "kty": { "type": "string", "description": "Key Type", "example": "RSA" }, "use": { "type": "string", "description": "Usage (sig for signature)", "example": "sig" }, "kid": { "type": "string", "description": "Key ID - SHA256 hash of the public key PEM (including headers) encoded as base64url. Generated by taking the public key in PEM format, hashing with SHA256, then base64url encoding (replacing + with -, / with _, and removing padding).", "example": "FHIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0vx7agoeb" }, "alg": { "type": "string", "description": "Algorithm used for JWT signing (RSA with SHA-384)", "example": "RS384" }, "n": { "type": "string", "description": "RSA Modulus (base64url encoded)", "example": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbIS" }, "e": { "type": "string", "description": "RSA Exponent (base64url encoded)", "example": "AQAB" } } }, "credential_expiry": { "type": "string", "format": "date-time", "description": "Expiry time for credentials (JWT auth only)", "example": "2024-12-31T23:59:59Z" }, "smart_configuration": { "type": "object", "description": "SMART on FHIR configuration for OAuth-based providers", "properties": { "authorization_endpoint": { "type": "string", "format": "uri", "description": "OAuth2 authorization endpoint", "example": "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/authorize" }, "token_endpoint": { "type": "string", "format": "uri", "description": "OAuth2 token endpoint", "example": "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token" }, "issuer": { "type": "string", "format": "uri", "description": "OIDC issuer URL", "example": "https://fhir.epic.com/interconnect-fhir-oauth" }, "jwks_uri": { "type": "string", "format": "uri", "description": "JSON Web Key Set URI", "example": "https://fhir.epic.com/interconnect-fhir-oauth/.well-known/jwks" }, "scopes_supported": { "type": "array", "description": "List of supported scopes", "items": { "type": "string" }, "example": [ "patient/*.read", "system/*.read" ] } } }, "service_account_metadata": { "type": "object", "description": "Non-sensitive metadata from a Google Cloud Service Account, exposed in API responses to help identify auth configurations without revealing sensitive credentials.", "properties": { "type": { "type": "string", "description": "Account type (always \"service_account\")", "example": "service_account" }, "project_id": { "type": "string", "description": "Google Cloud project ID", "example": "my-gcp-project" }, "client_email": { "type": "string", "format": "email", "description": "Service account email address", "example": "service-account@my-gcp-project.iam.gserviceaccount.com" }, "client_id": { "type": "string", "description": "Service account client ID", "example": "123456789012345678901" } } }, "scopes": { "type": "string", "description": "OAuth scopes", "example": "system/Patient.read system/Observation.read" }, "client_id": { "type": "string", "description": "OAuth client ID for this auth configuration. When set, takes precedence over the provider-level client_id.", "example": "your-client-id" } } } }, "last_updated": { "type": "string", "format": "date-time", "description": "Timestamp when the provider was last updated", "example": "2024-01-15T10:30:00Z" } } }, { "type": "object", "description": "Limited information returned for sandbox FHIR providers. Sandbox\nresponses omit `auth_configs` and `last_updated`, which is what\ndistinguishes this shape from `FhirProviderTemplate` in `oneOf`.\n", "required": [ "id", "name", "provider" ], "properties": { "id": { "type": "string", "description": "Unique identifier for the FHIR provider", "example": "1716d214-de93-43a4-aa6b-a878d864e2ad" }, "name": { "type": "string", "description": "Display name for the FHIR provider", "example": "PhenoML Sandbox" }, "description": { "type": "string", "description": "Optional description of the FHIR provider", "example": "Shared sandbox environment for experimentation" }, "provider": { "type": "string", "enum": [ "sandbox" ], "description": "Provider type (always \"sandbox\" for this schema)", "example": "sandbox" } } } ] } } } } ``` **Example:** ```json { "success": true, "message": "Fhir providers retrieved successfully", "fhir_providers": [ { "id": "1716d214-de93-43a4-aa6b-a878d864e2ad", "name": "Epic Sandbox", "description": "Epic sandbox environment for testing", "provider": "epic", "base_url": "https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4", "auth_configs": { "auth-config-123": { "auth_config_id": "auth-config-123", "auth_method": "jwt", "is_active_auth_config": true, "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z", "scopes": "system/Patient.read system/Observation.read", "client_id": "your-client-id" } }, "last_updated": "2024-01-15T10:30:00Z" }, { "id": "4da196da-5cf1-4574-9e65-f97d7ea20b38", "name": "PhenoML Sandbox", "description": "Shared sandbox environment for experimentation", "provider": "sandbox" } ] } ``` **401** - Unauthorized **500** - Server error --- # Voice Transcribe audio recordings into text with speech-to-text. Pair the transcript with Lang2FHIR to turn spoken clinical notes into structured FHIR resources. ### POST /transcribe **Transcribe audio** Transcribes an uploaded audio recording and returns the transcript. Send the raw audio bytes as the request body; the audio format is detected automatically (WAV, FLAC, MP3, OGG/WebM Opus). Supports up to ~5 minutes of audio per request. This limit is on audio duration regardless of file size or format, so a compressed recording within the size limit can still be rejected for being too long. Pair the transcript with a downstream text step (e.g. `POST /lang2fhir/create`) to turn it into a FHIR resource. **Operation ID:** `voice_transcribe` #### Parameters | Name | In | Type | Required | Description | |------|-----|------|----------|-------------| | `language` | query | string[] | No | BCP-47 language tag, repeatable for up to 4 candidate languages. Defaults to `en-US`. | #### Request Body Raw audio bytes (WAV, FLAC, MP3, or OGG/WebM Opus). **Required:** Yes **Content-Type:** `application/octet-stream` ```json { "type": "string", "format": "binary" } ``` #### Responses **200** - Transcription succeeded. Content-Type: `application/json` ```json { "type": "object", "required": [ "transcript" ], "properties": { "transcript": { "type": "string", "description": "The full transcript of the audio." } } } ``` **400** - Invalid request (empty body, too many languages, no transcript produced, or audio that is too long or in an unsupported format) **401** - Unauthorized **402** - Payment required (credits exhausted or subscription inactive) **413** - Audio exceeds the maximum size **502** - Speech recognition failed **503** - Transcription temporarily unavailable **504** - Transcription timed out ---