Skip to content

ecg/12-lead

12-lead ECG read from signal, PDF or photo: rhythm, QTc, STEMI-equivalents and AI-ECG screens.

BetaECGCardiacCardiologyEmergencyv1.0.0 · $0.02 / request

About

The full read of one resting 12-lead ECG: rhythm and conduction statements, global intervals and axes, and the STEMI criteria with the leads that meet them.

Endpoint ecg/12-lead/interpret · version 1.0.0 · $0.02 per request · the bare id ecg/12-lead is an alias.

1. Calling the API#

Set up your API key#

Create a key in Settings → API Keys and set it as MEDRUN_KEY in your runtime.

export MEDRUN_KEY="YOUR_API_KEY"

Submit a request#

Every call is asynchronous: submitting returns a request with its id and status, and you follow it until the result is ready.

response=$(curl --request POST \
  --url https://api.medrun.ai/v1/run/ecg/12-lead/interpret \
  --header "Authorization: Bearer $MEDRUN_KEY" \
  --header "Content-Type: application/json" \
  --data '{
  "input": {
    "files": [
      "file_01K6R4X2Q9Y7T3V5W8Z0A1B2C3"
    ],
    "options": {
      "report": false
    }
  }
}')
REQUEST_ID=$(echo "$response" | jq -r .id)

Request status

The submit call returns the request, not the result. Use the queue calls below to check its status and fetch the result, or subscribe to a webhook.

Stream progress#

Stages stream as server-sent events (received, queued, preprocessing, inference, report, completed). Critical findings are flagged first, before the full result.

curl --no-buffer \
  --url https://api.medrun.ai/v1/requests/$REQUEST_ID/events \
  --header "Authorization: Bearer $MEDRUN_KEY" \
  --header "Accept: text/event-stream"

2. Authentication#

The API uses API keys. Send Authorization: Bearer $MEDRUN_KEY with every call. Test keys (mr_test_…) run against the mock backend for free.

API key#

Protect your API key

Never ship a key in browser or mobile code. Call MedRun from your server, or use a server-side proxy.

3. Queue#

Long-running requests

Whole studies can take a minute or more. Rely on the event stream or webhooks instead of blocking while you wait.

Fetch request status#

Statuses run queued → preparing → running and end in succeeded, failed, canceled, rejected or expired.

curl --request GET \
  --url https://api.medrun.ai/v1/requests/$REQUEST_ID \
  --header "Authorization: Bearer $MEDRUN_KEY"

Get the result#

When the request has succeeded, output holds the result envelope. See the result format.

curl --request GET \
  --url https://api.medrun.ai/v1/requests/$REQUEST_ID \
  --header "Authorization: Bearer $MEDRUN_KEY" | jq .output

4. Files#

files is a flat list: DICOM files, folders, CD exports (DICOMDIR) and zip/tar archives. The platform groups them into series and runs.

Uploading files#

# 1. Create the upload (one PUT up to 100 MB; larger files get multipart part URLs)
upload=$(curl --request POST --url https://api.medrun.ai/v1/uploads \
  --header "Authorization: Bearer $MEDRUN_KEY" --header "Content-Type: application/json" \
  --data '{"filename": "study.zip", "bytes": 214000000, "media_type": "application/zip"}')
# 2. PUT the bytes to upload.url (with upload.headers)
curl --request PUT --upload-file study.zip "$(echo "$upload" | jq -r .upload.url)"
# 3. Complete it, then pass file.id in input.files
curl --request POST --url "$(echo "$upload" | jq -r .complete_url)" --header "Authorization: Bearer $MEDRUN_KEY"
FILE_ID=$(echo "$upload" | jq -r .file.id)

Hosted files (URL)#

You can also pass https URLs, for example signed S3 or GCS links. MedRun fetches them when the request starts.

5. Webhooks#

Add a webhook to the submit body. MedRun POSTs the request object, signed with Standard Webhooks headers, when the request ends. Configure secrets and see deliveries in Settings → Webhooks.

{
  "input": {
    "files": [
      "file_…"
    ]
  },
  "webhook": {
    "url": "https://example.org/medrun/webhook",
    "events": [
      "request.succeeded",
      "request.failed"
    ]
  }
}

