# Activate Account
Source: https://docs.usecobalt.com/api-reference/account/activate
POST /account/activate
Activates a deactivated account.
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/account/activate \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Account activated successfully"
}
```
# Deactivate Account
Source: https://docs.usecobalt.com/api-reference/account/deactivate
POST /account/deactivate
Deactivates an active account.
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/account/deactivate \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Account deactivated successfully"
}
```
# Delete Credential
Source: https://docs.usecobalt.com/api-reference/account/delete-credential
DELETE /credentials/{credentialId}
Removes a credential set from a connection.
Deletes a set of EHR credentials. Unlike [Disable Credential](/api-reference/account/disable-credential), this cannot be undone — the credential set cannot be re-enabled afterwards.
`credentialId` is the UUID of the credential set. Account events carry it as `credential_id`, so you can delete the exact credential an event reports on — see [Account Events](/docs/webhooks/account-events).
A connection must always keep one active credential set, so deleting the last one returns `409`.
### Example Request
```bash theme={null}
curl -X DELETE https://api.usecobalt.com/v1/credentials/550e8400-e29b-41d4-a716-446655440010 \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Credential deleted"
}
```
### Last Active Credential
```json theme={null}
{
"success": false,
"message": "Cannot delete the last active credential set. Add or enable another credential first."
}
```
# Disable Credential
Source: https://docs.usecobalt.com/api-reference/account/disable-credential
PATCH /credentials/{credentialId}/disable
Stops Cobalt using a credential set for EHR sessions, leaving it in place.
A connection can hold several sets of EHR credentials. Disabling one takes it out of rotation without removing it, so you can re-enable it later. Sessions already running on that credential are not interrupted.
`credentialId` is the UUID of the credential set. Account events carry it as `credential_id`, so you can disable the exact credential an event reports on — see [Account Events](/docs/webhooks/account-events).
A connection must always keep one active credential set, so disabling the last one returns `409`.
### Example Request
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/credentials/550e8400-e29b-41d4-a716-446655440010/disable \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Credential disabled"
}
```
### Last Active Credential
```json theme={null}
{
"success": false,
"message": "Cannot disable the last active credential set. Add or enable another credential first."
}
```
# Enable Credential
Source: https://docs.usecobalt.com/api-reference/account/enable-credential
PATCH /credentials/{credentialId}/enable
Puts a disabled credential set back into rotation.
Re-enables a credential set that was previously disabled. A deleted credential set cannot be restored this way.
`credentialId` is the UUID of the credential set, the same value account events carry as `credential_id`.
### Example Request
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/credentials/550e8400-e29b-41d4-a716-446655440010/enable \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Credential enabled"
}
```
# Lock Client
Source: https://docs.usecobalt.com/api-reference/account/lock
POST /client/lock
Emergency stop: immediately invalidates every access token, EHR session, and your client_secret.
Break-glass endpoint for a broad compromise. Locking is immediate and affects all users under your client: all access tokens are deactivated, all EHR sessions are invalidated, and your `client_secret` is cleared. Only `client_id` and `client_secret` headers are required.
Locking is not self-serve reversible — contact support to unlock, after which users reconnect through [Cobalt Link](/docs/link/overview).
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/client/lock \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Account has been locked. Contact support to unlock.",
"data": {
"cookies_invalidated": 12,
"tokens_deactivated": 12,
"users_deactivated": 12,
"locked_at": "2026-07-20T19:45:00.000Z"
}
}
```
# Rotate Access Token
Source: https://docs.usecobalt.com/api-reference/account/rotate-access-token
POST /access-token/rotate
Issues a new access token and immediately invalidates the current one.
Use this when an access token may have been exposed. The user's EHR connection is unaffected and no re-link is required — store the returned token and continue. Requests made with the old token return `401`.
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/access-token/rotate \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Access token rotated successfully. The old token has been invalidated immediately.",
"access_token": "8f2b41c09e77d3a5f6b1a0c4e9d82f7a"
}
```
# Create Appointments
Source: https://docs.usecobalt.com/api-reference/appointments/create
POST /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.
**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.
### 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)
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.
#### Booking Timezone
By default the appointment time is interpreted in the account's timezone. For EHR instances whose facilities span multiple timezones, pass an optional `timezone` (IANA name) to book the appointment at that facility's local wall-clock time. The time you send (via `datetime` or `date` and `time`) is then treated as local to that zone.
```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": "9:20 am",
"timezone": "America/Chicago",
"provider": "123456789",
"type": "new_patient"
}'
```
### 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.
```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).
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.
### 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."
}
}
```
# Fetch Appointments
Source: https://docs.usecobalt.com/api-reference/appointments/fetch
POST /appointments/fetch
Performs a live fetch of appointment data from the connected EMR system by date range, patient MRN, or provider.
This is a slow operation that fetches up-to-date appointment data directly from the EMR system. If the newest data is not critical, consider using the GET /appointments endpoint instead for faster results from cached data.
## Search Modes
### Date Range (default)
Fetches appointments for a date range (max 7 days). Results are synced to the database and returned via webhook.
```json theme={null}
{
"start_date": "2025-01-01",
"end_date": "2025-01-07",
"include": ["ehr_audit_log"]
}
```
### MRN
Fetches all appointments for a specific patient by MRN, enriched with `created_at` and `created_by` timestamps.
```json theme={null}
{
"search_by": "mrn",
"mrn": "12345"
}
```
### Provider
Fetches appointments for one or more providers in a single EMR call. Results are synced to the database (scoped to the requested providers) and returned via webhook.
* `provider_ids`: required array of EMR provider IDs (max 10)
* 1 provider: `end_date` may be up to 5 days after `start_date`
* 2-10 providers: `start_date` must equal `end_date`
```json theme={null}
{
"search_by": "provider",
"start_date": "2025-01-01",
"end_date": "2025-01-05",
"provider_ids": ["prov_789", "prov_790"],
"include": ["progress_note"]
}
```
## Visit Notes
Where the EMR supports it, each appointment in the webhook has a
`visit_note_document_id`: the Cobalt document ID of the encounter's visit note.
Pass it to [POST /documents/fetch](/api-reference/documents/fetch) to get the note
as a PDF. The same encounter has the same ID in the appointment and patient live
fetches.
## Webhook Notifications
When the appointment fetch is complete, we will send a webhook to your registered endpoint.
### Date Range Webhook
When the request includes `ehr_audit_log`, each appointment also carries `created_at`, `created_by`, and an `ehr_audit_log` array of every field change (who changed it, when, and old → new):
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2Cmnopqr",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cstuv",
"job_id": "job_1J9X2q2eZvKYlo2Cmnopqr",
"object": "event",
"created": "2023-10-28T11:00:00Z",
"timestamp": "2023-10-28T11:00:00Z",
"type": "appointment.live_fetch_completed",
"action": "sync",
"data": {
"success": true,
"appointment_count": 42,
"start_date": "2025-01-01",
"end_date": "2025-01-07",
"appointments": [
{
"id": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
"ehr_appointment_id": "12345678",
"datetime": "2025-01-15T10:00:00-05:00",
"duration": 30,
"appointment_type": "Office Visit",
"appointment_mode": null,
"status": "CHK (Check Out)",
"provider_ehr_id": "prov_789",
"provider_name": "Smith, Jane",
"provider_npi": "1234567890",
"location": "Main Office",
"patient_mrn": "85799",
"patient_first_name": "Alex",
"patient_last_name": "Doe",
"patient_dob": "1985-04-12",
"patient_gender": "M",
"patient_phone": "555-555-5555",
"patient_ehr_id": "PAT123",
"cobalt_patient_id": "bbbbbbbbccccddddeeeeffffffffffff",
"insurance": "Aetna",
"insurances": null,
"insurance_subscriber": null,
"insurance_number": "W123456789",
"insurance_group_number": null,
"secondary_insurance": null,
"secondary_insurance_number": null,
"diagnoses": null,
"created_at": "2025-01-10T09:15:22-05:00",
"created_by": "Doe, John",
"ehr_audit_log": [
{
"field_name": "Visit Status",
"old_value": "READY (Ready To Admit)",
"new_value": "CHK (Check Out)",
"action": "Modified",
"username": "Smith, Jane",
"timestamp": "2025-01-15T10:42:00-05:00"
},
{
"field_name": "Visit Status",
"old_value": "ARR (Check-in)",
"new_value": "READY (Ready To Admit)",
"action": "Modified",
"username": "Roe, Mary",
"timestamp": "2025-01-15T10:18:33-05:00"
},
{
"field_name": "Visit Status",
"old_value": "CON (Confirmed)",
"new_value": "ARR (Check-in)",
"action": "Modified",
"username": "Smith, Jane",
"timestamp": "2025-01-15T09:58:12-05:00"
},
{
"field_name": "Visit Status",
"old_value": "PEN (Pending)",
"new_value": "CON (Confirmed)",
"action": "Modified",
"username": "Doe, John",
"timestamp": "2025-01-11T14:05:40-05:00"
},
{
"field_name": "Visit Status",
"old_value": "",
"new_value": "PEN (Pending)",
"action": "Created",
"username": "Doe, John",
"timestamp": "2025-01-10T09:15:22-05:00"
}
]
}
]
}
}
```
### MRN Webhook
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2Cmnopqr",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cstuv",
"job_id": "job_1J9X2q2eZvKYlo2Cmnopqr",
"object": "event",
"created": "2023-10-28T11:00:00Z",
"timestamp": "2023-10-28T11:00:00Z",
"type": "appointment.live_fetch_completed",
"action": "sync",
"data": {
"success": true,
"search_by": "mrn",
"mrn": "12345",
"appointment_count": 7,
"appointments": [
{
"ehr_appointment_id": "12345678",
"datetime": "2025-04-07T13:00:00.000-07:00",
"appointment_type": "OV (Office Visit)",
"status": "PEN (Pending)",
"provider_ehr_id": "prov_456",
"provider_first_name": "Jane",
"provider_last_name": "Smith",
"reason": "Annual Checkup",
"location": "Main Office",
"locked": false,
"created_at": "2025-02-20T07:52:02.000-08:00",
"created_by": "Doe, John"
}
]
}
}
```
### Provider Webhook
Each appointment uses the same shape as the Date Range Webhook above.
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2Cmnopqr",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cstuv",
"job_id": "job_1J9X2q2eZvKYlo2Cmnopqr",
"object": "event",
"created": "2023-10-28T11:00:00Z",
"timestamp": "2023-10-28T11:00:00Z",
"type": "appointment.live_fetch_completed",
"action": "sync",
"data": {
"success": true,
"search_by": "provider",
"provider_ids": ["prov_789", "prov_790"],
"start_date": "2025-01-01",
"end_date": "2025-01-05",
"appointment_count": 12,
"appointments": [
{
"id": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
"ehr_appointment_id": "12345678",
"datetime": "2025-01-02T10:00:00-05:00",
"duration": 30,
"appointment_type": "Office Visit",
"status": "CHK (Check Out)",
"provider_ehr_id": "prov_789",
"provider_name": "Smith, Jane",
"provider_npi": "1234567890",
"location": "Main Office",
"patient_mrn": "85799",
"patient_first_name": "Alex",
"patient_last_name": "Doe",
"patient_ehr_id": "PAT123",
"cobalt_patient_id": "bbbbbbbbccccddddeeeeffffffffffff",
"progress_note": "Progress Notes Patient: Doe, Alex DOB: 04/12/1985 PRISMA Summary: External Timeline: The patient has had 1 ER/Hospital visit at an outside facility. External Results: The patient has undergone labs including CBC. Subjective: Chief Complaint(s): Follow up. HPI: Doing well since last visit. Assessment: Hypertension. Treatment: Continue current medication. Follow Up: 3 months"
}
]
}
}
```
# Get Appointments
Source: https://docs.usecobalt.com/api-reference/appointments/get
GET /appointments
Gets a list of appointments.
By default only real appointments are returned. Use `category` to include schedule slots and blocks, for example `?category=appointment,schedule_slot` or `?category=schedule_slot` for open availability only.
The legacy `include_schedule_blocks=true` parameter is deprecated but still honored: it is equivalent to `?category=appointment,schedule_block`. Prefer `category`, which also supports schedule slots. `category` takes precedence if both are supplied.
# Get Appointment by ID
Source: https://docs.usecobalt.com/api-reference/appointments/get-by-id
GET /appointments/{id}
Gets details for a specific appointment.
### Example Request
```bash theme={null}
curl -X GET https://api.usecobalt.com/v1/appointments/1276397812 \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH'
```
### Example Response
```json theme={null}
{
"success": true,
"appointment": {
"id": "1276397812",
"datetime": "2024-03-14T00:00:00-07:00",
"appointment_mode": "office",
"appointment_type": "f/u",
"location": "54252",
"patient_name": "Jane Doe",
"patient_mrn": "414421",
"patient_dob": "1994-08-12",
"patient_gender": "female",
"insurance": "Blue Shield",
"insurance_subscriber": "John Doe",
"insurance_number": "19228934",
"insurance_group_number": "FDL992829qe",
"reason": "Routine follow-up",
"provider_ehr_id": "6644",
"provider_npi": "2453453453",
"status": "completed"
}
}
```
# Update Appointment
Source: https://docs.usecobalt.com/api-reference/appointments/update
PATCH /appointments/{id}
Updates an existing appointment. The update process differs based on the current status of the appointment.
**Use the Cobalt `id` in the URL path.** The `{id}` parameter should be the Cobalt appointment ID returned from API responses or GET endpoints, not the EHR ID.
The update process differs based on the current status of the appointment:
### 1. Updating Pending or Failed Appointments
For appointments with a status of 'pending' or 'failed', you can update any attribute of the appointment.
| Parameter | Type | Required | Description |
| - | - | - | - |
| Any appointment attribute | varies | No | Any attribute of the appointment can be updated. All fields are optional. |
### 2. Updating Scheduled Appointments
For appointments with a status of 'scheduled', you can update the status, note, or visit type.
**Rescheduling (changing date/time):** a Scheduled appointment's date/time cannot be edited in place. To reschedule, follow the standard flow clinics use to keep cancellations tracked: PATCH the existing appointment's `status` to a cancelled status (from `GET /visit-statuses`), then create a new appointment at the new time with `POST /v1/appointments`.
| Parameter | Type | Required | Description |
| - | - | - | - |
| status | string | No | Must be one of the available statuses associated with the linked account. You can find the available statuses by using our GET /visit-statuses endpoint |
| note | string | No | A note associated with the appointment. This is not a progress note or addition to the patient chart. This is primarily used for admin (eg. "patient might be 5 minutes late"). |
| type | string | No | The new visit type for the appointment. Must be one of the visit types from GET /v1/visit-types, and must be available for the appointment's provider/resource in the EHR (skippable via `skip_visit_type_validation`). The appointment's duration is updated to the new visit type's configured duration unless `duration` is provided. |
| duration | string | No | Only valid together with `type`. The new appointment duration in minutes, as a positive integer string. Overrides the new visit type's configured duration. Required when `skip_visit_type_validation` is `"true"`. |
| skip\_visit\_type\_validation | string | No | Only valid together with `type`. When `"true"`, skips the check that the visit type is configured for the appointment's 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`. |
### Example Request for Updating a Pending/Failed Appointment
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/appointments/23456789 \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"appointment_datetime": "2024-01-15T14:00:00-07:00",
"location": "New Clinic",
"type": "f/u"
}'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Appointment updated successfully"
}
```
# Fetch Availability
Source: https://docs.usecobalt.com/api-reference/availability/fetch
POST /availability/fetch
Performs a live fetch of provider availability by combining a real-time EMR appointment fetch with availability calculation.
This is an async operation that fetches up-to-date appointment data directly from the EMR and computes availability in one pass. If freshness is not critical, use `GET /availability` instead, which returns availability against cached appointment data.
## Request Constraints
* `provider_ids`: required array of EMR provider IDs. Must contain between 1 and 10 entries.
* A single provider may span up to a 5-day window.
* Two or more providers must share a single date (`start_date` must equal `end_date`).
All availability-calculation parameters (`calculation_method`, `daily_appointment_limit`, `daily_limit_type`, `provider_type`, `fallback_to_default_hours`, `max_slot_duration`, `facility_scoped_scheduling`, `location_ids`, `cancelled_statuses`) are optional and follow the same defaults and validation rules as `GET /availability`.
### Example Request (1 provider, 5 days)
```json theme={null}
{
"start_date": "2026-07-01",
"end_date": "2026-07-05",
"provider_ids": ["prov_789"],
"calculation_method": "gaps",
"cancelled_statuses": ["canc", "rs", "cancsms"]
}
```
### Example Request (multiple providers, single day)
```json theme={null}
{
"start_date": "2026-07-01",
"end_date": "2026-07-01",
"provider_ids": ["prov_789", "prov_790", "prov_791"]
}
```
## Webhook Notification
When the fetch completes, we send an `availability.live_fetch_completed` event to your registered webhook endpoint with the computed slots inline. The slots themselves are not persisted, but as a side effect the underlying appointments returned by the EMR are written to our appointments cache — a follow-up `GET /availability` reflects the live state.
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2Cmnopqr",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cstuv",
"job_id": "job_1J9X2q2eZvKYlo2Cmnopqr",
"object": "event",
"created": "2026-07-01T11:00:00Z",
"timestamp": "2026-07-01T11:00:00Z",
"type": "availability.live_fetch_completed",
"action": "sync",
"data": {
"success": true,
"provider_ids": ["prov_789"],
"start_date": "2026-07-01",
"end_date": "2026-07-05",
"slot_count": 24,
"slots": [
{
"day_of_week": 3,
"date": "2026-07-01",
"duration_string": "30 minutes",
"range_start": "2026-07-01T09:00:00-07:00",
"range_end": "2026-07-01T09:30:00-07:00",
"provider_id": "prov_789",
"facility_id": "loc_1",
"facility_name": "Main Office"
}
]
}
}
```
Each slot always includes `day_of_week` (1-7, ISO weekday), `date` (YYYY-MM-DD), `duration_string`, `range_start`, `range_end`, and `provider_id`. `facility_id` and `facility_name` are present when the source EHR scopes the shift to a specific location. `visit_type`, `available_appointments`, and `max_visits` appear when `calculation_method` is `slots` or `equal_slots`.
# Get Availability
Source: https://docs.usecobalt.com/api-reference/availability/get
GET /availability
Returns open scheduling slots computed from synced provider hours and booked appointments over a date range.
**Provider Filtering**: Only providers with `active=true` AND `hide_in_availability=false` will appear in availability results. If you've set a provider's `hide_in_availability` to `true`, they won't appear here even if their status is active.
Use `provider_ids` and `location_ids` to narrow returned availability. Both parameters accept comma-separated EHR IDs, for example `provider_ids=prov1,prov2` and `location_ids=loc1,loc2`. Location filtering is applied to generated availability windows using each slot's `facility_id`; slots without a `facility_id` are excluded when `location_ids` is provided.
### Example Request
```bash theme={null}
curl -X GET https://api.usecobalt.com/v1/availability \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-G \
--data-urlencode "start_date=2024-03-14T00:00:00-07:00" \
--data-urlencode "end_date=2024-04-14T23:59:59-07:00" \
--data-urlencode "calculation_method=slots" \
--data-urlencode "provider_ids=3498234,9834521" \
--data-urlencode "location_ids=1" \
--data-urlencode "cancelled_statuses=canc,rs,cancsms"
```
### Example Response
```json theme={null}
{
"success": true,
"results": {
"availability": [
{
"day_of_week": 5,
"date": "2024-04-05",
"duration_string": "9h",
"range_start": "2024-04-05T08:00:00.000-07:00",
"range_end": "2024-04-05T17:00:00.000-07:00",
"provider_id": "3498234",
"facility_id": "1", // if available in the EHR
"facility_name": "Main St Clinic", // if available in the EHR
"visit_type": "New Patient" // only present when calculation_method=slots
}
]
},
"timezone": "America/Los_Angeles"
}
```
### Enhanced Response with Detailed Slot Information
When using `calculation_method=slots`, if the EHR provides detailed slot information, the response may include additional fields for capacity management:
```json theme={null}
{
"success": true,
"availability": [
{
"day_of_week": 2,
"date": "2025-01-14",
"duration_string": "30 minutes",
"range_start": "2025-01-14T09:00:00.000-08:00",
"range_end": "2025-01-14T09:30:00.000-08:00",
"provider_id": "12345",
"visit_type": "New Patient Visit",
"available_appointments": 3,
"max_visits": 5,
"facility_id": "LOC-001",
"facility_name": "Main Office"
},
{
"day_of_week": 2,
"date": "2025-01-14",
"duration_string": "15 minutes",
"range_start": "2025-01-14T10:00:00.000-08:00",
"range_end": "2025-01-14T10:15:00.000-08:00",
"provider_id": "12345",
"visit_type": "Follow-up",
"available_appointments": 1,
"max_visits": 1,
"facility_id": "LOC-001",
"facility_name": "Main Office"
}
],
"timezone": "America/Los_Angeles"
}
```
**Key fields when detailed slot information is available:**
* `visit_type`: The specific appointment type that can be booked in this slot
* `available_appointments`: How many more appointments can still be scheduled in this slot
* `max_visits`: The total capacity of this slot (useful for understanding how many are already booked)
* `facility_id`: Unique identifier for the facility/location
* `facility_name`: Name of the facility/location
The availability of these enhanced fields depends on your EHR system's capabilities. Not all EHRs provide this level of detail for slot-based availability.
## Calculation Methods
The `calculation_method` parameter determines how availability is calculated:
* **gaps** (Default): Calculates availability based on free time between a provider's working hours and existing appointments
* **slots**: Pre-defined appointment slots blocked only by appointments matching the slot's visit type
* **equal\_slots**: Pre-defined appointment slots blocked by ANY appointment at that time, regardless of type
### Example Scenarios
**Scenario 1:** A "New Patient" schedule\_slot exists at 10:00 AM. A "Follow-up" appointment is already booked at 10:00 AM.
* **gaps**: 10:00 AM **not returned as available** (appointment occupies that time)
* **slots**: "New Patient" slot **returned as available** (different appointment type doesn't block)
* **equal\_slots**: "New Patient" slot **not returned** (any appointment blocks all slot types)
**Scenario 2:** A "New Patient" schedule\_slot exists at 10:00 AM. A "New Patient" appointment is already booked at 10:00 AM.
* **gaps**: 10:00 AM **not returned as available** (appointment occupies that time)
* **slots**: "New Patient" slot **not returned** (same appointment type blocks)
* **equal\_slots**: "New Patient" slot **not returned** (any appointment blocks all slot types)
**Scenario 3:** A "New Patient" schedule\_slot exists at 10:00 AM. A schedule\_block (e.g., "Lunch") exists at 10:00 AM.
* **gaps**: 10:00 AM **not returned as available** (schedule\_block occupies that time)
* **slots**: "New Patient" slot **not returned** (schedule\_blocks block slots)
* **equal\_slots**: "New Patient" slot **not returned** (schedule\_blocks block all slot types)
Use `equal_slots` when multiple parties (e.g., clinic staff and automated systems) are scheduling different appointment types into the same time slots and you need to prevent double-booking.
# Create Claim
Source: https://docs.usecobalt.com/api-reference/claims/create
POST /claims
Creates a claim for a given appointment in the connected EMR system.
This is an async operation. The endpoint returns `202 Accepted` immediately after queuing the claim, and a webhook event is sent to your registered endpoint once the claim has been created (or has failed) in the EMR.
### Request Parameters
#### Required Fields
* **appointment\_id** (string, required): The Cobalt appointment ID to create a claim for. The appointment must belong to the authenticated user and have an associated EMR appointment ID.
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/claims \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"appointment_id": "a1b2c3d4e5f64g7h8i9jk0l1m2n3o4p5"
}'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Claim creation queued. A webhook event will be sent upon completion.",
"claim_id": "f4g5h6i7j8k9l0m1n2o3p4q5r6s7t8u9",
"appointment_id": "a1b2c3d4e5f64g7h8i9jk0l1m2n3o4p5",
"job_id": 12345
}
```
The response includes:
* **claim\_id**: Unique identifier for the queued claim record. Use this to correlate the eventual webhook event.
* **appointment\_id**: Echo of the appointment the claim was queued against.
* **job\_id**: Job execution identifier for tracking the async operation.
### Error Responses
#### Missing Required Field
```json theme={null}
{
"success": false,
"message": "'appointment_id' is required."
}
```
#### Invalid Appointment ID Format
```json theme={null}
{
"success": false,
"message": "Invalid 'appointment_id' format. Please provide a valid UUID."
}
```
#### Appointment Missing EMR ID
Returned if the appointment exists but has not yet been synced with an `emr_appointment_id`.
```json theme={null}
{
"success": false,
"message": "Appointment is missing emr_appointment_id; cannot create claim."
}
```
#### Appointment Not Found
```json theme={null}
{
"success": false,
"message": "Appointment not found."
}
```
#### Duplicate Claim
Returned if a claim for this appointment is already in-flight (`pending_create`) or has already been completed. Failed claims do not block retries.
```json theme={null}
{
"success": false,
"message": "A claim for this appointment is already pending or completed."
}
```
### Webhook Notifications
When the claim creation 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_1J9X2q2eZvKYlo2CluR9g9gV",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2026-05-22T10:30:00Z",
"type": "claim.created",
"job_id": "12345",
"data": {
"claim_id": "f4g5h6i7j8k9l0m1n2o3p4q5r6s7t8u9",
"appointment_id": "a1b2c3d4e5f64g7h8i9jk0l1m2n3o4p5",
"patient_mrn": "MRN-12345",
"emr_claim_id": "100234",
"emr_appointment_id": "500100",
"emr_patient_id": "40210"
}
}
```
#### Failure
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2CluR9g9gW",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2026-05-22T10:35:00Z",
"type": "claim.failed",
"job_id": "12345",
"data": {
"claim_id": "f4g5h6i7j8k9l0m1n2o3p4q5r6s7t8u9",
"appointment_id": "a1b2c3d4e5f64g7h8i9jk0l1m2n3o4p5",
"patient_mrn": "MRN-12345",
"failure_reason": "Failed to create claim"
}
}
```
# Get Claims
Source: https://docs.usecobalt.com/api-reference/claims/get
GET /claims
Returns paginated claims with line items, payments, insurance details, and billing activity for a given date range.
### Example Request
```bash theme={null}
curl -X GET https://api.usecobalt.com/v1/claims \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-G \
--data-urlencode "start_date=2025-08-01" \
--data-urlencode "end_date=2025-09-01"
```
### Example Response
```json theme={null}
{
"success": true,
"claims": [
{
"id": "a1b2c3d4e5f6789012345678abcdef90",
"emr_claim_id": "100234",
"emr_appointment_id": "500100",
"service_date": "2025-08-01",
"claim_date": "2025-08-08",
"claim_status": "48CL",
"claim_status_description": "Closed (48-hour rule)",
"claim_type": "0",
"void_flag": false,
"emr_patient_id": "40210",
"patient_name": "DOE, JANE, M",
"emr_provider_id": "10052",
"provider_name": "Smith, Robert",
"total_charge": "350.00",
"total_payment": "280.00",
"net_payment": "280.00",
"balance": "20.00",
"net_adjustment": "50.00",
"patient_responsibility": "20.00",
"insurances": [
{
"insurance_id": "101",
"insurance_name": "Blue Cross Blue Shield",
"insurance_type": "C1",
"claim_indicator": "P",
"claim_indicator_description": "Primary",
"sequence_number": "1",
"subscriber_name": "DOE, JANE, M",
"subscriber_number": "XYZ123456789",
"subscriber_dob": "1975-06-15",
"subscriber_relation": "1",
"group_name": "ACME CORP",
"group_number": "GRP-98765",
"provider_number": "BCBS1",
"payment_source": "16",
"assign_benefits": "Y",
"insurance_address_1": "PO BOX 12345",
"insurance_address_2": "",
"insurance_city": "CHICAGO",
"insurance_state": "IL",
"insurance_zip": "60601",
"medicaid_id": ""
},
{
"insurance_id": "202",
"insurance_name": "Medicare Part B",
"insurance_type": "C1",
"claim_indicator": "S",
"claim_indicator_description": "Secondary",
"sequence_number": "2",
"subscriber_name": "DOE, JANE, M",
"subscriber_number": "1EG4TE5MK72",
"subscriber_dob": "1975-06-15",
"subscriber_relation": "1",
"group_name": "",
"group_number": "",
"provider_number": "MED01",
"payment_source": "MB",
"assign_benefits": "Y",
"insurance_address_1": "CMS CLAIMS",
"insurance_address_2": "PO BOX 5678",
"insurance_city": "BALTIMORE",
"insurance_state": "MD",
"insurance_zip": "21244",
"medicaid_id": ""
}
],
"balances": {
"invoice_amount": "350.00",
"total_payment": "280.00",
"net_payment": "280.00",
"balance": "20.00",
"patient_balance": "20.00",
"patient_payment": "0.00",
"patient_responsibility": "20.00",
"on_plan": "false"
},
"icd_codes": ["M54.5", "Z96.641"],
"void_claim": {
"void_to_claim_id": "-1",
"void_from_claim_id": "-1",
"copy_to_claim_id": "-1",
"copy_from_claim_id": "-1"
},
"submission_history": {
"created_by": "Johnson, Sarah",
"entries": [],
"auto_claim_data": {
"isUserInactive": "false",
"schedulerJobId": "-1",
"isClaimCreatedByJob": "false"
}
},
"billing_activity_log": [
{
"date": "2025-08-19 14:57:00",
"action": "Modified",
"category": "Claim Status",
"notes": "Changed From: Pending With Errors to Closed Zero Balance",
"user_name": "Sarah Johnson (sjohnson)"
},
{
"date": "2025-08-08 15:40:40",
"action": "Created",
"category": "Insurance",
"notes": "Created Insurance [P] [Id: 101] Blue Cross Blue Shield",
"user_name": "Sarah Johnson (sjohnson)"
},
{
"date": "2025-08-08 15:40:00",
"action": "Modified",
"category": "Claim Status",
"notes": "Changed From: to Pending",
"user_name": "Sarah Johnson (sjohnson)"
}
],
"billing_notes": "Eligibility verified 2025-08-01: Primary active, deductible met, copay $20. Secondary Medicare active.",
"line_items": [
{
"id": "f1e2d3c4b5a6789012345678",
"line_number": 1,
"cpt_code": "99213",
"description": "Office visit, established patient",
"modifiers": ["25"],
"units": 1,
"billed_amount": 150.00,
"allowed_amount": 120.00,
"billed_unit_fee": 150.00,
"icd_pointers": ["1", "2"],
"place_of_service": "11",
"type_of_service": null,
"service_date_start": "2025-08-01",
"service_date_end": "2025-08-01",
"rendering_provider_npi": "1234567890",
"ordering_provider_npi": null,
"referring_provider_npi": null
},
{
"id": "a9b8c7d6e5f4321098765432",
"line_number": 2,
"cpt_code": "20610",
"description": "Arthrocentesis, major joint",
"modifiers": [],
"units": 1,
"billed_amount": 200.00,
"allowed_amount": 160.00,
"billed_unit_fee": 200.00,
"icd_pointers": ["1"],
"place_of_service": "11",
"type_of_service": null,
"service_date_start": "2025-08-01",
"service_date_end": "2025-08-01",
"rendering_provider_npi": "1234567890",
"ordering_provider_npi": null,
"referring_provider_npi": null
}
],
"payments": [
{
"id": "d4c3b2a1f6e5789012345678",
"emr_payment_id": "55001",
"check_number": "EFT-20250825-001",
"payment_date": "2025-08-25",
"amount": 280.00,
"payment_type": "Insurance",
"payer_name": "Blue Cross Blue Shield",
"payer_type": "Insurance",
"adjustment": 50.00,
"deductible": 0.00,
"coinsurance": 20.00,
"allowed": 280.00,
"member_balance": 20.00,
"withheld": 0.00,
"era_claim_status": "Processed as Primary",
"era_claim_status_code": "1",
"era_payer_name": "Blue Cross Blue Shield",
"era_check_amount": 280.00,
"era_adjustment_codes": null
}
],
"synced_at": "2025-08-31T04:40:00.002Z",
"created_at": "2025-08-31T04:40:00.002Z",
"updated_at": "2025-08-31T04:40:00.002Z"
}
],
"pagination": {
"page": 1,
"page_size": 100,
"total_count": 45,
"total_pages": 1
}
}
```
# Get Claim by ID
Source: https://docs.usecobalt.com/api-reference/claims/get-by-id
GET /claims/{id}
Returns a single claim with its line items, payments, and billing details by its Cobalt claim ID, for example the data.id from a claim webhook.
### Example Request
```bash theme={null}
curl -X GET https://api.usecobalt.com/v1/claims/a1b2c3d4e5f6789012345678abcdef90 \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH'
```
### Example Response
```json theme={null}
{
"success": true,
"claim": {
"id": "a1b2c3d4e5f6789012345678abcdef90",
"emr_claim_id": "100234",
"emr_appointment_id": "500100",
"service_date": "2025-08-01",
"claim_date": "2025-08-08",
"claim_status": "48CL",
"claim_status_description": "Closed (48-hour rule)",
"claim_type": "0",
"void_flag": false,
"emr_patient_id": "40210",
"patient_name": "DOE, JANE, M",
"emr_provider_id": "10052",
"provider_name": "Smith, Robert",
"total_charge": "350.00",
"total_payment": "280.00",
"net_payment": "280.00",
"balance": "20.00",
"net_adjustment": "50.00",
"patient_responsibility": "20.00",
"icd_codes": ["M54.5", "Z96.641"],
"line_items": [
{
"id": "f1e2d3c4b5a6789012345678",
"line_number": 1,
"cpt_code": "99213",
"description": "Office visit, established patient",
"modifiers": ["25"],
"units": 1,
"billed_amount": 150.00,
"allowed_amount": 120.00,
"icd_pointers": ["1", "2"],
"place_of_service": "11",
"service_date_start": "2025-08-01",
"service_date_end": "2025-08-01",
"rendering_provider_npi": "1234567890"
}
],
"payments": [
{
"id": "d4c3b2a1f6e5789012345678",
"emr_payment_id": "55001",
"check_number": "EFT-20250825-001",
"payment_date": "2025-08-25",
"amount": 280.00,
"payment_type": "Insurance",
"payer_name": "Blue Cross Blue Shield",
"adjustment": 50.00,
"coinsurance": 20.00,
"allowed": 280.00,
"era_claim_status": "Processed as Primary"
}
],
"synced_at": "2025-08-31T04:40:00.002Z",
"created_at": "2025-08-31T04:40:00.002Z",
"updated_at": "2025-08-31T04:40:00.002Z"
}
}
```
# Add Diagnosis Codes
Source: https://docs.usecobalt.com/api-reference/codes/add
POST /appointments/{appointment_id}/codes
Adds ICD-10 diagnosis codes to an existing appointment's encounter.
This is an asynchronous operation. The request returns a `job_id` immediately, and a webhook is sent when the operation completes. Codes already on the encounter are skipped, so re-sending a code is safe. Only ICD-10 diagnosis codes are supported today; CPT codes are not.
Each code is `{ "type": "icd10", "code": "..." }`. The dot in a code is optional (`E119` and `E11.9` are equivalent). Send one or many codes in a single request.
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/appointments/APPT-12345/codes \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"codes": [
{ "type": "icd10", "code": "E11.9" },
{ "type": "icd10", "code": "I10" }
]
}'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Codes operation in progress. A webhook event will be sent upon completion.",
"job_id": "12345"
}
```
### Webhook
On completion we send a `codes.added` event (or `codes.failed` on error). `icd` reports which codes were applied versus skipped as duplicates, not matched in the EMR catalog, or rejected as invalid for the encounter date.
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2CluR9g9gV",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2025-10-09T10:30:00Z",
"type": "codes.added",
"job_id": "12345",
"data": {
"appointment_id": "APPT-12345",
"operation": "add",
"icd": {
"added": ["E11.9", "I10"],
"skipped": [],
"unmatched": [],
"invalid": []
}
}
}
```
See [Operation Events](/docs/webhooks/operation-events) for the failure payload and error codes.
# Remove Diagnosis Codes
Source: https://docs.usecobalt.com/api-reference/codes/remove
DELETE /appointments/{appointment_id}/codes
Removes ICD-10 diagnosis codes from an existing appointment's encounter.
This is an asynchronous operation. The request returns a `job_id` immediately, and a webhook is sent when the operation completes. Codes that are not on the encounter are ignored.
The body is the same shape as [Add Diagnosis Codes](/api-reference/codes/add): each code is `{ "type": "icd10", "code": "..." }`, and you can remove one or many in a single request.
### Example Request
```bash theme={null}
curl -X DELETE https://api.usecobalt.com/v1/appointments/APPT-12345/codes \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"codes": [
{ "type": "icd10", "code": "I10" }
]
}'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Codes operation in progress. A webhook event will be sent upon completion.",
"job_id": "12346"
}
```
### Webhook
On completion we send a `codes.removed` event (or `codes.failed` on error). `not_found` lists codes that were not on the encounter.
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2CluR9g9gW",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2025-10-09T10:35:00Z",
"type": "codes.removed",
"job_id": "12346",
"data": {
"appointment_id": "APPT-12345",
"operation": "remove",
"icd": {
"removed": ["I10"],
"not_found": []
}
}
}
```
See [Operation Events](/docs/webhooks/operation-events) for the failure payload and error codes.
# Fetch Document
Source: https://docs.usecobalt.com/api-reference/documents/fetch
POST /documents/fetch
Fetch a document's file from the EMR.
Queues an on-demand fetch of a document's file from the EMR. This is asynchronous:
the endpoint returns a `job_id`, Cobalt retrieves the file from the EMR and stores
it, then sends a `document.live_fetch_completed` webhook. Retrieve the file with
[GET /documents/](/api-reference/documents/get).
Depending on the EMR, the request takes either `document_ids` (a batch of 1-10
Cobalt document IDs) or a single `document_id`. See the request body below for
which field your EMR uses.
## Getting document IDs
Use the IDs Cobalt returns for EMR documents:
* `documents[].id` on each patient in a [patient live fetch](/api-reference/patients/fetch): a file in the patient's chart.
* `encounters[].visit_note_document_id` on a patient live fetch, or `visit_note_document_id` on each appointment in an [appointment live fetch](/api-reference/appointments/fetch): the encounter's visit note, delivered as a PDF.
Cobalt document IDs are UUIDs, accepted with or without dashes. They are stable:
the same EMR document always has the same ID, so you can store them.
## Flow
1. `POST /documents/fetch` returns `202` and a `job_id`.
2. Cobalt fetches each file from the EMR and stores it. Visit notes are rendered to PDF.
3. A `document.live_fetch_completed` webhook is sent with a result per document.
4. `GET /documents/{id}` returns the file.
## Example Request
```bash theme={null}
curl -X POST "https://api.usecobalt.com/v1/documents/fetch" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token" \
-H "Content-Type: application/json" \
-d '{"document_ids": ["3f1c2b7e9d4a4c6f8b2e1a0d5c7e9f12", "8a7b6c5d4e3f4a2b9c1d0e9f8a7b6c5d"]}'
```
## Webhook
With `document_ids`, `data.documents` has one result per requested document. A
document that could not be fetched has `success: false` and a `message`; the
other documents in the batch are not affected.
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2Cmnopqr",
"job_id": "job_1J9X2q2eZvKYlo2Cmnopqr",
"object": "event",
"created": "2026-10-07T22:54:50Z",
"type": "document.live_fetch_completed",
"data": {
"success": true,
"documents": [
{
"id": "3f1c2b7e9d4a4c6f8b2e1a0d5c7e9f12",
"success": true,
"document_type": "visit_note",
"file_name": "visit_note_159820.pdf",
"mime_type": "application/pdf",
"byte_size": 41040,
"patient_mrn": "15322"
},
{
"id": "8a7b6c5d4e3f4a2b9c1d0e9f8a7b6c5d",
"success": false,
"message": "Document not found."
}
]
}
}
```
## Status Codes
* **202**: Fetch accepted; results are delivered via webhook and files are retrievable at `GET /documents/{id}`.
* **400**: Missing or invalid `document_ids` / `document_id`, more than 10 `document_ids`, or the connected EMR is not supported.
* **404**: One or more `document_ids` are not documents of this linked account. The message lists them as sent.
# Get Document
Source: https://docs.usecobalt.com/api-reference/documents/get
GET /documents/{id}
Download a document by its Cobalt ID.
Returns the raw file bytes for a document. The response is the file itself — the
`Content-Type` header carries the document's MIME type and `Content-Disposition`
carries the original filename.
Use it to retrieve:
* PDFs referenced by `document_ids` on a referral.
* Documents fetched with [POST /documents/fetch](/api-reference/documents/fetch):
chart files (`documents[].id` on a patient live fetch) and visit notes
(`visit_note_document_id`).
A document from a patient or appointment live fetch has no file until you fetch
it. Until then this endpoint returns `409`.
## Path Parameters
* **id** (string, required): The Cobalt document ID (UUID, with or without dashes).
## Example Request
```bash theme={null}
curl -X GET "https://api.usecobalt.com/v1/documents/b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token" \
--output document.pdf
```
## Response
On success, the response body is the raw file. Relevant headers:
* **Content-Type**: The document's MIME type (typically `application/pdf`).
* **Content-Disposition**: `attachment; filename=""`.
* **Content-Length**: The file size in bytes.
On failure, the response is JSON:
```json theme={null}
{
"success": false,
"message": "Document not found"
}
```
## Status Codes
* **200**: Document returned successfully.
* **404**: Document not found.
* **409**: The document's file has not been fetched yet. Request it with `POST /documents/fetch`, then retry after the `document.live_fetch_completed` webhook.
## Notes
* Access is scoped to your organization — only documents associated with your
linked accounts are returned.
* Documents are stored as they were received from the EMR. PDFs are returned
unmodified.
# Upload Document
Source: https://docs.usecobalt.com/api-reference/documents/upload
POST /documents
Upload a document to a patient's chart.
Documents are processed asynchronously. You'll receive a webhook notification when the upload is complete or if there was an error.
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/documents \
-H 'Content-Type: multipart/form-data' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-F 'folder_name=MedicalRecords' \
-F 'patient_mrn=123456' \
-F 'location_id=20' \
-F 'tags=Estimate' \
-F 'tags=Referral' \
-F 'document=@/path/to/document.pdf'
```
To attach the document to an existing referral or order instead of a folder, send `association_type` and `association_id` (the Cobalt `id` from `GET /v1/referrals` or `GET /v1/orders`) in place of `folder_name`:
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/documents \
-H 'Content-Type: multipart/form-data' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-F 'patient_mrn=123456' \
-F 'association_type=order' \
-F 'association_id=b1c2d3e4-5678-4abc-9def-0123456789ab' \
-F 'document=@/path/to/document.pdf'
```
To route the document to a staff member for review, send `emr_assigned_to_id`. This is the EMR-native staff ID, not a Cobalt ID. Valid IDs are the `ehr_id` values returned by `GET /v1/staff`.
### Example Response
```json theme={null}
{
"success": true,
"message": "Document uploaded successfully. It will be processed soon.",
"document_id": "9988776655443322"
}
```
### Example Success Webhook
```json theme={null}
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"object": "event",
"created": "2023-10-01T12:34:56Z",
"type": "document.uploaded",
"data": {
"document_id": "9988776655443322",
"patient_mrn": "123456",
"folder_name": "MedicalRecords"
}
}
```
### Example Failure Webhook
```json theme={null}
{
"id": "123e4567-e89b-12d3-a456-426614174001",
"object": "event",
"created": "2023-10-01T12:34:56Z",
"type": "document.upload_failed",
"data": {
"document_id": "9988776655443322",
"patient_mrn": "123456",
"folder_name": "MedicalRecords",
"failure_reason": "Patient not found. Please check the patient MRN and try again."
}
}
```
# Get Eligibility Benefits
Source: https://docs.usecobalt.com/api-reference/eligibility-checks/benefits
GET /eligibility-checks/{id}/benefits
Returns the per-benefit detail for a single eligibility check.
A 271 response breaks down into many benefit lines, one per service type and
coverage level: deductibles, copays, coinsurance, out-of-pocket maximums,
limitations, and exclusions. Get the check `id` from
[Get Eligibility Checks](/api-reference/eligibility-checks/get), then page the
benefits here. Narrow results with `benefit_type`.
### Example Request
```bash theme={null}
curl -X GET "https://api.usecobalt.com/v1/eligibility-checks/abc123def4567890abcdef1234567890/benefits?benefit_type=Co-Payment&page=1&page_size=100" \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH'
```
### Example Response
```json theme={null}
{
"success": true,
"benefits": [
{
"line_number": 17,
"benefit_type": "Co-Payment",
"benefit_type_code": "B",
"coverage_level": "IND",
"service_type_codes": ["98"],
"insurance_type": null,
"time_period": null,
"amount": 25,
"percent": null,
"network_indicator": "in-network",
"messages": ["Specialist Visit or Evaluation"],
"raw_segment": "EB*B*IND*98****25*****Y"
}
],
"pagination": {
"page": 1,
"page_size": 100,
"total_records": 1,
"total_pages": 1
}
}
```
### Query Parameters
* **benefit\_type**: Filter by decoded benefit type (e.g. `Deductible`, `Co-Payment`, `Co-Insurance`, `Out of Pocket`).
* **page**: Page number (default `1`).
* **page\_size**: Results per page (default `100`, max `500`).
### Response Parameters
* **line\_number**: Segment order within the 271.
* **benefit\_type**: Decoded benefit category, e.g. `Active Coverage`, `Deductible`, `Co-Payment`, `Co-Insurance`, `Out of Pocket`, `Limitations`, `Non-Covered`.
* **benefit\_type\_code**: The raw X12 EB01 code.
* **coverage\_level**: `IND` (individual) or `FAM` (family).
* **service\_type\_codes**: X12 service type codes the benefit applies to.
* **insurance\_type**: Insurance type code, when present.
* **time\_period**: Decoded time period, e.g. `Calendar Year` or `Remaining`.
* **amount**: Monetary amount (deductible, copay, or out-of-pocket).
* **percent**: Coinsurance percentage as a decimal (e.g. `0.2` = 20%).
* **network\_indicator**: `in-network`, `out-of-network`, `unknown`, or `not-applicable`.
* **messages**: Payer free-text notes attached to the benefit line.
* **raw\_segment**: The raw X12 EB segment, retained for reference.
* **pagination**: `page`, `page_size`, `total_records`, `total_pages`.
# Get Eligibility Checks
Source: https://docs.usecobalt.com/api-reference/eligibility-checks/get
GET /eligibility-checks
Returns insurance eligibility checks (270/271) for a clinic.
Each eligibility check is one 270/271 verification: a request sent to a payer and
the benefits response that came back. This endpoint returns the check **headers**,
each with a `benefits_summary` (the headline deductible and out-of-pocket numbers)
and a `benefit_count`. To read the full per-benefit detail for a check, use its
`id` with [Get Eligibility Benefits](/api-reference/eligibility-checks/benefits).
Filter by service-date range, `patient_mrn`, or `coverage_status`. A check whose
`coverage_status` is `error` is one the payer could not process (for example a
missing provider NPI); the reason is in `status_message`.
### Example Request
```bash theme={null}
curl -X GET "https://api.usecobalt.com/v1/eligibility-checks?start_date=2026-06-01&end_date=2026-06-30&coverage_status=active&page=1&page_size=100" \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH'
```
### Example Response
```json theme={null}
{
"success": true,
"eligibility_checks": [
{
"id": "abc123def4567890abcdef1234567890",
"emr_id": "4588",
"emr_patient_id": "100482",
"patient_name": "Sample, Patient",
"patient_dob": "1990-01-01",
"emr_encounter_id": "293018",
"provider_name": "Pat Provider",
"payer_name": "Sample Health Plan",
"subscriber_name": "Patient Sample",
"subscriber_member_id": "W000000000",
"patient_relationship": "self",
"plan_name": "Sample PPO Plan",
"coverage_status": "active",
"status_message": null,
"service_date": "2026-06-01",
"response_at": "2026-06-01T05:01:00.000Z",
"plan_begin_date": "2026-01-01",
"plan_end_date": "2026-12-31",
"benefits_summary": {
"deductible": {
"individual": { "total": 2000, "remaining": 0 },
"family": { "total": 4000, "remaining": 1500 }
},
"out_of_pocket": {
"individual": { "total": 7000, "remaining": 917.76 },
"family": { "total": 10000, "remaining": 6217.76 }
}
},
"benefit_count": 61,
"synced_at": "2026-06-22T15:00:00.000Z"
}
],
"pagination": {
"page": 1,
"page_size": 100,
"total_records": 1,
"total_pages": 1
}
}
```
### Query Parameters
* **start\_date** / **end\_date**: Filter by service date (`YYYY-MM-DD`).
* **patient\_mrn**: Filter to a single patient by medical record number.
* **coverage\_status**: Filter by `active`, `inactive`, `error`, or `unknown`.
* **page**: Page number (default `1`).
* **page\_size**: Results per page (default `100`, max `500`).
### Response Parameters
* **id**: Cobalt's eligibility check identifier. Use this in the benefits endpoint path.
* **emr\_id**: The eligibility request identifier as it appears in the EMR.
* **emr\_patient\_id** / **patient\_name** / **patient\_dob**: The patient the check was run for.
* **emr\_encounter\_id**: The encounter/visit the check is tied to.
* **provider\_name** / **payer\_name**: Rendering provider and the payer that responded.
* **subscriber\_name** / **subscriber\_member\_id** / **patient\_relationship**: Subscriber details; `patient_relationship` is `self` or `dependent`.
* **plan\_name**: Plan description from the 271.
* **coverage\_status**: `active`, `inactive`, `error` (payer could not process the request), or `unknown`.
* **status\_message**: Payer reject reason when `coverage_status` is `error`.
* **service\_date** / **response\_at**: Date of service and when the payer response was received.
* **plan\_begin\_date** / **plan\_end\_date**: The plan's effective date range (either may be `null`).
* **benefits\_summary**: Headline EOB rollup. `deductible` and `out_of_pocket` are each split by `individual` / `family` into `total` and `remaining` amounts.
* **benefit\_count**: Number of benefit lines parsed from the 271.
* **pagination**: `page`, `page_size`, `total_records`, `total_pages`.
# Create Encounter
Source: https://docs.usecobalt.com/api-reference/encounters/create
POST /encounters
Queues an encounter (an episode visit with form documentation) for creation in the provider's EMR system.
An encounter is an episode visit written to the patient's chart together with its form documentation (for example a scored questionnaire such as GAD-7). Encounters are created using an asynchronous processing model, so creating one is not instantaneous.
Instead of leaving your POST request hanging until completion, we immediately return a success response if the request is properly formed. We then notify you via a webhook when the encounter has been written to the EMR.
This gives you flexibility around your user experience. For example, when you first make the `/encounters` call you can display a **Processing** status to your user, and when you receive the webhook notification you can update that to **Completed**.
### How an encounter is created
Processing an encounter runs an ordered chain against the EMR:
1. **Episode** — the encounter is attached to the episode you give in `episode_id`. There is no fallback to another episode. Assign the patient to a team first, as a separate step, to open the episode.
2. **Encounter type** — the `encounter_type` is resolved against the client's live billing matrix. An encounter type that is not billable for the client fails the encounter (see [Failure](#failure)).
3. **Form documentation** — the `answers` you supply are validated against the synced form definition (`form_id`) and written on the encounter. For a scored questionnaire, per-question scores are entered and totals and risk bands are derived by the EMR.
4. **Sign and submit** — the encounter is signed with the service date (`encounter_date`), start and end times, and location you supplied.
5. **Read-back** — after signing, the encounter is re-read from the EMR to confirm it persisted and to read its status and approval state before the success webhook is sent.
### Request Parameters
#### Required Fields
* **patient\_mrn** (string, required): The patient's medical record number. The patient must already be synced to Cobalt.
* **episode\_id** (string, required): The episode the encounter is created under. Use the exact id from the patient episode payload.
* **encounter\_type** (string, required): The encounter type to add, by name or numeric visit-type id (for example `"GAD-7"`). Must be billable for the client — that is, present in the client's billing matrix.
* **form\_id** (string, required): EMR form id whose answers you are providing — the `emr_form_id` of a form from [`GET /v1/forms`](/api-reference/forms/get). Required when the encounter type documents a form.
* **answers** (object, required): Form answers keyed by EMR question id (the `emrQuestionId` of each question in the form definition — see [`GET /v1/forms/{id}`](/api-reference/forms/get-by-id)). For a scored questionnaire, provide the numeric score for each scored question; totals and risk bands are derived automatically. Answers are validated against the synced form definition before the encounter is written.
#### Optional Fields
* **encounter\_date** (string, optional): Encounter (service) date in `YYYY-MM-DD` format, in the practice's local time. Defaults to today. Cannot be in the future.
* **start\_time** (string, optional): Service start as an ISO 8601 date-time (for example `"2026-10-05T14:00:00-04:00"`). A value without an offset is read in the practice's local time. Sets the service date; if you also send `encounter_date`, it must be the same date. Cannot be in the future. Defaults to the current time.
* **end\_time** (string, optional): Service end as an ISO 8601 date-time, on the same day as `start_time` and after it. Defaults to one hour after `start_time`. Requires `start_time`.
* **location** (string, optional): Service location, by EMR location id or exact name from the Location list on the EMR's service form (for example `"Broadway Office"`). Defaults to the EMR's default location for the service.
* **callback\_urls** (array of strings, optional): URLs to receive the completion webhook for this encounter, in addition to your account webhook.
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/encounters \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"patient_mrn": "1234567",
"episode_id": "32340",
"encounter_type": "GAD-7",
"form_id": "392",
"encounter_date": "2026-08-26",
"start_time": "2026-08-26T14:00:00-04:00",
"end_time": "2026-08-26T15:00:00-04:00",
"location": "Broadway Office",
"answers": {
"453149": "3",
"453150": "2",
"453156": "Very difficult"
}
}'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Encounter processing. A webhook event will be sent upon completion.",
"encounter_id": "123e4567e89b12d3a456426614174000",
"job_id": 12345
}
```
The response includes:
* **encounter\_id**: Cobalt encounter ID (UUID without dashes). This is echoed back in the webhook payload so you can correlate the two.
* **job\_id**: Job execution identifier for tracking the async operation.
### Error Responses
#### Missing Required Field
```json theme={null}
{
"success": false,
"message": "Missing required field: patient_mrn"
}
```
#### Answers Not An Object
```json theme={null}
{
"success": false,
"message": "answers must be an object keyed by EMR question id."
}
```
#### Invalid Encounter Date
```json theme={null}
{
"success": false,
"message": "encounter_date must be a valid date (YYYY-MM-DD)."
}
```
```json theme={null}
{
"success": false,
"message": "encounter_date cannot be in the future."
}
```
#### Invalid Service Times
```json theme={null}
{
"success": false,
"message": "end_time must be after start_time."
}
```
Other messages: `start_time must be an ISO 8601 date-time (e.g. 2026-10-05T14:00:00-04:00).` (and the same for `end_time`), `end_time requires start_time.`, `end_time must be on the same day as start_time.`, `encounter_date must match the date of start_time ().`, and `start_time cannot be in the future.`
#### User Not Found
```json theme={null}
{
"success": false,
"message": "User not found."
}
```
This indicates an issue with your access token.
#### Unsupported EMR
```json theme={null}
{
"success": false,
"message": "Creating encounters is not supported for [EMR Name]."
}
```
Your EMR system may not currently support encounter creation.
### Webhook Notifications
When the encounter has finished processing, we send a webhook to your registered endpoint.
#### Success
```json theme={null}
{
"id": "",
"access_token_reference_id": "",
"object": "event",
"created": "2026-08-26T10:30:00.000Z",
"type": "encounter.created",
"data": {
"encounter_id": "123e4567e89b12d3a456426614174000",
"emr_encounter_id": "927341",
"emr_episode_id": "88214",
"emr_status": "COMPLETED",
"approved": false,
"patient_mrn": "1234567"
}
}
```
The webhook data includes:
* **encounter\_id**: The Cobalt encounter ID you received in the response.
* **emr\_encounter\_id**: The encounter id in the EMR.
* **emr\_episode\_id**: The episode the encounter was written under.
* **emr\_status**: The encounter status in the EMR after signing (for example `COMPLETED`). `null` if the status could not be read.
* **approved**: Whether the EMR approved the encounter on signing. Some EMR configurations approve an encounter automatically and others leave it unapproved; `false` means it still needs approval: approve it with [`PATCH /v1/encounters/{id}`](/api-reference/encounters/update). `null` if the approval state could not be read.
* **patient\_mrn**: The patient's medical record number.
#### Failure
```json theme={null}
{
"id": "",
"access_token_reference_id": "",
"object": "event",
"created": "2026-08-26T10:35:00.000Z",
"type": "encounter.failed",
"data": {
"encounter_id": "123e4567e89b12d3a456426614174000",
"emr_encounter_id": null,
"patient_mrn": "1234567",
"failure_reason": "Encounter type 'GAD-7' not available for client 1234567 (not in billing matrix)"
}
}
```
Transient problems are retried automatically and do not emit a webhook until they are resolved or the attempts are exhausted. A `encounter.failed` event is sent once, when the failure is permanent. Common `failure_reason` values:
* `Encounter type '' not available for client (not in billing matrix)` — the encounter type is not billable for the client.
* `Missing required answers: ` — one or more required form questions were not answered.
* `Location '' is not in the service Location list for client .` — the `location` does not match a location id or name in the EMR's service Location list.
# Update Encounter
Source: https://docs.usecobalt.com/api-reference/encounters/update
PATCH /encounters/{id}
Approves an existing encounter in the provider's EMR system.
Some EMR configurations approve an encounter automatically when it is signed; others leave it unapproved. The [`encounter.created`](/api-reference/encounters/create#success) webhook tells you which: when `approved` is `false`, call this endpoint to approve the encounter.
Updates are processed asynchronously. We return a success response as soon as the request is accepted, then send a webhook when the update has been applied in the EMR.
### Path Parameters
* **id** (string, required): The Cobalt `encounter_id` returned when the encounter was created.
### Request Parameters
#### Required Fields
* **approved** (boolean, required): Must be `true`. Approves the encounter. Unapproving is not supported. If the encounter was already approved in the EMR before your request (for example, approved by a user in the EMR), nothing is changed and the `encounter.updated` webhook has `already_approved: true`.
#### Optional Fields
* **callback\_urls** (array of strings, optional): URLs to receive the completion webhook for this update, in addition to your account webhook.
### Example Request
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/encounters/123e4567e89b12d3a456426614174000 \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"approved": true
}'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Encounter update processing. A webhook event will be sent upon completion.",
"encounter_id": "123e4567e89b12d3a456426614174000",
"job_id": 12346
}
```
### Error Responses
#### Missing Approved
```json theme={null}
{
"success": false,
"message": "Missing required field: approved (must be true)."
}
```
#### Encounter Not Found
```json theme={null}
{
"success": false,
"message": "Encounter with id '123e4567e89b12d3a456426614174000' not found."
}
```
#### Encounter Not Created Yet
```json theme={null}
{
"success": false,
"message": "Encounter has not been created in the EMR yet. Wait for the encounter.created webhook before updating it."
}
```
#### Update Already In Progress
```json theme={null}
{
"success": false,
"message": "An update is already in progress for this encounter. Please wait for it to complete before submitting another update."
}
```
#### Unsupported EMR
```json theme={null}
{
"success": false,
"message": "Updating encounters is not supported for [EMR Name]."
}
```
### Webhook Notifications
#### Success
```json theme={null}
{
"id": "",
"access_token_reference_id": "",
"object": "event",
"created": "2026-10-06T10:30:00.000Z",
"type": "encounter.updated",
"job_id": "12346",
"data": {
"encounter_id": "123e4567e89b12d3a456426614174000",
"emr_encounter_id": "927341",
"emr_status": "COMPLETED",
"approved": true,
"already_approved": false,
"patient_mrn": "1234567"
}
}
```
The webhook data includes:
* **encounter\_id**: The Cobalt encounter ID.
* **emr\_encounter\_id**: The encounter id in the EMR.
* **emr\_status**: The encounter status in the EMR.
* **approved**: `true` once the encounter is approved.
* **already\_approved**: `true` if the encounter was already approved in the EMR before your request, so nothing was changed. `false` if this request approved it.
* **patient\_mrn**: The patient's medical record number.
#### Failure
```json theme={null}
{
"id": "",
"access_token_reference_id": "",
"object": "event",
"created": "2026-10-06T10:35:00.000Z",
"type": "encounter.update_failed",
"job_id": "12346",
"data": {
"encounter_id": "123e4567e89b12d3a456426614174000",
"emr_encounter_id": "927341",
"patient_mrn": "1234567",
"failure_reason": "Service 927341 cannot be approved by this account (no Approve button on the visit view)."
}
}
```
A failed update is not retried automatically; send the request again once the cause is fixed. Common `failure_reason` values:
* `Service cannot be approved by this account (no Approve button on the visit view).` — the connected EMR user does not have rights to approve this encounter.
* `Approve did not persist for service ...` — the EMR did not record the approval. Retry the request.
# Get Fee Schedules
Source: https://docs.usecobalt.com/api-reference/fee-schedules/get
GET /fee-schedules
Returns the fee schedules configured for a clinic.
A clinic can have multiple fee schedules (for example a Master schedule, a
Medicare schedule, and a Self-Pay schedule). The CPT/HCPCS catalog is shared
across schedules, so each code appears in every schedule with that schedule's own
charge and allowed amounts.
This endpoint returns the schedule **headers** with an item count. To read the
per-code pricing for a schedule, use its `id` with
[Get Fee Schedule Items](/api-reference/fee-schedules/items).
### Example Request
```bash theme={null}
curl -X GET https://api.usecobalt.com/v1/fee-schedules \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH'
```
### Example Response
```json theme={null}
{
"success": true,
"fee_schedules": [
{
"id": "abc123def4567890abcdef1234567890",
"emr_id": "2",
"name": "2014 Medicare Fee Schedule",
"description": "Medicare Fee Schedule - 2014",
"sub_name": "Medicare Fee Schedule - 2014",
"is_master": false,
"taxable": false,
"effective_from": "2014-01-01",
"effective_to": "2034-12-31",
"item_count": 2624
},
{
"id": "def456abc7890123def456abc7890123",
"emr_id": "1",
"name": "Master Fee Schedule",
"description": "",
"sub_name": "",
"is_master": true,
"taxable": false,
"effective_from": null,
"effective_to": null,
"item_count": 2624
}
]
}
```
### Response Parameters
* **id**: Cobalt's fee schedule identifier. Use this in the items endpoint path.
* **emr\_id**: The fee schedule identifier as it appears in the EMR.
* **name** / **description** / **sub\_name**: Labels from the EMR.
* **is\_master**: Whether this is the master fee schedule.
* **taxable**: Whether the schedule is marked taxable.
* **effective\_from** / **effective\_to**: The schedule's effective date range (either may be `null`). Useful for cross-referencing a historical claim against the schedule that was in effect at the time.
* **item\_count**: Number of priced codes in the schedule.
# Get Fee Schedule Items
Source: https://docs.usecobalt.com/api-reference/fee-schedules/items
GET /fee-schedules/{feeScheduleId}/items
Returns a page of per-code pricing for a single fee schedule.
A fee schedule contains the full CPT/HCPCS catalog (thousands of codes), so its
items are paginated. Get the `feeScheduleId` from
[Get Fee Schedules](/api-reference/fee-schedules/get), then page through the
codes here. You can narrow results with `search` (code or description) and
`validity`.
### Example Request
```bash theme={null}
curl -X GET "https://api.usecobalt.com/v1/fee-schedules/abc123def4567890abcdef1234567890/items?page=1&page_size=100&search=99213&validity=valid" \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH'
```
### Example Response
```json theme={null}
{
"success": true,
"items": [
{
"item_id": "279840",
"code": "49082",
"name": "ABD PARACENTESIS",
"fee": 287.0,
"allowed_fee": 191.28,
"cost": 0.0,
"patient_portion": 0.0,
"bill_to_patient": false,
"modifiers": [],
"pos": null,
"tos": null,
"ndc": {
"code": null,
"units": null,
"uom": null,
"unit_price": null
},
"exclude_cpt": false,
"validity": "valid"
}
],
"pagination": {
"page": 1,
"page_size": 100,
"total_records": 2624,
"total_pages": 27
}
}
```
### Query Parameters
* **page**: Page number (default `1`).
* **page\_size**: Items per page (default `100`, max `500`).
* **search**: Filter by code or description (case-insensitive).
* **validity**: Filter to `valid` or `invalid` codes.
### Response Parameters
* **item\_id**: EMR item identifier, stable per code within the schedule.
* **code**: CPT/HCPCS code.
* **name**: Code description.
* **fee**: Billed/charge amount. **allowed\_fee**: Contracted allowed amount. These differ per schedule for the same code.
* **cost** / **patient\_portion**: Cost and patient-portion amounts.
* **bill\_to\_patient** / **exclude\_cpt**: Billing flags.
* **modifiers**: Procedure modifiers (only non-empty slots are returned).
* **pos** / **tos**: Place of service / type of service.
* **ndc**: National Drug Code details (`code`, `units`, `uom`, `unit_price`).
* **validity**: `valid` or `invalid`. Invalid codes are retained so historical claims can still be cross-referenced.
* **pagination**: `page`, `page_size`, `total_records`, `total_pages`.
# Sync Forms
Source: https://docs.usecobalt.com/api-reference/forms/fetch
POST /forms/fetch
Queues a sync of the connected EMR's form definitions into the Cobalt cache.
Queues a background sync that scrapes the connected EMR's form definitions and upserts them into the Cobalt cache. The request returns immediately with `202 Accepted`; a `forms.synced` webhook is sent when the sync completes. The cached results are then served by [`GET /v1/forms`](/api-reference/forms/get) and [`GET /v1/forms/{id}`](/api-reference/forms/get-by-id).
A daily scheduler drives the routine cadence — use this endpoint for on-demand or onboarding refreshes.
### Concurrency
Only one sync may run per account at a time. If a sync is already in progress, the request returns `409` with the id of the in-flight job so you can back off rather than queueing a duplicate.
### Request Parameters
#### Optional Fields
* **callback\_urls** (array of strings, optional): URLs to receive the `forms.synced` webhook, in addition to your account webhook.
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/forms/fetch \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{}'
```
### Example Response
```json theme={null}
{
"success": true,
"status": "queued",
"message": "Forms sync started. A forms.synced webhook will be sent when it completes.",
"job_execution_id": "123e4567e89b12d3a456426614174000"
}
```
### Error Responses
#### Sync Already Running
```json theme={null}
{
"success": false,
"status": "running",
"message": "A forms sync is already in progress for this account. Please try again once it completes.",
"job_execution_id": "123e4567e89b12d3a456426614174000"
}
```
Returned with `409`. Wait for the in-flight sync (identified by `job_execution_id`) to finish before retrying.
#### Unsupported EMR
```json theme={null}
{
"success": false,
"message": "Forms sync is not supported for [EMR Name]."
}
```
#### User Not Found
```json theme={null}
{
"success": false,
"message": "User not found."
}
```
This indicates an issue with your access token.
### Webhook Notification
When the sync finishes, we send a `forms.synced` webhook to your registered endpoint. Read the refreshed forms with [`GET /v1/forms`](/api-reference/forms/get).
# List Forms
Source: https://docs.usecobalt.com/api-reference/forms/get
GET /forms
Returns cached form metadata for the account.
Returns the metadata for every form Cobalt has cached for your account — id, name, type, version, and status. The full form definition (categories, questions, answers) is not included here; fetch it for a single form with [`GET /v1/forms/{id}`](/api-reference/forms/get-by-id).
Forms are cached by a sync. Trigger an on-demand refresh with [`POST /v1/forms/fetch`](/api-reference/forms/fetch); a daily scheduler also keeps the cache current.
### When to use this
Use the list to find the form you want to document an encounter with. The `emr_form_id` of the chosen form is the `form_id` you pass to [`POST /v1/encounters`](/api-reference/encounters/create). Then read that form's definition to get the question ids for the encounter `answers`.
### Example Request
```bash theme={null}
curl https://api.usecobalt.com/v1/forms \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH'
```
### Example Response
```json theme={null}
{
"success": true,
"forms": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"emr_form_id": "392",
"emr_fvid": "1045",
"name": "GAD-7",
"type": "Assessment",
"version": "3",
"status": "Active",
"build_date": "2026-01-15",
"synced_at": "2026-08-26T09:00:00.000Z",
"created_at": "2026-01-20T12:00:00.000Z",
"updated_at": "2026-08-26T09:00:00.000Z"
}
]
}
```
The fields on each form:
* **id**: Cobalt form id (UUID). Use this with [`GET /v1/forms/{id}`](/api-reference/forms/get-by-id).
* **emr\_form\_id**: The form's id in the EMR. This is the `form_id` you pass to [`POST /v1/encounters`](/api-reference/encounters/create).
* **emr\_fvid**: The EMR form-version id, or `null`.
* **name**: Form name.
* **type**, **version**, **status**, **build\_date**: Form metadata from the EMR (any may be `null`).
* **synced\_at**: When the form was last synced into the cache.
# Get Form
Source: https://docs.usecobalt.com/api-reference/forms/get-by-id
GET /forms/{id}
Returns one cached form with its full definition.
Returns a single cached form by its Cobalt id, including the full `definition` — the nested tree of categories, questions, and selectable answers. Use this to discover the question ids you supply in the `answers` object of [`POST /v1/encounters`](/api-reference/encounters/create).
The `id` path parameter is the Cobalt form id (UUID) from [`GET /v1/forms`](/api-reference/forms/get).
### The definition structure
`definition.categories` is an ordered tree. A category holds child `categories` and `questions`; a question holds selectable `answers`.
* Each **question** carries an `emrQuestionId`. That id is the key you use in the encounter `answers` object.
* Each **answer** carries a `value` — the option a question can be scored/set to (for a scored questionnaire this is the numeric score, e.g. `"0"`..`"3"`).
* `isRequired` / `isFormRequired` tell you which questions must be answered; omitting a required answer fails the encounter with `Missing required answers`.
The form metadata fields (`emr_form_id`, `synced_at`, ...) are snake\_case. The nested `definition` is passed through as the EMR structures it and keeps its own field names (e.g. `emrQuestionId`, `emrCategoryId`). Treat the definition as an opaque tree — read the ids and values out of it rather than depending on its exact field casing.
### Example Request
```bash theme={null}
curl https://api.usecobalt.com/v1/forms/123e4567-e89b-12d3-a456-426614174000 \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH'
```
### Example Response
```json theme={null}
{
"success": true,
"form": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"emr_form_id": "392",
"emr_fvid": "1045",
"name": "GAD-7",
"type": "Assessment",
"version": "3",
"status": "Active",
"build_date": "2026-01-15",
"synced_at": "2026-08-26T09:00:00.000Z",
"created_at": "2026-01-20T12:00:00.000Z",
"updated_at": "2026-08-26T09:00:00.000Z",
"definition": {
"categories": [
{
"emrCategoryId": "7781",
"parentEmrCategoryId": null,
"name": "GAD-7",
"order": 1,
"categories": [],
"questions": [
{
"emrQuestionId": "453149",
"emrCategoryId": "7781",
"order": 1,
"text": "Feeling nervous, anxious, or on edge",
"formatCode": "RB",
"formatLabel": "Radio Button",
"isRequired": true,
"isFormRequired": false,
"externalId": null,
"snomedCode": null,
"loincCode": null,
"units": null,
"calcFormula": null,
"answers": [
{ "emrAnswerId": "980011", "value": "0", "order": 1 },
{ "emrAnswerId": "980012", "value": "1", "order": 2 },
{ "emrAnswerId": "980013", "value": "2", "order": 3 },
{ "emrAnswerId": "980014", "value": "3", "order": 4 }
]
}
]
}
]
}
}
}
```
### Error Responses
#### Invalid ID Format
```json theme={null}
{
"success": false,
"message": "Invalid form ID format. Must be a valid UUID."
}
```
#### Form Not Found
```json theme={null}
{
"success": false,
"message": "Form not found"
}
```
# Get Insurance Providers
Source: https://docs.usecobalt.com/api-reference/insurance-providers/get
GET /insurance-providers
Retrieve insurance providers from the EMR system.
## Use Cases
* Get the correct `insurance_provider_id` before adding patient insurance
* Search providers by name for autocomplete functionality
* Display paginated lists of insurance options to end users
* Filter providers by active status
## Query Parameters
* **name** (string, optional): Filter by provider name (case-insensitive partial match)
* **page** (integer, optional): Page number (default: 1, min: 1)
* **page\_size** (integer, optional): Items per page (default: 100, max: 100)
* **active** (boolean, optional): Filter by active status (true/false)
* **ehr\_id** (string): Filter by EMR system's identifier.
## Example Requests
### Get First Page
```bash theme={null}
curl -X GET "https://api.usecobalt.com/v1/insurance-providers" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token"
```
### Search by Name
```bash theme={null}
curl -X GET "https://api.usecobalt.com/v1/insurance-providers?name=blue%20cross" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token"
```
### Get Page 2 with 50 Items
```bash theme={null}
curl -X GET "https://api.usecobalt.com/v1/insurance-providers?page=2&page_size=50" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token"
```
### Filter Active Providers
```bash theme={null}
curl -X GET "https://api.usecobalt.com/v1/insurance-providers?active=true" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token"
```
## Example Response
```json theme={null}
{
"success": true,
"insurance_providers": [
{
"id": "abc123def456",
"name": "AHMC Health",
"payer_id": "98999",
"active": true,
"created_at": "2025-01-01T10:00:00.000Z"
},
{
"id": "xyz789ghi012",
"name": "Blue Cross Blue Shield",
"payer_id": "12345",
"active": true,
"created_at": "2025-01-01T10:00:00.000Z"
}
],
"pagination": {
"current_page": 1,
"total_pages": 5,
"total_count": 450,
"page_size": 100
}
}
```
## Response Fields
### Top-Level Fields
* **success** (boolean): Whether the request was successful
* **insurance\_providers** (array): Array of insurance provider objects
* **pagination** (object): Pagination metadata
### Insurance Provider Object
* **id** (string): Cobalt insurance provider ID - use this value in `POST /v1/patients/:patient_mrn/insurances`
* **name** (string): Insurance provider name as it appears in the EMR system
* **payer\_id** (string): Insurance payer ID
* **active** (boolean): Whether the provider is currently active
* **created\_at** (string): ISO 8601 timestamp of when the provider was added
### Pagination Object
* **current\_page** (integer): Current page number
* **total\_pages** (integer): Total number of pages
* **total\_count** (integer): Total number of providers matching the filter
* **page\_size** (integer): Number of items per page
When adding patient insurance, using the `insurance_provider_id` from this endpoint is the most reliable method for identifying the insurance provider.
# Introduction
Source: https://docs.usecobalt.com/api-reference/introduction
Cobalt API
## Agent-ready API context
Copy these resources into your coding agent to give it the API contract and Cobalt-specific EHR guidance.
```text Copy for your agent theme={null}
Use these Cobalt API resources:
OpenAPI specification: https://docs.usecobalt.com/api-reference/openapi.json
Agent guide: https://docs.usecobalt.com/llms.txt
```
The machine-readable API contract for every endpoint, with per-EMR support
tags.
An index of the concepts and endpoints, written for agents. Append `.md` to
any docs page URL for its raw markdown.
**Per-EMR support lives in the spec, not in these pages.** An operation's
`x-supported-emrs` lists the EMRs that support that endpoint. A request
field's `x-required-for-emrs` lists the EMRs that require it, and
`x-allowed-values-for-emrs` maps each EMR to the values it accepts. Consult
those tags rather than assuming support.
You need a client\_id and client\_secret to interact with the Cobalt API. You will also need an access\_token for each user which can be obtained in through the Cobalt Link flow.
## Authentication Headers
| Parameter | Type | Description |
| - | - | - |
| client\_id | string | Your Cobalt API client id |
| client\_secret | string | Your Cobalt API secret |
| access\_token | string | The access token from the Link Flow |
Example request:
```bash theme={null}
curl -X GET https://api.usecobalt.com/v1/appointments \
-H 'Content-Type: application/json' \
-H 'client_id: "%COBALT_CLIENT_ID%"' \
-H 'client_secret: "%COBALT_CLIENT_SECRET%"' \
-H 'access_token: "%USER_ACCESS_TOKEN%"' \
-d '{
...
}'
```
## Response Warnings
Some responses include a top-level `warnings` array of human-readable strings. Warnings are non-fatal: the request still succeeds and the data is returned as usual. They flag conditions worth your attention without failing the call.
Unrecognized query parameters are one such condition. If a `GET` request includes a query parameter the endpoint does not support (a typo, or a parameter that was renamed or removed), it is **ignored, not applied**, and the response includes a warning that names it, so the mistake is visible rather than silent. The same message is also returned in a `Cobalt-Warning` response header.
```json theme={null}
{
"success": true,
"patients": [ ... ],
"warnings": [
"Ignored unrecognized query parameter: include_inactve. Unrecognized parameters are ignored, not applied. Check the names against the API reference; this may indicate a typo or a renamed or removed parameter."
]
}
```
Treat a warning as a signal to check your request against this reference. Unknown parameters are never rejected with an error, so an integration that relies on one silently having no effect will keep working, but the warning tells you it is doing nothing.
# Create Link Token
Source: https://docs.usecobalt.com/api-reference/link/create-token
POST /link/token/create
Create a Link token to initialize the Link flow.
Creates a Link token that you'll use to initialize the Link flow in your frontend application.
### Request Body Parameters
#### Required Parameters
* `user_id` (string) - A unique identifier for the end user from your system. Do not use PII like email or phone.
* `org_id` (string) - A unique identifier for the organization from your system (e.g., clinic or hospital ID).
#### Optional Parameters (for creating new organizations)
If the `org_id` doesn't exist yet, provide these parameters to create the organization:
* `emr_name` (string) - The EMR system name. Contact support for a list of supported EMR systems.
* `emr_instance_domain` (string) - The EMR instance URL (e.g., `https://your-emr-instance.com`)
#### Other Optional Parameters
* `access_token` (string) - Include to use [update mode](/docs/link/update-mode) for an existing connection
### Example Request (Existing Organization)
```bash theme={null}
curl -X POST https://api.usecobalt.com/link/token/create \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-d '{
"user_id": "user_12345",
"org_id": "org_67890"
}'
```
### Example Request (New Organization)
```bash theme={null}
curl -X POST https://api.usecobalt.com/link/token/create \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-d '{
"user_id": "user_12345",
"org_id": "org_67890",
"emr_name": "YourEMRName",
"emr_instance_domain": "https://your-emr-instance.com"
}'
```
### Example Response
```json theme={null}
{
"success": true,
"token": "lt_198908HJDKJSH98789OHKJL"
}
```
### Update Mode
To use update mode for an existing connection, include the `access_token` in your request:
```bash theme={null}
curl -X POST https://api.usecobalt.com/link/token/create \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-d '{
"user_id": "user_12345",
"org_id": "org_67890",
"access_token": "493JKLHIU98789hLKH9HHJH"
}'
```
The Link token is single-use and expires after 30 minutes.
# Exchange Public Token
Source: https://docs.usecobalt.com/api-reference/link/exchange-token
GET /link/token/exchange
Exchange a public token for an access token.
After a user successfully completes the Link flow, you'll receive a `public_token`. Exchange this for an `access_token` that you can use for subsequent API calls.
### Example Request
```bash theme={null}
curl -X GET https://api.usecobalt.com/v1/link/token/exchange \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-G \
--data-urlencode "public_token=pt_198908HJDKJSH98789OHKJL"
```
### Example Response
```json theme={null}
{
"success": true,
"token": "493JKLHIU98789hLKH9HHJH"
}
```
Store this access token securely - you'll need it for all future API calls related to this user's EHR connection.
# Get Locations
Source: https://docs.usecobalt.com/api-reference/locations/get
GET /locations
Returns a list of locations associated with an account.
### Understanding Location IDs
Each location has two identifiers:
* **`id`**: Cobalt's internal identifier (32-character UUID without hyphens)
* Use when updating location settings like status
* Operations: `PATCH /v1/locations/{id}`
* **`ehr_id`**: Your EMR system's location identifier
* Use when creating appointments or other EMR operations
* Operations: `POST /v1/appointments` (`location` field)
**Why two IDs?** Different operations work in different contexts. Location management (updating status) modifies Cobalt's cached configuration, while appointment creation communicates directly with your EMR. Cobalt uses its own IDs to manage location settings independently of EMR constraints, then maps to EMR IDs when interacting with your EMR system.
**Quick Reference:**
* Updating location settings → Use `id`
* Creating appointments → Use `ehr_id`
### Example Request
```bash theme={null}
curl -X GET https://api.usecobalt.com/v1/locations \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH'
```
### Example Response
```json theme={null}
{
"success": true,
"locations": [
{
"id": "abc123def4567890abcdef1234567890",
"ehr_id": "2452",
"name": "Happy Clinic",
"address": {
"address1": "1234 Main St",
"address2": "",
"city": "Sunnyland",
"state": "CA",
"zip": "23423"
},
"phone": "2223334444",
"fax": "5556667777",
"status": "active"
}
]
}
```
# Update Location Status
Source: https://docs.usecobalt.com/api-reference/locations/update
PATCH /locations/{id}
Updates the status of a location to active or inactive.
**Use the Cobalt `id` in the URL path.** The `{id}` parameter should be the Cobalt location ID (the `id` field from GET responses), not the `ehr_id`.
### Example Request
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/locations/abc123def4567890abcdef1234567890 \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"status": "inactive"
}'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Location status updated successfully.",
"location_id": "abc123def4567890abcdef1234567890"
}
```
### Notes
* The status update is case-insensitive ("active", "Active", "ACTIVE" are all accepted)
* Only the `status` field can be updated through this endpoint
* The location must belong to your organization
* Invalid location IDs will return a 404 error
# Send Message
Source: https://docs.usecobalt.com/api-reference/messages/create
POST /messages
Sends a message to the specified provider.
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/messages \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"provider": "123456789",
"subject": "Test Message",
"message": "This is a test message content."
}'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Message processing. A webhook event will be sent upon completion.",
"message_id": "msg_123456789",
"job_id": 15550942
}
```
### Request Parameters
The `/messages` endpoint requires the following fields:
* **provider** (required): The EHR provider ID to send the message to
* **subject** (required): The subject line for the message
* **message** (required): The content of the message to be sent
# Create Note
Source: https://docs.usecobalt.com/api-reference/notes/create
POST /notes
Creates a note for a given appointment.
**Use the Cobalt `appointment_id`.** The `appointment_id` parameter should be the Cobalt appointment ID returned from API responses or GET endpoints, not the EHR appointment ID.
The `note` parameter accepts a structured object with separate fields for clinical documentation, along with optional ICD-10 and CPT codes. The `note` keys depend on the connected EHR: use the HPI format (`hpi`, `exam`, `assessment`, `treatment`) or the SOAP format (`subjective`, `objective`, `assessment`, `plan`), as the examples below show.
### Example Request (HPI format)
```bash theme={null}
# eClinicalWorks
curl -X POST https://api.usecobalt.com/v1/notes \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"appointment_id": "728948",
"note": {
"hpi": "Patient presents with persistent lower back pain for 2 weeks. Pain is described as dull and achy, rated 6/10. Worse with prolonged sitting and bending forward. Denies radiation to legs, numbness, or tingling. No bowel or bladder changes. Patient tried over-the-counter ibuprofen with minimal relief.",
"exam": "Vital signs: BP 128/82, HR 74, Temp 98.6°F. General: Alert and oriented x3, in no acute distress. MSK: Limited range of motion in lumbar spine with forward flexion. Tenderness to palpation over L4-L5 region. Negative straight leg raise bilaterally. Motor strength 5/5 in bilateral lower extremities. Sensation intact.",
"assessment": "Acute mechanical low back pain, likely lumbar strain. No red flags for serious pathology.",
"treatment": "Prescribed naproxen 500mg BID for 10 days. Recommended ice/heat therapy alternating every 20 minutes. Physical therapy referral placed for core strengthening and flexibility exercises. Patient educated on proper lifting mechanics and posture. Return precautions discussed including progressive neurological symptoms."
},
"icd_10_codes": ["M54.5", "M54.50"],
"cpt_codes": ["99213", "97110"]
}'
```
### Example Request (SOAP format)
```bash theme={null}
# Practice Fusion (cpt_codes are not written to the EHR)
curl -X POST https://api.usecobalt.com/v1/notes \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"appointment_id": "728948",
"note": {
"subjective": "Patient presents with persistent lower back pain for 2 weeks. Pain is described as dull and achy, rated 6/10. Worse with prolonged sitting and bending forward. Denies radiation to legs, numbness, or tingling.",
"objective": "Vital signs: BP 128/82, HR 74, Temp 98.6°F. Limited range of motion in lumbar spine with forward flexion. Tenderness to palpation over L4-L5 region. Negative straight leg raise bilaterally.",
"assessment": "Acute mechanical low back pain, likely lumbar strain. No red flags for serious pathology.",
"plan": "Prescribed naproxen 500mg BID for 10 days. Physical therapy referral placed for core strengthening. Return precautions discussed."
},
"icd_10_codes": ["M54.5", "M54.50"]
}'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Note upload in progress. A webhook event will be sent upon completion.",
"job_id": 12345
}
```
### Webhook Notifications
When the note processing is complete, we will send a webhook to your registered endpoint. Here are examples of what those webhook payloads will look like:
See the [Webhook Events reference](/docs/webhooks/operation-events) for the full field breakdown and error codes.
#### Success
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2CluR9g9gV",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2023-10-27T10:30:00Z",
"type": "note.uploaded",
"job_id": 12345,
"data": {
"appointment_id": "728948",
"mrn": "12345",
"timezone": "America/New_York",
"status": "partial_success",
"icd_codes": {
"matched": [
{ "code": "E11.9", "name": "Type 2 diabetes mellitus without complications" }
],
"unmatched": [
{ "code": "Z00.00", "reason": "Code not found in EHR system" }
]
},
"cpt_codes": {
"matched": [
{ "code": "99213", "name": "Office/outpatient visit, established patient" }
],
"unmatched": []
}
}
}
```
#### Failure
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2CluR9g9gW",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2023-10-27T10:35:00Z",
"type": "note.failed",
"job_id": 12345,
"data": {
"appointment_id": "728948",
"mrn": "12345",
"status": "failed",
"failure_reason": "Text contains \"]]>\" which cannot be used in CDATA blocks. Please remove this sequence from the note text.",
"reasons": [
{
"code": "UNSUPPORTED_CHARACTERS",
"description": "Text contains \"]]>\" which cannot be used in CDATA blocks. Please remove this sequence from the note text."
}
]
}
}
```
# Search Order Catalog
Source: https://docs.usecobalt.com/api-reference/orders/catalog
POST /orders/catalog/fetch
Searches the practice's orderable lab, imaging, or procedure catalog.
Catalog searches run asynchronously against the live EMR: a valid request returns immediately with a `202`, and an `order_catalog.searched` webhook is sent with the results when the search completes.
Use the `item_id` values from the results when creating an order via `POST /v1/orders`.
### Request Parameters
#### Required Fields
* **type** (string, required): Which catalog to search. One of `lab`, `imaging`, or `procedure`.
#### Optional Fields
* **query** (string, optional): Name filter (prefix or substring). Omit to page the full catalog.
* **page** (integer, optional): Page number (1-based). Defaults to `1`.
* **page\_size** (integer, optional): Results per page. Defaults to `25`.
* **callback\_urls** (string\[], optional): URLs to receive the results webhook, in addition to the account webhook.
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/orders/catalog/fetch \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"type": "lab",
"query": "glucose",
"page": 1,
"page_size": 25
}'
```
### Example Response
```json theme={null}
{
"success": true,
"status": "queued",
"message": "Catalog search started. A order_catalog.searched webhook will be sent when it completes.",
"job_id": 12345
}
```
### Webhook Notifications
When the search completes, we send an `order_catalog.searched` webhook to your registered endpoint:
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2CluR9g9gV",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2025-10-09T10:30:00Z",
"type": "order_catalog.searched",
"job_id": "12345",
"data": {
"type": "lab",
"page": 1,
"has_more": true,
"items": [
{
"item_id": "80048",
"name": "Comprehensive Metabolic Panel",
"billable": true
},
{
"item_id": "82947",
"name": "Glucose, Serum",
"billable": true
}
]
}
}
```
# Create Order
Source: https://docs.usecobalt.com/api-reference/orders/create
POST /orders
Creates a lab, imaging, or procedure order in the provider's EMR system.
Orders are created asynchronously: a valid request returns immediately with a `202`, and an `order.created` webhook is sent when processing completes. If creation fails terminally, an `order.create_failed` webhook is sent instead.
Identify the test or procedure to order with either `item_id` or `name`. Discover valid values via [Search Order Catalog](/api-reference/orders/catalog). When both are provided, `item_id` wins.
### Request Parameters
#### Required Fields
* **type** (string, required): Order type. One of `lab`, `imaging`, or `procedure`.
* **patient\_mrn** (string, required): Medical Record Number of the patient the order is for.
One of the following is also required:
* **item\_id** (string): EMR catalog id of the test/procedure to order. Discover ids via `POST /v1/orders/catalog/fetch`.
* **name** (string): Catalog name of the test/procedure, resolved against the catalog when `item_id` is omitted.
#### Optional Fields
* **provider\_id** (string, optional): EMR id of the ordering provider.
* **facility\_id** (string, optional): EMR id of the ordering facility/location.
* **assigned\_to\_id** (string, optional): EMR staff id the order is assigned to.
* **order\_date** (string, optional): Order date (ISO 8601, YYYY-MM-DD).
* **collected\_date** (string, optional): Specimen collection date (ISO 8601, YYYY-MM-DD). Labs.
* **collection\_time** (string, optional): Specimen collection time, e.g. `"12:58 PM"`.
* **performed\_date** (string, optional): Performed date (ISO 8601, YYYY-MM-DD). Diagnostic imaging.
* **high\_priority** (boolean, optional): Flag the order high priority.
* **notes** (string, optional): Order notes.
* **clinical\_info** (string, optional): Clinical information for the order.
* **callback\_urls** (string\[], optional): URLs to receive the `order.created` webhook, in addition to the account webhook.
### Example Requests
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/orders \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"type": "lab",
"patient_mrn": "12345",
"item_id": "80048",
"provider_id": "789",
"facility_id": "25",
"collected_date": "2026-03-15",
"collection_time": "12:58 PM"
}'
```
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/orders \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"type": "imaging",
"patient_mrn": "12345",
"name": "Chest X-Ray",
"provider_id": "789",
"performed_date": "2026-03-15",
"high_priority": true,
"clinical_info": "Persistent cough, rule out pneumonia."
}'
```
### Example Response
```json theme={null}
{
"success": true,
"status": "queued",
"message": "Order queued for creation. An order.created webhook will be sent when it completes.",
"job_id": 12345
}
```
### Error Responses
#### Missing Required Field
```json theme={null}
{
"success": false,
"message": "Missing required field: patient_mrn"
}
```
#### Missing Order Identifier
```json theme={null}
{
"success": false,
"message": "Provide either item_id or name to identify the order."
}
```
### Webhook Notifications
When order processing completes, we send a webhook to your registered endpoint.
#### Success
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2CluR9g9gV",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2025-10-09T10:30:00Z",
"type": "order.created",
"job_id": "12345",
"data": {
"emr_order_id": "998877",
"emr_encounter_id": "445566",
"patient_mrn": "12345"
}
}
```
#### Failure
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2CluR9g9gW",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2025-10-09T10:35:00Z",
"type": "order.create_failed",
"job_id": "12345",
"data": {
"patient_mrn": "12345",
"failure_reason": "Order create failed after multiple attempts. Please try again later or contact support."
}
}
```
# Get Orders
Source: https://docs.usecobalt.com/api-reference/orders/get
GET /orders
Returns a list of orders for a patient.
### Example Request
```bash theme={null}
curl -X GET https://api.usecobalt.com/v1/orders \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-G \
--data-urlencode "patient_mrn=414421" \
--data-urlencode "start_date=2024-01-01" \
--data-urlencode "end_date=2024-03-31"
```
### Example Response
```json theme={null}
{
"success": true,
"orders": [
{
"id": "ord_123456",
"order_id": "998877",
"order_name": "Comprehensive Metabolic Panel",
"order_date": "2024-02-15",
"provider_id": "prov_789",
"patient_mrn": "414421",
"patient_name": "P-778899",
"patient_dob": "1980-06-15",
"appointment_id": "appt_456",
"priority": "routine",
"assigned_to_name": "Jane Doe",
"emr_assigned_to_id": "staff_101",
"lab_results": null
},
{
"id": "ord_789012",
"order_id": "998912",
"order_name": "Chest X-Ray",
"order_date": "2024-03-01",
"provider_id": "prov_789",
"patient_mrn": "414421",
"patient_name": "P-778899",
"patient_dob": "1980-06-15",
"appointment_id": "appt_789",
"priority": null,
"assigned_to_name": null,
"emr_assigned_to_id": null,
"lab_results": null
}
]
}
```
# Get Order
Source: https://docs.usecobalt.com/api-reference/orders/get-by-id
GET /orders/{id}
Returns a synced order and its writable result components.
Returns a single synced order along with its `result_components` — the writable result columns for that order. Each component's `field_id` is the write target accepted by [Add Order Results](/api-reference/orders/results), so fetch the order first to learn which components you can populate.
### Example Request
```bash theme={null}
curl -X GET https://api.usecobalt.com/v1/orders/ord_123456 \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH'
```
### Example Response
```json theme={null}
{
"success": true,
"order": {
"id": "ord_123456",
"order_id": "998877",
"appointment_id": "445566",
"patient_name": "P-778899",
"patient_mrn": "12345",
"order_date": "2026-02-15",
"order_name": "1hr Glucose Tolerance (OB)",
"provider_id": "789",
"patient_dob": "1980-06-15",
"lab_results": null,
"priority": "routine",
"assigned_to_name": "Jane Doe",
"emr_assigned_to_id": "staff_101",
"result_components": [
{
"field_id": "col_1001",
"name": "1hr Glucose (OB)"
},
{
"field_id": "col_1002",
"name": "Fasting Glucose (OB)"
}
]
}
}
```
# Create Order Results
Source: https://docs.usecobalt.com/api-reference/orders/results
POST /orders/{id}/results
Creates a lab-result record for an order and queues it for the EHR.
Creating results is asynchronous: a valid request creates a lab-result record, returns immediately with the `lab_result_id`, and queues the record for the EHR. A `lab_result.created` webhook is sent when processing completes. If the operation fails terminally, a `lab_result.create_failed` webhook is sent instead.
Each result targets a component of the order. Reference a component by its `component` (name) or `field_id`, both of which come from the `result_components` returned by [Get Order](/api-reference/orders/get-by-id).
### Request Parameters
#### Required Fields
* **results** (array, required): Result values, one per component. At least one entry is required. Each entry is an object with:
* **value** (string or number, required): The result value.
* **component** (string): The component name, from `GET /v1/orders/{id}`.
* **field\_id** (string): The component's EMR id, from `GET /v1/orders/{id}`.
Provide `component` or `field_id` to identify each component.
#### Optional Fields
* **result\_date** (string, optional): Result date (ISO 8601, YYYY-MM-DD). Defaults to today when omitted.
* **collected\_date** (string, optional): Specimen collection date (ISO 8601, YYYY-MM-DD).
* **collection\_time** (string, optional): Specimen collection time, e.g. `"12:58 PM"`.
* **callback\_urls** (string\[], optional): URLs to receive the `lab_result.created` webhook, in addition to the account webhook.
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/orders/ord_123456/results \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"results": [
{ "component": "1hr Glucose (OB)", "value": 142 },
{ "field_id": "col_1002", "value": "88" }
],
"result_date": "2026-03-17",
"collected_date": "2026-03-16",
"collection_time": "09:15 AM"
}'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Lab result created and queued. A lab_result.created webhook will be sent when it completes.",
"lab_result_id": "lr_123456",
"order_id": "ord_123456",
"job_id": 12345
}
```
### Webhook Notifications
When processing completes, we send a webhook to your registered endpoint.
#### Success
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2CluR9g9gV",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2025-10-09T10:30:00Z",
"type": "lab_result.created",
"job_id": "12345",
"data": {
"lab_result_id": "lr_123456",
"order_id": "ord_123456",
"emr_order_id": "998877",
"emr_encounter_id": "445566",
"patient_mrn": "12345"
}
}
```
#### Failure
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2CluR9g9gW",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2025-10-09T10:35:00Z",
"type": "lab_result.create_failed",
"job_id": "12345",
"data": {
"lab_result_id": "lr_123456",
"order_id": "ord_123456",
"patient_mrn": "12345",
"failure_reason": "Lab result creation failed after multiple attempts. Please try again later or contact support."
}
}
```
# Update Order
Source: https://docs.usecobalt.com/api-reference/orders/update
PATCH /orders/{id}
Updates an existing order's dates, assignee, or priority.
Order updates are processed asynchronously: a valid request returns immediately with a `202`, and an `order.updated` webhook is sent when processing completes. If the update fails terminally, an `order.update_failed` webhook is sent instead.
### Request Parameters
All fields are optional; send only the fields you want to change.
* **result\_date** (string, optional): Result date (ISO 8601, YYYY-MM-DD).
* **collected\_date** (string, optional): Specimen collection date (ISO 8601, YYYY-MM-DD).
* **collection\_time** (string, optional): Specimen collection time, e.g. `"12:58 PM"`.
* **performed\_date** (string, optional): Performed date (ISO 8601, YYYY-MM-DD). Diagnostic imaging.
* **assigned\_to\_id** (string, optional): EMR staff id to assign the order to.
* **high\_priority** (boolean, optional): Flag the order high priority.
* **callback\_urls** (string\[], optional): URLs to receive the `order.updated` webhook, in addition to the account webhook.
### Example Request
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/orders/ord_123456 \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"collected_date": "2026-03-16",
"collection_time": "09:15 AM",
"assigned_to_id": "staff_101",
"high_priority": true
}'
```
### Example Response
```json theme={null}
{
"success": true,
"status": "queued",
"message": "Order update queued. An order.updated webhook will be sent when it completes.",
"job_id": 12345
}
```
### Webhook Notifications
When processing completes, we send a webhook to your registered endpoint.
#### Success
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2CluR9g9gV",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2025-10-09T10:30:00Z",
"type": "order.updated",
"job_id": "12345",
"data": {
"emr_order_id": "998877",
"emr_encounter_id": "445566",
"patient_mrn": "12345"
}
}
```
#### Failure
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2CluR9g9gW",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2025-10-09T10:35:00Z",
"type": "order.update_failed",
"job_id": "12345",
"data": {
"patient_mrn": "12345",
"failure_reason": "Order update failed after multiple attempts. Please try again later or contact support."
}
}
```
# Fetch Org Settings
Source: https://docs.usecobalt.com/api-reference/org-settings/fetch
POST /org-settings/fetch
Queues a live sync of your organization's settings from the connected EMR system.
Cobalt automatically syncs org settings **nightly for every organization**. You
do **not** need to call this endpoint on a schedule — the nightly sync already
keeps providers, locations, visit types, and the rest of your org settings up to
date. Use this endpoint sparingly, only when you need a refresh sooner than the
next nightly run (for example, right after adding a new provider or location in
your EMR and wanting it reflected immediately).
This is an asynchronous operation. It returns immediately with a
`job_execution_id` and delivers an `org_settings.synced` webhook when the sync
finishes. To read the synced values, use the corresponding read endpoints such as
[Get Providers](/api-reference/providers/get),
[Get Locations](/api-reference/locations/get),
[Get Visit Types](/api-reference/visit-types/get),
[Get Visit Statuses](/api-reference/visit-statuses/get), and
[Get Settings](/api-reference/settings/get).
## What Gets Synced
A single sync refreshes the full set of organization settings from the EMR:
* Providers
* Locations
* Visit types
* Visit statuses
* Insurance companies
* Pharmacies
* Referring providers
* Timezone
* Required patient fields
## Concurrency
Only one org settings sync can be in flight per linked account at a time. If a sync
is already running when you call this endpoint, the request returns `409` with the
`job_execution_id` of the in-flight sync so you can wait for it to finish rather
than queuing a duplicate.
## Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/org-settings/fetch \
-H "Content-Type: application/json" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token" \
-d '{}'
```
### Routing the completion webhook
The completion webhook is delivered to your account's registered webhook URLs by
default. To route this specific sync's `org_settings.synced` event elsewhere,
include a `callback_urls` array (see [Webhook setup](/docs/webhooks/setup)). Each
URL must use HTTPS.
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/org-settings/fetch \
-H "Content-Type: application/json" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token" \
-d '{
"callback_urls": ["https://your-domain.com/cobalt-webhook"]
}'
```
### Example Response
```json theme={null}
{
"success": true,
"status": "queued",
"message": "Org settings sync started. An org_settings.synced webhook will be sent when it completes.",
"job_execution_id": "job_1J9X2q2eZvKYlo2Cmnopqr"
}
```
## Webhook Notification
When the sync completes, Cobalt sends an `org_settings.synced` webhook to your
registered endpoint (or to `callback_urls` if you supplied them). The payload is
intentionally minimal — it signals completion and reports counts of what changed.
Re-fetch the synced values from the read endpoints listed above.
```json theme={null}
{
"id": "508c368e7de13b40f9397eec966d0329",
"access_token_reference_id": "your-reference-id",
"object": "event",
"job_id": "job_1J9X2q2eZvKYlo2Cmnopqr",
"created": "2026-07-22T08:50:42.491-07:00",
"type": "org_settings.synced",
"action": "ehr_sync",
"data": {
"status": "completed",
"summary": {
"providers_created": 1,
"providers_updated": 3,
"locations_created": 0,
"locations_updated": 2,
"visit_types_created": 0,
"visit_types_updated": 5,
"visit_statuses_created": 0,
"visit_statuses_updated": 0,
"insurance_companies_created": 0,
"pharmacies_created": 0,
"pharmacies_updated": 0,
"referring_providers_created": 0,
"referring_providers_updated": 1,
"policy_types_count": 12,
"staff_list_count": 24,
"required_patient_fields_synced": true,
"timezone_synced": true,
"link_org_updated": true
}
}
}
```
You must be subscribed to the `org_settings.synced` event for the webhook to be
delivered. See [Webhook setup](/docs/webhooks/setup) to manage your
subscriptions.
# Create Patient Note
Source: https://docs.usecobalt.com/api-reference/patient-notes/create
POST /patient-notes
Creates a free-standing chart note on a patient. Unlike a note tied to an appointment, this writes directly to the patient's chart.
### Request Parameters
* **note** (string, required): Chart note body content
* **subject** (string, required): Chart note title
* **patient\_mrn** (string, required): Medical Record Number (MRN) of the patient
* **location\_id** (string): EMR location ID. Must match a location returned by `GET /v1/locations` for the account.
* **tags** (array of strings): One or more note category names, matched against the practice's configured note categories. An unknown category fails the note.
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/patient-notes \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"note": "Patient reports feeling well since last visit. No new concerns to report.",
"subject": "Wellness check-in",
"patient_mrn": "MRN-12345",
"location_id": "9b409d24-aa13-4ce5-a6b2-ea813eeb9530"
}'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Patient note processing. A webhook event will be sent upon completion.",
"patient_note_id": "abc123def456789012345678",
"job_id": 12345
}
```
The response includes:
* **patient\_note\_id**: Unique identifier for the created patient note record
* **job\_id**: Job execution identifier for tracking the async operation
### Error Responses
#### Missing Required Field
```json theme={null}
{
"success": false,
"message": "Missing required field: subject"
}
```
#### Invalid Location
```json theme={null}
{
"success": false,
"message": "Invalid location_id. Must be one of: ..."
}
```
### Webhook Notifications
When the patient note processing is complete, we will send a webhook to your registered endpoint.
#### Success
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2CluR9g9gV",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2025-10-09T10:30:00Z",
"type": "patient_note.created",
"job_id": "12345",
"data": {
"patient_note_id": "abc123def456789012345678",
"emr_note_id": "10d1c8d3-aa69-472a-a9eb-f5fbd12bf99f",
"patient_mrn": "MRN-12345",
"location_id": "9b409d24-aa13-4ce5-a6b2-ea813eeb9530",
"subject": "Wellness check-in",
"note": "Patient reports feeling well since last visit. No new concerns to report."
}
}
```
#### Failure
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2CluR9g9gW",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2025-10-09T10:35:00Z",
"type": "patient_note.failed",
"job_id": "12345",
"data": {
"patient_note_id": "abc123def456789012345678",
"failure_reason": "Failed to create patient note"
}
}
```
# Create Patient
Source: https://docs.usecobalt.com/api-reference/patients/create
POST /patients
Creates a new patient record.
### Provider IDs for Referrals
When creating patients with referral information, use the **`ehr_id`** value from providers:
* **`referred_to_provider_id`** (optional): Use the `ehr_id` from `GET /v1/providers` (not the `id`)
This value represents the rendering provider identifier your EMR system uses. Cobalt passes it directly to your EMR when creating the patient record.
**Don't use the Cobalt `id` here.** The `id` field from GET responses is Cobalt's internal UUID, used only for updating provider settings via PATCH endpoints.
### Referring Provider and PCP Options
When creating a patient, you can specify the referring provider and PCP (Primary Care Provider) using either names or provider IDs:
#### Option 1: Provider Names (All EMRs)
Provide the provider's first and last name:
```json theme={null}
{
"referring_provider_first_name": "John",
"referring_provider_last_name": "Smith",
"pcp_first_name": "Jane",
"pcp_last_name": "Doe"
}
```
#### Option 2: Provider IDs
Provide a Cobalt `id` (UUID, with or without dashes). This option:
* Automatically looks up the provider's name, phone, and fax
* Provides more accurate matching by validating contact information in the EMR
* Falls back to using provided names if the ID is not found
The accepted source depends on the field:
* **`referring_provider_id`**: the `id` from `GET /v1/referring-providers`.
* **`pcp_id`**: the `id` from **either** `GET /v1/referring-providers` **or** `GET /v1/providers`. Pass a `/v1/providers` `id` when the patient's PCP is one of the practice's own physicians rather than an external referring provider. Cobalt resolves the UUID against both sets of providers, so you can use whichever endpoint the provider appears in.
```json theme={null}
{
"referring_provider_id": "e35e82b85df58f08a9b38e06a91e9f1a",
"pcp_id": "223ecd1b29e546ca9db6b391eb49b213"
}
```
For `pcp_id`, use the `id` field (the Cobalt UUID), not the `ehr_id`. This differs from `referred_to_provider_id`, which expects the `ehr_id` from `GET /v1/providers`.
### Responsible Party
By default, the patient is their own responsible party (`responsible_party: "self"`). For minors or patients whose billing is managed by another person, set `responsible_party` to one of the values below and include the guarantor's demographic fields.
When a non-self responsible party is provided alongside insurance, Cobalt will:
1. Create a guarantor record in the EMR with the provided demographics
2. Link that guarantor to the insurance record
3. Set the responsible party on the patient
```json theme={null}
{
"responsible_party": "parent",
"responsible_party_first_name": "Jane",
"responsible_party_last_name": "Smith",
"responsible_party_sex": "female",
"responsible_party_dob": "1975-06-15",
"responsible_party_phone": "555-555-1234",
"responsible_party_email": "jane.smith@example.com",
"responsible_party_address_line1": "123 Main St",
"responsible_party_address_line2": "Apt 4B",
"responsible_party_address_city": "Springfield",
"responsible_party_address_state": "IL",
"responsible_party_address_zip": "62701",
"insurance_name": "Aetna",
"insurance_subscriber_number": "ABC123"
}
```
**Supported values:**
| Value | EMR Code | Description |
| - | - | - |
| `self` | 1 | Patient is the insured |
| `spouse` | 2 | Patient is the spouse of the insured |
| `child` | 3 | Natural Child — insured has financial responsibility |
| `adopted_child` | 4 | Natural Child — insured does not have financial responsibility (includes legally adopted) |
| `step_child` | 5 | Step Child |
| `foster_child` | 6 | Foster Child |
| `ward_of_court` | 7 | Ward of the Court |
| `employee` | 8 | Employee |
| `unknown` | 9 | Unknown / Other relationship |
| `handicapped_dependent` | 10 | Handicapped Dependent |
| `organ_donor` | 11 | Organ Donor |
| `cadaver_donor` | 12 | Cadaver Donor |
| `grandchild` | 13 | Grandchild |
| `niece_nephew` | 14 | Niece/Nephew |
| `injured_plaintiff` | 15 | Injured Plaintiff |
| `sponsored_dependent` | 16 | Sponsored Dependent |
| `minor_dependent` | 17 | Minor Dependent of a Minor Dependent |
| `parent` | 18 | Parent |
| `grandparent` | 19 | Grandparent |
| `life_partner` | 53 | Life Partner |
| `other` | 99 | Other |
**Optional guarantor fields:**
| Field | Type | Description |
| - | - | - |
| `responsible_party_sex` | string | `male` or `female` |
| `responsible_party_dob` | string | Date of birth in `YYYY-MM-DD` format |
| `responsible_party_phone` | string | Phone number in `222-333-4444` format |
| `responsible_party_email` | string | Email address |
| `responsible_party_address_line1` | string | Street address line 1 |
| `responsible_party_address_line2` | string | Street address line 2 |
| `responsible_party_address_city` | string | City |
| `responsible_party_address_state` | string | Two-letter U.S. state abbreviation |
| `responsible_party_address_zip` | string | 5-digit ZIP code |
`responsible_party_first_name` and `responsible_party_last_name` are required when using a non-self responsible party. The guarantor is created as a separate record in the EMR — if a guarantor with those demographics already exists in your instance, a duplicate will be created.
### Registration Fields
Additional demographic and consent fields can be set at patient creation:
| Field | Type | Description |
| - | - | - |
| `language` | string | Preferred language. Must match a valid language name in your EMR instance. |
| `race` | string | Race. Must match a valid race name in your EMR instance. |
| `ethnicity` | string | Ethnicity. Must match a valid ethnicity code or display name in your EMR instance. |
| `release_of_info` | string | Consent for release of information. Accepts `true`/`false` (`true` maps to `Y`, `false` to `N`) or an EMR code: `Y`, `M`, `N`, `I`. Defaults to `Y`. |
| `rx_history_consent` | string | Consent for pharmacy history sharing. Accepts `true`/`false` (`true` maps to `Y`, `false` to `N`) or an EMR code: `Y`, `N`, `U`. Defaults to `Y`. |
| `self_pay` | boolean | Explicitly marks the patient as self-pay, overriding insurance-derived logic. |
| `default_facility_id` | string | The EMR facility ID to set as the patient's primary service location. |
| `voice_enabled` | boolean | Enables voice (phone) notifications in the EMR patient communication settings. Defaults to off. |
| `text_enabled` | boolean | Enables text (SMS) notifications in the EMR patient communication settings. Defaults to off. |
```json theme={null}
{
"language": "Spanish",
"race": "White",
"ethnicity": "Hispanic or Latino",
"release_of_info": true,
"rx_history_consent": false,
"default_facility_id": "25",
"voice_enabled": true,
"text_enabled": true
}
```
**Notification language.** When `voice_enabled` or `text_enabled` is set, the notification language in the EHR follows the patient's `language`: Spanish when `language` contains "spanish" (case-insensitive), otherwise English. These are the only two options exposed for communication notifications.
### Insurance Options
When creating a patient, you can specify insurance using either the insurance name or an insurance provider ID:
**Option 1: Insurance Name (All EMRs)**
```json theme={null}
{
"insurance_name": "United Healthcare"
}
```
**Option 2: Insurance Provider ID**
Use `insurance_provider_id` from `GET /v1/insurance-providers` (UUID without dashes). This option:
* Automatically looks up the insurance name, address, city, and state
* Provides more accurate matching when there are duplicate insurance names
* Falls back to using provided insurance\_name if the ID is not found
```json theme={null}
{
"insurance_provider_id": "e35e82b85df58f08a9b38e06a91e9f1a"
}
```
### Example Request
#### Basic Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/patients \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"last_name": "Smith",
"first_name": "John",
"phone": "5551234567",
"dob": "1980-01-01",
"sex": "male"
}'
```
#### With Provider Names
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/patients \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"last_name": "Smith",
"first_name": "John",
"phone": "5551234567",
"dob": "1980-01-01",
"sex": "male",
"referring_provider_first_name": "Jane",
"referring_provider_last_name": "Doe",
"pcp_first_name": "Robert",
"pcp_last_name": "Johnson"
}'
```
#### With Provider IDs
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/patients \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"last_name": "Smith",
"first_name": "John",
"phone": "5551234567",
"dob": "1980-01-01",
"sex": "male",
"referring_provider_id": "e35e82b85df58f08a9b38e06a91e9f1a",
"pcp_id": "223ecd1b29e546ca9db6b391eb49b213"
}'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Patient processing. A webhook event will be sent upon completion.",
"patient_id": "9988776655443322",
"job_id": 12345
}
```
Store the returned `patient_id` to correlate the follow-up webhook. `job_id` is the API log ID for the request and is also present on the resulting webhook, so you can match either identifier back to this call.
### Webhook Notifications
When patient 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_pat_succ_g7h8i9",
"access_token_reference_id": "user_pat_ref_k3l4m5",
"object": "event",
"created": "2023-10-29T12:00:00Z",
"type": "patient.created",
"job_id": "12345",
"action": "cobalt_operation",
"data": {
"patient_id": "9988776655443322",
"mrn": "123456",
"eligibility_information": [
{
"insurance_name": "Aetna",
"status": "Active"
}
] // returned when check_eligibility=true. Availability depends on EHR support.
}
}
```
#### Failure Examples
The `patient.failed` webhook event includes a `failure_reason` and may contain additional fields in the `data` object depending on the cause of the failure.
**Duplicate Patient:**
```json theme={null}
{
"id": "evt_pat_fail_dup_p2q3r4",
"access_token_reference_id": "user_pat_ref_k3l4m5",
"object": "event",
"created": "2023-10-29T12:05:00Z",
"type": "patient.failed",
"data": {
"patient_id": "9988776655443322",
"failure_reason": "Duplicate patient found. Please use the existing patient or update the patient information using the PATCH /v1/patients/:id endpoint.",
"existing_mrn": "654321"
}
}
```
**Referring Provider Not Found:**
```json theme={null}
{
"id": "evt_pat_fail_ref_s5t6u7",
"access_token_reference_id": "user_pat_ref_k3l4m5",
"object": "event",
"created": "2023-10-29T12:10:00Z",
"type": "patient.failed",
"data": {
"patient_id": "9988776655443323",
"failure_reason": "No valid referring provider found. Please update the referring provider using the PATCH /v1/patients/:id endpoint."
}
}
```
**PCP Not Found:**
```json theme={null}
{
"id": "evt_pat_fail_pcp_y1z2a3",
"access_token_reference_id": "user_pat_ref_k3l4m5",
"object": "event",
"created": "2023-10-29T12:12:00Z",
"type": "patient.failed",
"data": {
"patient_id": "9988776655443325",
"failure_reason": "No valid PCP provider found. Please update the PCP provider using the PATCH /v1/patients/:id endpoint."
}
}
```
**Insurance Not Found:**
```json theme={null}
{
"id": "evt_pat_fail_ins_v8w9x0",
"access_token_reference_id": "user_pat_ref_k3l4m5",
"object": "event",
"created": "2023-10-29T12:15:00Z",
"type": "patient.failed",
"data": {
"patient_id": "9988776655443324",
"failure_reason": "No valid insurance found. Please update the insurance using the PATCH /v1/patients/:id endpoint."
}
}
```
Patient creation is asynchronous. Store the returned patient\_id and listen for webhooks to determine the final status.
# Fetch Patients
Source: https://docs.usecobalt.com/api-reference/patients/fetch
POST /patients/fetch
Performs a live fetch of patient data from the connected EMR system based on search criteria.
This is an async operation that fetches up-to-date patient data directly from the EMR system. If the newest data is not critical, consider using the GET /patients endpoint instead for faster results from cached data.
## Optional Includes
Use `include` to opt into additional live-fetch payloads. The API accepts either:
* a comma-delimited string, for example `include: "insurances"`
* an array of strings, for example `include: ["insurances"]`
Every include value:
* `insurances`
* `problems`
* `medical_history`
* `labs`
* `labs.results` (orders plus discrete result values; implies `labs`)
* `referrals` (the patient's incoming, outgoing, and external referrals, each with diagnoses)
* `documents`
* `encounters`
* `encounters.details` (implies `encounters`)
* `encounters.appointment_notes` (implies `encounters`)
* `encounters.referral` (implies `encounters`)
* `encounters.all` (full encounter history instead of the 50 most recent; implies `encounters`)
* `episodes`
* `notes`
* `assessments`
* `care_plans`
* `clinical_notes`
* `medical`
* `treatment_plan`
* `point_of_care`
* `tasks`
* `tasks.notes` (tasks plus attached notes; implies `tasks`)
* `all_pages` (fetch every page of a name or dob search instead of just the first — see below)
Which of these the connected EMR accepts varies. The `include` field in the [OpenAPI spec](https://docs.usecobalt.com/api-reference/openapi.json) carries the accepted set per EMR under `x-allowed-values-for-emrs`.
`tasks.notes` implies `tasks` — you do not need to pass both. Requesting `tasks.notes` makes an extra live fetch per task to pull its note history, so only request it when you need the notes.
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/patients/fetch \
-H "Content-Type: application/json" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token" \
-d '{
"mrn": "MRN123456",
"search_by": "mrn",
"include": ["insurances", "problems", "medical_history", "labs.results", "referrals"]
}'
```
## Narrowing a Search
A `name` or `dob` search returns a single page of matches. The page size is set by the EMR and can be as low as 20, so a common name, or a busy date of birth, can easily exceed one page. Add **one** secondary filter to narrow the results at the source:
* Narrow a **name** search with `dob` (YYYY-MM-DD) or `phone` (222-333-4444).
* Narrow a **dob** search with a name (`first_name` / `last_name`).
Only one secondary filter is allowed. The filter is applied by the EMR (it intersects both criteria server-side), so it reduces the result set rather than trimming it after the fact. A name plus a date of birth resolves to the same intersection whichever one you use as `search_by`.
If the first page was still capped, the completion webhook returns `has_more: true` and a `message` telling you to narrow further. To fetch every page instead of narrowing, add `include: ["all_pages"]`. This makes one extra EMR call per page, so prefer a secondary filter when you can.
```bash theme={null}
# Narrow a busy date of birth by name
curl -X POST https://api.usecobalt.com/v1/patients/fetch \
-H "Content-Type: application/json" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token" \
-d '{
"search_by": "dob",
"dob": "1985-03-15",
"last_name": "Smith"
}'
```
### Response Data
Patient data includes comprehensive information including active medications and associated pharmacies:
```json theme={null}
{
"id": "pat_123",
"mrn": "123456789",
"first_name": "Jane",
"last_name": "Smith",
"middle_name": "Marie",
"date_of_birth": "1985-03-15",
"address_street": "123 Market St",
"address_city": "San Francisco",
"address_state": "CA",
"address_zip": "94102",
"phone": "415-555-1234",
"cell_phone": "415-555-5678",
"sex": "female",
"email": "jane.smith@example.com",
"insurance_name": "Blue Shield of California",
"insurance_subscriber_number": "ABC123456789",
"insurances": [
{
"emr_insurance_id": "51638",
"priority": 1,
"insurance_ehr_id": "733",
"insurance_name": "Blue Shield of California",
"insurance_subscriber_number": "ABC123456789",
"group_id": "GRP12345",
"plan_begin_date": "2025-01-01",
"copayment": "25.00",
"relationship_to_subscriber": "self",
"guarantor_id": "123456",
"is_guarantor_patient": true
}
],
"rendering_provider_id": "67890",
"medications": [
{
"name": "Lisinopril",
"strength": "10 MG",
"frequency": "Once a day",
"start_date": "2025-01-21",
"encounter_date": "2025-01-21",
"refills": "3",
"notes": "Take with food"
}
],
"pharmacies": [
{
"pharmacy_ehr_id": "5001",
"is_primary": "1",
"name": "Walgreens Pharmacy",
"address": "500 Geary St",
"city": "San Francisco",
"state": "CA",
"zip": "94102",
"phone": "415-555-9000"
}
],
"encounters": [
{
"id": "3fa85f6457174562b3fc2c963f66afa6",
"date": "2025-10-14",
"start_time": "09:30",
"visit_type": "OV",
"status": "Checked Out",
"provider_ehr_id": "67890",
"provider_first_name": "Alice",
"provider_last_name": "Nguyen",
"reason": "Follow-up",
"facility_name": "Market Street Clinic",
"facility_id": "12",
"locked": "true"
}
],
"encounters_has_more": false,
"last_appointment_date": "2025-10-14",
"problems": [
{
"id": "293199",
"icd10": "I10",
"icd_version": "10",
"name": "Essential (primary) hypertension",
"status": "confirmed",
"severity": "2",
"onset_date": "",
"added_date": "09/01/2025",
"provider_name": "Nguyen, Alice",
"encounter_id": "428763",
"notes": "",
"inactive": false
}
],
"medical_history": {
"vitals": [
{ "name": "BP", "date": "05/12/2025", "value": "120/80" },
{ "name": "HR", "date": "05/12/2025", "value": "70" }
],
"allergies": ["N.K.D.A"],
"surgical_history": [
{ "date": "2022", "reason": "Appendectomy" }
],
"hospitalization": [
{ "date": "2020", "reason": "Observation" }
],
"family_history": [
{ "relation": "Father", "description": "alive" },
{ "relation": "Mother", "description": "alive" }
],
"past_medical_history": ["Hypertension"],
"health_maintenance": [
{
"name": "Influenza",
"last_done": "01/01/2025",
"frequency": "1Y",
"due_date": "01/01/2026",
"status": "Compliant",
"notes": ""
}
]
},
"labs": {
"orders": [
{
"id": "519286",
"report_id": "519286",
"name": "CBC",
"type": 0,
"order_date": "05/12/2025",
"collection_date": "05/12/2025",
"result_date": "05/13/2025",
"ordering_physician": "Nguyen, Alice",
"interface_status": "Received",
"encounter_id": "461655",
"facility_id": "3",
"received": true,
"reviewed": false
}
],
"results": [
{
"name": "Metabolic Panel",
"result_date": "05/13/2025",
"analytes": [
{
"name": "Glucose",
"value": "95",
"units": "mg/dL",
"range": "70-99",
"loinc": "2345-7",
"previous_value": "",
"status": "F"
}
]
}
]
},
"referrals": [
{
"emr_referral_id": "100611",
"direction": "incoming",
"referral_date": "2026-08-19",
"referred_from": null,
"referred_to": "Stone, Danielle M",
"specialty": "Cardiology",
"status": "insuranceAuth",
"subtype": "Visit",
"reason": "PLAQUE 75577 AUTH APPROVED TO BE DONE SHC",
"diagnoses": [
{ "ehr_id": "507464", "code": "I10", "description": "HTN (hypertension)" }
]
}
],
"alerts": {
"billing_alert": false,
"billing_notes": null,
"global_alerts": [
{
"name": "Allergy: Penicillin",
"alert_type": "Allergy",
"notes": "Hives",
"priority": "High",
"expiry_date": null
}
]
},
"collection_status": "C",
"guarantors": [
{
"id": "12345",
"name": "John Smith",
"dob": "1960-04-22",
"relationship": "spouse",
"is_guarantor_patient": false
}
],
"patient_balance": 0,
"account_balance": 125.50
}
```
### Insurances Array
`insurances` is only returned when `include` contains `insurances`.
| Field | Type | Description |
| - | - | - |
| `emr_insurance_id` | string | Stable EMR insurance record ID. Use this value when calling `PATCH /v1/patients/:patient_mrn/insurances/:emr_insurance_id`. |
| `priority` | integer | EMR priority / sequence number for the insurance record |
| `insurance_ehr_id` | string | EMR-native carrier/company ID |
| `insurance_name` | string | Carrier name for this specific insurance record |
| `insurance_subscriber_number` | string | Subscriber/member number for this specific insurance record |
| `group_id` | string | Insurance group number |
| `plan_begin_date` | string | Coverage start date |
| `copayment` | string \| null | Copayment value returned by the EMR |
| `relationship_to_subscriber` | string \| null | Relationship to the subscriber |
| `guarantor_id` | string \| null | EMR guarantor identifier associated with the insurance |
| `is_guarantor_patient` | boolean | Whether the guarantor is the patient |
The top-level `insurance_name` and `insurance_subscriber_number` fields remain convenience fields on the patient object. When present, prefer `insurances[]` for record-specific insurance details and update targeting.
### Guarantors Array
Each entry represents a guarantor on the patient's account. Empty array if the lookup fails.
| Field | Type | Description |
| - | - | - |
| `id` | string | Guarantor's EMR patient ID (if the guarantor is also a patient) |
| `name` | string | Guarantor's full name |
| `dob` | string | Date of birth |
| `relationship` | string | Relationship to the patient: `self`, `spouse`, `child`, or `other` |
| `is_guarantor_patient` | boolean | Whether this guarantor is also the patient on the account |
The top-level `patient_balance` and `account_balance` fields (numbers, in dollars) are returned alongside the guarantors. Both are `null` if the lookup fails.
### Alerts Object
Contains the patient's billing and global alerts. May be `null` if the alerts lookup fails.
| Field | Type | Description |
| - | - | - |
| `billing_alert` | boolean | Whether a billing alert is set on the patient |
| `billing_notes` | string \| null | Free-text notes attached to the billing alert |
| `global_alerts` | array | Global alerts; each has `name`, `alert_type`, `notes`, `priority`, `expiry_date` |
### Medications Array
Each patient includes an array of active medications with the following fields:
| Field | Type | Description |
| - | - | - |
| `name` | string | Medication name |
| `strength` | string | Medication strength/dosage |
| `frequency` | string | How often to take the medication |
| `start_date` | string | Date medication was started (MM/DD/YYYY) |
| `refills` | string | Number of refills remaining |
| `notes` | string | Additional notes about the medication |
### Pharmacies Array
Each patient includes an array of associated pharmacies with the following fields:
| Field | Type | Description |
| - | - | - |
| `pharmacy_id` | string | Pharmacy's EMR ID |
| `is_primary` | string | Whether this is the patient's primary pharmacy ("0" or "1") |
| `name` | string | Pharmacy name |
| `address` | string | Pharmacy street address |
| `city` | string | Pharmacy city |
| `state` | string | Pharmacy state code |
| `zip` | string | Pharmacy ZIP code |
| `phone` | string | Pharmacy phone number |
### Encounters Array
Each patient includes an array of encounters (past and upcoming appointments) returned by the EMR. Field availability varies by EMR and visit type.
| Field | Type | Description |
| - | - | - |
| `id` | string | Cobalt appointment ID for the encounter |
| `ehr_appointment_id` | string | Encounter ID in the EMR |
| `date` | string | Encounter date (YYYY-MM-DD) |
| `start_time` | string | Scheduled start time (HH:MM, 24-hour) |
| `visit_type` | string | EMR visit type code (e.g. `OV` for office visit, `TEL` for telephone encounter) |
| `status` | string | Encounter status (e.g. `Checked Out`, `Scheduled`) |
| `provider_ehr_id` | string | Rendering provider's EMR ID |
| `provider_first_name` | string | Rendering provider's first name |
| `provider_last_name` | string | Rendering provider's last name |
| `reason` | string | Reason for visit |
| `facility_name` | string | Facility name |
| `facility_id` | string | Facility EMR ID |
| `locked` | string | Whether the encounter is locked (`"true"` / `"false"`) |
| `visit_note_document_id` | string | Cobalt document ID of the encounter's visit note. Pass it to [POST /documents/fetch](/api-reference/documents/fetch) to get the note as a PDF. |
Telephone encounters (`visit_type: "TEL"`) are enriched with additional fields including `caller`, `message`, `actions`, `notes`, `assigned_to`, `answered_by`, `priority`, and `has_attachment`.
The top-level `last_appointment_date` field is derived from the encounters array and reflects the most recent appointment date for the patient.
### Documents Array
Documents in the patient's chart. Field availability varies by EMR.
| Field | Type | Description |
| - | - | - |
| `id` | string | Cobalt document ID. Pass it to [POST /documents/fetch](/api-reference/documents/fetch) to get the file. Stable across fetches. |
| `name` | string | Document name |
| `description` | string | Document description |
| `folder` | string | Chart folder |
| `subfolder` | string | Chart subfolder |
| `date` | string | Document date (YYYY-MM-DD) |
| `file_name` | string | Stored file name in the EMR |
The file itself is not included in the fetch. `GET /documents/{id}` returns `409`
until the document has been fetched with `POST /documents/fetch`.
### Tasks Array
Returned only when `include` contains `tasks` (or `tasks.notes`). Each entry is a task from the patient's chart. Some EMRs model telephone encounters as tasks with `category: "Telephone Encounter"` — use `category` to distinguish task types. All task types are returned; filter client-side on `category` if you only want a subset.
| Field | Type | Description |
| - | - | - |
| `emr_task_id` | string | The task's EMR ID. Use this value as `emr_task_id` when calling `POST /v1/tasks/notes`. |
| `follow_up_date` | string \| null | Follow-up date for the task |
| `status` | string \| null | Task status (e.g. `New`, `Complete`) |
| `tasking_id` | string \| null | Recipient tasking identifier |
| `priority` | string \| null | Task priority |
| `datetime` | string \| null | Task creation date/time |
| `subject` | string \| null | Task subject line |
| `recipients` | string \| null | Display names of the task recipients |
| `recipient_ids` | string \| null | Recipient identifiers |
| `category` | string \| null | Task type/category (e.g. `General`, `Telephone Encounter`) |
| `sent_by` | string \| null | Who the task was sent by |
| `notes` | array | Note history for the task. Present only when `include` contains `tasks.notes`. See below. |
#### Task Notes Array
Each task's `notes[]` (present only with `tasks.notes`) contains its note history, most recent first:
| Field | Type | Description |
| - | - | - |
| `emr_note_id` | string | The note's EMR ID |
| `created_date` | string \| null | When the note was created |
| `description` | string \| null | Note body. Some EMRs prefix the author, e.g. `"ACME Health AI Account - call back tomorrow"`. |
```json theme={null}
{
"tasks": [
{
"emr_task_id": "9bef4113-e9ce-4895-9a17-2c18cd625116",
"follow_up_date": "6/15/2026",
"status": "New",
"tasking_id": "3610210f-6f36-4cfc-b7b5-79fe7fc42d83",
"priority": "Normal",
"datetime": "6/15/2026 12:02 PM",
"subject": "Follow up call",
"recipients": "ACME Management",
"recipient_ids": "3610210f-6f36-4cfc-b7b5-79fe7fc42d83",
"category": "Telephone Encounter",
"sent_by": "ACME Health AI Account",
"notes": [
{
"emr_note_id": "f862b0a0-d820-418c-9e30-412bb62bde34",
"created_date": "6/15/2026 12:02 PM",
"description": "ACME Health AI Account - patient called back, scheduled for next week"
}
]
}
]
}
```
### Webhook Notifications
When the patient fetch is complete, we will send a webhook to your registered endpoint. Here is an example of what the webhook payload will look like:
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2Cmnopqr",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cstuv",
"job_id": "job_1J9X2q2eZvKYlo2Cmnopqr",
"object": "event",
"created": "2023-10-28T11:00:00Z",
"timestamp": "2023-10-28T11:00:00Z",
"type": "patient.live_fetch_completed",
"action": "sync",
"data": {
"success": true,
"patient_count": 20,
"has_more": true,
"message": "More results are available than were returned. Narrow the search with an additional filter (for example dob or name), or set include=all_pages to retrieve every page.",
"patients": [
{
"id": "pat_123",
"mrn": "123456789",
"first_name": "Jane",
"last_name": "Smith",
"date_of_birth": "1985-03-15",
"medications": [...],
"pharmacies": [...],
"encounters": [...],
"document_folders": [...],
"last_appointment_date": "2025-10-14"
}
]
}
}
```
`has_more` is `true` only when a name or dob search was capped and more matches exist (it is absent or `false` otherwise, and when `include: ["all_pages"]` fetched everything). `message` is present only when `has_more` is `true`.
# Get Patients
Source: https://docs.usecobalt.com/api-reference/patients/get
GET /patients
Returns a list of patients with optional filtering and pagination.
### Example Request
```bash theme={null}
curl -X GET https://api.usecobalt.com/v1/patients \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-G \
--data-urlencode "first_name=John" \
--data-urlencode "last_name=Doe" \
--data-urlencode "page=2" \
--data-urlencode "page_size=30" \
--data-urlencode "sort=-created_at"
```
### Example Response
```json theme={null}
{
"success": true,
"patients": [
{
"id": "65ed04f9d25fca3876f367d9ad94e3c3",
"ehr_id": "123456",
"mrn": "414421",
"first_name": "John",
"last_name": "Doe",
"dob": "1980-05-15",
"sex": "male",
"phone": "555-123-4567",
"cell_phone": "555-123-4568",
"home_phone": null,
"work_phone": null,
"phone_numbers": {
"primary": "555-123-4567",
"cell": "555-123-4568",
"home": null,
"work": null
},
"insurance_name": "Aetna",
"insurance_subscriber_number": "ABC123456",
"insurances": [
{
"emr_insurance_id": "102",
"priority": 1,
"insurance_name": "Aetna",
"insurance_policy_type": "Commercial",
"insurance_subscriber_number": "ABC123456",
"group_id": "A0001"
}
],
"address_street": "123 Main St",
"address_city": "Springfield",
"address_state": "IL",
"address_zip": "62701",
"pcp_first_name": "Jane",
"pcp_last_name": "Smith",
"status": "active",
"created_at": "2024-09-01T14:30:00Z",
"object_metadata": {
"source": "cobalt_operation",
"created_at": "2024-09-01T14:30:00Z"
}
}
],
"pagination": {
"current_page": 2,
"total_pages": 5,
"total_count": 150,
"page_size": 30
}
}
```
All filter parameters are optional. If no filters are provided, the endpoint returns all patients, paginated according to the default values or specified page and page\_size. To resolve a patient you already track by an external identifier, filter by `mrn` or `ehr_id` (both are exact-match): the response includes Cobalt's `id` alongside `ehr_id` and `mrn`.
`ehr_id` is the patient's EHR-native identifier. It is `null` while a patient is still pending creation or failed in the EHR, and is populated once the EHR record exists. `object_metadata.source` reports provenance: `cobalt_operation`, `ehr_sync`, or `unknown`.
# Add Patient Insurance
Source: https://docs.usecobalt.com/api-reference/patients/insurances/add
POST /patients/{patient_mrn}/insurances
Queue the addition of insurance information to a patient record in the EMR system. This is an asynchronous operation.
This endpoint queues the addition of insurance information to a patient record in the EMR system. The operation is asynchronous and returns immediately with a `job_id` for tracking. Results are delivered via webhook.
After a successful create, the success webhook includes `emr_insurance_id`. This is the same record identifier returned later as `emr_insurance_id` in `POST /v1/patients/fetch` with `include: ["insurances"]`, and it can be used with the insurance update endpoint.
`member_id` is the subscriber/member number you provide (the policy number from the insurance card), not an EHR-generated value. The EHR-generated record identifier is `emr_insurance_id`, returned on the webhook after the record is created.
## Insurance Provider Resolution
The API supports three methods for identifying the insurance provider (in order of priority):
1. **By Cobalt Provider ID** (Most specific, recommended):
```json theme={null}
{
"insurance_provider_id": "abc123def456"
}
```
2. **By Name + Payer ID** (Most specific when ID not available):
```json theme={null}
{
"insurance_name": "ACME Health",
"insurance_payer_id": "98999"
}
```
3. **By Name Only** (Least specific, may match first result if multiple exist):
```json theme={null}
{
"insurance_name": "ACME Health"
}
```
Use `GET /v1/insurance-providers` to retrieve the correct insurance provider identifiers for your organization.
## Validation Rules
### Address Validation
* **State**: Must be a valid two-letter US state abbreviation (accepts lowercase, e.g., "ca" or "CA")
* **ZIP Code**: Must be either 5 digits (e.g., "90001") or 9 digits with hyphen (e.g., "90001-1234")
### Date Validation
* **plan\_begin\_date**: Must be in YYYY-MM-DD format (e.g., "2025-01-15")
* **plan\_end\_date**: Optional. Must be in YYYY-MM-DD format (e.g., "2025-12-31"). Omit for open-ended coverage.
### Priority (Optional)
* **priority**: Insurance priority level (valid values: "1", "2", "3"). When not provided, the EMR will use its default priority setting.
### Relationship to Subscriber
Accepts both codes and names (case-insensitive):
* **Codes**: "01", "02", "32", "33", "17", "20", "53", "25"
* **Names**: "self", "spouse", "mother", "father", "step parent", "employee", "life partner", "other"
### Insurance Provider Validation
* `insurance_payer_id` alone is not supported (must be combined with `insurance_name`)
* If provider ID, name, or name+payer\_id combination is not found, returns 404 with helpful message
## Example Requests
### Minimal Request (Using Insurance Provider ID)
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/patients/MRN123456/insurances \
-H "Content-Type: application/json" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token" \
-d '{
"member_id": "MEM123456789",
"group_id": "GRP98999",
"plan_begin_date": "2025-01-01",
"insurance_provider_id": "abc123def456",
"subscriber_demographics": {
"first_name": "John",
"last_name": "Doe",
"street_line_1": "123 Main St",
"city": "Los Angeles",
"state": "CA",
"zip": "90001"
}
}'
```
### Complete Request (Using Insurance Name + Payer ID)
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/patients/MRN123456/insurances \
-H "Content-Type: application/json" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token" \
-d '{
"member_id": "MEM123456789",
"group_id": "GRP98999",
"insurance_name": "ACME Health",
"insurance_payer_id": "98999",
"plan_begin_date": "2025-01-01",
"plan_end_date": "2025-12-31",
"copayment": 25,
"priority": "1",
"relationship_to_subscriber": "spouse",
"subscriber_demographics": {
"first_name": "Jane",
"last_name": "Doe",
"street_line_1": "123 Main St",
"city": "Los Angeles",
"state": "CA",
"zip": "90001-1234"
}
}'
```
### Self-Insured Patient with 9-Digit ZIP
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/patients/MRN789012/insurances \
-H "Content-Type: application/json" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token" \
-d '{
"member_id": "MEM987654321",
"group_id": "GRP11111",
"insurance_name": "Blue Cross Blue Shield",
"plan_begin_date": "2025-01-01",
"relationship_to_subscriber": "01",
"subscriber_demographics": {
"first_name": "Jane",
"last_name": "Smith",
"street_line_1": "456 Oak Ave",
"city": "San Francisco",
"state": "ca",
"zip": "94102-1234"
}
}'
```
## Example Response
```json theme={null}
{
"success": true,
"message": "Insurance addition queued successfully. Processing will begin shortly.",
"patient_insurance_id": "xyz789abc123",
"job_id": 12345
}
```
## Webhook Events
After the insurance addition is processed, a webhook event will be sent to your configured webhook URL.
### Success Event (patient.insurance.added)
```json theme={null}
{
"id": "evt_abc123def456",
"access_token_reference_id": "your_reference_id",
"object": "event",
"created": "2025-01-15T10:30:00.000Z",
"type": "patient.insurance.added",
"job_id": "12345",
"data": {
"patient_insurance_id": "xyz789abc123",
"patient_mrn": "MRN123456",
"member_id": "MEM123456789",
"group_id": "GRP98999",
"plan_begin_date": "2025-01-01",
"plan_end_date": "2025-12-31",
"copayment": 25,
"priority": 1,
"relationship_to_subscriber": "self",
"emr_insurance_id": "51638"
}
}
```
`emr_insurance_id` is the EMR-native insurance record ID. The same value is returned in live fetch as `emr_insurance_id` and should be used when calling `PATCH /v1/patients/:patient_mrn/insurances/:emr_insurance_id`.
`audit_trail` is present in the success payload for some EMRs and absent for others, so the example above may carry more or fewer fields than your integration returns.
### Failure Event (patient.insurance.failed)
```json theme={null}
{
"id": "evt_xyz789abc123",
"access_token_reference_id": "your_reference_id",
"object": "event",
"created": "2025-01-15T10:30:00.000Z",
"type": "patient.insurance.failed",
"job_id": "12345",
"data": {
"patient_insurance_id": "xyz789abc123",
"patient_mrn": "MRN123456",
"failure_reason": "Patient not found in EMR system"
}
}
```
Insurance addition is asynchronous. Store the returned `patient_insurance_id` and `job_id`, then listen for webhooks to determine the final status.
# Update Patient Insurance
Source: https://docs.usecobalt.com/api-reference/patients/insurances/update
PATCH /patients/{patient_mrn}/insurances/{emr_insurance_id}
Queue an update to an existing patient insurance record in the EMR system.
This endpoint queues an asynchronous update for an existing patient insurance record.
**Ending / cancelling coverage:** there is no delete endpoint for insurance records. To end coverage, PATCH the record with a `plan_end_date`.
## Identifying The Insurance To Update
Use the EMR insurance record ID. You can get it from either:
* `POST /v1/patients/fetch` with `include: ["insurances"]`
* the `emr_insurance_id` returned in a prior `patient.insurance.added` or `patient.insurance.updated` webhook
In live fetch responses, the update target is returned as `insurances[].emr_insurance_id`.
## Provider Resolution
The API supports the same insurance provider resolution options as insurance create:
1. `insurance_provider_id`
2. `insurance_name` + `insurance_payer_id`
3. `insurance_name`
`insurance_payer_id` alone is not supported. If you request a carrier change, the resolved insurance provider must have an EMR `ehrId` configured or the request will be rejected.
## Validation Rules
* All request body fields are optional. Omitted fields are preserved from the current EMR insurance record.
* `emr_insurance_id` is required in the URL path.
* If you send `subscriber_demographics`, it must include `first_name` and `last_name`.
* If `relationship_to_subscriber` is a non-self value such as `spouse`, `child`, or `other`, `subscriber_demographics.first_name` and `subscriber_demographics.last_name` are required.
* `plan_begin_date`, when provided, must be in `YYYY-MM-DD` format.
* `plan_end_date`, when provided, must be in `YYYY-MM-DD` format. When omitted, the current coverage end date is preserved (not cleared).
## Discover The Record ID First
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/patients/fetch \
-H "Content-Type: application/json" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token" \
-d '{
"mrn": "MRN123456",
"search_by": "mrn",
"include": ["insurances"]
}'
```
Example insurance entry from the live-fetch webhook payload:
```json theme={null}
{
"emr_insurance_id": "51638",
"priority": 1,
"insurance_ehr_id": "733",
"insurance_name": "Alignment Health Plan(P)",
"insurance_subscriber_number": "MEM-POSTMAN-001",
"group_id": "GRP-POSTMAN-001",
"plan_begin_date": "2026-07-01",
"plan_end_date": "2027-06-30",
"copayment": "10.00",
"relationship_to_subscriber": "spouse",
"guarantor_id": "90688",
"is_guarantor_patient": false
}
```
## Example Requests
### Update A Few Insurance Fields
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/patients/MRN123456/insurances/51638 \
-H "Content-Type: application/json" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token" \
-d '{
"member_id": "MEM123456789",
"group_id": "GRP98999",
"plan_begin_date": "2025-01-01",
"copayment": 25
}'
```
### Update Coverage Dates
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/patients/MRN123456/insurances/51638 \
-H "Content-Type: application/json" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token" \
-d '{
"plan_begin_date": "2026-01-01",
"plan_end_date": "2026-12-31"
}'
```
### Change To A Non-Self Subscriber
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/patients/MRN123456/insurances/51638 \
-H "Content-Type: application/json" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token" \
-d '{
"relationship_to_subscriber": "spouse",
"subscriber_demographics": {
"first_name": "Jane",
"last_name": "Doe",
"dob": "1985-04-12",
"phone": "5551234567",
"sex": "F"
}
}'
```
### Change The Carrier
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/patients/MRN123456/insurances/51638 \
-H "Content-Type: application/json" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token" \
-d '{
"insurance_name": "ACE Medicare Supplement",
"insurance_payer_id": "14367"
}'
```
## Example Response
```json theme={null}
{
"success": true,
"message": "Insurance update queued successfully. Processing will begin shortly.",
"patient_insurance_id": "xyz789abc123",
"job_id": 12345
}
```
## Webhook Events
### Success Event (patient.insurance.updated)
```json theme={null}
{
"id": "evt_abc123def456",
"access_token_reference_id": "your_reference_id",
"object": "event",
"created": "2025-01-15T10:30:00.000Z",
"type": "patient.insurance.updated",
"job_id": "12345",
"data": {
"patient_insurance_id": "xyz789abc123",
"patient_mrn": "MRN123456",
"member_id": "MEM123456789",
"group_id": "GRP98999",
"plan_begin_date": "2025-01-01",
"plan_end_date": "2025-12-31",
"copayment": 25,
"priority": 1,
"relationship_to_subscriber": "spouse",
"emr_insurance_id": "51638"
}
}
```
### Failure Event (patient.insurance.failed)
```json theme={null}
{
"id": "evt_xyz789abc123",
"access_token_reference_id": "your_reference_id",
"object": "event",
"created": "2025-01-15T10:30:00.000Z",
"type": "patient.insurance.failed",
"job_id": "12345",
"data": {
"patient_insurance_id": "xyz789abc123",
"patient_mrn": "MRN123456",
"failure_reason": "No existing insurance found with emr_insurance_id 51638 for patient MRN123456"
}
}
```
# Update Patient
Source: https://docs.usecobalt.com/api-reference/patients/update
PATCH /patients/{id}
Updates an existing patient. The update process differs based on the current status of the patient.
**Use the Cobalt `id` in the URL path.** The `{id}` parameter should be the Cobalt patient ID returned from API responses or GET endpoints, not the MRN or EHR ID.
The update process differs based on the current status of the patient:
### 1. Updating Pending or Failed Patients
For patients with a status of 'pending' or 'failed', the patient does not yet exist in the EHR. You can update any attribute, and the new values will be used the next time the patient creation runs.
| Parameter | Type | Required | Description |
| - | - | - | - |
| Any patient attribute | varies | No | Any attribute of the patient can be updated. All fields are optional. |
### 2. Updating Active Patients
For patients with a status of 'active' (already created in the EHR), you can update the patient's contact information, address, and provider assignments. The change is queued and applied to the EHR asynchronously; the patient's status will move to 'pending\_update' while the update is in flight and back to 'active' once the EHR write completes.
#### Contact & Address Fields
| Parameter | Type | Required | Description |
| - | - | - | - |
| `phone` | string | No | Home phone, formatted as `222-333-4444`. |
| `cell_phone` | string | No | Cell phone, formatted as `222-333-4444`. |
| `email` | string | No | Patient email address. |
| `address_street` | string | No | Street address line 1. |
| `address_line2` | string | No | Address line 2 (apartment, suite, unit, etc.). |
| `address_city` | string | No | City. |
| `address_state` | string | No | Two-letter state code (e.g. `CA`). DC is accepted. |
| `address_zip` | string | No | ZIP code. Accepts 5-digit (`12345`) or ZIP+4 (`12345-6789`) formats. |
| `save_previous_address` | boolean | No | When `true` (default), the patient's current address is saved as address history in the EHR before the new address is applied. Set to `false` to overwrite without preserving history. |
#### Provider Fields
| Parameter | Type | Required | Description |
| - | - | - | - |
| `referring_provider_first_name` | string | No | Referring provider's first name. Must be used with `referring_provider_last_name`. |
| `referring_provider_last_name` | string | No | Referring provider's last name. Must be used with `referring_provider_first_name`. |
| `referring_provider_id` | string | No | Cobalt referring provider UUID (from `GET /v1/referring-providers`). Looks up the provider's name and contact info for more accurate matching. |
| `pcp_first_name` | string | No | PCP's first name. Must be used with `pcp_last_name`. |
| `pcp_last_name` | string | No | PCP's last name. Must be used with `pcp_first_name`. |
| `pcp_id` | string | No | Cobalt referring provider UUID (from `GET /v1/referring-providers`). Looks up the provider's name and contact info for more accurate matching. |
| `referred_to_provider_id` | string | No | Rendering provider EHR ID — use the `ehr_id` value from `GET /v1/providers` (not the `id`). |
#### Demographics & Contact Preference Fields
| Parameter | Type | Required | Description |
| - | - | - | - |
| `language` | string | No | Patient preferred language. Must match a valid language name in your EHR instance. |
| `race` | string | No | Patient race. Must match a valid race name in your EHR instance. |
| `ethnicity` | string | No | Patient ethnicity. Must match a valid ethnicity code or display name in your EHR instance. |
| `voice_enabled` | boolean | No | Enables or disables voice (phone) notifications in the EHR patient communication settings. |
| `text_enabled` | boolean | No | Enables or disables text (SMS) notifications in the EHR patient communication settings. |
| `billing_notes` | string | No | The patient's billing alert notes (free text). The value you send replaces the current notes verbatim; the same field is returned as `billing_notes` by `POST /v1/patients/fetch`. |
| `pharmacy_id` | string | No | The patient's primary pharmacy, as the EMR pharmacy ID (the `ehr_id` from `GET /v1/pharmacies`). Adds the pharmacy as the primary, keeping any existing pharmacies and demoting the prior primary. |
| `self_pay` | boolean | No | Marks the patient as self-pay. Accepts `true` or `false`. A provider-only update never changes this flag. |
**Billing notes.** A common workflow: read the current `billing_notes` via patient fetch, transform it (for example, rewrite `referral: ...;` to `scheduledreferral: ...;`), then PATCH it back.
**Notification language.** When `voice_enabled` or `text_enabled` is set, the notification language in the EHR follows the patient's `language` (using the new value if `language` is included in the same request, otherwise the patient's current language): Spanish when `language` contains "spanish" (case-insensitive), otherwise English. These are the only two options exposed for communication notifications.
Contact/address fields, provider fields, demographics, and contact preferences are applied independently. If one group is rejected by the EHR (for example a provider name that cannot be resolved, or a record the EHR will not let you modify), the other groups in the same request are still applied. Anything that could not be applied is returned in a `failed_fields` array on the `patient.updated` webhook, along with a human-readable `message`. If no fields could be applied, the request fails and a `patient.update_failed` webhook is sent instead. Use `referring_provider_id` or `pcp_id` instead of names when possible, as ID-based resolution is more reliable.
At least one data field must be provided.
### Example Request for Updating a Pending/Failed Patient
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/patients/65ed04f9d25fca3876f367d9ad94e3c3 \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"phone": "555-987-6543",
"insurance_name": "Aetna",
"insurance_subscriber_number": "ABC987654321"
}'
```
### Example Request for Updating an Active Patient's Contact Info
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/patients/65ed04f9d25fca3876f367d9ad94e3c3 \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"phone": "555-987-6543",
"cell_phone": "555-987-6544",
"email": "patient@example.com"
}'
```
### Example Request for Updating an Active Patient's Address
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/patients/65ed04f9d25fca3876f367d9ad94e3c3 \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"address_street": "456 New St",
"address_line2": "Apt 7",
"address_city": "Austin",
"address_state": "TX",
"address_zip": "78701"
}'
```
To update the address without saving the previous address as history, pass `save_previous_address: false`:
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/patients/65ed04f9d25fca3876f367d9ad94e3c3 \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"address_street": "456 New St",
"address_city": "Austin",
"address_state": "TX",
"address_zip": "78701",
"save_previous_address": false
}'
```
### Example Request for Updating an Active Patient's Providers
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/patients/65ed04f9d25fca3876f367d9ad94e3c3 \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"referring_provider_id": "e35e82b85df58f08a9b38e06a91e9f1a",
"pcp_id": "223ecd1b29e546ca9db6b391eb49b213",
"referred_to_provider_id": "82749"
}'
```
Or using names instead of IDs:
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/patients/65ed04f9d25fca3876f367d9ad94e3c3 \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"referring_provider_first_name": "Jane",
"referring_provider_last_name": "Doe",
"pcp_first_name": "Robert",
"pcp_last_name": "Johnson"
}'
```
### Example Request for Updating an Active Patient's Demographics & Contact Preferences
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/patients/65ed04f9d25fca3876f367d9ad94e3c3 \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"first_name": "Jane",
"last_name": "Doe",
"dob": "1980-01-15",
"language": "Spanish",
"race": "White",
"ethnicity": "Hispanic or Latino",
"voice_enabled": true,
"text_enabled": true
}'
```
### Example Request for Marking a Patient as Self-Pay
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/patients/65ed04f9d25fca3876f367d9ad94e3c3 \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"self_pay": true
}'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Patient update queued.",
"patient_id": "65ed04f9d25fca3876f367d9ad94e3c3",
"job_id": 12345
}
```
`job_id` is the API log ID for the request and is also present on the resulting `patient.updated` webhook, so you can match either identifier back to this call.
Only include the fields you want to update in the request body. Omitted fields will remain unchanged.
# Create Payment
Source: https://docs.usecobalt.com/api-reference/payments/create
POST /payments
Posts a patient payment back to the provider's EMR ledger.
Posting payments is an asynchronous operation. The endpoint validates your request, queues the payment, and returns immediately with a `payment_id` and `job_id`. The payment is posted to the EMR by a background worker, and a webhook event is sent to your registered endpoint upon completion.
### Request Parameters
#### Required Fields
* **patient\_mrn** (string, required): Medical Record Number (MRN) of the patient the payment belongs to.
* **payment\_method** (string, required): Name of the payment method as configured in the EMR (e.g. `"Card"`). The worker resolves this name to the EMR's internal payment method id at post time.
* **reference\_number** (string, required): Your reference for the payment (e.g. a transaction or receipt number). Reference numbers may be reused across payments — they are not used as a uniqueness key.
* **location** (string, required): Identifier of the EMR location/facility the payment is posted against.
* **amount** (number, required): Payment amount. Must be a positive number.
#### Optional Fields
* **notes** (string, optional): Free-text note recorded with the payment in the EMR.
* **deposit\_date** (string, optional): Deposit date in `YYYY-MM-DD` format. Defaults to today if omitted.
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/payments \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"patient_mrn": "MRN-12345",
"payment_method": "Card",
"reference_number": "#123456",
"location": "1404",
"amount": 350,
"notes": "Patient copay collected at front desk",
"deposit_date": "2026-06-15"
}'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Payment processing. A webhook event will be sent upon completion.",
"payment_id": "123e4567e89b12d3a456426614174001",
"job_id": 12345
}
```
The response includes:
* **payment\_id**: Unique identifier for the created payment record.
* **job\_id**: Job execution identifier for tracking the async operation.
### Error Responses
#### Missing or Invalid Field
If a required field is missing or invalid, the API returns a `400` with the specific field name:
```json theme={null}
{
"success": false,
"message": "Missing or invalid required field: amount (must be a positive number)"
}
```
#### Patient Not Found
If the patient MRN cannot be resolved to an EMR patient, the API returns a `404`:
```json theme={null}
{
"success": false,
"message": "Patient with MRN 'MRN-12345' not found. Please ensure the patient has been synced and has an EMR patient ID."
}
```
#### User Not Found
```json theme={null}
{
"success": false,
"message": "User not found."
}
```
### Webhook Notifications
When the payment posting 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_1J9X2q2eZvKYlo2CluR9g9gV",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2026-06-15T10:30:00Z",
"type": "payment.created",
"job_id": "12345",
"data": {
"payment_id": "123e4567e89b12d3a456426614174001",
"emr_transaction_id": "13969262",
"payment_method": "Card",
"amount": 350,
"reference_number": "#123456",
"patient_mrn": "MRN-12345"
}
}
```
#### Failure
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2CluR9g9gW",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2026-06-15T10:35:00Z",
"type": "payment.failed",
"job_id": "12345",
"data": {
"payment_id": "123e4567e89b12d3a456426614174001",
"failure_reason": "Failed to post payment"
}
}
```
# Get Pharmacies
Source: https://docs.usecobalt.com/api-reference/pharmacies/get
GET /pharmacies
Retrieve pharmacies from the EMR system for your organization.
## Example Request
```bash theme={null}
curl -X GET "https://api.usecobalt.com/v1/pharmacies" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token"
```
## Example Response
```json theme={null}
{
"success": true,
"pharmacies": [
{
"id": "abc123def456ghi789",
"ehr_id": "12345",
"ncpdp_id": "5846247",
"name": "Main Street Pharmacy",
"address": {
"address1": "123 Main St",
"city": "San Francisco",
"state": "CA",
"zip": "94102"
},
"phone": "(415) 555-0123",
"email": "info@mainstreetpharmacy.com",
"status": "active"
},
{
"id": "xyz789ghi012jkl345",
"ehr_id": "67890",
"ncpdp_id": "5702724",
"name": "Downtown Medical Pharmacy",
"address": {
"address1": "456 Market St",
"city": "San Francisco",
"state": "CA",
"zip": "94105"
},
"phone": "(415) 555-0456",
"email": "contact@downtownmedpharm.com",
"status": "active"
}
]
}
```
## Response Fields
### Top-Level Fields
* **success** (boolean): Whether the request was successful
* **pharmacies** (array): Array of pharmacy objects for the organization
### Pharmacy Object
* **id** (string): Cobalt pharmacy ID (UUID without dashes)
* **ehr\_id** (string): The pharmacy ID as it appears in the EMR system
* **ncpdp\_id** (string): The pharmacy's NCPDP ID (standard pharmacy identifier)
* **name** (string): Pharmacy name
* **address** (object): Pharmacy address information
* **address1** (string): Street address
* **city** (string): City name
* **state** (string): State abbreviation
* **zip** (string): ZIP code
* **phone** (string): Contact phone number
* **email** (string): Contact email address
* **status** (string): Pharmacy status - either "active" or "inactive"
# Get Providers
Source: https://docs.usecobalt.com/api-reference/providers/get
GET /providers
Returns a list of providers associated with a clinic.
### Understanding Provider IDs
Each provider has two identifiers:
* **`id`**: Cobalt's internal identifier (32-character UUID without hyphens)
* Use when updating provider settings like status or hours
* Operations: `PATCH /v1/providers/{id}`
* **`ehr_id`**: Your EMR system's provider identifier
* Use when creating appointments or other EMR operations
* Operations: `POST /v1/appointments` (`provider` field)
**Why two IDs?** Different operations work in different contexts. Provider management (updating status, hours) modifies Cobalt's cached configuration, while appointment creation communicates directly with your EMR. Cobalt uses its own IDs to manage provider settings independently of EMR constraints, then maps to EMR IDs when interacting with your EMR system.
**Quick Reference:**
* Updating provider settings → Use `id`
* Creating appointments → Use `ehr_id`
### Example Request
```bash theme={null}
curl -X GET https://api.usecobalt.com/v1/providers \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH'
```
To resolve a provider's Cobalt `id` from an EHR-native identifier you already hold (for example when setting `pcp_id` on a patient), filter by `ehr_id`:
```bash theme={null}
curl -X GET https://api.usecobalt.com/v1/providers \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-G \
--data-urlencode "ehr_id=99999"
```
### Example Response
```json theme={null}
{
"success": true,
"providers": [
{
"id": "abc123def4567890abcdef1234567890",
"ehr_id": "99999",
"timezone": "America/Phoenix",
"npi": "425345345",
"specialty": "Family Medicine",
"credentials": "MD",
"name": "Doe, John",
"status": "active",
"hide_in_availability": false,
"hours": [
{
"day": "Monday",
"shifts": [
{
"end": "T12:00:00",
"start": "T08:00:00",
"set_start_date": "2024-11-20",
"set_end_date": "2025-11-20",
"facility_id": "2",
"facility_name": "Acme Clinic",
"recurrence": {
"rec_start_date": "2024-11-20",
"recur_interval_type": "weeks",
"recur_interval_amount": 1,
"recur_interval_description": "Every 1 week."
},
"visit_type_rules": [
{
"end_time": "13:45:00",
"start_time": "13:00:00",
"total_visits": 1,
"visit_type_id": "NP",
"visit_type_desc": "New Patient"
},
]
},
{
"end": "T16:30:00",
"start": "T13:00:00"
}
]
},
]
}
]
}
```
### Response Parameters
#### Provider Fields
* **id**: Cobalt's internal provider identifier (used for updating provider settings)
* **ehr\_id**: EMR system's provider identifier (used for creating appointments)
* **timezone**: Provider's timezone
* **npi**: National Provider Identifier
* **name**: Provider's name
* **status**: Provider status (`active` or `inactive`)
* `active`: Provider's schedule will be synced from the EMR
* `inactive`: Provider's schedule will not be synced
* **hide\_in\_availability**: Whether provider is hidden from availability results (boolean, defaults to `false`)
* `false`: Provider appears in `/v1/availability` endpoint results (default behavior)
* `true`: Provider's schedule is synced but hidden from availability results
* **Use case**: Set to `true` when you want to continue syncing a provider's schedule (for reporting/historical purposes) but don't want them to appear as available for new appointments
* **Important**: For a provider to appear in availability, BOTH conditions must be true:
1. `active` must be `true` (schedule is being synced)
2. `hide_in_availability` must be `false` (not explicitly hidden)
#### Schedule Structure
* **Day**: Specifies which day of the week the schedule applies to
* **Shifts**: Array of work periods with:
* Start/end times using 24-hour format. Times are in the clinic's EMR timezone.
* Facility information (name and ID)
* Date range when the schedule is active (start date and optional end date. If there is no end date then the shift is active indefinitely).
* **Visit Type Rules** (optional):
* Pre-allocated slots for specific appointment types
* Each slot has its own start/end times
* Includes description and total allowed appointments
* **Recurrence** (optional):
* Defines repeating patterns (e.g., "every 2 weeks")
* Contains start date and interval information
* Allows for schedules that don't occur every week
# Update Provider
Source: https://docs.usecobalt.com/api-reference/providers/update
PATCH /providers/{id}
Updates a provider's status, working hours, and/or availability visibility.
**Use the Cobalt `id` in the URL path.** The `{id}` parameter should be the Cobalt provider ID (the `id` field from GET responses), not the `ehr_id`. If you prefer to use the EMR ID, see `PATCH /providers/ehr/{ehr_id}` instead.
### Example Request
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/providers/abc123def4567890abcdef1234567890 \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"status": "active",
"hours": [
{
"day": "Monday",
"shifts": [
{
"start": "T09:00:00",
"end": "T18:00:00",
"facility_id": "095f8067-d3fc-4e13-b771-32f87cd0c3f2",
"set_start_date": "2025-11-13T00:00:00",
"set_end_date": "2026-11-13T00:00:00"
}
]
},
{
"day": "Tuesday",
"shifts": [
{
"start": "T08:00:00",
"end": "T17:00:00",
"facility_id": "095f8067-d3fc-4e13-b771-32f87cd0c3f2",
"set_start_date": "2025-11-13T00:00:00",
"set_end_date": "2026-11-13T00:00:00"
}
]
}
]
}'
```
**Response:**
```json theme={null}
{
"success": true,
"message": "Provider status and hours updated successfully.",
"provider_id": "abc123def4567890abcdef1234567890"
}
```
### Request Body Parameters
You can update one or more of the following fields:
* **status** (string, optional): Provider's sync status
* `"active"`: Schedule will be synced from EMR
* `"inactive"`: Schedule will not be synced from EMR
* Status is case-insensitive ("active", "Active", "ACTIVE" are all accepted)
* **hide\_in\_availability** (string, optional): Controls whether provider is hidden from availability results
* `"false"`: Provider appears in `/v1/availability` endpoint (default behavior)
* `"true"`: Provider is hidden from `/v1/availability` endpoint
* **Common use case**: Set a provider to `"status": "active"` and `"hide_in_availability": "true"` to continue syncing their schedule (for reporting purposes) while hiding them from new appointment availability
* **hours** (array, optional): Provider's working schedule
* The `facility_id` must exist in your organization's locations
* The `facility_name` will be automatically enriched from the database
* Time format must be `THH:MM:SS` (e.g., `T08:00:00`)
* Dates must be in ISO 8601 format (e.g., `2025-11-13T00:00:00`)
* Days must be capitalized day names (Monday, Tuesday, etc.)
### Example: Hide Provider from Availability
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/providers/abc123def4567890abcdef1234567890 \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"status": "active",
"hide_in_availability": "true"
}'
```
**Response:**
```json theme={null}
{
"success": true,
"message": "Provider status and hide_in_availability updated successfully.",
"provider_id": "abc123def4567890abcdef1234567890"
}
```
# Update Provider by EMR ID
Source: https://docs.usecobalt.com/api-reference/providers/update-by-ehr
PATCH /providers/ehr/{ehr_id}
Updates a provider's status, working hours, and/or availability visibility using the EMR ID. This is an alternative to using Cobalt's internal provider ID.
### Example Request
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/providers/ehr/12345 \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"status": "active",
"hours": [
{
"day": "Monday",
"shifts": [
{
"start": "T09:00:00",
"end": "T18:00:00",
"facility_id": "095f8067-d3fc-4e13-b771-32f87cd0c3f2",
"set_start_date": "2025-11-13T00:00:00",
"set_end_date": "2026-11-13T00:00:00"
}
]
},
{
"day": "Tuesday",
"shifts": [
{
"start": "T08:00:00",
"end": "T17:00:00",
"facility_id": "095f8067-d3fc-4e13-b771-32f87cd0c3f2",
"set_start_date": "2025-11-13T00:00:00",
"set_end_date": "2026-11-13T00:00:00"
}
]
}
]
}'
```
**Response:**
```json theme={null}
{
"success": true,
"message": "Provider status and hours updated successfully.",
"provider_id": "abc123def4567890abcdef1234567890"
}
```
### Request Body Parameters
You can update one or more of the following fields:
* **status** (string, optional): Provider's sync status
* `"active"`: Schedule will be synced from EMR
* `"inactive"`: Schedule will not be synced from EMR
* Status is case-insensitive ("active", "Active", "ACTIVE" are all accepted)
* **hide\_in\_availability** (string, optional): Controls whether provider is hidden from availability results
* `"false"`: Provider appears in `/v1/availability` endpoint (default behavior)
* `"true"`: Provider is hidden from `/v1/availability` endpoint
* **Common use case**: Set a provider to `"status": "active"` and `"hide_in_availability": "true"` to continue syncing their schedule (for reporting purposes) while hiding them from new appointment availability
* **hours** (array, optional): Provider's working schedule
* The `facility_id` must exist in your organization's locations
* The `facility_name` will be automatically enriched from the database
* Time format must be `THH:MM:SS` (e.g., `T08:00:00`)
* Dates must be in ISO 8601 format (e.g., `2025-11-13T00:00:00`)
* Days must be capitalized day names (Monday, Tuesday, etc.)
### Example: Hide Provider from Availability
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/providers/ehr/12345 \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"status": "active",
"hide_in_availability": "true"
}'
```
**Response:**
```json theme={null}
{
"success": true,
"message": "Provider status and hide_in_availability updated successfully.",
"provider_id": "abc123def4567890abcdef1234567890"
}
```
# Create Recall
Source: https://docs.usecobalt.com/api-reference/recalls/create
POST /recalls
Creates a recall in the connected account's EMR.
Recalls are created asynchronously: a valid request returns immediately, and a `recall.created` or `recall.failed` webhook is sent when processing completes.
# Add Action to Recall
Source: https://docs.usecobalt.com/api-reference/recalls/create-action
POST /recalls/{id}/actions
Adds an action to an existing recall. A closing action closes the recall.
Actions are added asynchronously: a valid request returns immediately, and a `recall_action.created` or `recall_action.failed` webhook is sent when processing completes.
# Get Recalls
Source: https://docs.usecobalt.com/api-reference/recalls/list
GET /recalls
Lists recalls for the connected account.
# Update Recall
Source: https://docs.usecobalt.com/api-reference/recalls/update
PATCH /recalls/{id}
Changes a recall's status and/or adds a note.
# Create Referral
Source: https://docs.usecobalt.com/api-reference/referrals/create
POST /referrals
Queues a referral for creation in the provider's EMR system.
Referrals are created in the provider's EMR using an asynchronous processing model. Creating a referral this way is not instantaneous.
Instead of leaving your POST request hanging until completion, we immediately return a success response if the request is properly formed. We then notify you via a webhook when the referral has been created in the EMR.
This gives you flexibility around your user experience. For example, when you first make the `/referrals` call you can display a **Processing** status to your user, and when you receive the webhook notification you can update that to **Completed**.
### Request Parameters
#### Required Fields
* **patient\_mrn** (string, required): The patient's medical record number. The patient must already be synced to Cobalt.
* **referring\_from\_provider\_ehr\_id** (string, required): EMR ID of the provider the referral is coming **from**.
* **referring\_to\_provider\_ehr\_id** (string, required): EMR ID of the provider the referral is going **to**.
* **direction** (string, required): Direction of the referral — `incoming` or `outgoing`.
* **priority** (string, required): Referral priority — `routine`, `urgent`, or `stat`.
* **reason** (string, required): Reason for the referral.
#### Optional Fields
* **diagnosis\_codes** (array of strings, optional): ICD-10 diagnosis codes associated with the referral.
* **documents** (array, optional): Documents to attach to the referral in the EMR. Each entry is an object with `filename` and `content_base64`. See [Attaching Documents](#attaching-documents) below.
* **prior\_authorization\_code** (string, optional): Prior authorization code to write on the referral.
* **specialty** (string, optional): Referral specialty name — e.g. `"Cardiology"`. Resolved against the EMR instance's live specialty list when the referral is processed; an unrecognized specialty fails with a `referral.failed` webhook (`error_type: "ecw_validation_failure"`).
* **location\_id** (string, optional): EMR location ID of the facility being referred to. Validated **synchronously** against the account's synced locations — an unknown location returns a `404` and the referral is not queued. Resolve IDs with [`GET /v1/locations`](/api-reference/locations/get) (use the location's `emr_id`).
### Direction and Provider Validation
The two provider IDs are validated against different directories depending on the referral's `direction`:
| Direction | `referring_from_provider_ehr_id` validated against | `referring_to_provider_ehr_id` validated against |
| - | - | - |
| `incoming` | Referring providers directory | Providers directory |
| `outgoing` | Providers directory | Referring providers directory |
Pass `0` for a provider ID when there is no provider on that side. Providers must already be synced — use `GET /v1/providers` and `GET /v1/referring-providers` to resolve IDs.
### Attaching Documents
Documents are optional and supplied inline as base64. Each document is an object:
```json theme={null}
{
"filename": "consult-note.pdf",
"content_base64": "JVBERi0xLjQKJ..."
}
```
* **filename** must include a file extension (e.g. `report.pdf`).
* **content\_base64** must be non-empty, valid base64.
Documents are attached to the referral in the EMR **after** the referral itself is created. Because the referral already exists at that point, attachment failures are non-fatal: the referral is still created and the webhook reports how many attachments succeeded and failed.
Requests carrying inline documents can be large. The `POST /v1/referrals` endpoint accepts request bodies up to 25 MB.
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/referrals \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"patient_mrn": "1234567",
"referring_from_provider_ehr_id": "PROV-001",
"referring_to_provider_ehr_id": "PROV-002",
"direction": "outgoing",
"priority": "urgent",
"reason": "Cardiology consultation",
"diagnosis_codes": ["I10", "Z87.39"]
}'
```
#### Request with Documents
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/referrals \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"patient_mrn": "1234567",
"referring_from_provider_ehr_id": "PROV-001",
"referring_to_provider_ehr_id": "PROV-002",
"direction": "outgoing",
"priority": "routine",
"reason": "Dermatology referral",
"documents": [
{ "filename": "consult-note.pdf", "content_base64": "JVBERi0xLjQKJ..." }
]
}'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Referral queued for creation. A webhook event will be sent upon completion.",
"referral_id": "123e4567e89b12d3a456426614174000",
"job_id": 12345
}
```
The response includes:
* **referral\_id**: Cobalt referral ID (UUID without dashes). This is echoed back in the webhook payload so you can correlate the two.
* **job\_id**: Job execution identifier for tracking the async operation.
### Error Responses
#### Missing Required Field
```json theme={null}
{
"success": false,
"message": "Missing required fields: patient_mrn, reason."
}
```
#### Invalid Priority
```json theme={null}
{
"success": false,
"message": "Invalid priority. Must be one of: routine, urgent, stat."
}
```
#### Invalid Direction
```json theme={null}
{
"success": false,
"message": "Invalid direction. Must be one of: incoming, outgoing."
}
```
#### Invalid Document
```json theme={null}
{
"success": false,
"message": "documents[0].filename must include a file extension (e.g. \"report.pdf\")."
}
```
#### Patient Not Found
```json theme={null}
{
"success": false,
"message": "Patient with MRN '1234567' not found. Ensure the patient has been synced."
}
```
#### Unknown Provider
```json theme={null}
{
"success": false,
"message": "Unknown provider(s): referring_to_provider_ehr_id 'PROV-002' was not found in referring providers. Ensure the provider has been synced."
}
```
#### Unknown Location
Returned when `location_id` does not match a synced location for the account.
```json theme={null}
{
"success": false,
"message": "Location with EMR ID '99999' not found. Ensure the location has been synced."
}
```
#### User Not Found
```json theme={null}
{
"success": false,
"message": "User not found."
}
```
This indicates an issue with your access token.
### Webhook Notifications
When the referral has finished processing, we send a webhook to your registered endpoint.
#### Success
```json theme={null}
{
"id": "",
"access_token_reference_id": "",
"object": "event",
"created": "2026-03-10T10:30:00.000Z",
"type": "referral.created",
"job_id": "12345",
"data": {
"referral_id": "123e4567e89b12d3a456426614174000",
"ehr_id": "REF-00123",
"patient_mrn": "1234567",
"from_provider_ehr_id": "PROV-001",
"to_provider_ehr_id": "PROV-002",
"direction": "outgoing",
"documents_attached": 1,
"documents_failed": 0
}
}
```
Note: `documents_attached` and `documents_failed` are only included when the request contained documents.
#### Failure
```json theme={null}
{
"id": "",
"access_token_reference_id": "",
"object": "event",
"created": "2026-03-10T10:35:00.000Z",
"type": "referral.failed",
"job_id": "12345",
"data": {
"referral_id": "123e4567e89b12d3a456426614174000",
"patient_mrn": "1234567",
"failure_reason": "Unable to create referral in eCW. ECW rejected the request or returned an unexpected response."
}
}
```
# Get Referrals
Source: https://docs.usecobalt.com/api-reference/referrals/get
GET /referrals
Retrieve referrals from the Cobalt database for a specified date range.
## Query Parameters
* **start\_date** (string, required): Start of the date range in ISO format (YYYY-MM-DD)
* **end\_date** (string, required): End of the date range in ISO format (YYYY-MM-DD)
* **patient\_mrn** (string, optional): Filter by patient MRN
* **status** (string, optional): Filter by referral status
* **priority** (string, optional): Filter by priority — `routine`, `urgent`, or `stat`
* **direction** (string, optional): Filter by referral direction — `incoming` or `outgoing`
* **ehr\_id** (string, optional): Filter by the referral's EMR ID
* **receiving\_line** (string, optional): Filter by the receiving line — the fax number that received the document. Accepts any format; the value is canonicalized to E.164 before matching.
* **page** (integer, optional): Page number (default: 1)
* **page\_size** (integer, optional): Results per page, max 100 (default: 100)
* **sort** (string, optional): Sort order — pass `created_at` for ascending, defaults to descending by referral date
## Example Request
```bash theme={null}
curl -X GET "https://api.usecobalt.com/v1/referrals?start_date=2026-03-01&end_date=2026-03-31" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token"
```
## Example Response
```json theme={null}
{
"success": true,
"referrals": [
{
"id": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
"ehr_id": "REF-00123",
"patient_ehr_id": "PAT-456",
"patient_mrn": "1234567",
"patient_first_name": "Jane",
"patient_last_name": "Smith",
"patient_dob": "1985-03-15",
"from_provider_ehr_id": "PROV-001",
"from_provider_name": "Dr. John Doe",
"to_provider_ehr_id": "PROV-002",
"to_provider_name": "Dr. Sarah Lee",
"priority": "urgent",
"urgency": "urgent",
"reason": "Cardiology consultation",
"prior_authorization_code": "AUTH-12345",
"specialty": "Cardiology",
"to_facility_name": "Example Regional Hospital",
"diagnosis_codes": ["I10", "Z87.39"],
"document_ids": ["b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5"],
"direction": "incoming",
"receiving_line": "+12345678901",
"status": "pending",
"referral_date": "2026-03-10T00:00:00.000Z",
"last_activity_at": "2026-03-11T14:30:00.000Z",
"synced_at": "2026-03-11T14:35:00.000Z"
}
],
"pagination": {
"page": 1,
"page_size": 100,
"total_count": 1,
"total_pages": 1
}
}
```
## Response Fields
### Top-Level Fields
* **success** (boolean): Whether the request was successful
* **referrals** (array): Array of referral objects
* **pagination** (object): Pagination metadata
### Referral Object
* **id** (string): Cobalt referral ID (UUID without dashes)
* **ehr\_id** (string): The referral ID as it appears in the EMR
* **patient\_ehr\_id** (string, nullable): The patient's EMR ID
* **patient\_mrn** (string, nullable): Patient medical record number
* **patient\_first\_name** (string, nullable): Patient first name
* **patient\_last\_name** (string, nullable): Patient last name
* **patient\_dob** (string, nullable): Patient date of birth
* **from\_provider\_ehr\_id** (string, nullable): EMR ID of the referring provider
* **from\_provider\_name** (string, nullable): Name of the referring provider
* **to\_provider\_ehr\_id** (string, nullable): EMR ID of the provider being referred to
* **to\_provider\_name** (string, nullable): Name of the provider being referred to
* **priority** (string, nullable): Referral priority — `routine`, `urgent`, or `stat`
* **urgency** (string, nullable): Urgency designation as recorded in the EMR
* **reason** (string, nullable): Reason for the referral
* **prior\_authorization\_code** (string, nullable): Prior authorization code recorded on the referral
* **specialty** (string, nullable): Referral specialty
* **to\_facility\_name** (string, nullable): Name of the facility the referral is directed to
* **diagnosis\_codes** (array): ICD-10 diagnosis codes associated with the referral
* **document\_ids** (array): Cobalt IDs of attached documents (UUIDs without dashes)
* **direction** (string, nullable): Referral direction — `incoming` or `outgoing`
* **receiving\_line** (string, nullable): The receiving line — the fax number that received the document — in E.164 format (e.g. `+12345678901`).
* **status** (string, nullable): Current referral status
* **referral\_date** (string, nullable): Date the referral was created (ISO 8601)
* **last\_activity\_at** (string, nullable): Timestamp of the most recent activity on the referral (ISO 8601)
* **synced\_at** (string, nullable): Timestamp of the last sync from the EMR (ISO 8601)
## Notes
* This endpoint returns referrals from the Cobalt database. Data is updated during scheduled syncs.
# Update Referral
Source: https://docs.usecobalt.com/api-reference/referrals/update
PATCH /referrals/{id}
Queues an update to an existing referral in the provider's EMR system.
Referrals are updated in the provider's EMR using the same asynchronous processing model as [creation](/api-reference/referrals/create). The update is not instantaneous.
Instead of leaving your PATCH request hanging until completion, we immediately return a success response if the request is properly formed. We then notify you via a webhook when the update has been applied in the EMR.
### Path Parameter
* **id** (string, required): The Cobalt referral ID (UUID) returned by [Create Referral](/api-reference/referrals/create) or [Get Referrals](/api-reference/referrals/get). The referral must already exist and have been created in the EMR.
### Request Parameters
Supply **one or more** of the following fields. Omitted fields are left unchanged in the EMR — this is a partial update.
* **priority** (string, optional): Referral priority — `routine`, `urgent`, or `stat`. Case-insensitive: `"Routine"`, `"URGENT"`, and `"stat"` are all accepted and normalized.
* **status** (string, optional): Referral status label — e.g. `"Open"`, `"Pending"`, `"Internal Review"`, `"Insurance Auth"`, `"Addressed"`. See [Status Values](#status-values) below.
* **reason** (string, optional): Reason for the referral.
* **notes** (string, optional): Free-text notes on the referral.
* **prior\_authorization\_code** (string, optional): Prior authorization code to write on the referral.
* **specialty** (string, optional): Referral specialty name — e.g. `"Cardiology"`. See [Specialty](#specialty) below.
* **location\_id** (string, optional): EMR location ID of the facility the referral is directed to. See [To Facility](#to-facility) below.
At least one updatable field must be present. An empty body returns a `400`.
### Status Values
The set of valid statuses — and their exact labels — is **specific to each EMR instance and organization**, not a fixed global list. When you PATCH a `status`, the value is resolved against that instance's live status list at processing time.
Because of this, you can pass a human-friendly, title-cased label with spaces (e.g. `"Internal Review"`) regardless of how the status is stored internally in the EMR. Matching is case- and spacing-insensitive.
If the supplied status does not match any status configured for the instance, the update fails and a `referral.failed` webhook is sent with `error_type: "ecw_validation_failure"`.
To discover which statuses an instance supports, inspect the `status` field returned by [Get Referrals](/api-reference/referrals/get) for existing referrals.
### Specialty
Pass **specialty** as the human-friendly specialty name (e.g. `"Cardiology"`, `"Sport Medicine"`). The name is resolved against the EMR instance's live specialty list at processing time, so the exact set of valid names is instance/organization specific.
If the supplied specialty does not match any specialty configured for the instance, the update fails and a `referral.failed` webhook is sent with `error_type: "ecw_validation_failure"`.
### To Facility
Pass **location\_id** as the EMR location ID of the facility the referral is directed to. It is validated **synchronously** against the account's synced locations — an unknown location returns a `404` and no update is queued.
Resolve location IDs with [`GET /v1/locations`](/api-reference/locations/get); use the location's `emr_id` value.
### Example Request
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/referrals/123e4567e89b12d3a456426614174000 \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"priority": "urgent",
"status": "Internal Review",
"reason": "Updated cardiology consultation",
"notes": "Patient called to confirm availability.",
"prior_authorization_code": "AUTH-12345",
"specialty": "Cardiology",
"location_id": "loc-123"
}'
```
#### Update a Single Field
```bash theme={null}
curl -X PATCH https://api.usecobalt.com/v1/referrals/123e4567e89b12d3a456426614174000 \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{ "status": "Addressed" }'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Referral queued for update. A webhook event will be sent upon completion.",
"referral_id": "123e4567e89b12d3a456426614174000",
"job_id": 12345
}
```
The response includes:
* **referral\_id**: Cobalt referral ID (UUID without dashes). Echoed back in the webhook payload so you can correlate the two.
* **job\_id**: Job execution identifier for tracking the async operation.
### Error Responses
#### Invalid Priority
```json theme={null}
{
"success": false,
"message": "Invalid priority. Must be one of: routine, urgent, stat (case-insensitive)."
}
```
#### Invalid Status
```json theme={null}
{
"success": false,
"message": "Invalid status. Must be a non-empty string."
}
```
#### No Updatable Fields
```json theme={null}
{
"success": false,
"message": "No updatable fields provided. Supply at least one of: priority, status, reason, notes, prior_authorization_code, specialty, location_id."
}
```
#### Unexpected Fields
```json theme={null}
{
"success": false,
"message": "Unexpected fields in request body: foo. Updatable fields are: priority, status, reason, notes, prior_authorization_code, specialty, location_id."
}
```
#### Unknown Location
Returned when `location_id` does not match a synced location for the account. Validated synchronously, so no update is queued.
```json theme={null}
{
"success": false,
"message": "Location with EMR ID '99999' not found. Ensure the location has been synced."
}
```
#### Invalid Referral ID
```json theme={null}
{
"success": false,
"message": "Invalid referral ID format. Must be a valid UUID."
}
```
#### Referral Not Yet in the EMR
```json theme={null}
{
"success": false,
"message": "Referral has not been created in the EMR yet and cannot be updated."
}
```
#### Referral Not Found
```json theme={null}
{
"success": false,
"message": "Referral not found."
}
```
### Webhook Notifications
When the update has finished processing, we send a webhook to your registered endpoint.
#### Success
```json theme={null}
{
"id": "",
"access_token_reference_id": "",
"object": "event",
"created": "2026-03-10T10:30:00.000Z",
"type": "referral.updated",
"job_id": "12345",
"data": {
"referral_id": "123e4567e89b12d3a456426614174000",
"ehr_id": "REF-00123",
"patient_mrn": "1234567",
"direction": "outgoing",
"updated_fields": ["priority", "status", "specialty", "location_id"]
}
}
```
`updated_fields` lists the fields that were applied in this update.
#### Failure
```json theme={null}
{
"id": "",
"access_token_reference_id": "",
"object": "event",
"created": "2026-03-10T10:35:00.000Z",
"type": "referral.failed",
"job_id": "12345",
"data": {
"referral_id": "123e4567e89b12d3a456426614174000",
"patient_mrn": "1234567",
"failure_reason": "The status \"Foo\" is not a valid status for this eCW instance.",
"error_type": "ecw_validation_failure"
}
}
```
`error_type` is only present for validation failures (e.g. an unrecognized status or specialty). Other failures omit it.
# Create Referring Provider
Source: https://docs.usecobalt.com/api-reference/referring-providers/create
POST /referring-providers
Creates a new referring provider record in your EMR system.
### Request Parameters
#### Required Fields
* **first\_name** (string, required): Provider's first name
* **last\_name** (string, required): Provider's last name
* **npi** (string, required): National Provider Identifier
#### Optional Fields
* **phone** (string): Contact phone number in XXX-XXX-XXXX format
* **fax** (string): Fax number in XXX-XXX-XXXX format
* **email** (string): Contact email address
* **address** (string): Street address
* **city** (string): City name
* **state** (string): State abbreviation (e.g., "IL", "CA")
* **zip\_code** (string): ZIP code
### Phone and Fax Format
Phone and fax numbers must be provided in **XXX-XXX-XXXX** format. If the format is incorrect, you will receive a 400 error.
```json theme={null}
// Valid
"phone": "312-555-1234"
// Invalid
"phone": "3125551234"
"phone": "(312) 555-1234"
```
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/referring-providers \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"first_name": "John",
"last_name": "Smith",
"npi": "1234567890",
"phone": "312-555-1234",
"fax": "312-555-5678",
"email": "john.smith@example.com",
"address": "123 Main St",
"city": "Chicago",
"state": "IL",
"zip_code": "60601"
}'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Referring provider processing. A webhook event will be sent upon completion.",
"referring_provider_id": "e35e82b85df58f08a9b38e06a91e9f1a",
"job_id": 12345
}
```
The response includes:
* **referring\_provider\_id**: Unique identifier for the created referring provider record (UUID without dashes)
* **job\_id**: Job execution identifier for tracking the async operation
### Error Responses
#### Missing Required Field
```json theme={null}
{
"success": false,
"message": "Missing required fields: npi."
}
```
#### Invalid Phone Format
```json theme={null}
{
"success": false,
"message": "Phone number must be in XXX-XXX-XXXX format."
}
```
#### Invalid Fax Format
```json theme={null}
{
"success": false,
"message": "Fax number must be in XXX-XXX-XXXX format."
}
```
### Webhook Notifications
When the referring provider 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_1J9X2q2eZvKYlo2CluR9g9gV",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2025-01-18T10:30:00Z",
"type": "referring_provider.created",
"job_id": "12345",
"data": {
"referring_provider_id": "e35e82b85df58f08a9b38e06a91e9f1a",
"ehr_id": "350143",
"first_name": "John",
"last_name": "Smith",
"npi": "1234567890"
}
}
```
#### Failure - Invalid NPI
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2CluR9g9gW",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2025-01-18T10:35:00Z",
"type": "referring_provider.failed",
"job_id": "12345",
"data": {
"referring_provider_id": "e35e82b85df58f08a9b38e06a91e9f1a",
"first_name": "John",
"last_name": "Smith",
"npi": "1234567890",
"failure_reason": "Invalid NPI: 1234567890. The NPI number is not valid.",
"error_type": "invalid_npi"
}
}
```
#### Failure - EMR Validation Error
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2CluR9g9gX",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2025-01-18T10:40:00Z",
"type": "referring_provider.failed",
"job_id": "12345",
"data": {
"referring_provider_id": "e35e82b85df58f08a9b38e06a91e9f1a",
"first_name": "John",
"last_name": "Smith",
"npi": "1234567890",
"failure_reason": "Unable to create referring provider in eCW. ECW rejected the request. Please verify all required fields are provided and the provider doesn't already exist.",
"error_type": "ecw_validation_failure"
}
}
```
#### Failure - Other Errors
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2CluR9g9gY",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2025-01-18T10:45:00Z",
"type": "referring_provider.failed",
"job_id": "12345",
"data": {
"referring_provider_id": "e35e82b85df58f08a9b38e06a91e9f1a",
"first_name": "John",
"last_name": "Smith",
"npi": "1234567890",
"failure_reason": "Failed to create referring provider"
}
}
```
Referring provider creation is asynchronous. Store the returned referring\_provider\_id and listen for webhooks to determine the final status.
## Usage with Patient Creation
Once created, you can use the `referring_provider_id` when creating patients instead of providing referring provider names. See the [Create Patient](/api-reference/patients/create) documentation for details on using `referring_provider_id`.
## Notes
* NPI validation is performed by the EMR system
* Some EMRs may reject duplicate providers with the same NPI
* Phone and fax numbers are normalized before being sent to the EMR
* The `ehr_id` returned in the success webhook is the provider's ID in your EMR system
# Get Referring Providers
Source: https://docs.usecobalt.com/api-reference/referring-providers/get
GET /referring-providers
Retrieve referring providers from the EMR system for your organization.
## Query Parameters
All parameters are optional and can be combined to filter results:
* **first\_name** (string): Filter by first name (case-insensitive, partial match)
* **last\_name** (string): Filter by last name (case-insensitive, partial match)
* **phone** (string): Filter by phone number (accepts any format, e.g., "7734722936" or "773-472-2936")
* **fax** (string): Filter by fax number (accepts any format)
* **npi** (string): Filter by NPI (exact match)
* **emr\_referring\_provider\_id** (string): Filter by the referring provider's EMR ID (exact match). Use this to resolve a referring provider's Cobalt `id` (for `pcp_id`) from the EMR ID you already hold.
## Example Requests
### Get All Referring Providers
```bash theme={null}
curl -X GET "https://api.usecobalt.com/v1/referring-providers" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token"
```
### Filter by Last Name
```bash theme={null}
curl -X GET "https://api.usecobalt.com/v1/referring-providers?last_name=smith" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token"
```
### Filter by NPI
```bash theme={null}
curl -X GET "https://api.usecobalt.com/v1/referring-providers?npi=1780690362" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token"
```
### Filter by Phone
```bash theme={null}
curl -X GET "https://api.usecobalt.com/v1/referring-providers?phone=773-472-2936" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token"
```
### Resolve Cobalt id from EMR ID (for pcp\_id)
```bash theme={null}
curl -X GET "https://api.usecobalt.com/v1/referring-providers?emr_referring_provider_id=350143" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token"
```
## Example Response
```json theme={null}
{
"success": true,
"referring_providers": [
{
"id": "e35e82b85df58f08a9b38e06a91e9f1a",
"ehr_id": "350143",
"first_name": "jane",
"last_name": "Doe",
"middle_initial": null,
"speciality": "Primary Care Doctor",
"phone": "222-333-4444",
"fax": "222-333-4444",
"email": null,
"npi": "98374982374",
"address_street": "3336 N Main AVE",
"address_city": "Main",
"address_state": "IL",
"address_zip": "22333"
},
]
}
```
## Response Fields
### Top-Level Fields
* **success** (boolean): Whether the request was successful
* **referring\_providers** (array): Array of referring provider objects for the organization
### Referring Provider Object
* **id** (string): Cobalt referring provider ID (UUID without dashes)
* **ehr\_id** (string): The referring provider ID as it appears in the EMR system
* **name** (string): Full name (typically formatted as "LASTNAME,FIRSTNAME")
* **first\_name** (string): Provider's first name
* **last\_name** (string): Provider's last name
* **middle\_initial** (string, nullable): Provider's middle initial
* **speciality** (string, nullable): Medical speciality (e.g., "Cardiology", "Primary Care Doctor")
* **phone** (string, nullable): Contact phone number in format XXX-XXX-XXXX
* **fax** (string, nullable): Fax number in format XXX-XXX-XXXX
* **email** (string, nullable): Contact email address
* **npi** (string, nullable): National Provider Identifier
* **address\_street** (string, nullable): Street address
* **address\_city** (string, nullable): City name
* **address\_state** (string, nullable): State abbreviation
* **address\_zip** (string, nullable): ZIP code
## Notes
* All referring providers returned are active in the system
* Phone and fax numbers are normalized to XXX-XXX-XXXX format
* Search filters are applied as partial matches (except NPI which is exact)
* Results are ordered by last name, then first name alphabetically
# Get Settings
Source: https://docs.usecobalt.com/api-reference/settings/get
GET /settings
Returns the current settings for the associated access token.
### Example Request
```bash theme={null}
curl -X GET https://api.usecobalt.com/v1/settings \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH'
```
### Example Response
```json theme={null}
{
"success": true,
"data": {
"access_token_reference_id": "at_ref_123456789",
"visit_types": [
{
"code": "new_patient",
"description": "New Patient Visit (in-person)"
},
{
"code": "televisit1",
"description": "televisit1 (televisit / osa)"
}
],
"visit_statuses": [
{
"code": "CANC",
"description": "Cancelled in advance"
},
{
"code": "R/S",
"description": "Rescheduled"
}
],
"required_patient_fields": [
"first_name",
"last_name",
"dob",
"sex"
],
"timezone": "America/New_York",
"staff_list": [
{
"ehr_id": "12220",
"name": "Smith,Jane"
},
{
"ehr_id": "12241",
"name": "Doe,John"
}
],
"departments": [
{
"ehr_id": "1",
"name": "MEDICAL",
"type": "MED",
"location_ehr_id": "12"
},
{
"ehr_id": "2",
"name": "BEHAVIORAL HEALTH",
"type": "MED",
"location_ehr_id": "12"
},
{
"ehr_id": "5",
"name": "RADIOLOGY",
"type": "MED",
"location_ehr_id": "17"
}
]
}
}
```
Settings include the access token reference ID, available visit types (with codes and descriptions), and the user's timezone. If settings are not found for the user, a 404 error will be returned.
# Update Settings
Source: https://docs.usecobalt.com/api-reference/settings/update
POST /settings
Updates the settings for the associated access token.
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/settings \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"access_token_reference_id": "at_ref_123456789"
}'
```
### Example Response
```json theme={null}
{
"success": true,
"data": {
"access_token_reference_id": "at_ref_123456789"
}
}
```
The `access_token_reference_id` is required in the request body. No other fields are accepted.
# Get Staff
Source: https://docs.usecobalt.com/api-reference/staff/get
GET /staff
Returns the staff synced for the account.
### Example Request
```bash theme={null}
curl -X GET https://api.usecobalt.com/v1/staff \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH'
```
### Example Response
```json theme={null}
{
"success": true,
"data": [
{
"ehr_id": "12220",
"name": "Smith,Jane"
},
{
"ehr_id": "12241",
"name": "Doe,John"
}
]
}
```
Use an entry's `ehr_id` wherever a request takes a staff ID, such as `assigned_to_id`.
# Get Last Schedule Sync
Source: https://docs.usecobalt.com/api-reference/system/last-schedule-sync
GET /last-schedule-sync
Retrieves the timestamp of the last successful schedule synchronization.
### Example Request
```bash theme={null}
curl -X GET https://api.usecobalt.com/v1/last-schedule-sync \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH'
```
### Example Response
```json theme={null}
{
"success": true,
"last_sync": {
"timestamp": "2025-01-24T15:11:05.117-06:00"
}
}
```
# Create Task
Source: https://docs.usecobalt.com/api-reference/tasks/create
POST /tasks
Creates a task in the provider's EMR system.
Depending on the EMR system connected to the account, additional fields beyond
the base required fields may be required. If a conditionally required field is
missing, the API will return a `400` error specifying the missing field.
### Request Parameters
#### Required Fields
These fields are always required regardless of the connected EMR:
* **description** (string, required): Task description/body content
* **patient\_mrn** (string, required): Medical Record Number (MRN) of the patient
#### Conditionally Required Fields
Depending on the connected EMR, some combination of the following fields will also be required:
* **subject** (string, conditionally required): Task title/subject line
* **assignee\_user\_id** (string, conditionally required): EMR user ID to assign the task to
* **phone\_call\_type\_id** (string, conditionally required): Identifier for the phone call type
* **notify\_list** (string\[], optional): List of user identifiers to notify about the task. Must be an array of strings if provided.
### Example Requests
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/tasks \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"description": "Schedule patient follow-up appointment to review recent lab results and discuss treatment plan.",
"patient_mrn": "MRN-12345",
"subject": "Follow-up appointment needed",
"assignee_user_id": "74196090-5faa-11e9-9562-e12f6a3ce827"
}'
```
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/tasks \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"description": "Patient called requesting prescription refill for lisinopril 10mg.",
"patient_mrn": "MRN-67890",
"phone_call_type_id": "rx_refill",
"notify_list": ["user_001", "user_002"]
}'
```
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/tasks \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"description": "Patient reports side effects from new medication; please review.",
"patient_mrn": "MRN-24680",
"task_type": "Prescribe",
"details": "Medication",
"assigned_to": "4840",
"facility_id": "5954",
"due_date": "2026-11-25"
}'
```
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/tasks \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"patient_mrn": "MRN-13579",
"subject": "Add pharmacy",
"assigned_to": "152925",
"description": "Confirm preferred pharmacy on file.",
"due_date": "2026-11-25",
"start_date": "2026-11-18",
"priority": "Normal"
}'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Task processing. A webhook event will be sent upon completion.",
"task_id": "abc123def456789012345678",
"job_id": 12345
}
```
The response includes:
* **task\_id**: Unique identifier for the created task record
* **job\_id**: Job execution identifier for tracking the async operation
### Error Responses
#### Missing Required Field
If a required or conditionally required field is missing, the API returns a `400` with the specific field name:
```json theme={null}
{
"success": false,
"message": "Missing required field: description"
}
```
#### User Not Found
```json theme={null}
{
"success": false,
"message": "User not found."
}
```
### Webhook Notifications
When the task 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_1J9X2q2eZvKYlo2CluR9g9gV",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2025-10-09T10:30:00Z",
"type": "task.created",
"job_id": "12345",
"data": {
"task_id": "abc123def456789012345678",
"emr_task_id": "task_emr_internal_id",
"subject": "Follow-up appointment needed",
"description": "Schedule patient follow-up appointment to review recent lab results and discuss treatment plan.",
"assignee_user_id": "74196090-5faa-11e9-9562-e12f6a3ce827",
"patient_mrn": "MRN-12345"
}
}
```
#### Failure
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2CluR9g9gW",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2025-10-09T10:35:00Z",
"type": "task.failed",
"job_id": "12345",
"data": {
"task_id": "abc123def456789012345678",
"failure_reason": "Failed to create task"
}
}
```
# Create Task Note
Source: https://docs.usecobalt.com/api-reference/tasks/notes/create
POST /tasks/notes
Appends a note to an existing task in the provider's EMR system.
This endpoint appends a note to a task that already exists in the EMR. To find a task's `emr_task_id`, perform a live fetch with `POST /v1/patients/fetch` and `include: ["tasks"]` — each task in the response carries its `emr_task_id`.
### Request Parameters
* **emr\_task\_id** (string, required): The EMR ID of the task to append the note to. Obtain this from the `tasks[]` array returned by `POST /v1/patients/fetch` with `include: ["tasks"]`.
* **note** (string, required): The note body content.
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/tasks/notes \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"emr_task_id": "9bef4113-e9ce-4895-9a17-2c18cd625116",
"note": "Patient called back, scheduled for next week."
}'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Task note processing. A webhook event will be sent upon completion.",
"task_note_id": "abc123def456789012345678",
"job_id": 12345
}
```
The response includes:
* **task\_note\_id**: Unique identifier for the created task note record
* **job\_id**: Job execution identifier for tracking the async operation
### Error Responses
#### Missing Required Field
```json theme={null}
{
"success": false,
"message": "Missing required field: emr_task_id"
}
```
#### Unexpected Field
Only `emr_task_id` and `note` are accepted. Any other field returns a `400`:
```json theme={null}
{
"success": false,
"message": "Unexpected fields in request body: subject"
}
```
### Webhook Notifications
When the task note processing is complete, we will send a webhook to your registered endpoint.
#### Success
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2CluR9g9gV",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2026-06-15T12:02:40Z",
"type": "task_note.created",
"job_id": "12345",
"data": {
"task_note_id": "abc123def456789012345678",
"emr_note_id": "f862b0a0-d820-418c-9e30-412bb62bde34",
"emr_task_id": "9bef4113-e9ce-4895-9a17-2c18cd625116",
"note": "Patient called back, scheduled for next week."
}
}
```
#### Failure
```json theme={null}
{
"id": "evt_1J9X2q2eZvKYlo2CluR9g9gW",
"access_token_reference_id": "user_1J9X2q2eZvKYlo2Cxyz",
"object": "event",
"created": "2026-06-15T12:05:00Z",
"type": "task_note.failed",
"job_id": "12345",
"data": {
"task_note_id": "abc123def456789012345678",
"failure_reason": "Failed to create task note"
}
}
```
# Create Telephone Encounter
Source: https://docs.usecobalt.com/api-reference/telephone-encounters/create
POST /telephone-encounters
Creates a telephone encounter record in the provider's EMR system.
Telephone encounters are created in the provider's EMR using an asynchronous processing model. Creating telephone encounters this way is not instantaneous.
Instead of leaving your POST request hanging until completion, we immediately return a success response if the request is properly formed. We then notify you via a webhook when the telephone encounter processing has completed.
This gives you flexibility around your user experience. For example, when you first make the `/telephone-encounters` call you can display a **Processing** status to your user and when you get the webhook notification you can update that to **Completed**.
### Request Parameters
#### Required Fields
* **patient\_mrn** (string, required): Patient's Medical Record Number
* **provider\_id** (string, required): Provider's EMR ID
* **location\_id** (string, required): Location's EMR ID
* **assigned\_to\_id** (string, required): EMR user ID of the staff member the encounter is assigned to. This can be any staff member in your organization (provider, nurse, front desk), not just providers. Valid IDs are the `ehr_id` values returned by `GET /v1/staff`.
#### Optional Fields
* **reason** (string, optional, max 50 characters): Reason for telephone encounter
* **refill\_medication\_name** (string, optional, 2-50 characters): Name of medication to refill. If provided, the system will search for a matching medication in the patient's available refillable medications and add it to the encounter. The medication name is matched case-insensitively and supports partial matches.
* **pharmacy\_ehr\_id** (string, optional): Pharmacy's EMR ID. If provided, the pharmacy must exist in your organization's pharmacy list (validate via GET /v1/pharmacies). When used with a medication refill, the pharmacy will be associated with the encounter. If the pharmacy is not already in the patient's pharmacy list, it will be added automatically.
* **caller** (string, optional, max 100 characters): Name of the person who called
* **message** (string, optional): Message content from the caller
* **is\_high\_priority** (string, optional): Whether this encounter should be marked as high priority. Must be "true" or "false".
* **template\_name** (string, optional): The template name to use when filling out the document upload form.
### Medication Refill Behavior
When `refill_medication_name` is provided:
1. **Medication Search**: The system searches the patient's available medications for a match
2. **Filtering**: Only refillable medications that are available for the patient are considered
3. **Matching**: Medication names are matched case-insensitively with partial name support
4. **Success**: If found, the encounter is created and the medication refill is added to it
5. **Failure**: If the medication is not found, the encounter is NOT created and an error is returned with a list of available medications
### Example Request
#### Basic Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/telephone-encounters \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"patient_mrn": "MRN-123456",
"provider_id": "12241",
"location_id": "25",
"assigned_to_id": "12220",
"reason": "Follow up on test results"
}'
```
#### Request with Medication Refill
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/telephone-encounters \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"patient_mrn": "MRN-123456",
"provider_id": "12241",
"location_id": "25",
"assigned_to_id": "12220",
"reason": "Prescription refill",
"refill_medication_name": "Lisinopril",
"pharmacy_ehr_id": "1643"
}'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Telephone encounter processing. A webhook event will be sent upon completion.",
"telephone_encounter_id": "123e4567e89b12d3a456426614174000",
"job_id": 12345
}
```
The response includes:
* **telephone\_encounter\_id**: Unique identifier for the created telephone encounter record
* **job\_id**: Job execution identifier for tracking the async operation
### Error Responses
#### Missing Required Field
```json theme={null}
{
"success": false,
"message": "Missing required field: patient_mrn"
}
```
Possible missing fields: `patient_mrn`, `provider_id`, `location_id`, `assigned_to_id`
#### Reason Too Long
```json theme={null}
{
"success": false,
"message": "Reason exceeds maximum length of 50 characters"
}
```
#### Medication Name Invalid Length
```json theme={null}
{
"success": false,
"message": "refill_medication_name must be at least 2 characters"
}
```
```json theme={null}
{
"success": false,
"message": "refill_medication_name exceeds maximum length of 50 characters"
}
```
#### Provider Not Found
```json theme={null}
{
"success": false,
"message": "Provider with EMR ID '99999' not found."
}
```
This error occurs when `provider_id` doesn't exist in the providers table. Sync providers using `GET /v1/providers`.
#### Staff Member Not Found
```json theme={null}
{
"success": false,
"message": "Staff member with ID '99999' not found."
}
```
This error occurs when `assigned_to_id` doesn't exist in the staff list. Valid staff IDs are the `ehr_id` values returned by `GET /v1/staff`.
#### Location Not Found
```json theme={null}
{
"success": false,
"message": "Location with EMR ID '99999' not found."
}
```
Sync locations using `GET /v1/locations` to resolve this error.
#### Pharmacy Not Found
```json theme={null}
{
"success": false,
"message": "Pharmacy with EMR ID '99999' not found."
}
```
This error occurs when `pharmacy_ehr_id` is present but no corresponding pharmacy can be found. Call `GET /v1/pharmacies` to see what available pharmacies there are.
#### User Not Found
```json theme={null}
{
"success": false,
"message": "User not found."
}
```
This indicates an issue with your access token.
#### Unsupported EMR
```json theme={null}
{
"success": false,
"message": "Telephone encounters are only supported for [EMR Name] EMR."
}
```
Your EMR system may not currently support telephone encounter creation.
### Webhook Notifications
When the telephone encounter 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": "",
"access_token_reference_id": "",
"object": "event",
"created": "2025-10-27T10:30:00Z",
"type": "telephone_encounter.created",
"job_id": "12345",
"data": {
"telephone_encounter_id": "123e4567e89b12d3a456426614174000",
"emr_encounter_id": "ECW-98765",
"patient_mrn": "MRN-123456",
"provider_id": "12241",
"location_id": "25",
"assigned_to_id": "12220",
"reason": "Follow up on test results",
"refill_medication_name": "Lisinopril 10 MG"
}
}
```
Note: `refill_medication_name` will be included in the webhook data if a medication refill was requested and successfully added.
#### Partial Success
When the encounter is created successfully but the medication refill fails to be added, a partial success webhook is sent:
```json theme={null}
{
"id": "",
"access_token_reference_id": "",
"object": "event",
"created": "2025-10-27T10:35:00Z",
"type": "telephone_encounter.created_partial",
"job_id": "12345",
"data": {
"telephone_encounter_id": "123e4567e89b12d3a456426614174000",
"emr_encounter_id": "ECW-98765",
"patient_mrn": "MRN-123456",
"provider_id": "12241",
"location_id": "25",
"assigned_to_id": "12220",
"reason": "Prescription refill",
"refill_medication_name": "Lisinopril",
"refill_failure_reason": "Failed to add medication refill: Timeout error"
}
}
```
Note: The `telephone_encounter.created_partial` event indicates that the encounter was successfully created in the EMR, but the requested medication refill could not be added. The encounter exists and is usable, but the refill will need to be added manually.
#### Failure
##### General Failure
```json theme={null}
{
"id": "",
"access_token_reference_id": "",
"object": "event",
"created": "2025-10-27T10:35:00Z",
"type": "telephone_encounter.failed",
"job_id": "12345",
"data": {
"telephone_encounter_id": "123e4567e89b12d3a456426614174000",
"patient_mrn": "MRN-123456",
"refill_medication_name": null,
"failure_reason": "Failed to create telephone encounter in EMR"
}
}
```
##### Medication Not Found Failure
When a medication refill is requested but the medication cannot be found in the patient's available medications, the encounter is NOT created and a failure webhook is sent with the list of available medications:
```json theme={null}
{
"id": "",
"access_token_reference_id": "",
"object": "event",
"created": "2025-10-27T10:35:00Z",
"type": "telephone_encounter.failed",
"job_id": "12345",
"data": {
"telephone_encounter_id": "123e4567e89b12d3a456426614174000",
"patient_mrn": "MRN-123456",
"refill_medication_name": "Aspirin",
"failure_reason": "Medication \"Aspirin\" not found in available refillable medications. Available medications: [\"Lisinopril 10 MG\",\"Metformin 500 MG\",\"Atorvastatin 20 MG\"]"
}
}
```
# Add Action to Telephone Encounter
Source: https://docs.usecobalt.com/api-reference/telephone-encounters/create-action
POST /telephone-encounters/actions
Adds a timestamped action log to an existing telephone encounter in the provider's EMR system.
### Request Parameters
#### Required Fields
* **appointment\_id** (string, required): The identifier of the telephone encounter to add the action to. This is **not** the "Ref #" shown in the EHR UI. Use one of the identifiers Cobalt provides — any of the following is accepted:
* The `telephone_encounter_id` returned by [`POST /telephone-encounters`](/api-reference/telephone-encounters/create) when you created the encounter.
* The `emr_encounter_id` from the `telephone_encounter.created` webhook payload.
* The appointment `id` returned by the appointment fetch endpoints/webhooks (Cobalt resolves it to the underlying encounter).
* **text** (string, required): The action text/note to add to the telephone encounter log
### How It Works
When you add an action to a telephone encounter:
1. **Formatting**: The action is automatically formatted with the staff member's name, timestamp, and timezone
2. **Appending**: The formatted action is appended to the existing action log in the telephone encounter
3. **Timestamping**: Each action includes the exact date, time, and timezone when it was added
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/telephone-encounters/actions \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH' \
-d '{
"appointment_id": "3fa85f6457174562b3fc2c963f66afa6",
"text": "Patient called for prescription refill"
}'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Action processing. A webhook event will be sent upon completion.",
"action_id": "a7b8c9d0e1f2g3h4i5j6k7l8m9n0o1p2",
"job_id": 12345
}
```
### Response Fields
* **success** (boolean): Indicates if the request was accepted for processing
* **message** (string): Confirmation message
* **action\_id** (string): Unique identifier for the action record (32-character hex string)
* **job\_id** (integer): Reference to the job that will process this action
### Webhook Events
You'll receive a webhook when the action is processed:
#### Success Event
```json theme={null}
{
"id": "evt_abc123",
"object": "event",
"type": "telephone_encounter_action.created",
"created": "2026-01-21T20:15:30.000Z",
"job_id": "12345",
"access_token_reference_id": "user_123",
"data": {
"action_id": "a7b8c9d0e1f2g3h4i5j6k7l8m9n0o1p2",
"emr_appointment_id": "3784895",
"text": "Patient called for prescription refill"
}
}
```
# Get Visit Statuses
Source: https://docs.usecobalt.com/api-reference/visit-statuses/get
GET /visit-statuses
Returns a list of available visit statuses.
### Example Request
```bash theme={null}
curl -X GET https://api.usecobalt.com/v1/visit-types \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH'
```
### Example Response
```json theme={null}
{
"success": true,
"data": [
{
"code": "CANC",
"description": "Cancelled in advance"
},
{
"code": "R/S",
"description": "Rescheduled"
}
]
}
```
This endpoint returns a list of all visit statuses configured for the account associated with the provided access token. Each status type includes a `code` and a `description`. The code can be used in our PATCH /appointments endpoint to update the status of an appointment.
# Get Visit Types
Source: https://docs.usecobalt.com/api-reference/visit-types/get
GET /visit-types
Returns a list of available visit types.
### Example Request
```bash theme={null}
curl -X GET https://api.usecobalt.com/v1/visit-types \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: 493JKLHIU98789hLKH9HHJH'
```
### Example Response
```json theme={null}
{
"success": true,
"data": [
{
"code": "AWV",
"description": "Medicare Annual Wellness Visit"
},
{
"code": "BH Pre-Adm",
"description": "Behavioral Health Pre-Admission"
},
{
"code": "BH Visit",
"description": "Behavioral Health Admission & Treatment"
},
{
"code": "Cer Med NB",
"description": "Cervical Medial Branch NB"
}
]
}
```
This endpoint returns a list of all visit types configured for the account associated with the provided access token. Each visit type includes a `code` and a `description`.
# Get Webhook Events
Source: https://docs.usecobalt.com/api-reference/webhook-events/get
GET /webhook-events
Retrieve webhook events sent to your registered webhook URLs.
Use this endpoint to retrieve webhook events that have been sent to your registered webhook URLs.
## Use Cases
* Debug webhook delivery issues
* Audit webhook event history
* Recover missed webhook events after downtime
* Verify event payloads during integration testing
## Common Event Types
* `patient.insurance.added` - Insurance successfully added to patient
* `patient.insurance.failed` - Insurance addition failed
* `appointment.created` - Appointment created
* `appointment.updated` - Appointment updated
* `note.created` - Clinical note created
## Query Parameters
* **job\_id** (string, optional): Filter by job ID. Returns only events associated with a specific asynchronous operation. Useful for [awaiting results](/docs/awaiting-results/overview) of a single API call.
* **event\_type** (string, optional): Filter by event type (e.g., "patient.insurance.added", "appointment.created")
* **delivery\_status** (string, optional): Filter by delivery status - "success" or "failed". Indicates whether the webhook event was delivered to the webhook URL on file
* **start\_date** (string, optional): Filter events created on or after this date (ISO 8601 format: YYYY-MM-DD)
* **end\_date** (string, optional): Filter events created on or before this date (ISO 8601 format: YYYY-MM-DD)
* **page** (integer, optional): Page number (default: 1, min: 1)
* **page\_size** (integer, optional): Number of events per page (default: 50, max: 100)
* **sort** (string, optional): Sort order. Use "created\_at" for ascending (oldest first) or "-created\_at" for descending (newest first). Default: "-created\_at"
## Common Workflows
### Track Appointments You Created via the API
To track all appointments you've successfully created through Cobalt's API, filter by `appointment.created` events:
```bash theme={null}
curl -X GET "https://api.usecobalt.com/v1/webhook-events?event_type=appointment.created&start_date=2025-01-01" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token"
```
This returns all successful appointment creations since January 1, 2025. Each event includes the `appointment_id`, patient MRN, date/time, and provider information - allowing you to maintain a complete audit trail of appointments scheduled through your integration.
**Response:**
```json theme={null}
{
"success": true,
"webhook_events": [
{
"event_id": "evt_xyz789ghi012",
"event_type": "appointment.created",
"webhook_url": "https://your-webhook-url.com/webhooks",
"delivery_status": "success",
"data": {
"appointment_id": "appt123456789",
"date_time": "2025-01-20T14:30:00",
"timezone": "America/Los_Angeles",
"provider_id": "prov_456",
"secondary_provider_id": null,
"provider_name": "Dr. Jane Smith",
"mrn": "MRN123456"
},
"created_at": "2025-01-15T11:00:00.000Z",
"job_id": "67890",
"access_token_reference_id": "your_reference_id"
}
],
"pagination": {
"current_page": 1,
"total_pages": 5,
"total_count": 243,
"page_size": 50
}
}
```
## Additional Example Requests
### Get Recent Events
```bash theme={null}
curl -X GET "https://api.usecobalt.com/v1/webhook-events?page_size=20" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token"
```
### Filter by Event Type
```bash theme={null}
curl -X GET "https://api.usecobalt.com/v1/webhook-events?event_type=patient.insurance.added&page_size=10" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token"
```
### Filter by Date Range
```bash theme={null}
curl -X GET "https://api.usecobalt.com/v1/webhook-events?start_date=2025-01-01&end_date=2025-01-31" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token"
```
### Get Page 2
```bash theme={null}
curl -X GET "https://api.usecobalt.com/v1/webhook-events?page=2&page_size=50" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token"
```
## Example Response
### Patient Insurance Added Event
```json theme={null}
{
"success": true,
"webhook_events": [
{
"event_id": "evt_abc123def456",
"event_type": "patient.insurance.added",
"webhook_url": "https://your-webhook-url.com/webhooks",
"delivery_status": "success",
"data": {
"patient_insurance_id": "xyz789abc123",
"patient_mrn": "MRN123456"
},
"created_at": "2025-01-15T10:30:00.000Z",
"job_id": "12345",
"access_token_reference_id": "your_reference_id"
}
],
"pagination": {
"current_page": 1,
"total_pages": 10,
"total_count": 487,
"page_size": 50
}
}
```
## Response Fields
### Top-Level Fields
* **success** (boolean): Whether the request was successful
* **webhook\_events** (array): Array of webhook event objects
* **pagination** (object): Pagination metadata
### Event Object Fields
* **event\_id** (string): Unique event identifier
* **event\_type** (string): Event type (e.g., "patient.insurance.added", "appointment.created")
* **webhook\_url** (string): The URL the event was sent to
* **delivery\_status** (string): Delivery status - "success" or "failed". Indicates whether the webhook event was delivered to the webhook URL on file
* **data** (object): Event-specific payload data
* **created\_at** (string): ISO 8601 timestamp of event creation
* **job\_id** (string, nullable): Job ID if this event is related to an asynchronous operation
* **access\_token\_reference\_id** (string, nullable): The reference ID associated with your access token
### Pagination Object
* **current\_page** (integer): Current page number
* **total\_pages** (integer): Total number of pages
* **total\_count** (integer): Total number of events matching the filter
* **page\_size** (integer): Number of items per page
The `data` field in each event contains event-specific information that varies depending on the event type. Refer to the webhook event docs for payload structures: [Operation Events](/docs/webhooks/operation-events), [Sync Events](/docs/webhooks/sync-events), [Account Events](/docs/webhooks/account-events).
## Pagination
This endpoint supports page-based pagination:
1. Make an initial request with optional `page` and `page_size` parameters
2. Check the `pagination` object in the response for `total_pages`
3. Request subsequent pages by incrementing the `page` parameter
4. Continue until you reach `total_pages`
# Get Webhook Event
Source: https://docs.usecobalt.com/api-reference/webhook-events/get-by-id
GET /webhook-events/{id}
Retrieve a single webhook event by its event ID.
Use this endpoint to retrieve a specific webhook event by its ID.
### Path Parameters
* **id** (required): The unique identifier of the webhook event (the `event_id` from the list endpoint)
### Example Request
```bash theme={null}
curl -X GET "https://api.usecobalt.com/v1/webhook-events/evt_abc123def456" \
-H "client_id: your_client_id" \
-H "client_secret: your_client_secret" \
-H "access_token: your_access_token"
```
### Example Response
```json theme={null}
{
"success": true,
"webhook_event": {
"event_id": "evt_abc123def456",
"event_type": "appointment.created",
"webhook_url": "https://your-webhook-url.com/webhooks",
"delivery_status": "success",
"data": {
"appointment_id": "appt123456789",
"date_time": "2025-01-20T14:30:00",
"timezone": "America/Los_Angeles",
"provider_id": "prov_456",
"secondary_provider_id": null,
"provider_name": "Dr. Jane Smith",
"mrn": "MRN123456"
},
"created_at": "2025-01-15T11:00:00.000Z",
"job_id": "67890",
"access_token_reference_id": "your_reference_id"
}
}
```
### Response Fields
* **event\_id** (string): Unique event identifier
* **event\_type** (string): Event type (e.g., "patient.insurance.added", "appointment.created")
* **webhook\_url** (string): The URL the event was sent to
* **delivery\_status** (string): Delivery status - "success" or "failed"
* **data** (object): Event-specific payload data
* **created\_at** (string): ISO 8601 timestamp of event creation
* **job\_id** (string, nullable): Job ID if this event is related to an asynchronous operation
* **access\_token\_reference\_id** (string, nullable): The reference ID associated with your access token
### Error Responses
#### Webhook Event Not Found
```json theme={null}
{
"success": false,
"message": "Webhook event not found."
}
```
This error occurs when:
* The event ID doesn't exist
* The event belongs to a different user account
The `data` field contains event-specific information that varies depending on the event type. Refer to the webhook event docs for payload structures: [Operation Events](/docs/webhooks/operation-events), [Sync Events](/docs/webhooks/sync-events), [Account Events](/docs/webhooks/account-events).
# Create Webhook
Source: https://docs.usecobalt.com/api-reference/webhooks/create
POST /webhook
Registers a webhook URL for your account to receive event notifications.
Registers a webhook URL for your account. A webhook is registered per account, so this one registration receives events for every connection and user under your account. The response includes the account-wide signing secret that you should store securely - it is used to verify that incoming webhooks are actually from Cobalt.
Only `client_id` and `client_secret` headers are required. The request body accepts a single field, `webhook_url`; there is no per-connection webhook scoping.
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/webhook \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-d '{
"webhook_url": "https://api.example.com/webhook"
}'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Webhook URL added successfully",
"webhook_url": "https://api.example.com/webhook",
"webhook_id": "wh_123456789",
"webhook_secret_key": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
}
```
Store the `webhook_secret_key` securely - you'll need it to verify webhook signatures. It is a single account-wide key shared across all of your webhook deliveries.
# Delete Webhook
Source: https://docs.usecobalt.com/api-reference/webhooks/delete
DELETE /webhook/{id}
Deletes a webhook endpoint. Once deleted, no further events will be sent to the endpoint.
### Example Request
```bash theme={null}
curl -X DELETE https://api.usecobalt.com/v1/webhook/wh_123456789 \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Webhook deleted successfully"
}
```
# Get Webhooks
Source: https://docs.usecobalt.com/api-reference/webhooks/get
GET /webhook
Returns the webhook URLs registered for your account and the account-wide signing secret.
Returns every webhook URL registered under your account plus the single account-wide `webhook_secret_key`. Only `client_id` and `client_secret` headers are required.
### Example Request
```bash theme={null}
curl -X GET https://api.usecobalt.com/v1/webhook \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh'
```
### Example Response
```json theme={null}
{
"success": true,
"webhook_urls": [
{
"id": "wh_123456789",
"url": "https://api.example.com/webhook"
}
],
"webhook_secret_key": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
}
```
# Rotate Webhook Secret
Source: https://docs.usecobalt.com/api-reference/webhooks/rotate-secret
POST /webhook/rotate-secret
Generates a new signing secret for your account. This rotates the single account-wide webhook signing key, so every webhook delivery under this account is signed with the new key going forward.
Rotating the secret replaces the account-wide webhook signing key. Because the key is shared across every connection and webhook URL registered under your account, all future deliveries are signed with the new key. Update your verification logic before rotating, or immediately after, to avoid rejecting valid webhooks.
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/webhook/rotate-secret \
-H 'Content-Type: application/json' \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Webhook secret rotated successfully",
"webhook_secret_key": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
}
```
Only `client_id` and `client_secret` headers are required. Store the returned `webhook_secret_key` securely and use it to verify webhook signatures.
# Send Test Webhook
Source: https://docs.usecobalt.com/api-reference/webhooks/send-test-webhook
POST /webhook/test
Sends a test webhook event to verify your integration is working correctly.
Sends a `test.event` webhook to all configured webhook URLs for your client. Use this endpoint to:
* Verify your webhook endpoint is receiving events correctly
* Test your webhook signature verification logic
* Validate your event processing pipeline
* Debug webhook delivery issues
The test event will include the standard webhook structure with a `test.event` type.
### Prerequisites
You must have at least one webhook URL configured before sending a test event. If you haven't configured a webhook URL yet, use the [Create Webhook](/api-reference/webhooks/create) endpoint first.
### Example Request
```bash theme={null}
curl -X POST https://api.usecobalt.com/v1/webhook/test \
-H 'client_id: ci_live_198908HJDKJSH98789OHKJL' \
-H 'client_secret: cs_live_9827hofdsklOYYHJLJh' \
-H 'access_token: at_live_abc123def456'
```
### Example Response
```json theme={null}
{
"success": true,
"message": "Test webhook sent to 2 URL(s)",
"webhook_urls_count": 2,
"event": {
"id": "test-event-1703172600000",
"access_token_reference_id": "your-reference-id",
"object": "event",
"created": "2025-10-21T14:30:00.000Z",
"type": "test.event",
"data": {
"message": "This is a test webhook event",
"timestamp": "2025-10-21T14:30:00.000Z"
}
}
}
```
### What Your Webhook Endpoint Will Receive
Your webhook endpoint will receive the test event with a signature header that you should verify:
```json theme={null}
{
"id": "test-event-1703172600000",
"access_token_reference_id": "your-reference-id",
"object": "event",
"created": "2025-10-21T14:30:00.000Z",
"type": "test.event",
"data": {
"message": "This is a test webhook event",
"timestamp": "2025-10-21T14:30:00.000Z"
}
}
```
The test webhook will be signed with your webhook secret key. Make sure to verify the `cobalt-verification` header to ensure the webhook is authentic. See [Receiving Webhooks](/docs/webhooks/receiving) for signature verification details.
### Common Use Cases
After configuring your first webhook URL, send a test event to confirm your endpoint is reachable and processing webhooks correctly.
After updating your webhook handler code, send a test event to verify your changes work as expected before going live.
If you're not receiving production webhooks, send a test event to isolate whether the issue is with your endpoint or with specific event types.
Send a test event and verify the `cobalt-verification` header to ensure your signature verification logic is working correctly.
### Error Responses
**404 - No Webhook URLs Configured**
```json theme={null}
{
"success": false,
"message": "No webhook URLs configured. Please add a webhook URL first using POST /v1/webhook."
}
```
**401 - Invalid Access Token**
```json theme={null}
{
"success": false,
"message": "Invalid access token"
}
```
**401 - Access Token Mismatch**
```json theme={null}
{
"success": false,
"message": "Access token does not belong to this client"
}
```
# Best Practices
Source: https://docs.usecobalt.com/docs/awaiting-results/best-practices
Recommended settings and patterns for polling Cobalt operations.
## Polling Interval
A poll interval of **1 second** works well for most operations. Cobalt typically processes operations within a few seconds to a couple of minutes depending on the EHR system.
If you want to reduce API calls, you can increase the interval to 2-3 seconds with minimal impact on perceived latency.
## Timeout
Set a timeout based on the operation type:
| Operation | Recommended Timeout |
| - | - |
| Appointments | 2 minutes |
| Patients | 2 minutes |
| Notes | 3 minutes |
| Documents | 3 minutes |
| Insurance | 2 minutes |
Processing times vary by EHR system. If you experience frequent timeouts, increase the timeout rather than reducing the poll interval.
## Handle Timeouts Gracefully
A timeout does not mean the operation failed. It means the result wasn't available within your wait window. The operation may still complete successfully in the background.
If a timeout occurs:
1. **Log the `job_id`** so you can look it up later.
2. **Check back later** by calling `GET /v1/webhook-events?job_id={job_id}` at any point in the future.
3. **Don't retry the original operation** unless you've confirmed it failed. Creating a duplicate appointment or patient is worse than waiting a bit longer.
```jsx theme={null}
try {
const result = await awaitResult(jobId, { timeoutMs: 120000 });
// Handle success or failure
} catch (error) {
if (error.message.includes('Timed out')) {
// The operation may still succeed - don't retry blindly
console.log(`Operation still processing. Track with job_id: ${jobId}`);
}
}
```
## When to Use Webhooks Instead
Polling works well for low-volume, on-demand operations. For high-volume or background processing, [webhooks](/docs/webhooks/overview) are more efficient:
* **Use polling** when a user is waiting for an immediate result (e.g., a "Schedule Appointment" button in your UI).
* **Use webhooks** when processing records in bulk or when operations happen in the background without a user waiting.
* **Use both** for the best of both worlds: webhooks for production event processing, polling for ad-hoc operations and debugging.
You do not need to register a webhook URL to use the polling approach. Cobalt tracks all operation results internally regardless of whether you have webhooks configured.
## Supported Operations
Any Cobalt API operation that returns a `job_id` in its response supports this polling pattern. This includes:
* **Appointments** - Create and update
* **Patients** - Create
* **Notes** - Create
* **Documents** - Upload
* **Tasks** - Create
* **Messages** - Create
* **Insurance** - Add to patient
* **Referring Providers** - Create
* **Telephone Encounters** - Create
# Implementation
Source: https://docs.usecobalt.com/docs/awaiting-results/implementation
Code examples for polling Cobalt API operations to completion.
## JavaScript (Node.js)
This helper function polls `GET /v1/webhook-events` until a result for the given `job_id` appears or the timeout is reached.
```jsx theme={null}
const axios = require('axios');
const COBALT_BASE_URL = 'https://api.usecobalt.com';
const headers = {
'Content-Type': 'application/json',
'client_id': process.env.COBALT_CLIENT_ID,
'client_secret': process.env.COBALT_CLIENT_SECRET,
'access_token': process.env.COBALT_ACCESS_TOKEN,
};
/**
* Poll for the result of an asynchronous Cobalt operation.
* @param {string} jobId - The job_id returned from the initial API call.
* @param {object} options
* @param {number} options.timeoutMs - Max time to wait (default: 120000ms / 2 minutes).
* @param {number} options.pollIntervalMs - Time between polls (default: 1000ms).
* @returns {object} The webhook event object with the operation result.
* @throws {Error} If the timeout is reached before a result is available.
*/
async function awaitResult(jobId, { timeoutMs = 120000, pollIntervalMs = 1000 } = {}) {
const startTime = Date.now();
while (Date.now() - startTime < timeoutMs) {
const response = await axios.get(`${COBALT_BASE_URL}/v1/webhook-events`, {
headers,
params: { job_id: jobId },
});
const events = response.data.webhook_events;
if (events && events.length > 0) {
return events[0];
}
await new Promise(resolve => setTimeout(resolve, pollIntervalMs));
}
throw new Error(`Timed out after ${timeoutMs}ms waiting for result (job_id: ${jobId})`);
}
```
### Creating an Appointment and Awaiting the Result
```jsx theme={null}
async function createAppointmentSync(appointmentData) {
// Step 1: Create the appointment
const createResponse = await axios.post(
`${COBALT_BASE_URL}/v1/appointments`,
appointmentData,
{ headers }
);
const { appointment_id, job_id } = createResponse.data.data;
console.log(`Appointment queued: ${appointment_id}, polling for result...`);
// Step 2: Wait for the outcome
const event = await awaitResult(job_id);
// Step 3: Handle the result
if (event.event_type === 'appointment.created') {
console.log('Appointment created successfully:', event.data);
return { success: true, data: event.data };
} else {
console.error('Appointment failed:', event.data.failure_reason);
return { success: false, error: event.data.failure_reason };
}
}
// Usage
const result = await createAppointmentSync({
mrn: '123456789',
location: '123456789',
datetime: '2025-03-15T14:00:00-05:00',
provider: '123456789',
type: 'follow_up',
});
```
### Creating a Patient and Awaiting the Result
```jsx theme={null}
async function createPatientSync(patientData) {
const createResponse = await axios.post(
`${COBALT_BASE_URL}/v1/patients`,
patientData,
{ headers }
);
const { patient_id, job_id } = createResponse.data.data;
console.log(`Patient queued: ${patient_id}, polling for result...`);
const event = await awaitResult(job_id);
if (event.event_type === 'patient.created') {
console.log('Patient created successfully:', event.data);
return { success: true, data: event.data };
} else {
console.error('Patient creation failed:', event.data.failure_reason);
return { success: false, error: event.data.failure_reason };
}
}
```
## Python
```python theme={null}
import requests
import time
COBALT_BASE_URL = "https://api.usecobalt.com"
headers = {
"Content-Type": "application/json",
"client_id": COBALT_CLIENT_ID,
"client_secret": COBALT_CLIENT_SECRET,
"access_token": COBALT_ACCESS_TOKEN,
}
def await_result(job_id, timeout_seconds=120, poll_interval_seconds=1):
"""
Poll for the result of an asynchronous Cobalt operation.
Args:
job_id: The job_id returned from the initial API call.
timeout_seconds: Max time to wait (default: 120 seconds).
poll_interval_seconds: Time between polls (default: 1 second).
Returns:
The webhook event dict with the operation result.
Raises:
TimeoutError: If the timeout is reached before a result is available.
"""
start_time = time.time()
while time.time() - start_time < timeout_seconds:
response = requests.get(
f"{COBALT_BASE_URL}/v1/webhook-events",
headers=headers,
params={"job_id": job_id},
)
response.raise_for_status()
events = response.json().get("webhook_events", [])
if events:
return events[0]
time.sleep(poll_interval_seconds)
raise TimeoutError(
f"Timed out after {timeout_seconds}s waiting for result (job_id: {job_id})"
)
def create_appointment_sync(appointment_data):
# Step 1: Create the appointment
create_response = requests.post(
f"{COBALT_BASE_URL}/v1/appointments",
headers=headers,
json=appointment_data,
)
create_response.raise_for_status()
data = create_response.json()["data"]
appointment_id = data["appointment_id"]
job_id = data["job_id"]
print(f"Appointment queued: {appointment_id}, polling for result...")
# Step 2: Wait for the outcome
event = await_result(job_id)
# Step 3: Handle the result
if event["event_type"] == "appointment.created":
print("Appointment created successfully:", event["data"])
return {"success": True, "data": event["data"]}
else:
print("Appointment failed:", event["data"]["failure_reason"])
return {"success": False, "error": event["data"]["failure_reason"]}
```
## cURL
You can also poll manually with cURL for testing or debugging:
```bash theme={null}
# Step 1: Create the appointment
curl -X POST https://api.usecobalt.com/v1/appointments \
-H 'Content-Type: application/json' \
-H 'client_id: your_client_id' \
-H 'client_secret: your_client_secret' \
-H 'access_token: your_access_token' \
-d '{
"mrn": "123456789",
"location": "123456789",
"datetime": "2025-03-15T14:00:00-05:00",
"provider": "123456789",
"type": "follow_up"
}'
# Response: { "success": true, "data": { "appointment_id": "abc123", "job_id": "67890" } }
# Step 2: Poll for the result using the job_id
curl -X GET "https://api.usecobalt.com/v1/webhook-events?job_id=67890" \
-H 'client_id: your_client_id' \
-H 'client_secret: your_client_secret' \
-H 'access_token: your_access_token'
# Repeat until webhook_events array is non-empty
```
# Overview
Source: https://docs.usecobalt.com/docs/awaiting-results/overview
Wait for the result of asynchronous operations without setting up webhooks.
Many Cobalt API operations are asynchronous. When you create an appointment, patient, or other record via the API, Cobalt returns immediately with a `job_id` and processes the request in the background. Normally, you'd set up [webhooks](/docs/webhooks/overview) to receive the result.
**Awaiting results** is an alternative pattern that lets you poll for the outcome directly, giving you a synchronous-style workflow without needing a webhook endpoint. This is useful for:
* Getting started quickly without configuring webhook infrastructure
* Simple scripts or one-off integrations
* Environments where receiving inbound HTTP requests is difficult
* Prototyping and testing
This pattern uses the [Get Webhook Events](/api-reference/webhook-events/get) endpoint to poll for results by `job_id`. Every asynchronous operation returns a `job_id` that you can use to track its outcome.
## How It Works
1. **Make the API call** - Create an appointment, patient, or other record. The response includes a `job_id`.
2. **Poll for the result** - Call `GET /v1/webhook-events?job_id={job_id}` on an interval until a matching event appears.
3. **Handle the outcome** - The event tells you whether the operation succeeded or failed, with full details.
```
POST /v1/appointments ──► { job_id: "12345" }
│
▼
GET /v1/webhook-events?job_id=12345 ──► (empty, not ready)
│ wait 1 second
▼
GET /v1/webhook-events?job_id=12345 ──► (empty, not ready)
│ wait 1 second
▼
GET /v1/webhook-events?job_id=12345 ──► { type: "appointment.created", data: {...} }
```
# Welcome
Source: https://docs.usecobalt.com/docs/introduction
Cobalt provides a unified API for healthcare data, making it easy to integrate with any EHR system. Our API handles the complexity of different EHR systems, providing you with a consistent interface for managing appointments, patient data, and clinical notes.
## Features
* **Unified API**: One integration for all EHR systems
* **Real-time Updates**: Webhook notifications for changes in the EHR
* **Secure Authentication**: Authentication through Cobalt Link
* **HIPAA Compliant**: Enterprise-grade security for healthcare data
## Getting Started
1. **Authentication**: Learn how to [authenticate](/docs/authentication) your requests
2. **Cobalt Link**: Implement [secure EHR authentication](/docs/link/overview)
3. **Webhooks**: Set up [real-time notifications](/docs/webhooks/overview)
## Agent-ready API context
Copy these resources into your coding agent to give it the API contract and Cobalt-specific EHR guidance.
```text Copy for your agent theme={null}
Use these Cobalt API resources:
OpenAPI specification: https://docs.usecobalt.com/api-reference/openapi.json
Agent guide: https://docs.usecobalt.com/llms.txt
```
The machine-readable API contract for every endpoint, with per-EMR support
tags.
An index of the concepts and endpoints, written for agents. Append `.md` to
any docs page URL for its raw markdown.
**Per-EMR support lives in the spec, not in these pages.** An operation's
`x-supported-emrs` lists the EMRs that support that endpoint. A request
field's `x-required-for-emrs` lists the EMRs that require it, and
`x-allowed-values-for-emrs` maps each EMR to the values it accepts. Consult
those tags rather than assuming support.
## Need Help?
If you need assistance, please don't hesitate to:
* Email us at [bryan@usecobalt.com](mailto:bryan@usecobalt.com)
* Check our API reference documentation
# Overview
Source: https://docs.usecobalt.com/docs/link/overview
## **Overview**
Cobalt Link is the client-side component that your users will interact with in order to link their EMR to Cobalt and allow you to access their EMR via the Cobalt API. Link is used to obtain a `public_token`, which can then be exchanged for an `access_token`, which is used to authenticate requests to the Cobalt API.
**The Cobalt Link** flow has the following steps:
1. Call `https://api.usecobalt.com/link/token/create` to create a `link_token` and pass it to your app's client.
2. Use the `link_token` to open Link for your user. In the `onSuccess` callback, Link will provide a temporary `public_token`.
3. Call `https://api.usecobalt.com/link/token/exchange` to exchange the `public_token` for a permanent `access_token`.
4. Store the `access_token` and use it to make API requests.
# Setup
Source: https://docs.usecobalt.com/docs/link/setup
**The Cobalt Link** flow has the following steps:
1. Call `https://api.usecobalt.com/link/token/create` to create a `link_token` and pass it to your app's client.
2. Use the `link_token` to open Link for your user. In the `onSuccess` callback, Link will provide a temporary `public_token`.
3. Call `https://api.usecobalt.com/link/token/exchange` to exchange the `public_token` for a permanent `access_token`.
4. Store the `access_token` and use it to make API requests.
## Detailed Steps
### Create Link Token
The `/link/token/create` endpoint creates a `link_token`, which is required as a parameter when initializing Link. Once Link has been initialized, it returns a `public_token`, which can then be exchanged for an `access_token` via `/link/token/exchange` as part of the main Link flow.
```bash theme={null}
curl -X POST https://api.usecobalt.com/link/token/create \
-H 'Content-Type: application/json' \
-H 'client_id: "%COBALT_CLIENT_ID%"' \
-H 'client_secret: "%COBALT_CLIENT_SECRET%"' \
-d '{
"user_id": "%REFERENCE_USER_ID%",
"org_id": "%REFERENCE_ORG_ID%"
}'
```
The request requires the following parameters:
* `client_id` this is your Cobalt API client id.
* `client_secret` this is your Cobalt API secret.
* `user_id` this is a unique ID representing the end user. Typically, this will be a user ID number from your application. Personally identifiable information, such as an email address or phone number, should not be used in the `user_id`.
* `org_id` this is a unique identifier for the organization that this user belongs to in your system. This is often a clinic or hospital. This association is important to handle any custom settings that an org has. You choose this identifier - it can be any string that uniquely identifies the organization in your system.
#### Creating a New Organization
If this is the first user from a new organization, you'll need to provide additional parameters to create the organization:
* `emr_name` **(required for new orgs)** - The name of the EMR system. Contact support for a list of supported EMR systems.
* `emr_instance_domain` **(required for new orgs)** - The EMR instance URL (e.g., `https://mypractice.example.com`). Domain requirements vary by EMR.
**Example request for a new organization:**
```bash theme={null}
curl -X POST https://api.usecobalt.com/link/token/create \
-H 'Content-Type: application/json' \
-H 'client_id: "%COBALT_CLIENT_ID%"' \
-H 'client_secret: "%COBALT_CLIENT_SECRET%"' \
-d '{
"user_id": "%REFERENCE_USER_ID%",
"org_id": "%REFERENCE_ORG_ID%",
"emr_name": "%EMR_NAME%",
"emr_instance_domain": "https://your-emr-instance.com"
}'
```
Example response:
```bash theme={null}
{
"success": true,
"token": "189hisdf78w9r3ysdfhi" // used in next step.
}
```
### Initialize Client Link
**Lightbox Mode**
Lightbox Mode will activate the Cobalt Link experience in a modal rather than having the element appear directly embedded elsewhere on the page. The lightbox takes up the entire user's screen, darkening the background content with a semi-transparent overlay of the page and centering Cobalt’s Link UI in a modal located at the center of the user's screen.
To utilize Lightbox mode, include the Javascript snippet on your site, before the closing `
` tag. Make sure to attach a button's `onClick` event to call the `launch_cobalt()` function. Alternatively, you can call the `window.CobaltLink.init()` function directly within an event callback of your choice.
`CobaltLink.init` accepts one argument, a configuration `Object`. The configuration object requires the following parameters:
* `token` this is the temporary `link_token` from the [create link token step](https://www.notion.so/Getting-Started-9d469ab83e1e421abfc770feed375c65?pvs=21).
* `onSuccess` this callback is called when a user successfully links their account. It takes one argument: the `public_token`. The `public_token` can then be used in the [exchange public token step](https://www.notion.so/Getting-Started-9d469ab83e1e421abfc770feed375c65?pvs=21).
**New Window Mode**
If you prefer to not include the Cobalt Link code in your site you can use the Cobalt dashboard to generate a Link to share with your users so they can enter their credentials. You will then be able to view the access\_token in the Cobalt dashboard.
### Exchange Public Token
The `/link/token/exchange` endpoint exchanges a `public_token` for an `access_token`.
```bash theme={null}
curl -X GET "https://api.usecobalt.com/link/token/exchange" \
-H 'Content-Type: application/json' \
-H 'client_id: "%COBALT_CLIENT_ID%"' \
-H 'client_secret: "%COBALT_CLIENT_SECRET%"'
-G \
--data-urlencode "public_token=234p852489035y29083y4" \
```
The request requires the following parameters:
* `client_id` this is your Cobalt API client id.
* `client_secret` this is your Cobalt API secret.
* `public_token` this is the token acquired during the Initialize Client Link step.
Example response:
```bash theme={null}
{
"success": true,
"token": "9872394hjkldsfh987re9iwqhjosdffh9sdychosdofc"
}
```
## Examples
### Code snippet
```jsx theme={null}
```
### Javascript
```jsx theme={null}