curl --request POST \
--url https://api.usecobalt.com/v1/availability/fetch \
--header 'Content-Type: application/json' \
--header 'access_token: <api-key>' \
--header 'client_id: <api-key>' \
--header 'client_secret: <api-key>' \
--data '
{
"start_date": "2026-03-15",
"end_date": "2026-03-20",
"provider_ids": [
"PROV-1"
],
"buffer": 15,
"visit_type": "FOLLOW-UP",
"calculation_method": "gaps",
"daily_appointment_limit": 8,
"daily_limit_type": "all",
"provider_type": "primary",
"fallback_to_default_hours": true,
"max_slot_duration": 30,
"facility_scoped_scheduling": true,
"location_ids": [
"LOC-1"
],
"cancelled_statuses": [
"canc",
"rs",
"cancsms"
],
"callback_urls": [
"<string>"
]
}
'import requests
url = "https://api.usecobalt.com/v1/availability/fetch"
payload = {
"start_date": "2026-03-15",
"end_date": "2026-03-20",
"provider_ids": ["PROV-1"],
"buffer": 15,
"visit_type": "FOLLOW-UP",
"calculation_method": "gaps",
"daily_appointment_limit": 8,
"daily_limit_type": "all",
"provider_type": "primary",
"fallback_to_default_hours": True,
"max_slot_duration": 30,
"facility_scoped_scheduling": True,
"location_ids": ["LOC-1"],
"cancelled_statuses": ["canc", "rs", "cancsms"],
"callback_urls": ["<string>"]
}
headers = {
"client_id": "<api-key>",
"client_secret": "<api-key>",
"access_token": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
client_id: '<api-key>',
client_secret: '<api-key>',
access_token: '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
start_date: '2026-03-15',
end_date: '2026-03-20',
provider_ids: ['PROV-1'],
buffer: 15,
visit_type: 'FOLLOW-UP',
calculation_method: 'gaps',
daily_appointment_limit: 8,
daily_limit_type: 'all',
provider_type: 'primary',
fallback_to_default_hours: true,
max_slot_duration: 30,
facility_scoped_scheduling: true,
location_ids: ['LOC-1'],
cancelled_statuses: ['canc', 'rs', 'cancsms'],
callback_urls: ['<string>']
})
};
fetch('https://api.usecobalt.com/v1/availability/fetch', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.usecobalt.com/v1/availability/fetch",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'start_date' => '2026-03-15',
'end_date' => '2026-03-20',
'provider_ids' => [
'PROV-1'
],
'buffer' => 15,
'visit_type' => 'FOLLOW-UP',
'calculation_method' => 'gaps',
'daily_appointment_limit' => 8,
'daily_limit_type' => 'all',
'provider_type' => 'primary',
'fallback_to_default_hours' => true,
'max_slot_duration' => 30,
'facility_scoped_scheduling' => true,
'location_ids' => [
'LOC-1'
],
'cancelled_statuses' => [
'canc',
'rs',
'cancsms'
],
'callback_urls' => [
'<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"access_token: <api-key>",
"client_id: <api-key>",
"client_secret: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.usecobalt.com/v1/availability/fetch"
payload := strings.NewReader("{\n \"start_date\": \"2026-03-15\",\n \"end_date\": \"2026-03-20\",\n \"provider_ids\": [\n \"PROV-1\"\n ],\n \"buffer\": 15,\n \"visit_type\": \"FOLLOW-UP\",\n \"calculation_method\": \"gaps\",\n \"daily_appointment_limit\": 8,\n \"daily_limit_type\": \"all\",\n \"provider_type\": \"primary\",\n \"fallback_to_default_hours\": true,\n \"max_slot_duration\": 30,\n \"facility_scoped_scheduling\": true,\n \"location_ids\": [\n \"LOC-1\"\n ],\n \"cancelled_statuses\": [\n \"canc\",\n \"rs\",\n \"cancsms\"\n ],\n \"callback_urls\": [\n \"<string>\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("client_id", "<api-key>")
req.Header.Add("client_secret", "<api-key>")
req.Header.Add("access_token", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.usecobalt.com/v1/availability/fetch")
.header("client_id", "<api-key>")
.header("client_secret", "<api-key>")
.header("access_token", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"start_date\": \"2026-03-15\",\n \"end_date\": \"2026-03-20\",\n \"provider_ids\": [\n \"PROV-1\"\n ],\n \"buffer\": 15,\n \"visit_type\": \"FOLLOW-UP\",\n \"calculation_method\": \"gaps\",\n \"daily_appointment_limit\": 8,\n \"daily_limit_type\": \"all\",\n \"provider_type\": \"primary\",\n \"fallback_to_default_hours\": true,\n \"max_slot_duration\": 30,\n \"facility_scoped_scheduling\": true,\n \"location_ids\": [\n \"LOC-1\"\n ],\n \"cancelled_statuses\": [\n \"canc\",\n \"rs\",\n \"cancsms\"\n ],\n \"callback_urls\": [\n \"<string>\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.usecobalt.com/v1/availability/fetch")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["client_id"] = '<api-key>'
request["client_secret"] = '<api-key>'
request["access_token"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"start_date\": \"2026-03-15\",\n \"end_date\": \"2026-03-20\",\n \"provider_ids\": [\n \"PROV-1\"\n ],\n \"buffer\": 15,\n \"visit_type\": \"FOLLOW-UP\",\n \"calculation_method\": \"gaps\",\n \"daily_appointment_limit\": 8,\n \"daily_limit_type\": \"all\",\n \"provider_type\": \"primary\",\n \"fallback_to_default_hours\": true,\n \"max_slot_duration\": 30,\n \"facility_scoped_scheduling\": true,\n \"location_ids\": [\n \"LOC-1\"\n ],\n \"cancelled_statuses\": [\n \"canc\",\n \"rs\",\n \"cancsms\"\n ],\n \"callback_urls\": [\n \"<string>\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"message": "<string>",
"job_id": 123
}{
"success": false,
"message": "<string>"
}{
"success": false,
"message": "<string>"
}{
"success": false,
"message": "<string>"
}Fetch Availability
Performs a live fetch of provider availability by combining a real-time EMR appointment fetch with availability calculation.
curl --request POST \
--url https://api.usecobalt.com/v1/availability/fetch \
--header 'Content-Type: application/json' \
--header 'access_token: <api-key>' \
--header 'client_id: <api-key>' \
--header 'client_secret: <api-key>' \
--data '
{
"start_date": "2026-03-15",
"end_date": "2026-03-20",
"provider_ids": [
"PROV-1"
],
"buffer": 15,
"visit_type": "FOLLOW-UP",
"calculation_method": "gaps",
"daily_appointment_limit": 8,
"daily_limit_type": "all",
"provider_type": "primary",
"fallback_to_default_hours": true,
"max_slot_duration": 30,
"facility_scoped_scheduling": true,
"location_ids": [
"LOC-1"
],
"cancelled_statuses": [
"canc",
"rs",
"cancsms"
],
"callback_urls": [
"<string>"
]
}
'import requests
url = "https://api.usecobalt.com/v1/availability/fetch"
payload = {
"start_date": "2026-03-15",
"end_date": "2026-03-20",
"provider_ids": ["PROV-1"],
"buffer": 15,
"visit_type": "FOLLOW-UP",
"calculation_method": "gaps",
"daily_appointment_limit": 8,
"daily_limit_type": "all",
"provider_type": "primary",
"fallback_to_default_hours": True,
"max_slot_duration": 30,
"facility_scoped_scheduling": True,
"location_ids": ["LOC-1"],
"cancelled_statuses": ["canc", "rs", "cancsms"],
"callback_urls": ["<string>"]
}
headers = {
"client_id": "<api-key>",
"client_secret": "<api-key>",
"access_token": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
client_id: '<api-key>',
client_secret: '<api-key>',
access_token: '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
start_date: '2026-03-15',
end_date: '2026-03-20',
provider_ids: ['PROV-1'],
buffer: 15,
visit_type: 'FOLLOW-UP',
calculation_method: 'gaps',
daily_appointment_limit: 8,
daily_limit_type: 'all',
provider_type: 'primary',
fallback_to_default_hours: true,
max_slot_duration: 30,
facility_scoped_scheduling: true,
location_ids: ['LOC-1'],
cancelled_statuses: ['canc', 'rs', 'cancsms'],
callback_urls: ['<string>']
})
};
fetch('https://api.usecobalt.com/v1/availability/fetch', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.usecobalt.com/v1/availability/fetch",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'start_date' => '2026-03-15',
'end_date' => '2026-03-20',
'provider_ids' => [
'PROV-1'
],
'buffer' => 15,
'visit_type' => 'FOLLOW-UP',
'calculation_method' => 'gaps',
'daily_appointment_limit' => 8,
'daily_limit_type' => 'all',
'provider_type' => 'primary',
'fallback_to_default_hours' => true,
'max_slot_duration' => 30,
'facility_scoped_scheduling' => true,
'location_ids' => [
'LOC-1'
],
'cancelled_statuses' => [
'canc',
'rs',
'cancsms'
],
'callback_urls' => [
'<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"access_token: <api-key>",
"client_id: <api-key>",
"client_secret: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.usecobalt.com/v1/availability/fetch"
payload := strings.NewReader("{\n \"start_date\": \"2026-03-15\",\n \"end_date\": \"2026-03-20\",\n \"provider_ids\": [\n \"PROV-1\"\n ],\n \"buffer\": 15,\n \"visit_type\": \"FOLLOW-UP\",\n \"calculation_method\": \"gaps\",\n \"daily_appointment_limit\": 8,\n \"daily_limit_type\": \"all\",\n \"provider_type\": \"primary\",\n \"fallback_to_default_hours\": true,\n \"max_slot_duration\": 30,\n \"facility_scoped_scheduling\": true,\n \"location_ids\": [\n \"LOC-1\"\n ],\n \"cancelled_statuses\": [\n \"canc\",\n \"rs\",\n \"cancsms\"\n ],\n \"callback_urls\": [\n \"<string>\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("client_id", "<api-key>")
req.Header.Add("client_secret", "<api-key>")
req.Header.Add("access_token", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.usecobalt.com/v1/availability/fetch")
.header("client_id", "<api-key>")
.header("client_secret", "<api-key>")
.header("access_token", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"start_date\": \"2026-03-15\",\n \"end_date\": \"2026-03-20\",\n \"provider_ids\": [\n \"PROV-1\"\n ],\n \"buffer\": 15,\n \"visit_type\": \"FOLLOW-UP\",\n \"calculation_method\": \"gaps\",\n \"daily_appointment_limit\": 8,\n \"daily_limit_type\": \"all\",\n \"provider_type\": \"primary\",\n \"fallback_to_default_hours\": true,\n \"max_slot_duration\": 30,\n \"facility_scoped_scheduling\": true,\n \"location_ids\": [\n \"LOC-1\"\n ],\n \"cancelled_statuses\": [\n \"canc\",\n \"rs\",\n \"cancsms\"\n ],\n \"callback_urls\": [\n \"<string>\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.usecobalt.com/v1/availability/fetch")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["client_id"] = '<api-key>'
request["client_secret"] = '<api-key>'
request["access_token"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"start_date\": \"2026-03-15\",\n \"end_date\": \"2026-03-20\",\n \"provider_ids\": [\n \"PROV-1\"\n ],\n \"buffer\": 15,\n \"visit_type\": \"FOLLOW-UP\",\n \"calculation_method\": \"gaps\",\n \"daily_appointment_limit\": 8,\n \"daily_limit_type\": \"all\",\n \"provider_type\": \"primary\",\n \"fallback_to_default_hours\": true,\n \"max_slot_duration\": 30,\n \"facility_scoped_scheduling\": true,\n \"location_ids\": [\n \"LOC-1\"\n ],\n \"cancelled_statuses\": [\n \"canc\",\n \"rs\",\n \"cancsms\"\n ],\n \"callback_urls\": [\n \"<string>\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"message": "<string>",
"job_id": 123
}{
"success": false,
"message": "<string>"
}{
"success": false,
"message": "<string>"
}{
"success": false,
"message": "<string>"
}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_datemust equalend_date).
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)
{
"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)
{
"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 anavailability.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.
{
"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"
}
]
}
}
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.Authorizations
Body
Range start (YYYY-MM-DD).
"2026-03-15"
Range end (YYYY-MM-DD). One provider spans up to 5 days; 2–10 providers must share a single day.
"2026-03-20"
EMR provider IDs to fetch availability for (1–10).
["PROV-1"]
Minutes of buffer between slots (0–59).
15
Visit-type code to size slots for. Requires buffer to be set.
"FOLLOW-UP"
Slot calculation method: gaps, slots, or equal_slots.
"gaps"
Max appointments per day (positive integer). Requires daily_limit_type.
8
Visit-type code the daily limit applies to. Requires daily_appointment_limit.
"all"
Which provider slot to match on: primary or secondary.
"primary"
Use default business hours when a provider has no configured hours.
Cap on slot length in minutes (5–60, multiples of 5).
30
Scope slots per facility rather than per provider.
Filter returned slots to these EMR location IDs.
["LOC-1"]
Appointment statuses to treat as cancelled, freeing the slot. When provided, this overrides the default cancelled/rescheduled detection; statuses are matched case-insensitively. Use this when your clinic uses custom status codes (e.g. "RS" for rescheduled).
["canc", "rs", "cancsms"]
URLs to receive the results webhook, in addition to the account webhook.