Skip to content

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:

curl
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"
200 OK
{"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:

curl
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
  }'
200 OK
{
  "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

Conventions

  • IDs are UUIDs.
  • Times are ISO 8601 in UTC. Some responses write the offset as Z and 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 as cursor to get the next page. On the last page, next_cursor is null.
  • Errors have the shape {"error": {"code": "...", "message": "..."}}. Branch on code; 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_reference is a POST request.
  • 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.

MedChartScan E/M API: overview and quickstart