Skip to main content

ECG Long-Term (Holter) Analysis API

Long-term ECG analysis (Holter Analysis) supports continuous ECG data for 24 hours or longer and provides professional long-term ECG reports.

Asynchronous processing

Long-term analysis runs asynchronously. After submitting a job, poll or use a Webhook to obtain results. Analysis time depends on data volume and analysis depth.


Analysis flow


API endpoints

EndpointMethodDescription
/api/v1/advanced/ecg/holter/upload-urlPOSTGet file upload credentials
/api/v1/advanced/ecg/holter/submitPOSTSubmit analysis job
/api/v1/advanced/ecg/holter/status/:task_idGETQuery job status
/api/v1/advanced/ecg/holter/result/:task_idGETGet analysis result
/api/v1/advanced/ecg/holter/report/:task_idGETDownload PDF report
/api/v1/advanced/ecg/holter/cancel/:task_idPOSTCancel analysis job

Step 1: Get upload credentials

POST /api/v1/advanced/ecg/holter/upload-url

Returns a presigned URL for secure upload of large files.

Request parameters

ParameterTypeRequiredDescription
filenamestringFile name (with extension)
file_sizenumberFile size in bytes
file_formatstringFile format: aiecg / edf / mit / csv
duration_hoursnumberRecording duration in hours
checksumstringMD5 checksum of the file

Request example

curl -X POST "https://api.heartvoice.com.cn/api/v1/advanced/ecg/holter/upload-url" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filename": "patient_001_24h.aiecg",
"file_size": 86400000,
"file_format": "aiecg",
"duration_hours": 24
}'

Response example

{
"status": "success",
"data": {
"task_id": "holter_task_abc123xyz",
"upload_url": "https://upload.aiecg.com/holter/xxxxx?signature=xxxxx",
"upload_method": "PUT",
"upload_headers": {
"Content-Type": "application/octet-stream"
},
"expires_at": "2024-01-15T11:30:00Z",
"max_file_size": 500000000
}
}

Upload the file

Upload using the returned upload_url:

curl -X PUT "https://upload.aiecg.com/holter/xxxxx?signature=xxxxx" \
-H "Content-Type: application/octet-stream" \
--data-binary @patient_001_24h.aiecg

Step 2: Submit analysis job

POST /api/v1/advanced/ecg/holter/submit

After the file upload completes, submit the analysis job.

Request parameters

ParameterTypeRequiredDescription
task_idstringtask_id from the previous step
sampling_ratenumberSampling rate (Hz)
gainnumberGain factor
zero_voltagenumberZero voltage
patient_infoobjectPatient information
analysis_optionsobjectAnalysis options
callback_urlstringWebhook callback URL
prioritystringPriority: normal / high / urgent

patient_info parameters

{
"patient_id": "P001",
"name": "John Doe",
"age": 55,
"gender": "male",
"chief_complaint": "Palpitations, chest tightness",
"medical_history": "Hypertension for 5 years",
"current_medications": ["Aspirin", "Metoprolol"]
}

analysis_options parameters

{
"arrhythmia_detection": true,
"st_analysis": true,
"hrv_analysis": true,
"pacemaker_detection": false,
"doctor_review": true,
"report_language": "en-US"
}

Request example

curl -X POST "https://api.heartvoice.com.cn/api/v1/advanced/ecg/holter/submit" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"task_id": "holter_task_abc123xyz",
"sampling_rate": 256,
"gain": 1000,
"zero_voltage": 512,
"patient_info": {
"patient_id": "P001",
"age": 55,
"gender": "male",
"chief_complaint": "Palpitations, chest tightness"
},
"analysis_options": {
"arrhythmia_detection": true,
"st_analysis": true,
"hrv_analysis": true,
"doctor_review": true
},
"callback_url": "https://your-server.com/webhook/holter",
"priority": "normal"
}'

Response example

{
"status": "success",
"data": {
"task_id": "holter_task_abc123xyz",
"status": "processing",
"estimated_completion": "2024-01-15T14:30:00Z",
"queue_position": 3,
"created_at": "2024-01-15T10:30:00Z"
}
}

Step 3: Query job status

GET /api/v1/advanced/ecg/holter/status/:task_id

Returns the current status of the analysis job. Path parameter task_id is the job ID.

Request example

curl -X GET "https://api.heartvoice.com.cn/api/v1/advanced/ecg/holter/status/holter_task_abc123xyz" \
-H "Authorization: Bearer YOUR_API_KEY"

Response example

