Skip to main content
Public endpoints do not require authentication and are designed for patient-facing applications and portals.

Patient Registration

curl -X POST https://api.omniehr.com/public/patient-register \
  -H "Content-Type: application/json" \
  -d '{
    "givenName": "John",
    "familyName": "Doe",
    "birthDate": "1985-06-15",
    "gender": "male",
    "phone": "+1-555-0123",
    "email": "[email protected]",
    "line1": "123 Main Street",
    "city": "Springfield",
    "state": "IL",
    "postalCode": "62701"
  }'
Register a new patient in the system. This endpoint is designed for patient portal self-registration.

Request Body

givenName
string
required
Patient’s given (first) name. Must be 1-120 characters.
familyName
string
required
Patient’s family (last) name. Must be 1-120 characters.
birthDate
string
required
Patient’s date of birth in YYYY-MM-DD format (e.g., “1985-06-15”).
gender
string
default:"unknown"
Patient’s gender. Must be one of: male, female, other, unknown. Defaults to unknown.
phone
string
Patient’s phone number. Maximum 40 characters. Optional.
email
string
Patient’s email address. Must be a valid email format if provided. Optional.
line1
string
First line of patient’s address (street address). Maximum 200 characters. Optional.
city
string
Patient’s city. Maximum 80 characters. Optional.
state
string
Patient’s state/province. Maximum 40 characters. Optional.
postalCode
string
Patient’s postal/ZIP code. Maximum 20 characters. Optional.

Response

message
string
required
Success message confirming registration
pid
string
required
Patient identifier (PID) - a unique sequential identifier assigned to the patient (e.g., “PAT-00001234”)
patientId
string
required
FHIR resource ID (MongoDB ObjectId) for the patient record
patient
object
required
Complete FHIR Patient resource
resourceType
string
required
Always “Patient”
id
string
required
FHIR resource ID
identifier
array
required
Array of patient identifiers
system
string
required
Identifier system (e.g., “https://omniehr.com/patient-id”)
value
string
required
Identifier value (PID)
active
boolean
required
Patient record active status (always true for new registrations)
name
array
required
Array of patient names
family
string
Family name
given
array
Array of given names
telecom
array
Array of contact information
system
string
Contact system: “phone” or “email”
value
string
Contact value
gender
string
Patient’s gender
birthDate
string
Patient’s birth date (YYYY-MM-DD)
address
array
Array of addresses
line
array
Array of address lines
city
string
City
state
string
State/province
postalCode
string
Postal code

Example Response

{
  "message": "Registration completed",
  "pid": "PAT-00001234",
  "patientId": "65a1b2c3d4e5f6a7b8c9d0e4",
  "patient": {
    "resourceType": "Patient",
    "id": "65a1b2c3d4e5f6a7b8c9d0e4",
    "identifier": [
      {
        "system": "https://omniehr.com/patient-id",
        "value": "PAT-00001234"
      }
    ],
    "active": true,
    "name": [
      {
        "family": "Doe",
        "given": ["John"]
      }
    ],
    "telecom": [
      {
        "system": "phone",
        "value": "+1-555-0123"
      },
      {
        "system": "email",
        "value": "[email protected]"
      }
    ],
    "gender": "male",
    "birthDate": "1985-06-15",
    "address": [
      {
        "line": ["123 Main Street"],
        "city": "Springfield",
        "state": "IL",
        "postalCode": "62701"
      }
    ]
  }
}

Minimal Registration Example

Only required fields:
curl -X POST https://api.omniehr.com/public/patient-register \
  -H "Content-Type: application/json" \
  -d '{
    "givenName": "Jane",
    "familyName": "Smith",
    "birthDate": "1992-03-20"
  }'

Example Response (Minimal)

{
  "message": "Registration completed",
  "pid": "PAT-00001235",
  "patientId": "65a1b2c3d4e5f6a7b8c9d0e5",
  "patient": {
    "resourceType": "Patient",
    "id": "65a1b2c3d4e5f6a7b8c9d0e5",
    "identifier": [
      {
        "system": "https://omniehr.com/patient-id",
        "value": "PAT-00001235"
      }
    ],
    "active": true,
    "name": [
      {
        "family": "Smith",
        "given": ["Jane"]
      }
    ],
    "telecom": [],
    "gender": "unknown",
    "birthDate": "1992-03-20",
    "address": []
  }
}

Validation Rules

All string fields are automatically trimmed of leading and trailing whitespace before validation.

Name Validation

  • givenName and familyName must be at least 1 character
  • Maximum length: 120 characters
  • Both fields are required

Birth Date Validation

  • Must be in YYYY-MM-DD format (e.g., “1985-06-15”)
  • Required field
  • Must be a valid calendar date

Gender Validation

  • Must be one of: male, female, other, unknown
  • Defaults to unknown if not provided
  • Optional field

Contact Information Validation

  • Phone: Maximum 40 characters, optional
  • Email: Must be valid email format if provided, optional

