Mahalo Health API Examples
Explore practical examples of integrating with the Mahalo Health Platform API for common healthcare scenarios.
Patient Data Integration
Learn how to retrieve and sync patient health data from wearable devices
- Fetch sleep, HRV, and activity metrics
- Sync data from Oura, WHOOP, and Dexcom
- Calculate health scores and trends
Care Team Communication
Implement secure messaging between patients and providers
- Create and manage message threads
- Send notifications for new messages
- Implement read receipts and status tracking
Appointment Management
Create, update, and manage patient appointments
- Schedule and reschedule appointments
- Send reminders and confirmations
- Sync with external calendar systems
Health Monitoring
Implement continuous health monitoring and alerts
- Set up threshold-based alerts
- Track medication adherence
- Generate health reports and insights
Patient Data Integration
Fetching Patient Wearable Data
// Fetch a patient's sleep data from Oura Ring
async function fetchPatientSleepData(patientId, startDate, endDate) {
const token = await getAccessToken();
const response = await fetch(
`https://api.mahalo.health/v1/patients/${patientId}/wearables/oura/sleep?` +
`start_date=${startDate}&end_date=${endDate}`,
{
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
}
);
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return await response.json();
}
// Calculate sleep score trends
function calculateSleepTrends(sleepData) {
const scores = sleepData.map(day => day.sleep_score);
const average = scores.reduce((sum, score) => sum + score, 0) / scores.length;
const trend = scores.length > 1
? scores[scores.length - 1] - scores[0]
: 0;
return {
average: Math.round(average),
trend: trend > 0 ? 'improving' : trend < 0 ? 'declining' : 'stable',
trendValue: Math.abs(trend)
};
}
// Example usage
async function displayPatientSleepInsights(patientId) {
try {
const today = new Date();
const oneMonthAgo = new Date();
oneMonthAgo.setMonth(today.getMonth() - 1);
const startDate = oneMonthAgo.toISOString().split('T')[0];
const endDate = today.toISOString().split('T')[0];
const sleepData = await fetchPatientSleepData(patientId, startDate, endDate);
const trends = calculateSleepTrends(sleepData.sleep_records);
console.log(`Sleep Score: ${trends.average} (Trend: ${trends.trend} by ${trends.trendValue} points)`);
// Additional analysis could be performed here
} catch (error) {
console.error('Error fetching sleep insights:', error);
}
}Syncing Data from Multiple Wearables
// Sync data from all connected wearables for a patient
async function syncAllWearableData(patientId) {
const token = await getAccessToken();
// First, get all connected devices
const devicesResponse = await fetch(
`https://api.mahalo.health/v1/patients/${patientId}/wearables/devices`,
{
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
}
);
const devices = await devicesResponse.json();
// For each connected device, trigger a sync
const syncPromises = devices.connected_devices.map(async (device) => {
const syncResponse = await fetch(
`https://api.mahalo.health/v1/patients/${patientId}/wearables/${device.provider}/sync`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
force_refresh: true
})
}
);
return syncResponse.json();
});
// Wait for all syncs to complete
const syncResults = await Promise.all(syncPromises);
return {
devices: devices.connected_devices.map(d => d.provider),
sync_results: syncResults
};
}Care Team Communication
Creating a New Message Thread
// Create a new message thread between patient and provider
async function createMessageThread(patientId, providerId, subject) {
const token = await getAccessToken();
const response = await fetch(
'https://api.mahalo.health/v1/messages/threads',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
patient_id: patientId,
provider_id: providerId,
subject: subject
})
}
);
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return await response.json();
}
// Send a message in an existing thread
async function sendMessage(threadId, senderId, senderType, content) {
const token = await getAccessToken();
const response = await fetch(
`https://api.mahalo.health/v1/messages/threads/${threadId}/messages`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
sender_id: senderId,
sender_type: senderType, // 'patient' or 'provider'
content: content
})
}
);
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return await response.json();
}
// Example usage: Create a thread and send an initial message
async function startConversation(patientId, providerId, subject, initialMessage) {
try {
// Create the thread
const thread = await createMessageThread(patientId, providerId, subject);
console.log(`Created thread: ${thread.id}`);
// Send the initial message
const message = await sendMessage(
thread.id,
patientId,
'patient',
initialMessage
);
console.log(`Sent message: ${message.id}`);
return {
thread_id: thread.id,
message_id: message.id
};
} catch (error) {
console.error('Error starting conversation:', error);
throw error;
}
}Implementing Real-time Notifications
// Set up WebSocket connection for real-time message notifications
function setupMessageNotifications(userId, userType, onMessageReceived) {
const token = getAccessToken();
// Create WebSocket connection
const socket = new WebSocket(`wss://api.mahalo.health/v1/ws/messages?token=${token}`);
socket.onopen = () => {
console.log('WebSocket connection established');
// Subscribe to messages for this user
socket.send(JSON.stringify({
action: 'subscribe',
user_id: userId,
user_type: userType // 'patient' or 'provider'
}));
};
socket.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'new_message') {
// Call the callback with the new message data
onMessageReceived(data.message);
// Acknowledge receipt
socket.send(JSON.stringify({
action: 'acknowledge',
message_id: data.message.id
}));
}
};
socket.onerror = (error) => {
console.error('WebSocket error:', error);
};
socket.onclose = () => {
console.log('WebSocket connection closed');
};
// Return functions to manage the connection
return {
close: () => socket.close(),
reconnect: () => setupMessageNotifications(userId, userType, onMessageReceived)
};
}
// Example usage
const notificationManager = setupMessageNotifications(
'patient_123',
'patient',
(message) => {
console.log('New message received:', message);
// Update UI or show notification
showNotification(`New message from ${message.sender_name}: ${message.content.substring(0, 50)}...`);
}
);
// Clean up when component unmounts
function cleanup() {
notificationManager.close();
}Appointment Management
Scheduling an Appointment
// Schedule a new appointment
async function scheduleAppointment(patientId, providerId, appointmentDetails) {
const token = await getAccessToken();
const response = await fetch(
'https://api.mahalo.health/v1/appointments',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
patient_id: patientId,
provider_id: providerId,
...appointmentDetails
})
}
);
if (!response.ok) {
const errorData = await response.json();
throw new Error(`Failed to schedule appointment: ${errorData.message || response.statusText}`);
}
return await response.json();
}
// Example usage
async function bookFollowUpAppointment(patientId, providerId) {
// Calculate date for next week
const nextWeek = new Date();
nextWeek.setDate(nextWeek.getDate() + 7);
// Format as ISO string and adjust for timezone
const startTime = new Date(nextWeek);
startTime.setHours(10, 0, 0, 0);
const endTime = new Date(startTime);
endTime.setMinutes(endTime.getMinutes() + 30);
try {
const appointment = await scheduleAppointment(
patientId,
providerId,
{
start_time: startTime.toISOString(),
end_time: endTime.toISOString(),
appointment_type: 'follow_up',
location_type: 'video',
notes: 'Follow-up appointment to discuss treatment progress'
}
);
console.log('Appointment scheduled:', appointment);
// Send confirmation to patient
await sendAppointmentConfirmation(patientId, appointment.id);
return appointment;
} catch (error) {
console.error('Error scheduling appointment:', error);
throw error;
}
}
// Send appointment confirmation
async function sendAppointmentConfirmation(patientId, appointmentId) {
const token = await getAccessToken();
const response = await fetch(
`https://api.mahalo.health/v1/notifications/appointments/${appointmentId}/confirm`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
patient_id: patientId,
notification_type: 'email_and_sms'
})
}
);
if (!response.ok) {
console.warn('Failed to send appointment confirmation, but appointment was created');
return null;
}
return await response.json();
}Rescheduling an Appointment
// Reschedule an existing appointment
async function rescheduleAppointment(appointmentId, newStartTime, newEndTime) {
const token = await getAccessToken();
const response = await fetch(
`https://api.mahalo.health/v1/appointments/${appointmentId}/reschedule`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
start_time: newStartTime,
end_time: newEndTime,
reason: 'Patient requested new time'
})
}
);
if (!response.ok) {
const errorData = await response.json();
throw new Error(`Failed to reschedule appointment: ${errorData.message || response.statusText}`);
}
return await response.json();
}Health Monitoring
Setting Up Health Alerts
// Create a health alert for a patient
async function createHealthAlert(patientId, metricType, thresholdValue, comparisonType) {
const token = await getAccessToken();
const response = await fetch(
'https://api.mahalo.health/v1/monitoring/alerts',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
patient_id: patientId,
metric_type: metricType, // e.g., 'heart_rate', 'blood_glucose', 'hrv'
threshold_value: thresholdValue,
comparison_type: comparisonType, // 'above', 'below', 'equal'
notification_channels: ['sms', 'email', 'app'],
notify_care_team: true
})
}
);
if (!response.ok) {
throw new Error(`Failed to create health alert: ${response.statusText}`);
}
return await response.json();
}
// Example: Set up glucose monitoring alert
async function setupGlucoseAlert(patientId) {
try {
// Alert if glucose goes above 180 mg/dL
const highGlucoseAlert = await createHealthAlert(
patientId,
'blood_glucose',
180,
'above'
);
console.log('High glucose alert created:', highGlucoseAlert);
// Alert if glucose goes below 70 mg/dL
const lowGlucoseAlert = await createHealthAlert(
patientId,
'blood_glucose',
70,
'below'
);
console.log('Low glucose alert created:', lowGlucoseAlert);
return {
highGlucoseAlertId: highGlucoseAlert.id,
lowGlucoseAlertId: lowGlucoseAlert.id
};
} catch (error) {
console.error('Error setting up glucose alerts:', error);
throw error;
}
}Generating Health Reports
// Generate a health report for a patient
async function generateHealthReport(patientId, reportType, timeframe) {
const token = await getAccessToken();
const response = await fetch(
'https://api.mahalo.health/v1/reports/generate',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
patient_id: patientId,
report_type: reportType, // 'monthly_summary', 'quarterly_review', 'medication_adherence'
timeframe: timeframe, // e.g., { start_date: '2023-01-01', end_date: '2023-01-31' }
include_sections: [
'vitals',
'sleep',
'activity',
'nutrition',
'medication'
],
format: 'pdf'
})
}
);
if (!response.ok) {
throw new Error(`Failed to generate report: ${response.statusText}`);
}
// This returns a job ID since report generation is asynchronous
const { job_id } = await response.json();
// Poll for report completion
return await pollReportStatus(job_id);
}
// Poll for report generation status
async function pollReportStatus(jobId, maxAttempts = 10, interval = 2000) {
const token = await getAccessToken();
for (let attempt = 0; attempt < maxAttempts; attempt++) {
const response = await fetch(
`https://api.mahalo.health/v1/reports/status/${jobId}`,
{
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
}
);
if (!response.ok) {
throw new Error(`Failed to check report status: ${response.statusText}`);
}
const status = await response.json();
if (status.status === 'completed') {
return {
report_id: status.report_id,
download_url: status.download_url,
expires_at: status.expires_at
};
} else if (status.status === 'failed') {
throw new Error(`Report generation failed: ${status.error}`);
}
// Wait before polling again
await new Promise(resolve => setTimeout(resolve, interval));
}
throw new Error('Report generation timed out');
}API Documentation
For complete API documentation, including all available endpoints and parameters, please refer to theAPI Reference.
