Skip to main content

Overview

HANA’s EHR Proxy provides a standardized REST API that abstracts the differences between EHR systems. Write once against HANA’s API, and the Proxy handles translation to Epic, Cerner, Athena, AllScripts, or any FHIR-enabled system. Base URL: https://api.hana.health/v1 Authentication: All requests require an X-API-KEY header and X-ORG-ID header.
curl https://api.hana.health/v1/patients \
  --header 'X-API-KEY: <your-api-key>' \
  --header 'X-ORG-ID: <your-organization-id>'

Patients

List Patients

Retrieves a list of patients for a practitioner.
GET /v1/patients
Parameters:
NameInTypeRequiredDescription
X-API-KEYheaderstringYesAPI key
X-ORG-IDheaderstringYesOrganization ID
practitioner_idquerystringNoFilter by practitioner
practitioner_emailquerystringNoAlternative practitioner lookup
countqueryintegerNoResults to return (default: 20)
include_fhirquerybooleanNoInclude raw FHIR in response
Response (200):
{
  "status": "ok",
  "data": [
    {
      "id": "pat_abc123",
      "first_name": "Maria",
      "last_name": "Garcia",
      "date_of_birth": "1985-03-14",
      "gender": "female",
      "phone": "+1-555-0142",
      "email": "[email protected]",
      "primary_provider_id": "prov_xyz789"
    }
  ],
  "count": 1,
  "total": 1
}

Create Patient

POST /v1/patients
Request Body:
{
  "first_name": "string",
  "last_name": "string",
  "date_of_birth": "YYYY-MM-DD",
  "gender": "male | female | other | unknown",
  "email": "string",
  "phone_numbers": ["string"],
  "address": {
    "street": "string",
    "city": "string",
    "state": "string",
    "postal_code": "string",
    "country": "string"
  },
  "practitioner_id": "string"
}
Response (201): Created patient object.

Confirm Patient Identity

Validates if a patient exists. Requires either (first_name + last_name + date_of_birth) OR (phone_number).
GET /v1/patients/exists
Response (200): Patient found with matching record. Response (404): Patient not found.

Patient Records

Get Patient Record

Retrieves a comprehensive patient record.
GET /v1/patients/record
Parameters: Patient identified by (first_name + last_name + date_of_birth) OR (phone_number). Response (200):
{
  "status": "ok",
  "data": {
    "demographics": { },
    "conditions": [
      {
        "code": "I10",
        "display": "Essential hypertension",
        "status": "active",
        "onset_date": "2020-06-15"
      }
    ],
    "medications": [
      {
        "name": "Lisinopril",
        "dosage": "10mg",
        "frequency": "daily",
        "status": "active",
        "prescriber": "Dr. Smith"
      }
    ],
    "allergies": [
      {
        "substance": "Penicillin",
        "reaction": "rash",
        "severity": "moderate"
      }
    ],
    "vital_signs": [ ],
    "lab_results": [ ],
    "encounter_notes": [ ],
    "insurance": { }
  }
}

Get Vital Signs

GET /v1/patients/record/vital-signs

Update Vital Signs

PUT /v1/patients/record/vital-signs

Get Lab Results

GET /v1/patients/record/lab-results

Get Medications

GET /v1/patients/record/medications

Get Insurance

GET /v1/patients/record/insurance

Update Insurance

PUT /v1/patients/record/insurance

Practitioners

List Practitioners

GET /v1/practitioners
Parameters:
NameInTypeRequiredDescription
countqueryintegerNoResults to return (default: 20)
include_fhirquerybooleanNoInclude FHIR format
Response (200):
{
  "status": "ok",
  "data": [
    {
      "id": "prov_xyz789",
      "first_name": "Sarah",
      "last_name": "Johnson",
      "email": "[email protected]",
      "specialty": "Family Medicine",
      "npi": "1234567890",
      "locations": ["loc_main", "loc_satellite"]
    }
  ]
}

Appointments

List Appointments

GET /v1/appointments
Parameters:
NameInTypeRequiredDescription
start_date_timequerystringYesStart of range (ISO 8601)
end_date_timequerystringYesEnd of range (ISO 8601)
practitioner_idquerystringNoFilter by practitioner
patient identifiersqueryvariousNoFilter by patient
countqueryintegerNoResults to return
Response (200):
{
  "status": "ok",
  "data": [
    {
      "id": "appt_001",
      "patient_id": "pat_abc123",
      "practitioner_id": "prov_xyz789",
      "start": "2026-02-10T09:00:00Z",
      "end": "2026-02-10T09:30:00Z",
      "status": "confirmed",
      "type": "follow-up",
      "reason": "Hypertension management"
    }
  ]
}

Book Appointment

POST /v1/appointments
Request Body:
{
  "patient_id": "string",
  "practitioner_id": "string",
  "start_date_time": "ISO 8601",
  "end_date_time": "ISO 8601",
  "reason": "string",
  "notes": "string"
}

Reschedule Appointment

