> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usecobalt.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create Appointments

> Creates a new appointment for a patient.

### Provider and Location IDs

When creating appointments, use the **`ehr_id`** values from your providers and locations:

* **`provider`**: Use the `ehr_id` from `GET /v1/providers` (not the `id`)
* **`location`**: Use the `ehr_id` from `GET /v1/locations` (not the `id`)
* **`secondary_provider`**: Use the `ehr_id` from `GET /v1/providers` (not the `id`)

These values represent the identifiers your EMR system uses. Cobalt passes them directly to your EMR when creating the appointment.

<Note>
  **Don't use the Cobalt `id` here.** The `id` field from GET responses is Cobalt's internal UUID, used only for updating provider/location settings via PATCH endpoints.
</Note>

### Date and Time Formats

You have two options for specifying the appointment date and time:

#### Option 1: ISO 8601 Format (Recommended)

Use the `datetime` parameter with full ISO 8601 timestamp including timezone:

```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/appointments \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
    "mrn": "123456789",
    "location": "123456789",
    "datetime": "2025-01-01T10:00:00-05:00",
    "provider": "123456789",
    "type": "new_patient"
}'
```

**Format:** `YYYY-MM-DDTHH:mm:ss±HH:MM` (24-hour time with timezone offset)

#### Option 2: Separate Date and Time

Use `date` and `time` parameters separately. **Important:** When using this option, the `time` must be in 12-hour format with `am` or `pm`.

```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/appointments \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
    "mrn": "123456789",
    "location": "123456789",
    "date": "2025-01-01",
    "time": "10:00 am",
    "provider": "123456789",
    "type": "new_patient"
}'
```

**Date Format:** `YYYY-MM-DD`
**Time Format:** `h:mm am/pm` or `hh:mm am/pm` (12-hour format, must include am/pm)

<Warning>
  Common mistake: Using `"time": "10:00"` without `am` or `pm` will result in an error. Always include `am` or `pm` when using separate date and time parameters.
</Warning>

### Preventing Double Bookings

Set `prevent_double_booking` to `"true"` to have Cobalt check the provider's schedule for conflicts before submitting the appointment to your EHR. If the requested time slot overlaps with an existing patient visit or a schedule block, the appointment fails immediately with a descriptive error rather than being submitted.

<Note>
  Supported EMRs: **eClinicalWorks**, **Practice Fusion**. This field is accepted but ignored for all other EHR systems.
</Note>

```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/appointments \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
    "mrn": "123456789",
    "location": "123456789",
    "datetime": "2025-01-01T10:00:00-05:00",
    "provider": "123456789",
    "type": "follow_up",
    "prevent_double_booking": "true"
}'
```

