Skip to main content
POST

Overview

This endpoint records an appointment that was booked outside of Setter (e.g. directly on your Calendly, a manual phone callback, or any other calendar tool). Once a booking is stored against a contact, the bot will see it on the next inbound message and will not ask the contact to book another appointment or send a booking link.
Authentication: All requests require a Bearer token in the Authorization header.

Contact Identification

You must provide either phone or wa_id to locate the contact. The contact must already exist in Setter — bookings cannot create new contacts. Lookup order:
  1. Exact wa_id match (if wa_id is supplied)
  2. wa_id derived from phone (E.164 minus the leading +)
  3. sms_phone_number match (both with and without leading +)
If both phone and wa_id are provided, wa_id is tried first. Pass default_country (ISO 3166-1 alpha-2) to disambiguate national-format phone numbers.

Bot Scope

A booking is only visible to the bot_id it was filed against. A bot that runs on multiple channels (e.g. WhatsApp + SMS) sees the same booking on both channels, but a separate bot owned by the same organization will not. Find the bot_id in the dashboard URL.

Idempotency

If external_id is provided, the unique key (organization_id, source, external_id) makes retries safe. A re-POST with the same triple returns the existing booking with deduplicated: true and HTTP 200 instead of creating a duplicate.

Important Notes

  • Authentication: All requests require a Bearer token in the Authorization header
  • Phone Format: Accepted with or without leading + and separators (parsed via libphonenumber)
  • Bot Visibility: Bookings are scoped to the bot_id they were filed against
  • Soft Cancellation: Use Cancel Booking to remove a booking from the bot’s context
  • Time Zone: Pass an IANA time_zone (e.g. Europe/London) for correct rendering in the bot’s context

Getting Your API Key

API keys can be generated from your Setter AI dashboard under Settings > API Keys. Keep your API key secure and never expose it in client-side code.

Example Usage

Create by phone number

Create by WhatsApp ID

Authorizations

Authorization
string
header
required

Bearer token authentication using your API key

Body

application/json
bot_id
integer
required

The bot this booking is for. Find the id in the dashboard URL.

Example:

700

start_time
string<date-time>
required

ISO 8601 timestamp of the appointment start.

Example:

"2026-05-25T14:00:00Z"

phone
string

Contact's phone number. Accepted with or without leading + and separators (parsed via libphonenumber). Provide either phone or wa_id.

Example:

"+447813194799"

wa_id
string

WhatsApp ID of the contact. Use this instead of phone if you have it. If both are provided, wa_id is tried first.

Example:

"447813194799"

end_time
string<date-time>

ISO 8601 timestamp of the appointment end. Must be after start_time.

Example:

"2026-05-25T15:00:00Z"

time_zone
string

IANA time zone (e.g. Europe/London).

Example:

"Europe/London"

source
string

Free-form provenance tag. Defaults to manual.

Example:

"calendly"

external_id
string

Stable id from your system used to deduplicate retries. Unique key is (organization_id, source, external_id).

Example:

"calendly-invitee-abc"

default_country
string

ISO 3166-1 alpha-2 country code (e.g. GB). Used to disambiguate national-format phone numbers.

Example:

"GB"

metadata
object

Arbitrary JSON stored alongside the booking.

Example:

Response

Idempotent replay — a booking with the same (organization_id, source, external_id) already existed and is returned with deduplicated: true.

id
integer
Example:

555

event_id
integer
Example:

999

bot_id
integer
Example:

700

contact_id
integer
Example:

42

source
string
Example:

"calendly"

external_id
string | null
Example:

"calendly-invitee-abc"

start_time
string<date-time>
Example:

"2026-05-25T14:00:00.000Z"

end_time
string<date-time> | null
Example:

"2026-05-25T15:00:00.000Z"

time_zone
string | null
Example:

"Europe/London"

deduplicated
boolean

true when an external_id collision returned the existing record instead of creating a new one.

Example:

false