PUT /v1/appointments
Request Body:
{
  "patient_id": "string",
  "appointment_start_date_time": "ISO 8601 (original)",
  "new_start_date_time": "ISO 8601",
  "new_end_date_time": "ISO 8601",
  "reason": "string"
}

Cancel Appointment

DELETE /v1/appointments

Get Open Slots

GET /v1/appointments/open-slots
Parameters:
NameInTypeRequiredDescription
start_date_timequerystringYesStart of search window
end_date_timequerystringNoEnd of search window
practitioner_idquerystringNoFilter by practitioner

Pre-Visit Notes

GET /v1/appointments/pre-visit/notes
PUT /v1/appointments/pre-visit/notes

Encounters & Clinical Notes

Get Encounter Notes

GET /v1/appointments/encounters/notes
Retrieves clinical notes for a given encounter or patient.

Create Encounter Note

POST /v1/appointments/encounters/notes
Request Body:
{
  "text_content": "string (markdown or plain text)",
  "json_content": {
    "subjective": "string",
    "objective": "string",
    "assessment": "string",
    "plan": "string"
  }
}

Update Encounter Note

PUT /v1/appointments/encounters/notes

Delete Encounter Note

DELETE /v1/appointments/encounters/notes

SOAP Note Sections

Get or update individual SOAP sections:
GET /v1/appointments/encounters/notes/soap/sections/{section_id}
PUT /v1/appointments/encounters/notes/soap/sections/{section_id}

Add Chief Complaints

POST /v1/appointments/encounters/notes/chief-complaints
Request Body: ["string"]

Add Intake Questionnaire

POST /v1/appointments/encounters/notes/intake-questionnaire

Clinical Codes

Add ICD-10 Codes

POST /v1/appointments/encounters/notes/codes/icd10
Request Body: ["I10", "E11.9", "F32.1"]

Add CPT Codes

POST /v1/appointments/encounters/notes/codes/cpt
Request Body: ["99213", "99490", "96127"]

Medications & Patient Instructions

Add Medications

POST /v1/appointments/encounters/notes/medications
Request Body: ["Lisinopril 10mg daily", "Metformin 500mg BID"]

Add Patient Instructions

POST /v1/appointments/encounters/notes/patient-instructions
Request Body: ["Schedule follow-up in 2 weeks", "Monitor blood pressure daily"]

Conversations

Create Conversation

Initiate an AI-driven patient conversation.
POST /v1/conversations
Request Body:
{
  "patient_id": "string",
  "protocol": "intake | follow_up | ccm_checkin | bhi_screen | care_gap | custom",
  "protocol_config": {
    "custom_protocol_id": "string (if protocol=custom)"
  },
  "channel": "voice_outbound | voice_inbound | sms",
  "scheduled_at": "ISO 8601 (optional, for scheduled outbound)",
  "priority": "normal | high | urgent",
  "metadata": {}
}
Response (201):
{
  "status": "ok",
  "data": {
    "conversation_id": "conv_abc123",
    "status": "scheduled",
    "scheduled_at": "2026-02-10T14:00:00Z",
    "patient_id": "pat_abc123",
    "protocol": "ccm_checkin"
  }
}

Get Conversation

GET /v1/conversations/{conversationId}
Response (200):
{
  "status": "ok",
  "data": {
    "id": "conv_abc123",
    "status": "completed",
    "patient_id": "pat_abc123",
    "protocol": "ccm_checkin",
    "started_at": "2026-02-10T14:00:12Z",
    "completed_at": "2026-02-10T14:07:45Z",
    "duration_seconds": 453,
    "outcome": {
      "goals_completed": 4,
      "goals_total": 5,
      "escalated": false,
      "quality_score": 4.5,
      "extracted_data": { }
    },
    "transcript_url": "https://api.hana.health/v1/conversations/conv_abc123/transcript"
  }
}

List Conversations

GET /v1/conversations
Parameters: Filter by patient, protocol, status, date range.

Get Transcript

GET /v1/conversations/{conversationId}/transcript

Metadata

List Protocols

GET /v1/protocols

List Note Templates

GET /v1/appointments/encounters/notes/templates

List Note Fields

GET /v1/appointments/encounters/notes/fields

Monitoring

Health Check

GET /v1/health

EHR Connection Health

GET /v1/ehr/health
Response (200):
{
  "status": "connected",
  "ehr_system": "Epic",
  "last_sync": "2026-02-07T13:45:00Z",
  "latency_ms": 145
}

Error Handling

All errors follow a consistent format:
{
  "status": "error",
  "error": {
    "code": "PATIENT_NOT_FOUND",
    "message": "No patient found matching the provided identifiers.",
    "details": {}
  }
}
Common Error Codes:
CodeHTTP StatusDescription
UNAUTHORIZED401Invalid or missing API key
FORBIDDEN403Insufficient permissions
PATIENT_NOT_FOUND404No matching patient
APPOINTMENT_NOT_FOUND404No matching appointment
INVALID_INPUT400Malformed request
EHR_UNAVAILABLE503EHR system temporarily unreachable
RATE_LIMITED429Too many requests

Rate Limits

TierRequests/minuteBurst
Standard60100
Scale300500
Enterprise1,0002,000