MedChartScan E/M API
The MedChartScan E/M API reads an office visit note and returns the E/M code that the documentation supports, with the exact lines from the note behind each part of the decision. It runs the same analysis as the web app, from your own software.
What you can do
- Analyze one note and get the full report in the response.
- Send up to 100 notes as a batch, analyzed in the background, and check on them until they finish.
- List, search, and delete the results that your API keys created.
- Read your organization's credit balance.
Each analysis that succeeds costs one credit, from the same balance as the web app. A note that isn't an office E/M visit, or an analysis that fails, costs nothing.
Base URL and format
All requests go to https://api.medchartscan.io, and every path starts with /v1. Requests and responses are JSON in
UTF-8. The token endpoint also accepts a form body.
The API sees only what it creates: results and batches created through the API in your organization, by any of its API keys. Results created in the web app aren't visible through the API.
The OpenAPI 3.1 document describes every endpoint, field, and error response. Open the OpenAPI document.
Quickstart
This quickstart gets an access token and analyzes one synthetic note. It takes a few minutes.
Before you begin
- You need a MedChartScan account with the owner or admin role in your organization.
- Create an API key: in the app, open the API keys page and create a key. The page shows the client ID and the client secret. Copy the secret when it's shown, because it's shown only once.
- Use synthetic notes until your organization accepts the Business Associate Agreement (BAA). For more information, see Test mode.
Store your credentials
Keep the client ID and secret in environment variables, not in your code:
export CLIENT_ID="mcs_ci_k3x7q2mzr5tvw4yb6nhd2pfa"
export CLIENT_SECRET="mcs_sk_..."Get an access token
Exchange the key for an access token. The token is valid for one hour.
curl -s https://api.medchartscan.io/v1/oauth/token \
-d grant_type=client_credentials \
-d client_id="$CLIENT_ID" \
-d client_secret="$CLIENT_SECRET"{"access_token": "mcs_at_0TSMMdMumGLrM21zFYAa_tguW2mymxcUh51LgRHIH2g", "token_type": "Bearer", "expires_in": 3600}For the curl examples on these pages, keep the token in a variable:
export ACCESS_TOKEN="mcs_at_0TSMMdMumGLrM21zFYAa_tguW2mymxcUh51LgRHIH2g"Analyze a note
Send the note text. The response arrives when the analysis finishes, usually in under a minute, so give the request a
long timeout. This example sets "test_data": true, which a new organization needs until it accepts the BAA.
curl -s https://api.medchartscan.io/v1/analyses \
--max-time 300 \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"document_text": "Established patient seen for follow-up of type 2 diabetes and hypertension. Reports good adherence to metformin; no hypoglycemia. BP 138/86. A1c 7.4% reviewed. Assessment: diabetes, improving; hypertension, not at goal. Plan: increase lisinopril to 20 mg daily, recheck BMP in 2 weeks, follow up in 3 months.",
"jurisdiction": "TX",
"test_data": true
}'{
"id": "74853b97-f66b-478e-b633-2995ed52632f",
"status": "succeeded",
"is_test": true,
"expires_at": "2026-11-24T05:09:30.613847+00:00",
"credits_charged": 1,
"credits_remaining": 49,
"organization_status": "pending",
"client_reference": null,
"channel": "api",
"submitted_code": null,
"coding_change": "not_submitted",
"missed_revenue_count": 0,
"denial_risk_count": 0,
"report": {
"codingAnalysis": {
"finalCptCode": "99214",
"codingBasis": "Medical Decision Making (MDM)",
"governingGuideline": "Health E/M Coding Guidelines (CY 2026)"
},
"timeBasedJustification": null,
"mdmAnalysis": {
"finalMdmLevel": "Moderate",
"mdmElements": [
{"elementName": "Problems Addressed", "levelAchieved": "Moderate", "justification": "The note names the problems addressed at this visit.", "exactSnippet": "Established patient seen for follow-up of type 2 diabetes and hypertension"},
{"elementName": "Data Reviewed", "levelAchieved": "Moderate", "justification": "The note records data reviewed or ordered.", "exactSnippet": "A1c 7.4% reviewed"},
{"elementName": "Risk of Management", "levelAchieved": "Moderate", "justification": "The note records a management decision.", "exactSnippet": "Plan: increase lisinopril to 20 mg daily, recheck BMP in 2 weeks, follow up in 3 months"}
]
},
"revenueAndCompliance": {"missedRevenueOpportunities": [], "denialRiskAssessment": []},
"supplementalCodes": {"addOnCodes": [], "modifiers": []}
}
}The code is in report.codingAnalysis.finalCptCode. Each MDM element quotes the line of the note that supports it in
exactSnippet. For every field, see The report.
Next steps
- Learn how tokens expire and how to revoke a key in Authentication.
- Send many notes at once with Batches.
- Make retries safe with Idempotency.
- Handle every error code with Errors.
Conventions
- IDs are UUIDs.
- Times are ISO 8601 in UTC. Some responses write the offset as
Zand others as+00:00; parse both with an ISO 8601 parser. - Lists are newest first. When a response has a
next_cursor, pass it back ascursorto get the next page. On the last page,next_cursorisnull. - Errors have the shape
{"error": {"code": "...", "message": "..."}}. Branch oncode; the message is for people and can change. Messages never repeat what you sent. - Patient data stays out of URLs. Note text and your own references always travel in a request body, never in a
query string. That's why searching by
client_referenceis aPOSTrequest. - Unknown fields: new fields can appear in responses within
/v1. Ignore fields that you don't recognize. For more information, see Versioning and changelog.
Get help
Write to support@medchartscan.io. Include the request's method, path, status code, and the analysis or batch ID if there is one. Don't include note text or other patient information.