{
"status": "success",
"data": {
"task_id": "holter_task_abc123xyz",
"status": "doctor_reviewing",
"progress": {
"overall": 85,
"stages": {
"upload": {"status": "completed", "progress": 100},
"preprocessing": {"status": "completed", "progress": 100},
"ai_analysis": {"status": "completed", "progress": 100},
"doctor_review": {"status": "in_progress", "progress": 40}
}
},
"estimated_completion": "2024-01-15T14:30:00Z",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T12:45:00Z"
}
}

Job status values

StatusDescription
pendingWaiting to be processed
uploadingFile upload in progress
preprocessingPreprocessing
ai_analyzingAI analysis in progress
doctor_reviewingUnder physician review (if enabled)
completedAnalysis complete
failedAnalysis failed
cancelledCancelled

Step 4: Get analysis result

GET /api/v1/advanced/ecg/holter/result/:task_id

After the job completes, retrieve detailed analysis results. Path parameter task_id is the job ID.

Request example

curl -X GET "https://api.heartvoice.com.cn/api/v1/advanced/ecg/holter/result/holter_task_abc123xyz" \
-H "Authorization: Bearer YOUR_API_KEY"

Response example

{
"status": "success",
"data": {
"task_id": "holter_task_abc123xyz",
"report_id": "RPT_20240115_001",
"analysis_time": "2024-01-15T14:28:35Z",

"summary": {
"recording_duration": "23:45:32",
"analyzable_duration": "23:30:15",
"data_quality": "good",
"overall_conclusion": "Sinus rhythm, occasional PVCs and PACs"
},

"heart_rate": {
"total_beats": 102458,
"average_hr": 72,
"max_hr": 128,
"max_hr_time": "2024-01-15T09:23:45Z",
"min_hr": 52,
"min_hr_time": "2024-01-15T03:15:22Z",
"hr_distribution": {
"below_60": 8.5,
"60_to_100": 85.2,
"above_100": 6.3
}
},

"arrhythmia": {
"summary": {
"total_abnormal_beats": 856,
"abnormal_percentage": 0.84
},
"ventricular": {
"pvc_count": 523,
"pvc_per_hour": 22.1,
"pvc_singles": 498,
"pvc_pairs": 12,
"pvc_runs": 1,
"longest_pvc_run": 3,
"r_on_t": 0
},
"supraventricular": {
"pac_count": 333,
"pac_per_hour": 14.1,
"pac_singles": 320,
"pac_pairs": 6,
"pac_runs": 1,
"longest_pac_run": 4
},
"atrial_fibrillation": {
"detected": false,
"episodes": 0,
"total_duration": 0,
"burden_percentage": 0
},
"pauses": {
"count": 2,
"longest_pause": 2.1,
"longest_pause_time": "2024-01-15T04:22:33Z"
}
},

"st_segment": {
"st_depression_episodes": 3,
"st_elevation_episodes": 0,
"max_depression": -1.2,
"max_depression_time": "2024-01-15T11:45:00Z",
"total_ischemic_time": "00:15:30",
"ischemic_burden": 1.1
},

"hrv": {
"time_domain": {
"sdnn": 128,
"sdnn_index": 52,
"sdann": 112,
"rmssd": 32,
"pnn50": 8.5
},
"frequency_domain": {
"total_power": 3250,
"vlf": 1850,
"lf": 920,
"hf": 480,
"lf_hf_ratio": 1.92
},
"interpretation": "HRV within normal range; autonomic function favorable"
},

"representative_strips": [
{
"type": "normal_sinus",
"time": "2024-01-15T08:30:00Z",
"description": "Normal sinus rhythm",
"strip_url": "https://api.heartvoice.com.cn/strips/xxx_normal.png"
},
{
"type": "pvc",
"time": "2024-01-15T10:15:22Z",
"description": "Premature ventricular contraction",
"strip_url": "https://api.heartvoice.com.cn/strips/xxx_pvc.png"
},
{
"type": "max_hr",
"time": "2024-01-15T09:23:45Z",
"description": "Fastest heart rate 128 BPM",
"strip_url": "https://api.heartvoice.com.cn/strips/xxx_max_hr.png"
},
{
"type": "min_hr",
"time": "2024-01-15T03:15:22Z",
"description": "Slowest heart rate 52 BPM",
"strip_url": "https://api.heartvoice.com.cn/strips/xxx_min_hr.png"
},
{
"type": "pause",
"time": "2024-01-15T04:22:33Z",
"description": "Longest pause 2.1 s",
"strip_url": "https://api.heartvoice.com.cn/strips/xxx_pause.png"
}
],

"diagnosis": {
"primary": [
"Sinus rhythm",
"Occasional PVCs",
"Occasional PACs"
],
"secondary": [
"Normal nocturnal heart rate decline",
"No significant ST-segment changes"
],
"risk_assessment": {
"arrhythmia_risk": "low",
"ischemia_risk": "low",
"overall_risk": "low"
}
},

"recommendations": [
{
"priority": "low",
"category": "follow_up",
"content": "Ectopy count within normal range; periodic follow-up recommended"
},
{
"priority": "medium",
"category": "lifestyle",
"content": "Avoid overexertion and irregular sleep; maintain regular routine"
},
{
"priority": "low",
"category": "monitoring",
"content": "If palpitations worsen, seek timely re-evaluation"
}
],

"reviewer": {
"ai_model": "AIECG-Holter-v2.1",
"ai_confidence": 0.94,
"doctor_reviewed": true,
"doctor_id": "DR_001",
"review_time": "2024-01-15T14:20:00Z"
}
}
}

