Lead Distro AILead Distro AI
DocsAppointmentsAppointments API & Webhooks

Appointments API & Webhooks

Send booked appointments into Lead Distro AI from a calendar tool, and update their status from a source or a destination's CRM. Endpoints, fields, and error codes for appointment tracking.

Last updated:

Send appointments from your own calendar

A source can send appointments that are already booked, from GoHighLevel or any other calendar tool, to the same ingest address it uses for leads. On an appointments campaign, a post with appointment_time is a booked appointment: it is delivered right away and marked booked.

curl -X POST https://app.leaddistro.ai/api/v1/ingest \
  -H "x-api-key: YOUR_SOURCE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "flo_campaign_id": "YOUR_CAMPAIGN_ID",
    "flo_supplier_id": "YOUR_SOURCE_ID",
    "first_name": "Maria",
    "last_name": "Garcia",
    "phone": "5551234567",
    "appointment_time": "2026-10-21T15:30:00-05:00",
    "appointment_timezone": "America/Chicago"
  }'

To update it later, the same source posts the person's phone or email with appointment_status set to showed, no_show or canceled. Lead Distro AI finds the appointment that source sent and updates it, replying 200 with "updated": true. No new lead is made and the source is not charged again. Sending the same booking twice replies with the first appointment. Step-by-step for GoHighLevel: Send GoHighLevel Appointments to Lead Distro AI.

ReplyMeaning
201A new appointment was created and is being delivered.
200 with updatedAn earlier appointment from this source was updated or moved.
200 with deduplicatedThe same booking was sent again. Nothing changed.
400The time could not be read (saved as a Failed lead to fix), or the status word is unknown.
404A status was sent, but this source sent no earlier appointment for that phone or email.
409Showed or no-show was sent before the appointment was delivered to a destination.

Post an appointment status from a CRM

The buyer outcome webhook accepts an appointment status alongside everything else it already handles. The buyer authenticates with their own secret, so they can only touch their own leads.

curl -X POST https://www.leaddistro.ai/api/webhooks/buyer-outcome \
  -H "X-Buyer-Secret: BUYER_WEBHOOK_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "lead_id": "LEAD_UUID",
    "appointment_status": "showed"
  }'
FieldTypeRequiredNotes
lead_idstringYes*The lead to update. Instead of this you may match on phone or email plus campaign_id.
appointment_statusenumYes*One of booked, showed, no_show, canceled. Send this or appointment_qualified.
appointment_atISO 8601NoWhen the appointment is scheduled. Usually sent with booked. Must include a timezone offset.
appointment_qualifiedenumNoOne of qualified, unqualified. The review call on an appointment that showed up. Only accepted when the campaign tracks qualification, otherwise the call returns 403.

Send appointment_at with the booking. Without it you know an appointment exists but not when, which makes time-to-appointment and upcoming-appointment views impossible to build later.

Booking and attendance in one flow

A typical integration sends two calls. The first when the appointment is created, the second when the buyer knows whether it happened.

// 1. When the appointment is booked
{
  "lead_id": "LEAD_UUID",
  "appointment_status": "booked",
  "appointment_at": "2026-09-11T15:00:00-07:00"
}

// 2. After the appointment time passes
{
  "lead_id": "LEAD_UUID",
  "appointment_status": "showed"
}

Sending the same status twice is safe. A repeat of a status the lead already has is recognized and does not bill twice.

Reporting the review

If the buyer pays for appointments that showed up and qualified, a third call reports the review. It is a separate field, not another appointment status, so posting "appointment_status": "qualified" returns 400.

// 3. After someone reviews the appointment
{
  "lead_id": "LEAD_UUID",
  "appointment_qualified": "qualified"
}

The two marks can arrive in either order. If the review lands before the show is reported, nothing bills until the show arrives, and then it bills once. Send unqualified when the review decides the appointment was not worth paying for. If it had already been billed, the charge is reversed.

Call outcomes

If the booking comes out of a phone call rather than a calendar, post it as a call outcome instead. This needs no appointment feature enabled.

curl -X POST https://www.leaddistro.ai/api/v1/lead-update \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "lead_id": "LEAD_UUID",
    "call_outcome": "appointment_set"
  }'

Outcome stages

Both endpoints also accept a stage field carrying a custom outcome stage key, which is how you record an appointment without the billing add-on.

{
  "lead_id": "LEAD_UUID",
  "stage": "meeting_booked"
}

Error codes

CodeMeaningFix
400The appointment status is not one of the four allowed values.Send exactly booked, showed, no_show, or canceled, lowercase.
400The lead has not been accepted yet.A buyer can only set an appointment on a lead they accepted. Deliver and accept it first.
401The buyer secret is missing or wrong.Send the buyer's secret in the X-Buyer-Secret header.
403Appointment tracking is not enabled for the account.Contact support to have it turned on.
404No matching lead.Check the lead id, or that the matching phone or email belongs to a lead assigned to this buyer.

Frequently Asked Questions

How does a buyer's CRM report that an appointment showed up?
It posts to https://www.leaddistro.ai/api/webhooks/buyer-outcome with the buyer's secret in the X-Buyer-Secret header and a body containing the lead id and appointment_status. The four accepted values are booked, showed, no_show, and canceled. Add appointment_at with an ISO timestamp when reporting a booking.
Where do I find these fields in the app?
Open the destination on your campaign and choose Postback Webhook. The spec there lists the appointment fields, shows the booked then showed example, and has a Copy Share Link button so you can hand the whole page to the buyer's developer. The appointment part only appears when that destination is paid per appointment, since that is the only setup where the status changes what gets billed.
Is it safe to send the same appointment status twice?
Yes. Sending a status the lead already has is recognized as a repeat and does not bill the buyer twice, so a CRM that retries on a timeout cannot double-charge anyone.
Why am I getting a 400 saying the lead has not been accepted?
A buyer can only set an appointment on a lead they have accepted, which prevents a buyer marking appointments on leads that were never theirs. Deliver the lead and have it accepted first. Updates you make yourself from the dashboard are not restricted this way.
Why am I getting a 403 on the appointment endpoints?
Appointment tracking is not enabled for the account. It is a limited-release feature, so contact support to have it turned on. In the meantime, post a stage value instead to record the same thing through outcome stages.
Why am I getting a 403 when I post appointment_qualified?
The lead's campaign does not track qualification. Turn on Track Appointment Qualification on that campaign first. Until it is on, there is no review step for the appointment to be in, so the field is refused rather than quietly ignored.
Why does posting appointment_status of qualified return 400?
Qualification is a separate field, not a fifth appointment status. Send appointment_qualified with a value of qualified or unqualified. Keeping them apart is what lets an appointment be Showed and Unqualified at the same time, which is a real and common state.

If you have any questions, send us an email at support@leaddistro.ai