Address Validation

  • line1: Maximum 200 characters
  • city: Maximum 80 characters
  • state: Maximum 40 characters
  • postalCode: Maximum 20 characters
  • All address fields are optional

Error Responses

400 Bad Request

Returned when validation fails.
{
  "error": "Validation failed",
  "details": [
    {
      "field": "birthDate",
      "message": "birthDate must be YYYY-MM-DD"
    }
  ]
}

Common Validation Errors

givenName validation
{
  "field": "givenName",
  "message": "String must contain at least 1 character(s)"
}
familyName validation
{
  "field": "familyName",
  "message": "String must contain at least 1 character(s)"
}
birthDate format
{
  "field": "birthDate",
  "message": "birthDate must be YYYY-MM-DD"
}
email format
{
  "field": "email",
  "message": "Invalid email"
}
gender enum
{
  "field": "gender",
  "message": "Invalid enum value. Expected 'male' | 'female' | 'other' | 'unknown'"
}

500 Internal Server Error

Returned when an unexpected server error occurs.
{
  "error": "Internal server error"
}

Patient Identifier (PID)

Every registered patient is automatically assigned a unique, sequential Patient Identifier (PID) in the format PAT-########.
The PID system provides:
  • Sequential numbering: PIDs are assigned in order (PAT-00000001, PAT-00000002, etc.)
  • Human-readable: Easy to reference in conversations and documentation
  • Unique: Each patient receives exactly one PID that never changes
  • FHIR compatible: Stored as a standard FHIR identifier with system URL

PID in FHIR Resource

The PID is always included in the patient’s identifier array:
{
  "identifier": [
    {
      "system": "https://omniehr.com/patient-id",
      "value": "PAT-00001234"
    }
  ]
}

FHIR Compliance

This endpoint creates FHIR R4-compliant Patient resources. The response includes:
  • Standard FHIR Patient resource structure
  • Proper identifier system for PIDs
  • Valid telecom and address arrays
  • Compliant name structure with family and given names
  • Standard gender and birthDate fields

Using the Patient Resource

The returned patient resource can be:
  • Stored in patient-facing applications
  • Referenced in subsequent FHIR API calls using the patientId
  • Used to link clinical resources (Observations, Conditions, etc.)
  • Searched using the PID or FHIR resource ID

Example: Creating an Observation for a Registered Patient

After registration, you can create clinical resources:
curl -X POST https://api.omniehr.com/fhir/Observation \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "resourceType": "Observation",
    "status": "final",
    "code": {
      "coding": [{
        "system": "http://loinc.org",
        "code": "29463-7",
        "display": "Body Weight"
      }]
    },
    "subject": {
      "reference": "Patient/65a1b2c3d4e5f6a7b8c9d0e4"
    },
    "valueQuantity": {
      "value": 70.5,
      "unit": "kg",
      "system": "http://unitsofmeasure.org",
      "code": "kg"
    }
  }'

Integration Examples

Patient Portal Registration Form

const registerPatient = async (formData) => {
  const response = await fetch('https://api.omniehr.com/public/patient-register', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      givenName: formData.firstName,
      familyName: formData.lastName,
      birthDate: formData.dob, // YYYY-MM-DD format
      gender: formData.gender,
      phone: formData.phone,
      email: formData.email,
      line1: formData.address,
      city: formData.city,
      state: formData.state,
      postalCode: formData.zipCode
    })
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.error);
  }

  const result = await response.json();
  
  // Store PID and patient ID for future use
  localStorage.setItem('patientId', result.patientId);
  localStorage.setItem('pid', result.pid);
  
  return result;
};

React Registration Component

import { useState } from 'react';

function PatientRegistration() {
  const [formData, setFormData] = useState({
    givenName: '',
    familyName: '',
    birthDate: '',
    gender: 'unknown',
    phone: '',
    email: '',
    line1: '',
    city: '',
    state: '',
    postalCode: ''
  });

  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const handleSubmit = async (e) => {
    e.preventDefault();
    setLoading(true);
    setError(null);

    try {
      const response = await fetch('https://api.omniehr.com/public/patient-register', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(formData)
      });

      if (!response.ok) {
        const errorData = await response.json();
        throw new Error(errorData.error);
      }

      const result = await response.json();
      console.log('Registration successful:', result.pid);
      // Redirect to confirmation page or next step
      
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      {error && <div className="error">{error}</div>}
      
      <input
        type="text"
        placeholder="First Name"
        value={formData.givenName}
        onChange={(e) => setFormData({...formData, givenName: e.target.value})}
        required
      />
      
      <input
        type="text"
        placeholder="Last Name"
        value={formData.familyName}
        onChange={(e) => setFormData({...formData, familyName: e.target.value})}
        required
      />
      
      <input
        type="date"
        value={formData.birthDate}
        onChange={(e) => setFormData({...formData, birthDate: e.target.value})}
        required
      />
      
      {/* Additional form fields */}
      
      <button type="submit" disabled={loading}>
        {loading ? 'Registering...' : 'Register'}
      </button>
    </form>
  );
}

Build docs developers (and LLMs) love