HealthSave API Contract
Updated April 2026
HealthSave can sync Apple Health data to any self-hosted server that implements this contract. Configure the app with the base server URL only, such as https://health.example.com; HealthSave appends the endpoint paths below.
- Base URL: enter only the origin or base path in the app.
- Authentication: optional
x-api-keyheader. - Ingest:
POST /api/apple/batchreceives metric batches. - Status:
GET /api/apple/statusreturns a flat metric dictionary.
Endpoints
| Method | Path | Purpose |
|---|---|---|
GET |
/health |
Minimal process health check. |
GET |
/api/health |
App-friendly health check. |
POST |
/api/apple/batch |
Receives one HealthKit metric batch. |
GET |
/api/apple/status |
Returns per-metric server counts for the sync status screen. |
Authentication
If your backend requires an API key, HealthSave sends it with protected requests as an x-api-key header.
x-api-key: your-api-key
Health Checks
Both health endpoints should return a simple success object.
{
"status": "ok"
}
Batch Ingest
POST /api/apple/batch receives one metric at a time. A successful 2xx response is enough for the app; the response body below matches the reference backend.
{
"metric": "heart_rate",
"batch_index": 0,
"total_batches": 1,
"samples": [
{
"date": "2026-04-10T12:00:00Z",
"qty": 72,
"source": "Apple Watch"
}
]
}
{
"status": "processed",
"metric": "heart_rate",
"batch": 0,
"total_batches": 1,
"records": 1
}
Quantity Samples
Quantity-like metrics use date, qty, and source. Some compatible servers also accept unit, but HealthSave does not require it on every sample.
Sleep Samples
{
"metric": "sleep_analysis",
"samples": [
{
"startDate": "2026-04-09T23:20:00Z",
"endDate": "2026-04-10T06:45:00Z",
"value": 3,
"source": "Apple Watch"
}
]
}
Workout Samples
{
"metric": "workouts",
"samples": [
{
"name": "Running",
"start": "2026-04-10T07:00:00Z",
"end": "2026-04-10T07:45:00Z",
"duration": 2700,
"source": "Apple Watch",
"activeEnergy": 420,
"distance": 6500,
"avgHeartRate": 145,
"maxHeartRate": 178,
"heartRateData": [
{"date": "2026-04-10T07:01:00Z", "qty": 132}
],
"route": [
{
"latitude": 41.01,
"longitude": 28.97,
"altitude": 42.0,
"speed": 2.8,
"timestamp": "2026-04-10T07:01:00Z"
}
]
}
]
}
Activity Summary Samples
{
"metric": "activity_summaries",
"samples": [
{
"date": "2026-04-10",
"activeEnergyBurned": 540,
"activeEnergyBurnedGoal": 600,
"appleExerciseTime": 42,
"appleExerciseTimeGoal": 30,
"appleStandHours": 12,
"appleStandHoursGoal": 12
}
]
}
Blood Pressure Correlations
Blood pressure batches use metric: "blood_pressure" at the batch level. Each sample carries its own inner metric value so systolic and diastolic readings remain distinct.
{
"metric": "blood_pressure",
"samples": [
{
"metric": "blood_pressure_systolic",
"date": "2026-04-10T09:00:00Z",
"qty": 120,
"source": "Blood Pressure Monitor"
},
{
"metric": "blood_pressure_diastolic",
"date": "2026-04-10T09:00:00Z",
"qty": 80,
"source": "Blood Pressure Monitor"
}
]
}
Category Event Samples
Category events use date, qty, source, and, when available, endDate plus rawValue. For duration-based events, qty is the duration in seconds and rawValue keeps the raw HealthKit category value. For instant events, qty is the raw category value.
{
"metric": "mindful_session",
"samples": [
{
"date": "2026-04-10T08:00:00Z",
"endDate": "2026-04-10T08:15:00Z",
"qty": 900,
"rawValue": 0,
"source": "Apple Watch"
}
]
}
ECG Samples
ECG batches can include start, end, classification, numberOfVoltageMeasurements, samplingFrequency, and averageHeartRate. Store them if your backend has an ECG model, or accept the batch for compatibility.
Status Contract
GET /api/apple/status must return a flat JSON object. Every top-level key is treated as a metric name, and every top-level value should be an object with at least count. oldest and newest are optional.
{
"heart_rate": {
"count": 123,
"oldest": "2026-04-01T08:00:00Z",
"newest": "2026-04-10T12:00:00Z"
},
"heart_rate_variability": {
"count": 45,
"oldest": "2026-04-01T08:00:00Z",
"newest": "2026-04-10T12:00:00Z"
},
"quantity_samples": {
"count": 900
}
}
Do not return {"status":"ok","counts":{...}} from this endpoint. That wrapped shape makes status look like a metric and makes counts look like one metric instead of the metric dictionary.
Metric Catalog
HealthSave accepts compatible backends that store unknown metrics generically. The names below are the source-derived catalog the app can send.
Heart & Cardiovascular
heart_rate, resting_heart_rate, walking_heart_rate_average, heart_rate_variability, heart_rate_recovery, atrial_fibrillation_burden, vo2_max, oxygen_saturation, respiratory_rate, peripheral_perfusion_index
Blood Pressure & Metabolic
blood_pressure, blood_pressure_systolic, blood_pressure_diastolic, blood_glucose, insulin_delivery, blood_alcohol_content, number_of_alcoholic_beverages
Activity & Movement
step_count, distance_walking_running, distance_cycling, distance_swimming, distance_wheelchair, distance_downhill_snow_sports, distance_cross_country_skiing, distance_paddle_sports, distance_rowing, distance_skating_sports, flights_climbed, swimming_stroke_count, push_count, nike_fuel, apple_exercise_time, apple_stand_time, apple_move_time, active_energy_burned, basal_energy_burned, number_of_times_fallen
Mobility, Running & Cycling
walking_speed, walking_step_length, walking_asymmetry, walking_double_support, stair_ascent_speed, stair_descent_speed, apple_walking_steadiness, six_minute_walk_test_distance, running_power, running_speed, running_stride_length, running_vertical_oscillation, running_ground_contact_time, cycling_speed, cycling_power, cycling_cadence, cycling_functional_threshold_power
Sport Speeds, Effort & Body
cross_country_skiing_speed, paddle_sports_speed, rowing_speed, physical_effort, workout_effort_score, estimated_workout_effort_score, body_temperature, wrist_temperature, basal_body_temperature, body_mass, body_fat_percentage, bmi, lean_body_mass, height, waist_circumference, electrodermal_activity
Respiratory, Sleep, Environment & Water
forced_expiratory_volume_1, forced_vital_capacity, peak_expiratory_flow_rate, inhaler_usage, sleep_analysis, sleeping_breathing_disturbances, environmental_audio_exposure, headphone_audio_exposure, environmental_sound_reduction, uv_exposure, time_in_daylight, underwater_depth, water_temperature
Nutrition
dietary_energy_consumed, dietary_protein, dietary_fat_total, dietary_fat_saturated, dietary_fat_monounsaturated, dietary_fat_polyunsaturated, dietary_carbohydrates, dietary_sugar, dietary_fiber, dietary_cholesterol, dietary_sodium, dietary_potassium, dietary_calcium, dietary_iron, dietary_magnesium, dietary_phosphorus, dietary_zinc, dietary_manganese, dietary_copper, dietary_selenium, dietary_chromium, dietary_molybdenum, dietary_chloride, dietary_biotin, dietary_vitamin_a, dietary_vitamin_b6, dietary_vitamin_b12, dietary_vitamin_c, dietary_vitamin_d, dietary_vitamin_e, dietary_vitamin_k, dietary_folate, dietary_niacin, dietary_pantothenic_acid, dietary_riboflavin, dietary_thiamin, dietary_iodine, dietary_water, dietary_caffeine
Structured Types
workouts, activity_summaries, ecg
Category Events
high_heart_rate_event, low_heart_rate_event, irregular_heart_rhythm_event, low_cardio_fitness_event, mindful_session, handwashing_event, toothbrushing_event, environmental_audio_exposure_event, headphone_audio_exposure_event, apple_walking_steadiness_event
Reproductive Health & Symptoms
menstrual_flow, intermenstrual_bleeding, ovulation_test_result, cervical_mucus_quality, sexual_activity, contraceptive, pregnancy, pregnancy_test_result, lactation, progesterone_test_result, infrequent_menstrual_cycles, irregular_menstrual_cycles, persistent_intermenstrual_bleeding, prolonged_menstrual_periods, bleeding_after_pregnancy, bleeding_during_pregnancy, abdominal_cramps, acne, appetite_changes, generalized_body_ache, bloating, breast_pain, chest_tightness_or_pain, chills, constipation, coughing, diarrhea, dizziness, fainting, fatigue, fever, headache, heartburn, hot_flashes, lower_back_pain, loss_of_smell, loss_of_taste, mood_changes, nausea, pelvic_pain, rapid_pounding_or_fluttering_heartbeat, runny_nose, shortness_of_breath, sinus_congestion, skipped_heartbeat, sleep_changes, sore_throat, vomiting, wheezing, bladder_incontinence, dry_skin, hair_loss, vaginal_dryness, memory_lapse, night_sweats, sleep_apnea_event