Step 5: Download PDF report

GET /api/v1/advanced/ecg/holter/report/:task_id

Returns a download link for a standard PDF report. Path parameter task_id is the job ID.

Request parameters

ParameterTypeRequiredDescription
formatstringReport format: pdf (default) / html
templatestringReport template: standard / detailed / summary

Request example

curl -X GET "https://api.heartvoice.com.cn/api/v1/advanced/ecg/holter/report/holter_task_abc123xyz?format=pdf&template=standard" \
-H "Authorization: Bearer YOUR_API_KEY"

Response example

{
"status": "success",
"data": {
"report_url": "https://reports.aiecg.com/holter/xxx.pdf?token=xxx",
"expires_at": "2024-01-15T18:00:00Z",
"file_size": 2458624,
"pages": 8
}
}

Webhook callback

If callback_url was set when submitting the job, a Webhook is sent when the job completes or fails.

Webhook payload

{
"event": "holter_analysis_completed",
"task_id": "holter_task_abc123xyz",
"status": "completed",
"timestamp": "2024-01-15T14:28:35Z",
"data": {
"report_id": "RPT_20240115_001",
"summary": "Sinus rhythm, occasional PVCs and PACs",
"result_url": "https://api.heartvoice.com.cn/api/v1/advanced/ecg/holter/result/holter_task_abc123xyz"
},
"signature": "sha256=xxxxxxxx"
}

Verify signature

import hmac
import hashlib

def verify_webhook(payload, signature, secret):
expected = 'sha256=' + hmac.new(
secret.encode(),
payload.encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)

Supported data formats

Our proprietary format with efficient compression and full metadata.

{
"format": "aiecg",
"version": "1.0",
"header": {
"sampling_rate": 256,
"gain": 1000,
"zero_voltage": 512,
"duration_seconds": 86400,
"start_time": "2024-01-14T10:00:00Z"
},
"data": [512, 515, 520, ...]
}

EDF / EDF+

Standard European data format widely used by medical devices.

MIT-BIH

PhysioNet standard format with .dat and .hea files.

CSV

Simple comma-separated format; a timestamp column is required.


Code examples

import { AIECG } from '@aiecg/sdk';
import fs from 'fs';

const client = new AIECG('YOUR_API_KEY');

async function analyzeHolter(filePath) {
// 1. Get upload credentials
const uploadInfo = await client.holter.getUploadUrl({
filename: 'patient_24h.aiecg',
fileSize: fs.statSync(filePath).size,
fileFormat: 'aiecg',
durationHours: 24
});

// 2. Upload file
await client.holter.uploadFile(uploadInfo.upload_url, filePath);

// 3. Submit analysis job
const task = await client.holter.submit({
taskId: uploadInfo.task_id,
samplingRate: 256,
gain: 1000,
zeroVoltage: 512,
patientInfo: { age: 55, gender: 'male' },
analysisOptions: { doctorReview: true }
});

console.log(`Job submitted: ${task.task_id}`);

// 4. Poll status
let status;
do {
await new Promise(r => setTimeout(r, 30000)); // poll every 30 s
status = await client.holter.getStatus(task.task_id);
console.log(`Progress: ${status.progress.overall}%`);
} while (status.status !== 'completed' && status.status !== 'failed');

// 5. Fetch result
if (status.status === 'completed') {
const result = await client.holter.getResult(task.task_id);
console.log(`Diagnosis: ${result.diagnosis.primary.join(', ')}`);

// Download PDF report
const report = await client.holter.downloadReport(task.task_id);
console.log(`Report URL: ${report.report_url}`);
}
}

Pricing

Analysis typeAdvanced tier
24-hour Holter¥50 per study
48-hour Holter¥80 per study
7-day Holter¥150 per study