API Reference
Business scheduling
Set up B2B meeting scheduling — hosts, weekly hours, days off, closures, meeting types and calendar connections — and book, move and cancel business appointments.
For workspaces that run Business Appointments (the scheduling your agents use to book meetings with your team). Hosts are the people who take meetings; each has weekly hours on their own clock, days off, and optionally connected calendars whose busy time blocks them. Meeting types set the length, buffers, start-time steps, location and booking window, and which hosts take them. Setup needs business_setup:read or business_setup:write; appointments need appointments:read or appointments:write.
From nothing to a booked meeting
1. POST /v1/business/hosts for each person who takes meetings.
2. POST /v1/business/hosts/:id/availability with their weekly hours (a lunch break is two windows).
3. POST /v1/business/meeting-types with the hosts who take it.
4. GET /v1/business/availability for free times, then POST /v1/business/appointments with one of them.
Changes follow the dashboard's rules
Every change runs through the same handler as the dashboard (overlapping weekly hours are refused, hosts must be hosts of your workspace, bookings go through the booking engine and the hosts' calendars), acting as the member who created the key, with that member's role: owners (as admins), admins, builders and operators can change business scheduling, a key made by a viewer only reads, and only owners, admins and builders change calendar connections. If that member leaves the workspace, the key can no longer make changes. Reseller keys (rk_…) read only.
Times and time zones
Instants (starts_at, slot_start, from) are ISO 8601 with an offset or Z, and answers come back in UTC. Weekly hours are HH:MM on the host's own time zone (the workspace's when the host has none), and weekdays go from 0 (Sunday) to 6 (Saturday). A whole day off runs from one local midnight to the next.
Endpoints
/v1/business/hostsList hostsPOST/v1/business/hostsCreate a hostGET/v1/business/hosts/:idGet a hostPATCH/v1/business/hosts/:idUpdate a hostDELETE/v1/business/hosts/:idArchive a hostGET/v1/business/hosts/:id/availabilityList a host's weekly hoursPOST/v1/business/hosts/:id/availabilityAdd weekly hoursPATCH/v1/business/availability-windows/:idUpdate a weekly windowDELETE/v1/business/availability-windows/:idDelete a weekly windowGET/v1/business/hosts/:id/days-offList a host's days offPOST/v1/business/hosts/:id/days-offAdd a day offPATCH/v1/business/days-off/:idUpdate a day offDELETE/v1/business/days-off/:idDelete a day offGET/v1/business/closuresList closuresPOST/v1/business/closuresAdd a closurePATCH/v1/business/closures/:idUpdate a closureDELETE/v1/business/closures/:idDelete a closureGET/v1/business/meeting-typesList meeting typesPOST/v1/business/meeting-typesCreate a meeting typeGET/v1/business/meeting-types/:idGet a meeting typePATCH/v1/business/meeting-types/:idUpdate a meeting typeDELETE/v1/business/meeting-types/:idArchive a meeting typeGET/v1/business/hosts/:id/calendar-connectionsList a host's calendar connectionsGET/v1/business/calendar-connections/:id/calendarsList a connected account's calendarsPATCH/v1/business/calendar-connections/:idUpdate a calendar connectionDELETE/v1/business/calendar-connections/:idDisconnect a calendarList hosts
/v1/business/hostsLists the people who take meetings, by name.
business_setup:readQuery parameters
| Name | Type | Description |
|---|---|---|
limit | integer | Results per page. 1–100. Default: |
offset | integer | Results to skip. At least 0. Default: |
status | string | Active hosts (the default) or archived ones. One of: active, archived. Default: |
Example request
curl -X GET "https://www.nutalk.ai/v1/business/hosts?limit=20" \ -H "Authorization: Bearer YOUR_API_KEY"A page of hosts.
{
"success": true,
"data": [
{
"id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"name": "Ana López",
"email": "ana@example.com",
"title": "Account executive",
"timezone": "America/Monterrey",
"status": "active",
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
}
],
"pagination": {
"total": 1,
"limit": 20,
"offset": 0,
"has_more": false
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | A query parameter is invalid (details.errors lists each one). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Create a host
/v1/business/hostsAdds a person who takes meetings. Give them weekly hours (POST /v1/business/hosts/:id/availability) before they can be booked.
business_setup:writeWorkspace keys only · acts as the key's creatorThe change runs through the dashboard's own rules, as the member who created the key (an owner acts as an admin). Owners, admins, builders and operators can change business scheduling; a key made by a viewer can only read. Reseller keys (rk_…) can't make this change.
Request body (JSON)
| Name | Type | Description |
|---|---|---|
nameRequired | string | The host's name. 1–200 characters. |
email | string | null | The host's email. Up to 320 characters. |
title | string | null | Their role, shown to the team. Up to 200 characters. |
timezone | string | null | The host's time zone (an IANA name such as |
Example request
curl -X POST "https://www.nutalk.ai/v1/business/hosts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Ana López", "email": "ana@example.com", "title": "Account executive", "timezone": "America/Monterrey"}'The host.
{
"success": true,
"data": {
"id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"name": "Ana López",
"email": "ana@example.com",
"title": "Account executive",
"timezone": "America/Monterrey",
"status": "active",
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | The body is not JSON, or a field is missing or invalid (details.errors lists each field). |
| 400 | validation_error | timezone is not a time zone name. |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
| 403 | forbidden | The member who created the key can't do this (a viewer, or a clinic-only role), is no longer in the workspace, or the key is not a workspace key (sk_…). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Get a host
/v1/business/hosts/:idReturns one host, active or archived.
business_setup:readPath parameters
| Name | Type | Description |
|---|---|---|
idRequired | uuid | The host id. |
Example request
curl -X GET "https://www.nutalk.ai/v1/business/hosts/6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e" \ -H "Authorization: Bearer YOUR_API_KEY"The host.
{
"success": true,
"data": {
"id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"name": "Ana López",
"email": "ana@example.com",
"title": "Account executive",
"timezone": "America/Monterrey",
"status": "active",
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
}
}Errors
| Status | Code | When |
|---|---|---|
| 404 | not_found | No host with this id in your workspace (ids of other workspaces answer the same). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Update a host
/v1/business/hosts/:idChanges the fields you send; null clears email, title or timezone.
business_setup:writeCan wait for approvalWorkspace keys only · acts as the key's creatorThe change runs through the dashboard's own rules, as the member who created the key (an owner acts as an admin). Owners, admins, builders and operators can change business scheduling; a key made by a viewer can only read. Reseller keys (rk_…) can't make this change.
Path parameters
| Name | Type | Description |
|---|---|---|
idRequired | uuid | The host id. |
Request body (JSON)
| Name | Type | Description |
|---|---|---|
name | string | New name. 1–200 characters. |
email | string | null | New email. Up to 320 characters. |
title | string | null | New role. Up to 200 characters. |
timezone | string | null | The host's time zone (an IANA name such as |
Example request
curl -X PATCH "https://www.nutalk.ai/v1/business/hosts/6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Sales lead", "timezone": "America/Mexico_City"}'The updated host.
{
"success": true,
"data": {
"id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"name": "Ana López",
"email": "ana@example.com",
"title": "Sales lead",
"timezone": "America/Mexico_City",
"status": "active",
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | The body is not JSON, or a field is missing or invalid (details.errors lists each field). |
| 400 | validation_error | No field to change was sent, or timezone is not a time zone name. |
| 404 | not_found | No host with this id in your workspace (ids of other workspaces answer the same). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
| 403 | forbidden | The member who created the key can't do this (a viewer, or a clinic-only role), is no longer in the workspace, or the key is not a workspace key (sk_…). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Archive a host
/v1/business/hosts/:idArchives the host: they are no longer offered or booked. Their booked meetings stay booked; agents whose business scheduler defaults to this host offer no times until another default is chosen.
business_setup:writeCan wait for approvalWorkspace keys only · acts as the key's creatorThe change runs through the dashboard's own rules, as the member who created the key (an owner acts as an admin). Owners, admins, builders and operators can change business scheduling; a key made by a viewer can only read. Reseller keys (rk_…) can't make this change.
Path parameters
| Name | Type | Description |
|---|---|---|
idRequired | uuid | The host id. |
Example request
curl -X DELETE "https://www.nutalk.ai/v1/business/hosts/6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e" \ -H "Authorization: Bearer YOUR_API_KEY"The archived host.
{
"success": true,
"data": {
"id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"name": "Ana López",
"email": "ana@example.com",
"title": "Account executive",
"timezone": "America/Monterrey",
"status": "archived",
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
}
}Errors
| Status | Code | When |
|---|---|---|
| 404 | not_found | No host with this id in your workspace (ids of other workspaces answer the same). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
| 403 | forbidden | The member who created the key can't do this (a viewer, or a clinic-only role), is no longer in the workspace, or the key is not a workspace key (sk_…). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
List a host's weekly hours
/v1/business/hosts/:id/availabilityLists every weekly window of the host, switched on or off, by weekday and start time. Meetings are offered inside active windows only, on the host's clock.
business_setup:readPath parameters
| Name | Type | Description |
|---|---|---|
idRequired | uuid | The host id. |
Example request
curl -X GET "https://www.nutalk.ai/v1/business/hosts/6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e/availability" \ -H "Authorization: Bearer YOUR_API_KEY"The host's windows.
{
"success": true,
"data": [
{
"id": "3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c6d",
"host_id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"day_of_week": 1,
"start_time": "09:00",
"end_time": "13:00",
"is_active": true,
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
},
{
"id": "4b5c6d7e-8f9a-4b0c-9d1e-2f3a4b5c6d7e",
"host_id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"day_of_week": 1,
"start_time": "14:00",
"end_time": "18:00",
"is_active": true,
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
}
]
}Errors
| Status | Code | When |
|---|---|---|
| 404 | not_found | No host with this id in your workspace (ids of other workspaces answer the same). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Add weekly hours
/v1/business/hosts/:id/availabilityAdds the same hours on one or more weekdays (one window per day). All or nothing: when the hours overlap the host's existing hours on any of the days, nothing is added.
business_setup:writeWorkspace keys only · acts as the key's creatorA host's active windows on one weekday never overlap: overlapping hours read as one continuous run and would erase the break between them (a lunch break is two windows, 09:00–13:00 and 14:00–18:00). Windows that only touch (13:00 end, 13:00 start) are fine.
The change runs through the dashboard's own rules, as the member who created the key (an owner acts as an admin). Owners, admins, builders and operators can change business scheduling; a key made by a viewer can only read. Reseller keys (rk_…) can't make this change.
Path parameters
| Name | Type | Description |
|---|---|---|
idRequired | uuid | The host id. |
Request body (JSON)
| Name | Type | Description |
|---|---|---|
days_of_weekRequired | integer[] | The weekdays. Weekday: 0 = Sunday, 1 = Monday … 6 = Saturday. 1–7 items. |
start_timeRequired | string | HH:MM, 24-hour (00:00–23:59), on the host's clock. 5–5 characters. |
end_timeRequired | string | HH:MM, 24-hour (00:00–23:59), on the host's clock. After start_time; a meeting must end inside the window. 5–5 characters. |
Example request
curl -X POST "https://www.nutalk.ai/v1/business/hosts/6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e/availability" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "days_of_week": [ 1, 2, 3, 4, 5 ], "start_time": "09:00", "end_time": "13:00"}'The windows added, one per weekday.
{
"success": true,
"data": [
{
"id": "3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c6d",
"host_id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"day_of_week": 1,
"start_time": "09:00",
"end_time": "13:00",
"is_active": true,
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
}
]
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | The body is not JSON, or a field is missing or invalid (details.errors lists each field). |
| 400 | validation_error | end_time is not after start_time, or the hours overlap the host's existing hours (the message names the window). |
| 404 | not_found | No host with this id in your workspace (ids of other workspaces answer the same). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
| 403 | forbidden | The member who created the key can't do this (a viewer, or a clinic-only role), is no longer in the workspace, or the key is not a workspace key (sk_…). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Update a weekly window
/v1/business/availability-windows/:idChanges one window's weekday or hours, or switches it off (is_active: false) and on again. The window as it will read must not overlap the host's other active windows that day.
business_setup:writeCan wait for approvalWorkspace keys only · acts as the key's creatorA host's active windows on one weekday never overlap: overlapping hours read as one continuous run and would erase the break between them (a lunch break is two windows, 09:00–13:00 and 14:00–18:00). Windows that only touch (13:00 end, 13:00 start) are fine.
The change runs through the dashboard's own rules, as the member who created the key (an owner acts as an admin). Owners, admins, builders and operators can change business scheduling; a key made by a viewer can only read. Reseller keys (rk_…) can't make this change.
Path parameters
| Name | Type | Description |
|---|---|---|
idRequired | uuid | The availability window id. |
Request body (JSON)
| Name | Type | Description |
|---|---|---|
day_of_week | integer | Weekday: 0 = Sunday, 1 = Monday … 6 = Saturday. 0–6. |
start_time | string | HH:MM, 24-hour (00:00–23:59), on the host's clock. 5–5 characters. |
end_time | string | HH:MM, 24-hour (00:00–23:59), on the host's clock. 5–5 characters. |
is_active | boolean | Switch the window on or off (an inactive window offers nothing). |
Example request
curl -X PATCH "https://www.nutalk.ai/v1/business/availability-windows/6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "end_time": "12:30"}'The updated window.
{
"success": true,
"data": {
"id": "3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c6d",
"host_id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"day_of_week": 1,
"start_time": "09:00",
"end_time": "12:30",
"is_active": true,
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | The body is not JSON, or a field is missing or invalid (details.errors lists each field). |
| 400 | validation_error | No field to change was sent, end_time is not after start_time, or the window would overlap the host's other hours. |
| 404 | not_found | No availability window with this id in your workspace (ids of other workspaces answer the same). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
| 403 | forbidden | The member who created the key can't do this (a viewer, or a clinic-only role), is no longer in the workspace, or the key is not a workspace key (sk_…). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Delete a weekly window
/v1/business/availability-windows/:idRemoves one window for good; booked meetings stay. To pause it instead, set is_active: false.
business_setup:writeCan wait for approvalWorkspace keys only · acts as the key's creatorThe change runs through the dashboard's own rules, as the member who created the key (an owner acts as an admin). Owners, admins, builders and operators can change business scheduling; a key made by a viewer can only read. Reseller keys (rk_…) can't make this change.
Path parameters
| Name | Type | Description |
|---|---|---|
idRequired | uuid | The availability window id. |
Example request
curl -X DELETE "https://www.nutalk.ai/v1/business/availability-windows/6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e" \ -H "Authorization: Bearer YOUR_API_KEY"The window was deleted.
{
"success": true,
"data": {
"id": "3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c6d",
"deleted": true
}
}Errors
| Status | Code | When |
|---|---|---|
| 404 | not_found | No availability window with this id in your workspace (ids of other workspaces answer the same). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
| 403 | forbidden | The member who created the key can't do this (a viewer, or a clinic-only role), is no longer in the workspace, or the key is not a workspace key (sk_…). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
List a host's days off
/v1/business/hosts/:id/days-offLists the host's time off, oldest first. Company-wide closures are listed by GET /v1/business/closures.
business_setup:readPath parameters
| Name | Type | Description |
|---|---|---|
idRequired | uuid | The host id. |
Query parameters
| Name | Type | Description |
|---|---|---|
limit | integer | Results per page. 1–100. Default: |
offset | integer | Results to skip. At least 0. Default: |
from | datetime | Only the ones that end after this time (ISO 8601 with an offset or Z). |
to | datetime | Only the ones that start before this time. |
Example request
curl -X GET "https://www.nutalk.ai/v1/business/hosts/6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e/days-off?from=2026-10-12T00:00:00Z" \ -H "Authorization: Bearer YOUR_API_KEY"A page of days off.
{
"success": true,
"data": [
{
"id": "5c6d7e8f-9a0b-4c1d-ae2f-3a4b5c6d7e8f",
"host_id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"starts_at": "2026-12-24T06:00:00+00:00",
"ends_at": "2026-12-26T06:00:00+00:00",
"reason": "Vacation",
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
}
],
"pagination": {
"total": 1,
"limit": 20,
"offset": 0,
"has_more": false
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | A query parameter is invalid (details.errors lists each one). |
| 404 | not_found | No host with this id in your workspace (ids of other workspaces answer the same). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Add a day off
/v1/business/hosts/:id/days-offBlocks the host from starts_at to ends_at: no meeting is offered or booked with them in that time. Meetings already booked then stay booked.
business_setup:writeWorkspace keys only · acts as the key's creatorThe change runs through the dashboard's own rules, as the member who created the key (an owner acts as an admin). Owners, admins, builders and operators can change business scheduling; a key made by a viewer can only read. Reseller keys (rk_…) can't make this change.
Path parameters
| Name | Type | Description |
|---|---|---|
idRequired | uuid | The host id. |
Request body (JSON)
| Name | Type | Description |
|---|---|---|
starts_atRequired | datetime | When it starts (ISO 8601 with an offset or Z). A whole day starts at its local midnight. |
ends_atRequired | datetime | When it ends, after starts_at (the next local midnight for a whole day). |
reason | string | null | A note for your team. Up to 500 characters. |
Example request
curl -X POST "https://www.nutalk.ai/v1/business/hosts/6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e/days-off" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "starts_at": "2026-12-24T00:00:00-06:00", "ends_at": "2026-12-26T00:00:00-06:00", "reason": "Vacation"}'The day off.
{
"success": true,
"data": {
"id": "5c6d7e8f-9a0b-4c1d-ae2f-3a4b5c6d7e8f",
"host_id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"starts_at": "2026-12-24T06:00:00+00:00",
"ends_at": "2026-12-26T06:00:00+00:00",
"reason": "Vacation",
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | The body is not JSON, or a field is missing or invalid (details.errors lists each field). |
| 400 | validation_error | ends_at is not after starts_at (as it will read). |
| 404 | not_found | No host with this id in your workspace (ids of other workspaces answer the same). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
| 403 | forbidden | The member who created the key can't do this (a viewer, or a clinic-only role), is no longer in the workspace, or the key is not a workspace key (sk_…). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Update a day off
/v1/business/days-off/:idChanges a host's day off; null clears the reason.
business_setup:writeCan wait for approvalWorkspace keys only · acts as the key's creatorThe change runs through the dashboard's own rules, as the member who created the key (an owner acts as an admin). Owners, admins, builders and operators can change business scheduling; a key made by a viewer can only read. Reseller keys (rk_…) can't make this change.
Path parameters
| Name | Type | Description |
|---|---|---|
idRequired | uuid | The day off id. |
Request body (JSON)
| Name | Type | Description |
|---|---|---|
starts_at | datetime | When it starts (ISO 8601 with an offset or Z). A whole day starts at its local midnight. |
ends_at | datetime | When it ends, after starts_at (the next local midnight for a whole day). |
reason | string | null | A note for your team. Up to 500 characters. |
Example request
curl -X PATCH "https://www.nutalk.ai/v1/business/days-off/6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "ends_at": "2026-12-27T00:00:00-06:00"}'The updated day off.
{
"success": true,
"data": {
"id": "5c6d7e8f-9a0b-4c1d-ae2f-3a4b5c6d7e8f",
"host_id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"starts_at": "2026-12-24T06:00:00+00:00",
"ends_at": "2026-12-27T06:00:00+00:00",
"reason": "Vacation",
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | The body is not JSON, or a field is missing or invalid (details.errors lists each field). |
| 400 | validation_error | No field to change was sent. |
| 400 | validation_error | ends_at is not after starts_at (as it will read). |
| 404 | not_found | No day off with this id in your workspace (ids of other workspaces answer the same). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
| 403 | forbidden | The member who created the key can't do this (a viewer, or a clinic-only role), is no longer in the workspace, or the key is not a workspace key (sk_…). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Delete a day off
/v1/business/days-off/:idRemoves a host's day off: the time is bookable again within their weekly hours.
business_setup:writeCan wait for approvalWorkspace keys only · acts as the key's creatorThe change runs through the dashboard's own rules, as the member who created the key (an owner acts as an admin). Owners, admins, builders and operators can change business scheduling; a key made by a viewer can only read. Reseller keys (rk_…) can't make this change.
Path parameters
| Name | Type | Description |
|---|---|---|
idRequired | uuid | The day off id. |
Example request
curl -X DELETE "https://www.nutalk.ai/v1/business/days-off/6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e" \ -H "Authorization: Bearer YOUR_API_KEY"The day off was deleted.
{
"success": true,
"data": {
"id": "5c6d7e8f-9a0b-4c1d-ae2f-3a4b5c6d7e8f",
"deleted": true
}
}Errors
| Status | Code | When |
|---|---|---|
| 404 | not_found | No day off with this id in your workspace (ids of other workspaces answer the same). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
| 403 | forbidden | The member who created the key can't do this (a viewer, or a clinic-only role), is no longer in the workspace, or the key is not a workspace key (sk_…). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
List closures
/v1/business/closuresLists company-wide closures (every host is blocked), oldest first.
business_setup:readQuery parameters
| Name | Type | Description |
|---|---|---|
limit | integer | Results per page. 1–100. Default: |
offset | integer | Results to skip. At least 0. Default: |
from | datetime | Only the ones that end after this time (ISO 8601 with an offset or Z). |
to | datetime | Only the ones that start before this time. |
Example request
curl -X GET "https://www.nutalk.ai/v1/business/closures?from=2026-10-12T00:00:00Z" \ -H "Authorization: Bearer YOUR_API_KEY"A page of closures.
{
"success": true,
"data": [
{
"id": "6d7e8f9a-0b1c-4d2e-bf3a-4b5c6d7e8f9a",
"starts_at": "2027-01-01T06:00:00+00:00",
"ends_at": "2027-01-02T06:00:00+00:00",
"reason": "New Year's Day",
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
}
],
"pagination": {
"total": 1,
"limit": 20,
"offset": 0,
"has_more": false
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | A query parameter is invalid (details.errors lists each one). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Add a closure
/v1/business/closuresCloses the business from starts_at to ends_at (a holiday, an event): no host is offered or booked in that time.
business_setup:writeWorkspace keys only · acts as the key's creatorThe change runs through the dashboard's own rules, as the member who created the key (an owner acts as an admin). Owners, admins, builders and operators can change business scheduling; a key made by a viewer can only read. Reseller keys (rk_…) can't make this change.
Request body (JSON)
| Name | Type | Description |
|---|---|---|
starts_atRequired | datetime | When it starts (ISO 8601 with an offset or Z). A whole day starts at its local midnight. |
ends_atRequired | datetime | When it ends, after starts_at (the next local midnight for a whole day). |
reason | string | null | A note for your team. Up to 500 characters. |
Example request
curl -X POST "https://www.nutalk.ai/v1/business/closures" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "starts_at": "2027-01-01T00:00:00-06:00", "ends_at": "2027-01-02T00:00:00-06:00", "reason": "New Year'\''s Day"}'The closure.
{
"success": true,
"data": {
"id": "6d7e8f9a-0b1c-4d2e-bf3a-4b5c6d7e8f9a",
"starts_at": "2027-01-01T06:00:00+00:00",
"ends_at": "2027-01-02T06:00:00+00:00",
"reason": "New Year's Day",
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | The body is not JSON, or a field is missing or invalid (details.errors lists each field). |
| 400 | validation_error | ends_at is not after starts_at (as it will read). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
| 403 | forbidden | The member who created the key can't do this (a viewer, or a clinic-only role), is no longer in the workspace, or the key is not a workspace key (sk_…). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Update a closure
/v1/business/closures/:idChanges a company-wide closure; null clears the reason.
business_setup:writeCan wait for approvalWorkspace keys only · acts as the key's creatorThe change runs through the dashboard's own rules, as the member who created the key (an owner acts as an admin). Owners, admins, builders and operators can change business scheduling; a key made by a viewer can only read. Reseller keys (rk_…) can't make this change.
Path parameters
| Name | Type | Description |
|---|---|---|
idRequired | uuid | The closure id. |
Request body (JSON)
| Name | Type | Description |
|---|---|---|
starts_at | datetime | When it starts (ISO 8601 with an offset or Z). A whole day starts at its local midnight. |
ends_at | datetime | When it ends, after starts_at (the next local midnight for a whole day). |
reason | string | null | A note for your team. Up to 500 characters. |
Example request
curl -X PATCH "https://www.nutalk.ai/v1/business/closures/6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "reason": "Holiday"}'The updated closure.
{
"success": true,
"data": {
"id": "6d7e8f9a-0b1c-4d2e-bf3a-4b5c6d7e8f9a",
"starts_at": "2027-01-01T06:00:00+00:00",
"ends_at": "2027-01-02T06:00:00+00:00",
"reason": "Holiday",
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | The body is not JSON, or a field is missing or invalid (details.errors lists each field). |
| 400 | validation_error | No field to change was sent. |
| 400 | validation_error | ends_at is not after starts_at (as it will read). |
| 404 | not_found | No closure with this id in your workspace (ids of other workspaces answer the same). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
| 403 | forbidden | The member who created the key can't do this (a viewer, or a clinic-only role), is no longer in the workspace, or the key is not a workspace key (sk_…). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Delete a closure
/v1/business/closures/:idRemoves a company-wide closure.
business_setup:writeCan wait for approvalWorkspace keys only · acts as the key's creatorThe change runs through the dashboard's own rules, as the member who created the key (an owner acts as an admin). Owners, admins, builders and operators can change business scheduling; a key made by a viewer can only read. Reseller keys (rk_…) can't make this change.
Path parameters
| Name | Type | Description |
|---|---|---|
idRequired | uuid | The closure id. |
Example request
curl -X DELETE "https://www.nutalk.ai/v1/business/closures/6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e" \ -H "Authorization: Bearer YOUR_API_KEY"The closure was deleted.
{
"success": true,
"data": {
"id": "6d7e8f9a-0b1c-4d2e-bf3a-4b5c6d7e8f9a",
"deleted": true
}
}Errors
| Status | Code | When |
|---|---|---|
| 404 | not_found | No closure with this id in your workspace (ids of other workspaces answer the same). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
| 403 | forbidden | The member who created the key can't do this (a viewer, or a clinic-only role), is no longer in the workspace, or the key is not a workspace key (sk_…). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
List meeting types
/v1/business/meeting-typesLists meeting types in the dashboard's order, each with the hosts who take it (host_ids; empty means every active host).
business_setup:readQuery parameters
| Name | Type | Description |
|---|---|---|
limit | integer | Results per page. 1–100. Default: |
offset | integer | Results to skip. At least 0. Default: |
status | string | Active meeting types (the default) or archived ones. One of: active, archived. Default: |
Example request
curl -X GET "https://www.nutalk.ai/v1/business/meeting-types?limit=20" \ -H "Authorization: Bearer YOUR_API_KEY"A page of meeting types.
{
"success": true,
"data": [
{
"id": "8f9a0b1c-2d3e-4f4a-8b5c-6d7e8f9a0b1c",
"name": "Intro call",
"slug": "intro-call",
"description": "A 30-minute first conversation.",
"duration_minutes": 30,
"buffer_before_minutes": 0,
"buffer_after_minutes": 10,
"slot_interval_minutes": 30,
"location_kind": "google_meet",
"location_details": null,
"min_notice_minutes": 240,
"max_advance_days": 60,
"color": "#3B82F6",
"sort_order": 0,
"status": "active",
"host_ids": [
"1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"7e8f9a0b-1c2d-4e3f-9a4b-5c6d7e8f9a0b"
],
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
}
],
"pagination": {
"total": 1,
"limit": 20,
"offset": 0,
"has_more": false
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | A query parameter is invalid (details.errors lists each one). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Create a meeting type
/v1/business/meeting-typesCreates a kind of meeting customers and agents can book: its length, buffers, start-time steps, location and booking window, and the hosts who take it.
business_setup:writeWorkspace keys only · acts as the key's creatorThe change runs through the dashboard's own rules, as the member who created the key (an owner acts as an admin). Owners, admins, builders and operators can change business scheduling; a key made by a viewer can only read. Reseller keys (rk_…) can't make this change.
Request body (JSON)
| Name | Type | Description |
|---|---|---|
nameRequired | string | The name customers and agents see, e.g. Intro call. 1–200 characters. |
slug | string | Lowercase letters, digits and dashes, unique among the workspace's active meeting types. Omitted: made from the name. Up to 60 characters. |
description | string | null | What the meeting is for. Up to 2000 characters. |
duration_minutes | integer | How long the meeting lasts. 5–480. Default: |
buffer_before_minutes | integer | Free time the host needs before it. 0–120. Default: |
buffer_after_minutes | integer | Free time the host needs after it. 0–120. Default: |
slot_interval_minutes | integer | Offered start times step by this many minutes from the start of each window. 5–120. Default: |
location_kind | string |
Default: |
location_details | string | null | The address, phone number or instructions. Up to 1000 characters. |
min_notice_minutes | integer | How far ahead a meeting must be booked. 0–10080. Default: |
max_advance_days | integer | How many days ahead it can be booked. 1–365. Default: |
color | string | null | A hex color for the dashboard, e.g. #3B82F6. Up to 7 characters. |
sort_order | integer | Position in lists (lowest first). 0–999. Default: |
host_ids | uuid[] | The hosts who take this meeting type, in priority order. Omitted or empty: every active host. 0–200 items. |
Example request
curl -X POST "https://www.nutalk.ai/v1/business/meeting-types" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Intro call", "description": "A 30-minute first conversation.", "duration_minutes": 30, "buffer_after_minutes": 10, "location_kind": "google_meet", "host_ids": [ "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f", "7e8f9a0b-1c2d-4e3f-9a4b-5c6d7e8f9a0b" ]}'The meeting type.
{
"success": true,
"data": {
"id": "8f9a0b1c-2d3e-4f4a-8b5c-6d7e8f9a0b1c",
"name": "Intro call",
"slug": "intro-call",
"description": "A 30-minute first conversation.",
"duration_minutes": 30,
"buffer_before_minutes": 0,
"buffer_after_minutes": 10,
"slot_interval_minutes": 30,
"location_kind": "google_meet",
"location_details": null,
"min_notice_minutes": 240,
"max_advance_days": 60,
"color": "#3B82F6",
"sort_order": 0,
"status": "active",
"host_ids": [
"1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"7e8f9a0b-1c2d-4e3f-9a4b-5c6d7e8f9a0b"
],
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | The body is not JSON, or a field is missing or invalid (details.errors lists each field). |
| 400 | validation_error | A host in host_ids is not a host of your workspace. |
| 409 | conflict | An active meeting type already uses the slug (send another name or a slug). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
| 403 | forbidden | The member who created the key can't do this (a viewer, or a clinic-only role), is no longer in the workspace, or the key is not a workspace key (sk_…). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Get a meeting type
/v1/business/meeting-types/:idReturns one meeting type, active or archived, with its hosts.
business_setup:readPath parameters
| Name | Type | Description |
|---|---|---|
idRequired | uuid | The meeting type id. |
Example request
curl -X GET "https://www.nutalk.ai/v1/business/meeting-types/6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e" \ -H "Authorization: Bearer YOUR_API_KEY"The meeting type.
{
"success": true,
"data": {
"id": "8f9a0b1c-2d3e-4f4a-8b5c-6d7e8f9a0b1c",
"name": "Intro call",
"slug": "intro-call",
"description": "A 30-minute first conversation.",
"duration_minutes": 30,
"buffer_before_minutes": 0,
"buffer_after_minutes": 10,
"slot_interval_minutes": 30,
"location_kind": "google_meet",
"location_details": null,
"min_notice_minutes": 240,
"max_advance_days": 60,
"color": "#3B82F6",
"sort_order": 0,
"status": "active",
"host_ids": [
"1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"7e8f9a0b-1c2d-4e3f-9a4b-5c6d7e8f9a0b"
],
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
}
}Errors
| Status | Code | When |
|---|---|---|
| 404 | not_found | No meeting type with this id in your workspace (ids of other workspaces answer the same). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Update a meeting type
/v1/business/meeting-types/:idChanges the fields you send. host_ids replaces the hosts who take it (an empty list means every active host); the new hosts are added before the old ones are removed, so a failure part-way never opens the type to every host.
business_setup:writeCan wait for approvalWorkspace keys only · acts as the key's creatorThe change runs through the dashboard's own rules, as the member who created the key (an owner acts as an admin). Owners, admins, builders and operators can change business scheduling; a key made by a viewer can only read. Reseller keys (rk_…) can't make this change.
Path parameters
| Name | Type | Description |
|---|---|---|
idRequired | uuid | The meeting type id. |
Request body (JSON)
| Name | Type | Description |
|---|---|---|
name | string | The name customers and agents see, e.g. Intro call. 1–200 characters. |
description | string | null | What the meeting is for. Up to 2000 characters. |
duration_minutes | integer | How long the meeting lasts (booked meetings keep their length). 5–480. |
buffer_before_minutes | integer | Free time the host needs before it. 0–120. |
buffer_after_minutes | integer | Free time the host needs after it. 0–120. |
slot_interval_minutes | integer | Offered start times step by this many minutes from the start of each window. 5–120. |
location_kind | string |
|
location_details | string | null | The address, phone number or instructions. Up to 1000 characters. |
min_notice_minutes | integer | How far ahead a meeting must be booked. 0–10080. |
max_advance_days | integer | How many days ahead it can be booked. 1–365. |
color | string | null | A hex color for the dashboard, e.g. #3B82F6. Up to 7 characters. |
sort_order | integer | Position in lists (lowest first). 0–999. |
host_ids | uuid[] | Replaces the hosts who take it, in priority order; an empty list means every active host. 0–200 items. |
Example request
curl -X PATCH "https://www.nutalk.ai/v1/business/meeting-types/6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "duration_minutes": 45, "host_ids": [ "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f" ]}'The updated meeting type.
{
"success": true,
"data": {
"id": "8f9a0b1c-2d3e-4f4a-8b5c-6d7e8f9a0b1c",
"name": "Intro call",
"slug": "intro-call",
"description": "A 30-minute first conversation.",
"duration_minutes": 45,
"buffer_before_minutes": 0,
"buffer_after_minutes": 10,
"slot_interval_minutes": 30,
"location_kind": "google_meet",
"location_details": null,
"min_notice_minutes": 240,
"max_advance_days": 60,
"color": "#3B82F6",
"sort_order": 0,
"status": "active",
"host_ids": [
"1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f"
],
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | The body is not JSON, or a field is missing or invalid (details.errors lists each field). |
| 400 | validation_error | No field to change was sent, or a host in host_ids is not a host of your workspace. |
| 404 | not_found | No meeting type with this id in your workspace (ids of other workspaces answer the same). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
| 403 | forbidden | The member who created the key can't do this (a viewer, or a clinic-only role), is no longer in the workspace, or the key is not a workspace key (sk_…). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Archive a meeting type
/v1/business/meeting-types/:idArchives the meeting type: it is no longer offered or booked, and its booked meetings stay. Agents whose business scheduler defaults to it offer no times until another default is chosen.
business_setup:writeCan wait for approvalWorkspace keys only · acts as the key's creatorThe change runs through the dashboard's own rules, as the member who created the key (an owner acts as an admin). Owners, admins, builders and operators can change business scheduling; a key made by a viewer can only read. Reseller keys (rk_…) can't make this change.
Path parameters
| Name | Type | Description |
|---|---|---|
idRequired | uuid | The meeting type id. |
Example request
curl -X DELETE "https://www.nutalk.ai/v1/business/meeting-types/6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e" \ -H "Authorization: Bearer YOUR_API_KEY"The archived meeting type.
{
"success": true,
"data": {
"id": "8f9a0b1c-2d3e-4f4a-8b5c-6d7e8f9a0b1c",
"name": "Intro call",
"slug": "intro-call",
"description": "A 30-minute first conversation.",
"duration_minutes": 30,
"buffer_before_minutes": 0,
"buffer_after_minutes": 10,
"slot_interval_minutes": 30,
"location_kind": "google_meet",
"location_details": null,
"min_notice_minutes": 240,
"max_advance_days": 60,
"color": "#3B82F6",
"sort_order": 0,
"status": "archived",
"host_ids": [
"1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"7e8f9a0b-1c2d-4e3f-9a4b-5c6d7e8f9a0b"
],
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
}
}Errors
| Status | Code | When |
|---|---|---|
| 404 | not_found | No meeting type with this id in your workspace (ids of other workspaces answer the same). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
| 403 | forbidden | The member who created the key can't do this (a viewer, or a clinic-only role), is no longer in the workspace, or the key is not a workspace key (sk_…). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
List a host's calendar connections
/v1/business/hosts/:id/calendar-connectionsLists the calendar accounts connected for the host: Google and Outlook (their busy time blocks the host, and one of them can receive the meetings) and iCloud/CalDAV accounts and iCal links (busy time only). Tokens, passwords and iCal addresses are never returned.
business_setup:readPath parameters
| Name | Type | Description |
|---|---|---|
idRequired | uuid | The host id. |
Example request
curl -X GET "https://www.nutalk.ai/v1/business/hosts/6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e/calendar-connections" \ -H "Authorization: Bearer YOUR_API_KEY"The host's connections.
{
"success": true,
"data": [
{
"id": "9a0b1c2d-3e4f-4a5b-9c6d-7e8f9a0b1c2d",
"host_id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"provider": "google",
"account": "ana@example.com",
"calendar_id": "primary",
"selected_calendar_ids": [
"primary"
],
"sync_enabled": true,
"connected_at": "2026-10-12T15:04:05.123456+00:00",
"revoked_at": null,
"last_sync_error": null
}
]
}Errors
| Status | Code | When |
|---|---|---|
| 404 | not_found | No host with this id in your workspace (ids of other workspaces answer the same). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
List a connected account's calendars
/v1/business/calendar-connections/:id/calendarsAsks the provider for the account's calendars, with the connection's current choice: the ids to use in selected_calendar_ids and calendar_id.
business_setup:readWorkspace keys only · acts as the key's creatorRuns as the member who created the key (it reads with their access); reseller keys can't call it.
Path parameters
| Name | Type | Description |
|---|---|---|
idRequired | uuid | The calendar connection id. |
Example request
curl -X GET "https://www.nutalk.ai/v1/business/calendar-connections/6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e/calendars" \ -H "Authorization: Bearer YOUR_API_KEY"The account's calendars.
{
"success": true,
"data": {
"calendars": [
{
"id": "primary",
"name": "Ana López",
"primary": true,
"writable": true,
"color": "#039BE5"
},
{
"id": "team@example.com",
"name": "Team",
"primary": false,
"writable": false,
"color": "#7986CB"
}
],
"selected_calendar_ids": [
"primary"
],
"appointment_calendar_id": "primary",
"sync_enabled": true
}
}Errors
| Status | Code | When |
|---|---|---|
| 404 | not_found | No calendar connection with this id in your workspace (ids of other workspaces answer the same). |
| 409 | conflict | The account must be connected again (its access was revoked). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
| 403 | forbidden | The member who created the key can't do this (a viewer, or a clinic-only role), is no longer in the workspace, or the key is not a workspace key (sk_…). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Update a calendar connection
/v1/business/calendar-connections/:idChooses which of the account's calendars block the host's time (selected_calendar_ids), which one new meetings are written to (calendar_id, Google and Outlook only) and whether they are written at all (sync_enabled; turning it on turns it off on the host's other accounts).
business_setup:writeCan wait for approvalWorkspace keys only · acts as the key's creatorRuns as the member who created the key: only owners, admins and builders change calendar connections. Connecting a new account (Google, Outlook, iCloud/CalDAV, an iCal link) is done in the dashboard.
Path parameters
| Name | Type | Description |
|---|---|---|
idRequired | uuid | The calendar connection id. |
Request body (JSON)
| Name | Type | Description |
|---|---|---|
selected_calendar_ids | string[] | The calendars whose busy time blocks the host. 1–50 items. |
calendar_id | string | Where new meetings are written: one of the selected calendars (Google and Outlook accounts). Up to 1000 characters. |
sync_enabled | boolean | Write the host's meetings to this account (iCal links and CalDAV accounts never receive them). |
Example request
curl -X PATCH "https://www.nutalk.ai/v1/business/calendar-connections/6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "selected_calendar_ids": [ "primary", "team@example.com" ], "calendar_id": "primary"}'The updated connection. For iCal and CalDAV the new selection is read again at once; sync_error says why that read failed (the selection is saved either way).
{
"success": true,
"data": {
"id": "9a0b1c2d-3e4f-4a5b-9c6d-7e8f9a0b1c2d",
"host_id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"provider": "google",
"account": "ana@example.com",
"calendar_id": "primary",
"selected_calendar_ids": [
"primary",
"team@example.com"
],
"sync_enabled": true,
"connected_at": "2026-10-12T15:04:05.123456+00:00",
"revoked_at": null,
"last_sync_error": null
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | The body is not JSON, or a field is missing or invalid (details.errors lists each field). |
| 400 | validation_error | No field to change was sent, calendar_id is not a selected calendar, a new selected_calendar_ids leaves out the calendar meetings are written to without naming another in calendar_id, a calendar isn't the account's (iCal and CalDAV accounts), or an iCal/CalDAV account was asked to receive meetings. |
| 404 | not_found | No calendar connection with this id in your workspace (ids of other workspaces answer the same). |
| 409 | conflict | The account was reconnected meanwhile; read it again and retry. |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
| 403 | forbidden | The member who created the key can't do this (a viewer, or a clinic-only role), is no longer in the workspace, or the key is not a workspace key (sk_…). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Disconnect a calendar
/v1/business/calendar-connections/:idDisconnects the account from the host and removes its tokens: its busy time no longer blocks the host, and meetings are no longer written there.
business_setup:writeCan wait for approvalWorkspace keys only · acts as the key's creatorRuns as the member who created the key: only owners, admins and builders change calendar connections. Connecting a new account (Google, Outlook, iCloud/CalDAV, an iCal link) is done in the dashboard.
Path parameters
| Name | Type | Description |
|---|---|---|
idRequired | uuid | The calendar connection id. |
Example request
curl -X DELETE "https://www.nutalk.ai/v1/business/calendar-connections/6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e" \ -H "Authorization: Bearer YOUR_API_KEY"The account was disconnected.
{
"success": true,
"data": {
"id": "9a0b1c2d-3e4f-4a5b-9c6d-7e8f9a0b1c2d",
"disconnected": true
}
}Errors
| Status | Code | When |
|---|---|---|
| 404 | not_found | No calendar connection with this id in your workspace (ids of other workspaces answer the same). |
| 409 | conflict | The account still holds an active meeting: cancel or move it first. |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
| 403 | forbidden | The member who created the key can't do this (a viewer, or a clinic-only role), is no longer in the workspace, or the key is not a workspace key (sk_…). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Business appointments
The business meetings of the agenda. Bookings and moves are checked by the engine that checks the dashboard's and the agents' bookings, so a time from GET /v1/business/availability can still be refused (409) when someone took it first. These endpoints are also listed with the clinic appointments in the Agenda reference.
Endpoints
/v1/business/appointmentsList business appointmentsPOST/v1/business/appointmentsBook a business appointmentGET/v1/business/appointments/:idGet a business appointmentPATCH/v1/business/appointments/:idReschedule, cancel or update a business appointmentGET/v1/business/availabilityFind free business meeting times| Status | Meaning |
|---|---|
| confirmed | Booked; the only status that blocks the host's time. |
| cancelled | Called off (PATCH status cancelled); its calendar event is removed. |
| completed | Took place (once it has started). |
| no_show | The invitee didn't come (once it has started). |
List business appointments
/v1/business/appointmentsLists business meetings by start time, oldest first. from and to keep the meetings that overlap the range (send from = now for the upcoming ones).
appointments:readQuery parameters
| Name | Type | Description |
|---|---|---|
limit | integer | Results per page. 1–100. Default: |
offset | integer | Results to skip. At least 0. Default: |
from | datetime | Only meetings that end after this time (ISO 8601 with an offset or Z). |
to | datetime | Only meetings that start before this time. |
host_id | uuid | Only this host's meetings. |
meeting_type_id | uuid | Only meetings of this type. |
contact_id | uuid | Only this contact's meetings. |
status | string | Only meetings in this status. One of: confirmed, cancelled, completed, no_show. |
Example request
curl -X GET "https://www.nutalk.ai/v1/business/appointments?from=2026-10-12T00:00:00Z&status=confirmed" \ -H "Authorization: Bearer YOUR_API_KEY"A page of meetings.
{
"success": true,
"data": [
{
"id": "6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e",
"meeting_type_id": "8f9a0b1c-2d3e-4f4a-8b5c-6d7e8f9a0b1c",
"meeting_type_name": "Intro call",
"host_id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"host_name": "Ana López",
"invitee_name": "Carlos Ruiz",
"invitee_email": "carlos@example.com",
"invitee_phone": "+528112345678",
"invitee_company": "Acme",
"invitee_notes": null,
"starts_at": "2026-10-20T16:00:00+00:00",
"ends_at": "2026-10-20T16:30:00+00:00",
"timezone": "America/Monterrey",
"status": "confirmed",
"location_kind": "google_meet",
"location_details": null,
"meeting_url": "https://meet.google.com/abc-defg-hij",
"source": "dashboard",
"contact_id": "9595b646-ab97-4485-b1b8-e8b58dfcdd19",
"channel_id": null,
"call_id": null,
"conversation_id": null,
"cancellation_reason": null,
"calendar_sync_status": "synced",
"calendar_sync_error": null,
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
}
],
"pagination": {
"total": 1,
"limit": 20,
"offset": 0,
"has_more": false
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | A query parameter is invalid (details.errors lists each one). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Book a business appointment
/v1/business/appointmentsBooks a meeting at a start time from GET /v1/business/availability, through the engine that validates the dashboard's and the agents' bookings: the time must still be free. Without host_id, the least busy host who can take the meeting type is chosen.
appointments:writeSupports Idempotency-KeyWorkspace keys only · acts as the key's creatorWhen the host's Google or Outlook calendar is connected, the meeting is written there (with a Meet link for google_meet) and the invitee gets the calendar's invitation; a calendar that fails never undoes the change (calendar_sync_status, calendar_sync_error).
The change runs through the dashboard's own rules, as the member who created the key (an owner acts as an admin). Owners, admins, builders and operators can change business scheduling; a key made by a viewer can only read. Reseller keys (rk_…) can't make this change.
Request body (JSON)
| Name | Type | Description |
|---|---|---|
meeting_type_idRequired | uuid | The meeting type. |
slot_startRequired | datetime | The start time: a slot's |
invitee_nameRequired | string | Who the meeting is with. 1–200 characters. |
invitee_phoneRequired | string | Their phone with the country code (at least 10 digits), e.g. +528112345678: reminders, the contact link and WhatsApp notes use it. Up to 40 characters. |
invitee_email | string | null | Their email: the host's connected calendar sends them the invitation. Up to 320 characters. |
invitee_company | string | null | Their company. Up to 200 characters. |
invitee_notes | string | null | Notes for the host. Up to 2000 characters. |
host_id | uuid | null | Book this host. Omitted or null: any host who can take the meeting type (least busy first). |
override_validation | boolean | Book even outside the hosts' hours, days off and notice, without checking their connected calendars. A host is never double-booked. Default: |
Example request
curl -X POST "https://www.nutalk.ai/v1/business/appointments" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Idempotency-Key: 11111111-2222-4333-8444-555555555555" \ -H "Content-Type: application/json" \ -d '{ "meeting_type_id": "8f9a0b1c-2d3e-4f4a-8b5c-6d7e8f9a0b1c", "slot_start": "2026-10-20T16:00:00Z", "invitee_name": "Carlos Ruiz", "invitee_phone": "+528112345678", "invitee_email": "carlos@example.com", "invitee_company": "Acme"}'The booked meeting.
{
"success": true,
"data": {
"id": "6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e",
"meeting_type_id": "8f9a0b1c-2d3e-4f4a-8b5c-6d7e8f9a0b1c",
"meeting_type_name": "Intro call",
"host_id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"host_name": "Ana López",
"invitee_name": "Carlos Ruiz",
"invitee_email": "carlos@example.com",
"invitee_phone": "+528112345678",
"invitee_company": "Acme",
"invitee_notes": null,
"starts_at": "2026-10-20T16:00:00+00:00",
"ends_at": "2026-10-20T16:30:00+00:00",
"timezone": "America/Monterrey",
"status": "confirmed",
"location_kind": "google_meet",
"location_details": null,
"meeting_url": "https://meet.google.com/abc-defg-hij",
"source": "dashboard",
"contact_id": "9595b646-ab97-4485-b1b8-e8b58dfcdd19",
"channel_id": null,
"call_id": null,
"conversation_id": null,
"cancellation_reason": null,
"calendar_sync_status": "synced",
"calendar_sync_error": null,
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | The body is not JSON, or a field is missing or invalid (details.errors lists each field). |
| 400 | validation_error | A field the booking needs is missing or invalid (the message names it). |
| 404 | not_found | The meeting type doesn't exist or is archived. |
| 409 | conflict | The time can't be booked: it is taken, outside the hosts' hours or notice, a host's connected calendar couldn't be checked, or no host can take the meeting type (host_id is not an active host who takes it). The message says which. |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
| 403 | forbidden | The member who created the key can't do this (a viewer, or a clinic-only role), is no longer in the workspace, or the key is not a workspace key (sk_…). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Get a business appointment
/v1/business/appointments/:idReturns one business meeting, in any status.
appointments:readPath parameters
| Name | Type | Description |
|---|---|---|
idRequired | uuid | The appointment id. |
Example request
curl -X GET "https://www.nutalk.ai/v1/business/appointments/6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e" \ -H "Authorization: Bearer YOUR_API_KEY"The meeting.
{
"success": true,
"data": {
"id": "6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e",
"meeting_type_id": "8f9a0b1c-2d3e-4f4a-8b5c-6d7e8f9a0b1c",
"meeting_type_name": "Intro call",
"host_id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"host_name": "Ana López",
"invitee_name": "Carlos Ruiz",
"invitee_email": "carlos@example.com",
"invitee_phone": "+528112345678",
"invitee_company": "Acme",
"invitee_notes": null,
"starts_at": "2026-10-20T16:00:00+00:00",
"ends_at": "2026-10-20T16:30:00+00:00",
"timezone": "America/Monterrey",
"status": "confirmed",
"location_kind": "google_meet",
"location_details": null,
"meeting_url": "https://meet.google.com/abc-defg-hij",
"source": "dashboard",
"contact_id": "9595b646-ab97-4485-b1b8-e8b58dfcdd19",
"channel_id": null,
"call_id": null,
"conversation_id": null,
"cancellation_reason": null,
"calendar_sync_status": "synced",
"calendar_sync_error": null,
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
}
}Errors
| Status | Code | When |
|---|---|---|
| 404 | not_found | No appointment with this id in your workspace (ids of other workspaces answer the same). |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Reschedule, cancel or update a business appointment
/v1/business/appointments/:idMakes one change per request: a new time (slot_start, with duration_minutes, host_id, notify_invitee and override_validation), a status (cancelled with cancellation_reason, or completed / no_show once the meeting has started), or the invitee's details. A move keeps the meeting's host unless you name another in host_id; host_id: null lets any host who can take the meeting type have it when its host isn't free.
appointments:writeCan wait for approvalWorkspace keys only · acts as the key's creatorWhen the host's Google or Outlook calendar is connected, the meeting is written there (with a Meet link for google_meet) and the invitee gets the calendar's invitation; a calendar that fails never undoes the change (calendar_sync_status, calendar_sync_error).
The change runs through the dashboard's own rules, as the member who created the key (an owner acts as an admin). Owners, admins, builders and operators can change business scheduling; a key made by a viewer can only read. Reseller keys (rk_…) can't make this change.
Path parameters
| Name | Type | Description |
|---|---|---|
idRequired | uuid | The appointment id. |
Request body (JSON)
| Name | Type | Description |
|---|---|---|
slot_start | datetime | Move the meeting to this start time (find one with the availability search and |
duration_minutes | integer | With slot_start: a new length. Omitted: the meeting keeps its own length. 5–480. |
host_id | uuid | null | With slot_start: move it to this host. Omitted: it keeps its host. null: its host when free, else any host who can take the meeting type. |
notify_invitee | boolean | With slot_start: send the invitee a WhatsApp note with the new time ( Default: |
override_validation | boolean | With slot_start: move it even outside the host's hours, without checking their connected calendars (never onto another meeting of the host). Default: |
status | string |
|
cancellation_reason | string | null | With status cancelled: why. Up to 500 characters. |
invitee_name | string | Who the meeting is with. 1–200 characters. |
invitee_phone | string | Their phone with the country code (at least 10 digits), e.g. +528112345678: reminders, the contact link and WhatsApp notes use it. Up to 40 characters. |
invitee_email | string | null | Their email: the host's connected calendar sends them the invitation. Up to 320 characters. |
invitee_company | string | null | Their company. Up to 200 characters. |
invitee_notes | string | null | Notes for the host. Up to 2000 characters. |
Example request
curl -X PATCH "https://www.nutalk.ai/v1/business/appointments/6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "slot_start": "2026-10-21T17:00:00Z", "notify_invitee": true}'The updated meeting. A move with notify_invitee also returns notification; a move to another host reports previous_host_calendar_cleanup, and a cancel calendar_cleanup (removed, skipped or failed).
{
"success": true,
"data": {
"id": "6b1d2c3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e",
"meeting_type_id": "8f9a0b1c-2d3e-4f4a-8b5c-6d7e8f9a0b1c",
"meeting_type_name": "Intro call",
"host_id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"host_name": "Ana López",
"invitee_name": "Carlos Ruiz",
"invitee_email": "carlos@example.com",
"invitee_phone": "+528112345678",
"invitee_company": "Acme",
"invitee_notes": null,
"starts_at": "2026-10-21T17:00:00+00:00",
"ends_at": "2026-10-21T17:30:00+00:00",
"timezone": "America/Monterrey",
"status": "confirmed",
"location_kind": "google_meet",
"location_details": null,
"meeting_url": "https://meet.google.com/abc-defg-hij",
"source": "dashboard",
"contact_id": "9595b646-ab97-4485-b1b8-e8b58dfcdd19",
"channel_id": null,
"call_id": null,
"conversation_id": null,
"cancellation_reason": null,
"calendar_sync_status": "synced",
"calendar_sync_error": null,
"created_at": "2026-10-12T15:04:05.123456+00:00",
"updated_at": "2026-10-12T15:04:05.123456+00:00"
},
"notification": {
"status": "sent",
"reason": null,
"message": "WhatsApp note sent with the new time."
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | The body is not JSON, or a field is missing or invalid (details.errors lists each field). |
| 400 | validation_error | The body asks for no change or for more than one, or an option is sent without the change it belongs to. |
| 404 | not_found | No appointment with this id in your workspace (ids of other workspaces answer the same). |
| 404 | not_found | Cancelling a meeting that is no longer confirmed (already cancelled, completed or a no-show). |
| 409 | conflict | The new time can't be booked (taken, outside the host's hours, a connected calendar couldn't be checked, or the host can't take the meeting type: archived, or not one who takes it), the meeting is not confirmed or has not started yet (completed, no_show), or it changed meanwhile. |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
| 403 | forbidden | The member who created the key can't do this (a viewer, or a clinic-only role), is no longer in the workspace, or the key is not a workspace key (sk_…). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Find free business meeting times
/v1/business/availabilityReturns the free start times for a meeting type from the engine that validates bookings: the hosts' weekly hours, days off, closures, booked meetings, buffers, notice and booking window, and their connected calendars. Searches one day (date) or a range (at most 31 days, up to 300 times); with neither, the next 7 days.
appointments:readWorkspace keys only · acts as the key's creatorRuns as the member who created the key (it reads with their access); reseller keys can't call it.
Query parameters
| Name | Type | Description |
|---|---|---|
meeting_type_idRequired | uuid | The meeting type. |
date | string | One day, YYYY-MM-DD, in the workspace's time zone. Don't combine it with a range. |
range_start | datetime | Start of the range (default: now plus the meeting type's notice). |
range_end | datetime | End of the range (default: 7 days after its start). |
host_id | uuid | Only this host's times. |
appointment_id | uuid | The meeting you want to move: its own time doesn't count as busy and the times have its length. It must be of this meeting type. |
language | string | The language of each slot's Default: |
Example request
curl -X GET "https://www.nutalk.ai/v1/business/availability?meeting_type_id=8f9a0b1c-2d3e-4f4a-8b5c-6d7e8f9a0b1c&date=2026-10-20" \ -H "Authorization: Bearer YOUR_API_KEY"The free times, each with the host it would be booked with. warnings names hosts whose connected calendar couldn't be read (their times show, but booking them is refused until it can be); with no times, reason says why, and code is no_eligible_host or host_missing when no host can take the meeting type.
{
"success": true,
"data": {
"timezone": "America/Monterrey",
"meeting_type": {
"id": "8f9a0b1c-2d3e-4f4a-8b5c-6d7e8f9a0b1c",
"name": "Intro call",
"duration_minutes": 30
},
"slots": [
{
"start": "2026-10-20T16:00:00.000Z",
"end": "2026-10-20T16:30:00.000Z",
"display": "Tue, Oct 20, 10:00 AM",
"timezone": "America/Monterrey",
"host": {
"id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"name": "Ana López"
},
"available_hosts": 2
}
],
"warnings": [],
"reason": null,
"code": null
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | A query parameter is invalid (details.errors lists each one). |
| 400 | validation_error | date was sent with a range, the range ends before it starts, or appointment_id is a meeting of another type. |
| 404 | not_found | The meeting type doesn't exist or is archived. |
| 403 | forbidden | The workspace doesn't run Business Appointments (it is turned on per workspace). |
| 403 | forbidden | The member who created the key can't do this (a viewer, or a clinic-only role), is no longer in the workspace, or the key is not a workspace key (sk_…). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Done in the dashboard
Connecting a calendar account (Google, Outlook, iCloud/CalDAV, an iCal link), calendar subscription links, a meeting's change history, and which agents book with business scheduling (an agent's scheduler settings).