Online booking systems, AI receptionists and other appointment diary solutions need to identify gaps in the appointment diary and then present a set of appointment slots. This process is more involved than you might expect given the need to know the existing appointments, appointment blocks, additional working days and any diary zone restrictions. The good news is that most of this can be calculated for you by using the `api/providerSchedules` endpoint.
Request Appointment Availability
The appointment diary has separate availability for each provider. Practices can specify separate working hours for online bookings, so there will be two `providerSchedules` returned for each provider. You decide whether you should use the "online" working hours, or the standard diary working hours, depending on your integration's purpose.
Step 1 - Get the gaps
GET /api/providerSchedules? from=2026-01-15 & to=2026-01-22 & filter=isProviderActive eq true and isOnlineBooking eq false & expand=gaps
The request returns a list of provider schedules for the next week and each schedule has a list of gaps.
In the example response below, we can see that provider '102010942057506740' has a 30 minute gap at 09:00 and a 2 hour and 15 minute gap at 9:45, so there must be an existing appointment between 09:30 and 09:45.
{
"@odata.context": "https://bridgeitonline.co.uk/api/$metadata#ProviderSchedules",
"value": [
{
"date": "2026-01-15",
"providerId": "102010942057506740",
"isOnlineBooking": false,
"start": "09:00:00.0000000",
"finish": "18:00:00.0000000",
"lunchStart": "13:00:00.0000000",
"lunchFinish": "14:00:00.0000000",
"isProviderActive": true,
"gaps": [
{
"date": "2026-01-15",
"providerId": "102010942057506740",
"start": "09:00:00.0000000",
"end": "09:30:00.0000000",
"diaryZoneDescription": "",
"diaryZoneId": "0",
"isOnlineBooking": false,
"isProviderActive": true
},
{
"date": "2026-01-15",
"providerId": "102010942057506740",
"start": "09:45:00.0000000",
"end": "12:00:00.0000000",
"diaryZoneDescription": "",
"diaryZoneId": "0",
"isOnlineBooking": false,
"isProviderActive": true
},
{
"date": "2026-01-15",
"providerId": "102010942057506740",
"start": "12:00:00.0000000",
"end": "12:30:00.0000000",
"diaryZoneDescription": "Fillings only",
"diaryZoneId": "1501267424507775056",
"isOnlineBooking": false,
"isProviderActive": true
},
...
]
},
...
]
}
Step 2 - Check for diary zone restrictions
Practices may add booking restrictions in appointment diary zones. This information is returned as "diaryZoneId" and "diaryZoneDescription", for each gap. If the diary section is not zoned these values will be empty.
For example, from the response above we see that the gap from 09:45 to 12:00 is not zoned ("diaryZoneId": 0), so we can book any appointment type in this section:
{
"date": "2026-01-15",
"providerId": "102010942057506740",
"start": "09:45:00.0000000",
"end": "12:00:00.0000000",
"diaryZoneDescription": "",
"diaryZoneId": "0",
"isOnlineBooking": false,
"isProviderActive": true
},Whereas the gap from 12:00 to 12:30 is in the "Fillings only" diary zone:
{
"date": "2026-01-15",
"providerId": "102010942057506740",
"start": "12:00:00.0000000",
"end": "12:30:00.0000000",
"diaryZoneDescription": "Fillings only",
"diaryZoneId": "1501267424507775056",
"isOnlineBooking": false,
"isProviderActive": true
}We can use the `/api/diaryZones` endpoint to get the diary zone details and check for any booking restrictions.
Here's the query passing the "diaryZoneId" from the example above:
GET /api/diaryZones(1501267424507775056)
In the example response below we see that "hasTreatmentCategoryRestrictions" is `true`, which means we need to check which treatment categories we're allowed to book appointments for. The "permittedTreatmentCategoryIds" property shows there are two valid treatment categories only. If we try to book an appointment for a different treatment category in this zone, the request will be rejected.
{
"@odata.context": "https://bridgeitonline.co.uk/api/$metadata#DiaryZones/$entity",
"start": "12:00:00.0000000",
"end": "13:00:00.0000000",
"dayOfWeek": "THURSDAY",
"providerId": "102010942057506740",
"description": "Fillings only",
"hasTreatmentCategoryRestrictions": true,
"permittedTreatmentCategoryIds": [
"105010907444562720",
"105010955639428864"
],
"staffCanOverride": false,
"id": "1501267424507775056",
"colour": "#8080ff"
}
The diary zone information is also available as an expansion on schedule gaps, so we can get all of the information in a single request with a nested expand:
Here's the query:
GET /api/providerSchedules?
from=2026-01-15 &
to=2026-01-22 &
filter=isProviderActive eq true and isOnlineBooking eq false &
expand=gaps(expand=diaryZone)
Which returns a response like this:
{
"@odata.context": "https://bridgeitonline.co.uk/api/$metadata#ProviderSchedules",
"value": [
{
"date": "2026-01-15",
"providerId": "102010942057506740",
"isOnlineBooking": false,
"start": "09:00:00.0000000",
"finish": "18:00:00.0000000",
"lunchStart": "13:00:00.0000000",
"lunchFinish": "14:00:00.0000000",
"isProviderActive": true,
"gaps": [
...
{
"date": "2026-01-15",
"providerId": "102010942057506740",
"start": "12:00:00.0000000",
"end": "12:30:00.0000000",
"diaryZoneDescription": "Fillings only",
"diaryZoneId": "1501267424507775056",
"isOnlineBooking": false,
"isProviderActive": true,
"diaryZone": {
"start": "12:00:00.0000000",
"end": "13:00:00.0000000",
"dayOfWeek": "THURSDAY",
"providerId": "102010942057506740",
"description": "Fillings only",
"hasTreatmentCategoryRestrictions": true,
"permittedTreatmentCategoryIds": [
"105010907444562720",
"105010955639428864"
],
"staffCanOverride": false,
"id": "1501267424507775056",
"colour": "#8080ff"
}
},
...
]
},
...
]
}
- For the provider schedules, we just need the date and provider id.
- For the gaps, we need start and end times.
- For the diary zones, we need to know whether there are restrictions, and if so, the permitted categories.
We use the `select` query option for this.
Tip: when you have multiple queries nested in an expand query, they are separated by ; not &
Here's the full query:
GET /api/providerSchedules?
from=2026-01-15 &
to=2026-01-22 &
filter=isProviderActive eq true and isOnlineBooking eq false &
select=date, providerId &
expand=gaps(
select=start, end ;
expand=diaryZone(
select=hasTreatmentCategoryRestrictions, permittedTreatmentCategoryIds
)
)
You can see the difference in in the response size below:
{
"@odata.context": "https://bridgeitonline.co.uk/api/$metadata#ProviderSchedules",
"value": [
{
"date": "2026-01-15",
"providerId": "102010942057506740",
"gaps": [
{
"start": "09:00:00.0000000",
"end": "09:30:00.0000000",
"diaryZone": null
},
{
"start": "09:45:00.0000000",
"end": "12:00:00.0000000",
"diaryZone": null
},
{
"start": "12:00:00.0000000",
"end": "12:30:00.0000000",
"diaryZone": {
"hasTreatmentCategoryRestrictions": true,
"permittedTreatmentCategoryIds": [
"105010907444562720",
"105010955639428864"
]
}
},
{
"start": "14:00:00.0000000",
"end": "18:00:00.0000000",
"diaryZone": null
}
]
},
...
]
}
If you're struggling with your integration, ask a question over on the API Integration Support forum.