When a conflict is detected, you will receive an `appointment.failed` webhook with the `conflict_type` and `conflict_details` fields populated (see [Failure Examples](#failure-examples) below).

<Note>
  If Cobalt is unable to check the provider's schedule due to a network or EHR connectivity issue, the appointment proceeds normally rather than blocking. The conflict check is a best-effort safeguard.
</Note>

### Complete Example Request

```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/appointments \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
    "mrn": "123456789",
    "location": "123456789",
    "date": "2025-01-01",
    "time": "10:00 am",
    "provider": "123456789",
    "secondary_provider": "123456789",
    "type": "new_patient",
    "note": "This is a test appointment",
    "reason": "Patient requested appointment for routine checkup",
    "department_id": "1",
    "non_billable": "false"
}'
```

### Example Response

```json theme={null}
{
    "success": true,
    "message": "Appointment processing. A webhook event will be sent upon completion.",
    "appointment_id": "123456789",
    "job_id": 15550942
}
```

### Webhook Notifications

When the appointment processing is complete, we will send a webhook to your registered endpoint. Here are examples of what those webhook payloads will look like:

#### Success

```json theme={null}
{
    "id": "evt_1J9X2q2eZvKYlo2Cmnopqr",
    "access_token_reference_id": "user_1J9X2q2eZvKYlo2Cstuv",
    "object": "event",
    "created": "2023-10-28T11:00:00Z",
    "type": "appointment.created",
    "data": {
        "appointment_id": "123456789",
        "date_time": "2025-01-01T10:00",
        "timezone": "America/New_York",
        "provider_id": "emr_prov_123",
        "secondary_provider_id": "emr_sec_prov_456",
        "provider_name": "Dr. Smith",
        "mrn": "123456789"
    }
}
```

#### Failure Examples

The `appointment.failed` webhook event includes a `failure_reason` and can contain additional fields in the `data` object depending on the cause of the failure.

**Patient Not Found:**

```json theme={null}
{
    "id": "evt_1J9X2q2eZvKYlo2Cwxyz",
    "access_token_reference_id": "user_1J9X2q2eZvKYlo2Cstuv",
    "object": "event",
    "created": "2023-10-28T11:05:00Z",
    "type": "appointment.failed",
    "data": {
        "appointment_id": "123456790",
        "mrn": "000000",
        "failure_reason": "Patient MRN '000000' not found in eCW. Please update the MRN using the PATCH /v1/appointments/:id endpoint."
    }
}
```

**Visit Type Not Found:**

```json theme={null}
{
    "id": "evt_1J9X2q2eZvKYlo2Cabcde",
    "access_token_reference_id": "user_1J9X2q2eZvKYlo2Cstuv",
    "object": "event",
    "created": "2023-10-28T11:10:00Z",
    "type": "appointment.failed",
    "data": {
        "appointment_id": "123456791",
        "mrn": "123456789",
        "failure_reason": "Visit type \"Annual Wellness Visit\" not available for the selected resource/provider/location combination in eCW. Allowed visit types for this resource: New Patient, Follow Up, Telehealth. Please update the visit type using the PATCH /v1/appointments/:id endpoint, or re-create with skip_visit_type_validation: \"true\" if this visit type is bookable in eCW (e.g. via availability slots).",
        "visit_type": "Annual Wellness Visit",
        "allowed_visit_types": ["New Patient", "Follow Up", "Telehealth"]
    }
}
```

If the visit type is bookable in your EHR but not part of the resource's configured visit type list (for example, visit types offered through availability slots), re-create the appointment with `skip_visit_type_validation` set to `"true"` and an explicit `duration`.

**Provider Not Found:**

```json theme={null}
{
    "id": "evt_1J9X2q2eZvKYlo2Cfghij",
    "access_token_reference_id": "user_1J9X2q2eZvKYlo2Cstuv",
    "object": "event",
    "created": "2023-10-28T11:15:00Z",
    "type": "appointment.failed",
    "data": {
        "appointment_id": "123456792",
        "mrn": "123456789",
        "failure_reason": "Provider 'Dr. Unknown' not found in eCW. Please check the provider configuration or use PATCH /v1/appointments/:id endpoint to update.",
        "provider_name": "Dr. Unknown"
    }
}
```

**Schedule Block Conflict:**

```json theme={null}
{
    "id": "evt_1J9X2q2eZvKYlo2Cklmno",
    "access_token_reference_id": "user_1J9X2q2eZvKYlo2Cstuv",
    "object": "event",
    "created": "2023-10-28T11:20:00Z",
    "type": "appointment.failed",
    "data": {
        "appointment_id": "123456793",
        "mrn": "123456789",
        "failure_reason": "Appointment creation failed: The appointment conflicts with a schedule block (Admin Block 9am-12pm). Permission denied. Please choose a different time or resolve the schedule conflict.",
        "conflict_type": "schedule_block",
        "block_details": "Admin Block 9am-12pm"
    }
}
```

**Appointment Conflict (Permission Denied):**

```json theme={null}
{
    "id": "evt_1J9X2q2eZvKYlo2Cpqrst",
    "access_token_reference_id": "user_1J9X2q2eZvKYlo2Cstuv",
    "object": "event",
    "created": "2023-10-28T11:25:00Z",
    "type": "appointment.failed",
    "data": {
        "appointment_id": "123456794",
        "mrn": "123456789",
        "failure_reason": "Appointment creation failed: This appointment conflicts with another existing appointment. Permission denied. Please choose a different time.",
        "conflict_type": "appointment_conflict"
    }
}
```

**Double Booking Conflict — Existing Patient Visit:**

```json theme={null}
{
    "id": "evt_1J9X2q2eZvKYlo2Cuvwxy",
    "access_token_reference_id": "user_1J9X2q2eZvKYlo2Cstuv",
    "object": "event",
    "created": "2023-10-28T11:28:00Z",
    "type": "appointment.failed",
    "data": {
        "appointment_id": "123456796",
        "patient_mrn": "123456789",
        "failure_reason": "Provider already has an appointment with Doe, Jane from 10:00 AM to 10:15 AM",
        "conflict_type": "existing_patient_visit",
        "conflict_details": {
            "patient_name": "Doe, Jane",
            "start_time": "10:00 AM",
            "end_time": "10:15 AM",
            "visit_type": "F/U"
        }
    }
}
```

**Double Booking Conflict — Schedule Block:**

```json theme={null}
{
    "id": "evt_1J9X2q2eZvKYlo2Cuvwxz",
    "access_token_reference_id": "user_1J9X2q2eZvKYlo2Cstuv",
    "object": "event",
    "created": "2023-10-28T11:29:00Z",
    "type": "appointment.failed",
    "data": {
        "appointment_id": "123456797",
        "patient_mrn": "123456789",
        "failure_reason": "Provider has a scheduled block (Admin Block) from 9:00 AM to 12:00 PM",
        "conflict_type": "scheduled_block",
        "conflict_details": {
            "block_description": "Admin Block",
            "start_time": "9:00 AM",
            "end_time": "12:00 PM"
        }
    }
}
```

**Generic Failure (Max Retries):**

```json theme={null}
{
    "id": "evt_1J9X2q2eZvKYlo2Cuvwxyz",
    "access_token_reference_id": "user_1J9X2q2eZvKYlo2Cstuv",
    "object": "event",
    "created": "2023-10-28T11:30:00Z",
    "type": "appointment.failed",
    "data": {
        "appointment_id": "123456795",
        "mrn": "123456789",
        "failure_reason": "Appointment creation failed after 3 attempts. Last error: Some internal error message. Please check logs or contact support."
    }
}
```


## OpenAPI

````yaml POST /appointments
openapi: 3.0.0
info:
  title: Cobalt API
  version: 1.0.1
  description: API for interacting with Cobalt's EHR integration services
servers:
  - url: https://api.usecobalt.com/v1
security:
  - ClientCredentials: []
    ClientSecret: []
    AccessToken: []
paths:
  /appointments:
    post:
      summary: Create Appointment
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - mrn
                - location
                - date
                - time
                - provider
                - type
              properties:
                mrn:
                  type: string
                location:
                  type: string
                date:
                  type: string
                time:
                  type: string
                provider:
                  type: string
                secondary_provider:
                  type: string
                type:
                  type: string
                note:
                  type: string
                duration:
                  type: string
                  description: >-
                    Optional appointment duration in minutes, as a string of
                    digits (e.g. "30"). Where the EHR supports it, this
                    overrides the default visit-type duration.
                reason:
                  type: string
                new_patient:
                  type: string
                  enum:
                    - 'true'
                    - 'false'
                prevent_double_booking:
                  type: string
                  enum:
                    - 'true'
                    - 'false'
                  description: >-
                    When set to "true", Cobalt checks the provider's schedule
                    for conflicts before submitting the appointment to the EHR.
                    If an overlap is detected with an existing patient visit or
                    schedule block, the appointment fails immediately with a
                    structured error rather than being submitted. Supported for
                    eClinicalWorks and Practice Fusion; ignored for all other
                    EHR systems. Defaults to no conflict check when omitted.
                skip_visit_type_validation:
                  type: string
                  enum:
                    - 'true'
                    - 'false'
                  description: >-
                    eClinicalWorks only. When "true", skips the check that the
                    visit type is configured for the selected provider/resource
                    in the EHR. Use this for visit types that are bookable in
                    the EHR (for example via availability slots) but not part of
                    the resource's configured visit type list. Requires
                    `duration`, since the visit type's configured duration
                    cannot be read when validation is skipped. Defaults to
                    "false".
                department_id:
                  type: string
                  description: >-
                    eClinicalWorks only. The EHR department to book the
                    appointment under, given as the `ehr_id` of a department
                    from `GET /v1/settings` (the `departments` array; match the
                    one whose `location_ehr_id` equals this appointment's
                    `location`). Validated against the chosen `location`'s
                    departments; an invalid value is rejected with a 400.
                    Ignored for other EHR systems.
                non_billable:
                  type: string
                  enum:
                    - 'true'
                    - 'false'
                  description: >-
                    eClinicalWorks only. When "true", the created encounter is
                    marked non-billable (no claim required). Ignored for other
                    EHR systems.
                recall_id:
                  type: string
                  description: >-
                    ModMed Gastro only. Links the created appointment to an
                    existing recall (the recall `id` from GET /v1/recalls).
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message:
                    type: string
                  appointment_id:
                    type: string
                  job_id:
                    type: integer
components:
  securitySchemes:
    ClientCredentials:
      type: apiKey
      in: header
      name: client_id
    ClientSecret:
      type: apiKey
      in: header
      name: client_secret
    AccessToken:
      type: apiKey
      in: header
      name: access_token

````