Book or reschedule
PUT /
Books the lead's appointment at an open time, or moves its existing appointment there.
Scope: leads:write
Access: The key's member must also be allowed to create appointments (an admin, or a role with the Create appointments action).
A lead has one active appointment in its campaign: the first PUT books it and later PUTs move that same appointment (any other upcoming appointment the lead has there is cancelled). start must be a time the slots endpoint would list right now; whether a host has room is decided atomically at booking time.
Appointments that have started, completed or been handled are history and are never moved or overwritten: while the lead's current appointment is one of those the request fails with 409 appointment_not_movable and nothing changes. A new time can be booked once that appointment started more than an hour ago.
What happens next is what happens for appointments the AI books: the team member is chosen by the campaign's routing (a moved appointment keeps its member when they have room), the lead's card moves to the appointment stage (a card is created if the lead has none) unless your team placed it in a stage automation may not change, the campaign's connected calendars, team notifications and appointment texts to the lead follow your settings, and the campaign's automated outreach stops while the appointment is active.
Retries are safe: sending the start the lead already holds answers 200 with status: "unchanged" and never books twice, even once that time is no longer listed.
The lead must belong to a campaign the key may reach and be one the key's member can see in DialEcho, otherwise 404, checked before the member's permission to create appointments.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
lead_id | UUID | Yes | The lead to book. |
Body
Content type: application/json
| Name | Type | Required | Description |
|---|---|---|---|
start | timestamp | Yes | A start from the campaign's open slots, or the same instant in any offset (2026-11-02T14:30:00Z). ISO 8601 with a UTC offset; a timestamp without one is rejected. |
notes | string | No | Saved as the appointment's notes, shown on it in DialEcho's calendar. Omitted or blank keeps the stored notes. Up to 5,000 characters. |
Response
Status: 201 Created · 200 OK
201 when a new appointment was booked; 200 when the lead already had an active appointment (same appointment_id). Responses never include the assigned team member or the lead's details.
| Name | Type | Description |
|---|---|---|
appointment_id | UUID | The appointment. |
lead_id | UUID | The lead. |
start | timestamp | The appointment's start in the campaign's appointment time zone, whatever offset you sent. |
status | string | booked: a new appointment. rescheduled: the existing one was moved to start. unchanged: it was already at start. One of booked, rescheduled, unchanged. |
Example request
curl
bash
curl -X PUT "https://development.agencydevworks.ai/v1/leads/aaaaaaaa-0000-4000-8000-000000000001/appointment" \
-H "Authorization: Bearer dei_your_key" \
-H "Content-Type: application/json" \
-d '{
"start": "2026-11-02T09:30:00-05:00",
"notes": "Prefers the side door."
}'JavaScript
js
const response = await fetch("https://development.agencydevworks.ai/v1/leads/aaaaaaaa-0000-4000-8000-000000000001/appointment", {
method: "PUT",
headers: {
"Authorization": "Bearer dei_your_key",
"Content-Type": "application/json",
},
body: JSON.stringify({
"start": "2026-11-02T09:30:00-05:00",
"notes": "Prefers the side door."
}),
});
const data = await response.json();Example response
Status: 201 Created
json
{
"appointment_id": "77777777-0000-4000-8000-000000000001",
"lead_id": "aaaaaaaa-0000-4000-8000-000000000001",
"start": "2026-11-02T09:30:00-05:00",
"status": "booked"
}Errors
| HTTP | Code | When |
|---|---|---|
| 403 | insufficient_scope | The key does not have leads:write. |
| 403 | permission_denied | The key's member may not create appointments. Only for a lead they can see; any other lead is 404. |
| 404 | not_found | The lead does not exist or the key cannot reach it. |
| 409 | slot_unavailable | The time is not open (any more): just taken, too soon, or not one of the campaign's slots. Nothing was booked or changed; re-fetch the slots. |
| 409 | appointment_not_movable | The lead's current appointment started less than an hour ago, or is completed or handled. Nothing was booked or changed. |
| 409 | availability_not_configured | The campaign has no appointment hours. |
| 409 | no_hosts_configured | No team member can take appointments in the campaign (none has an assignment weight above 0%). Fix its routing in DialEcho. |
| 413 | payload_too_large | The body is larger than 1 MB. It was not read and nothing was booked or changed. |
| 422 | invalid_request | lead_id is not a UUID, or the body is invalid: start missing or without a UTC offset, notes too long, or an unknown field. |
Every endpoint can also answer 401 invalid_api_key, 429 rate_limited and 503 dependency_unavailable. See Errors in the overview.
Related endpoints
- GET
/· List open timesv1/ campaigns/ {campaign_id}/ appointment-slots - POST
/· Create or update a leadv1/ leads - GET
/· Retrieve a conversionv1/ leads/ {lead_id}/ conversion