Skip to main content

Patient Onboarding Workflow

This guide walks through the complete patient onboarding process, from creating a patient record to scheduling their first appointment.

Overview

The patient onboarding workflow typically involves:
  1. Create Patient - Add patient to the system
  2. Send Intake Form - Collect necessary information
  3. Schedule Appointment - Book their first visit
  4. Send Confirmation - Notify patient of appointment details

Step 1: Create Patient Record

First, create a new patient in the system:
curl -X POST "https://api.decodahealth.com/user/patient/create" \
     -H "API-KEY: YOUR_API_KEY" \
     -H "TENANT: YOUR_TENANT" \
     -H "Content-Type: application/json" \
     -d '{
       "first_name": "Jane",
       "last_name": "Smith",
       "phone_number": "+1234567890",
       "email": "[email protected]",
       "date_of_birth": "1990-01-15",
       "external_id": "EHR_PATIENT_12345"
     }'
Response:
{
  "id": "pat_1234567890",
  "first_name": "Jane",
  "last_name": "Smith",
  "phone_number": "+1234567890",
  "email": "[email protected]",
  "date_of_birth": "1990-01-15",
  "external_id": "EHR_PATIENT_12345",
  "created_date": "2024-03-15T10:00:00Z"
}
Save the patient_id from the response - you’ll need it for subsequent steps. The external_id field allows you to link the patient to your EHR system.

Step 2: Send Intake Form

Send an intake form to collect additional patient information:
curl -X POST "https://api.decodahealth.com/forms/send-intake-forms" \
     -H "API-KEY: YOUR_API_KEY" \
     -H "TENANT: YOUR_TENANT" \
     -H "Content-Type: application/json" \
     -d '{
       "patient_id": "pat_1234567890",
       "form_ids": ["form_intake_general"],
       "send_email": true,
       "send_sms": true
     }'
Replace form_intake_general with your actual intake form ID. Use the List Forms endpoint to find available forms.

Step 3: Check Form Submission Status

Monitor form submission status (optional - you can also use webhooks):
curl -X GET "https://api.decodahealth.com/forms/patient-submissions?patient_id=pat_1234567890" \
     -H "API-KEY: YOUR_API_KEY" \
     -H "TENANT: YOUR_TENANT"

Step 4: Check Availability

Before scheduling, check available appointment slots:
curl -X GET "https://api.decodahealth.com/calendar/availability?start_date=2024-03-20&end_date=2024-03-27&service_id=svc_1234567890" \
     -H "API-KEY: YOUR_API_KEY" \
     -H "TENANT: YOUR_TENANT"

Step 5: Schedule Appointment

Create the appointment:
curl -X POST "https://api.decodahealth.com/calendar/appointment" \
     -H "API-KEY: YOUR_API_KEY" \
     -H "TENANT: YOUR_TENANT" \
     -H "Content-Type: application/json" \
     -d '{
       "patient_id": "pat_1234567890",
       "start_time": "2024-03-20T14:00:00Z",
       "duration_minutes": 30,
       "service_id": "svc_1234567890",
       "provider_id": "prov_1234567890",
       "location_id": "loc_1234567890",
       "notes": "New patient intake appointment"
     }'

Step 6: Send Appointment Confirmation

Send confirmation message to the patient:
curl -X POST "https://api.decodahealth.com/comms/send-message" \
     -H "API-KEY: YOUR_API_KEY" \
     -H "TENANT: YOUR_TENANT" \
     -H "Content-Type: application/json" \
     -d '{
       "patient_id": "pat_1234567890",
       "message": "Your appointment is confirmed for March 20, 2024 at 2:00 PM. We look forward to seeing you!",
       "send_sms": true,
       "send_email": true
     }'

Complete Workflow Example

Here’s a complete example that ties everything together:
import requests
from datetime import datetime, timedelta

API_KEY = "YOUR_API_KEY"
TENANT = "YOUR_TENANT"
BASE_URL = "https://api.decodahealth.com"