6. Schema#

Input#

  • fileslist<string>* required

    One resting 12-lead ECG: a DICOM ECG waveform, HL7 aECG or GE MUSE XML, a WFDB record (.hea and .dat), a CSV file, a PDF printout, or photos or scans of the paper ECG (every page of one ECG), or a zip of them. `file_…` ids from /v1/uploads or https URLs.

  • clinical_contextobject

    Optional. Age and sex set the QTc and ST-elevation thresholds when the file does not carry them; never names, IDs or dates.

    • age_yearsnumber

      Range: 0 … 130

    • sexenum

      Possible values: female, male, other, unknown

    • indicationstring

      For example "chest pain for 2 hours" or "QTc check before starting a QT-prolonging drug".

  • optionsobject
    • reportbooleanadd-on

      Adds a draft ECG report written from the structured result (English). +$0.02 per run.

      Default value: false

    • report_languageenum

      Default value: "en"

      Possible values: en

    • paper_speed_mm_senum

      For a PDF, scan or photo whose paper speed should not be read from the page.

      Possible values: 25, 50

    • gain_mm_mvenum

      For a PDF, scan or photo whose calibration pulse is not printed.

      Possible values: 5, 10, 20

    • sampling_rate_hznumber

      For CSV files that do not state their sampling rate.

      Range: 250 … 10000

    • returnlist<enum>

      JSON is always returned.

      Default value: ["json"]

      Possible values: json

Example input:

{
  "files": [
    "file_01K6R4X2Q9Y7T3V5W8Z0A1B2C3"
  ],
  "options": {
    "report": false
  }
}

Output#

The output is the MedRun result envelope: sections[] with a status per section, then findings, measurements, scores, classifications, guidance, the optional report and artifacts (DICOM SR/SEG, overlays, PDF, FHIR).

  • rhythm Rhythm and conduction: Rhythm (sinus, atrial fibrillation or flutter, SVT, junctional, paced, wide-complex tachycardia), ectopy, AV block, bundle-branch and fascicular blocks, pre-excitation, LVH and Q-wave infarcts of undetermined age, each with its SNOMED CT code, score and the measurements it rests on; critical flags in the triage.
  • intervals Intervals and axes: Heart rate, RR, PR, P duration, QRS, QT, QTc (Bazett and Fridericia), P/QRS/T axes from median beats with global fiducials, and the J-point and ST level at J+60 ms in every lead.
  • stemi STEMI and occlusion MI: Fourth Universal Definition ST-elevation criteria per lead with age and sex thresholds, contiguity and reciprocal change, the STEMI-equivalent patterns (posterior, de Winter, aVR pattern, Smith-modified Sgarbossa in LBBB and paced rhythm), the likely culprit territory and the margin to threshold in every lead.
  • digitize Digitisation: Photos, scans and PDF printouts of the paper ECG turned into calibrated lead signals: layout and lead names, paper speed and gain from the page, the device's printed interpretation ignored, a confidence per lead, and the re-rendered 12-lead drawn from the traced samples only. Each statement and measurement is returned from such input only where it matched the read of the original signal file on the digitisation bench (precision 0.85 or more for statements and the overall call; IEC 60601-2-25 limits for intervals); the rest is listed as not assessable.
  • quality Recording quality: Per-lead noise, baseline wander, saturation and suspected lead reversal.
  • low-ef Low EF screen: Probability of a left ventricular ejection fraction of 40–45 % or less, with an echocardiography recommendation.
  • structural-heart-disease Structural heart disease screen: Probability of moderate or greater structural heart disease.
  • compare Comparison with prior ECG: New or resolved findings against a prior ECG.
  • segment-waves Wave delineation: Per-beat P, QRS and T boundaries.
  • hyperkalemia Hyperkalaemia estimate: Estimated serum potassium band from the ECG.
  • af-risk Future AF risk: Risk of incident atrial fibrillation from a sinus-rhythm ECG.
  • report Draft report: Opt-in draft report (findings, impression, limitations) written from the structured result; every number is validated against it.

OpenAPI document: https://api.medrun.ai/v1/models/ecg/12-lead/interpret/openapi.json