headers = {
    "API-KEY": API_KEY,
    "TENANT": TENANT,
    "Content-Type": "application/json"
}

def onboard_patient(
    first_name: str,
    last_name: str,
    phone_number: str,
    email: str,
    service_id: str,
    provider_id: str,
    location_id: str
):
    """Complete patient onboarding workflow."""

    # Step 1: Create patient
    patient = requests.post(
        f"{BASE_URL}/user/patient/create",
        headers=headers,
        json={
            "first_name": first_name,
            "last_name": last_name,
            "phone_number": phone_number,
            "email": email
        }
    ).json()
    patient_id = patient["id"]
    print(f"✓ Created patient: {patient_id}")

    # Step 2: Send intake form
    requests.post(
        f"{BASE_URL}/forms/send-intake-forms",
        headers=headers,
        json={
            "patient_id": patient_id,
            "form_ids": ["form_intake_general"],
            "send_email": True,
            "send_sms": True
        }
    )
    print(f"✓ Sent intake form")

    # Step 3: Check availability (next week)
    start_date = (datetime.now() + timedelta(days=7)).strftime("%Y-%m-%d")
    end_date = (datetime.now() + timedelta(days=14)).strftime("%Y-%m-%d")

    availability = requests.get(
        f"{BASE_URL}/calendar/availability",
        headers=headers,
        params={
            "start_date": start_date,
            "end_date": end_date,
            "service_id": service_id
        }
    ).json()

    if not availability.get("slots"):
        raise Exception("No available slots")

    # Use first available slot
    slot = availability["slots"][0]

    # Step 4: Schedule appointment
    appointment = requests.post(
        f"{BASE_URL}/calendar/appointment",
        headers=headers,
        json={
            "patient_id": patient_id,
            "start_time": slot["start_time"],
            "duration_minutes": slot["duration_minutes"],
            "service_id": service_id,
            "provider_id": provider_id,
            "location_id": location_id,
            "notes": "New patient intake"
        }
    ).json()
    appointment_id = appointment["id"]
    print(f"✓ Scheduled appointment: {appointment_id}")

    # Step 5: Send confirmation
    appointment_time = datetime.fromisoformat(slot["start_time"].replace("Z", "+00:00"))
    message_text = (
        f"Hi {first_name}, your appointment is confirmed for "
        f"{appointment_time.strftime('%B %d, %Y at %I:%M %p')}. "
        "We look forward to seeing you!"
    )

    requests.post(
        f"{BASE_URL}/comms/send-message",
        headers=headers,
        json={
            "patient_id": patient_id,
            "message": message_text,
            "send_sms": True,
            "send_email": True
        }
    )
    print(f"✓ Sent confirmation")

    return {
        "patient_id": patient_id,
        "appointment_id": appointment_id,
        "appointment_time": slot["start_time"]
    }

# Usage
result = onboard_patient(
    first_name="Jane",
    last_name="Smith",
    phone_number="+1234567890",
    email="[email protected]",
    service_id="svc_1234567890",
    provider_id="prov_1234567890",
    location_id="loc_1234567890"
)

print(f"\n✓ Patient onboarding complete!")
print(f"  Patient ID: {result['patient_id']}")
print(f"  Appointment ID: {result['appointment_id']}")

Using Webhooks for Automation

Instead of polling for form submissions, you can use webhooks to be notified when forms are completed:
  1. Subscribe to PATIENT_CREATED - Get notified when patient is created
  2. Subscribe to form submission events - Get notified when intake forms are completed
  3. Automatically schedule - When form is complete, automatically check availability and schedule
See the Webhook Events Reference for details.

Error Handling

Always implement proper error handling:
try:
    patient = requests.post(...).json()
except requests.exceptions.HTTPError as e:
    if e.response.status_code == 409:
        # Patient already exists
        patient_id = extract_patient_id_from_error(e.response.json())
    else:
        raise
except Exception as e:
    # Log and handle error
    print(f"Error: {e}")
    raise

Next Steps