# Create Event Source: https://docs.trysetter.com/calendly-scheduling/api-reference/create-event/post POST /api/scheduled_events Schedules a new event > [!WARNING] > > A status code of 200 does not imply sucessful scheduling, but rather that the request was received successfully. > For reliable scheduling completion info, please use the `webhook_url` field in the request to receive a webhook on completion. > [!NOTE] > > Note: Currently the API only supports Calendly event types set to English, German, French, Spanish and Portuguese. Please [reach out](mailto:contact@trysetter.com), if you'd like us to support more languages. We can add more languages if there is a demand. Watch the video below to learn how to use this endpoint step by step. [YouTube video player](https://www.youtube.com/embed/qrmMOd6_6M4?si=BAJMZbrk80c0ND__) ## Completion webhook If you pass a `webhook_url`, we send a `POST` request to it once scheduling has finished. Check `error` to see whether the event was scheduled: * `error` is `null`: the event was scheduled. * `error` is not `null`: scheduling failed. The value is `time_not_available` if the slot was no longer free, otherwise `scheduling_failed`. On failure, `errorReason` tells you which step failed, so you can decide whether to retry: | `errorReason` | Meaning | | - | - | | `page_load_failed` | The Calendly page did not load. Usually temporary, safe to retry. | | `form_failed` | The booking form did not appear or could not be filled in. | | `submission_failed` | The form could not be submitted. | | `confirmation_timeout` | The form was submitted, but Calendly did not confirm the booking in time. Check Calendly before retrying, the event may have been created. | | `time_not_available` | Calendly reported the time slot as no longer available. Pick another time. | | `unknown` | Any other failure. | `errorReason` is `null` when scheduling succeeded. More values may be added over time, so treat unrecognised values like `unknown`. ```json Example failure payload theme={null} { "type": "calendly_scheduling_completion", "error": "scheduling_failed", "errorReason": "page_load_failed", "schedulingUrl": "https://calendly.com/acme/intro/2026-10-26T13:00:00Z", "timeZone": "Europe/Berlin", "webhookUrl": "https://example.com/webhook", "formData": [{ "name": "Email", "type": "string", "value": "jane@example.com" }], "metadata": { "requestId": "abc" } } ``` # Introduction Source: https://docs.trysetter.com/calendly-scheduling/introduction Schedule events directly to Calendly automatically. > [!NOTE] > > Disclaimer: This is not an official API from Calendly. While we strive to ensure maximum uptime, changes introduced by Calendly may disrupt the API's functionality at any time. Please keep this in mind when building on top of our API. ## Welcome As of the date of this writing (01/25/2025), Calendly does not offer a way to automatically schedule events via its API (see [Calendly API reference](https://developer.calendly.com/api-docs)). With our API, you can schedule events directly in Calendly. Learn how to automate your Calendly scheduling. > **[Create Event Endpoint](/calendly-scheduling/api-reference/create-event/post)** > > View the API documentation > [!NOTE] > > Note: Currently the API only supports Calendly event types set to English, German, French and Spanish. Please [reach out](mailto:contact@trysetter.com), if you'd like us to support more languages. We can add more languages if there is a demand. ## Authentication All API endpoints are authenticated using API keys passed on through the request header. ```json theme={null} "header": { { "X-API-Key": "" } } ``` # Audience Filtering Source: https://docs.trysetter.com/campaigns/audience-filtering Narrow a scheduled campaign send to a real-time list of leads from your side For the endpoint spec (URL, auth, request/response shapes, examples), see [Filter Send Audience](/campaigns/filter-audience). This page covers when to use audience filtering, how to configure it on a send, and the rules that apply when the filter event lands. ## Why Most sends go to your full uploaded audience. Sometimes you want to **narrow a specific send** based on signals that aren't known at upload time — e.g. *"for tomorrow's send, only message leads who completed step X by tonight."* Audience filtering lets your system POST a list of leads to **include** or **exclude** for a specific send, up until 5 minutes before that send fires. ## Enabling on a send When adding a send to your campaign sequence, toggle **"Apply filter from inbound webhook"** on. The send will then accept filter events at the audience-filter endpoint until its filter deadline (5 min before its scheduled time). A send with the filter off ignores any incoming filter events targeting it. ## Authentication setup Pick the auth mode for inbound endpoints once per organization, in **Settings → Webhooks**: * **API key** (default) — bearer-token auth using any active org-level API key. * **HMAC** — generate a signing key, sign the raw request body with HMAC-SHA256, send as `X-Setter-Signature: sha256=`. Multiple signing keys can be active concurrently for rotation. The same auth setting applies to all inbound endpoints for your org (audience filtering, lead events, etc.). ## When the filter is applied The send's recipient list is materialized about 60 seconds before `scheduledFor`. At that moment, the materializer: 1. Loads every lead in the campaign's audience whose ingest status is `ok` 2. Drops opted-out phone numbers 3. If the send has the audience filter enabled, applies the **most recent** filter event for that send: `include` keeps only listed leads; `exclude` removes them 4. Inserts one row per remaining lead into the per-recipient send queue So if you POST multiple filter events before the deadline, only the latest one matters. ## Lead matching A lead in your filter payload matches an audience lead if **either** of these is true: * The payload's `externalId` matches the audience lead's `external_id` column from the CSV (case-sensitive). * The payload's `phoneE164` matches the normalized E.164 stored on the audience lead. Leads in your filter payload that don't match any audience lead are silently ignored (logged). ## Combining with the event filter A send can have **both** an audience filter (this page) **and** an event filter (matching against [Send Lead Event](/campaigns/send-lead-event)) configured. Both must keep a recipient for them to receive the message — the filters are ANDed. # Filter Send Audience Source: https://docs.trysetter.com/campaigns/filter-audience POST /api/v1/webhooks/campaigns/audience-filter Narrow a scheduled campaign send to a real-time include or exclude list of leads ## Overview Most campaign sends go to the full uploaded audience. This endpoint lets you narrow a specific send based on signals that aren't known at upload time — e.g. *"for tomorrow's send, only message leads who completed step X by tonight."* POST an `include` or `exclude` list to a specific send up until 5 minutes before that send fires (the filter deadline). > [!NOTE] > > **Enabling on a send**: in the campaign editor, toggle **"Apply filter from inbound webhook"** on for the target send. A send with the filter off ignores any webhook events targeting it. ## Authentication Pick the auth mode for inbound webhooks once per organization, in **Settings → Webhooks**: * **API key** (default) — Bearer-token auth using any active org-level API key. * **HMAC** — generate a signing key, sign the raw request body with HMAC-SHA256, send as `X-Setter-Signature: sha256=`. Multiple signing keys can be active concurrently for rotation. ## When the filter is applied The send's recipient list is materialized about 60 seconds before `scheduledFor`. At that moment: 1. Every lead in the campaign's audience whose ingest status is `ok` is loaded. 2. Opted-out phone numbers are dropped. 3. The **most recent** filter event for that send is applied: `include` keeps only listed leads; `exclude` removes them. 4. One row per remaining lead is inserted into the per-recipient send queue. If you POST multiple distinct filter events before the deadline, only the latest one matters. Idempotent replays of the exact same payload return `{ status: "already_received" }` and are no-ops. ## Lead matching A lead in your filter payload matches an audience lead if **either** of these is true: * The payload's `externalId` matches the audience lead's `external_id` column from the CSV (case-sensitive). * The payload's `phoneE164` matches the normalized E.164 stored on the audience lead. Leads in your filter payload that don't match any audience lead are silently ignored. ## Combining with lead events A send can have **both** an audience filter (this endpoint) **and** an event filter (matching against [Send Lead Event](/campaigns/send-lead-event)) configured. Both must keep a recipient for them to receive the message — the filters are ANDed. ## Example Usage ### HMAC signature ```bash theme={null} SECRET="your-signing-secret" BODY='{"campaignId":42,"sendId":137,"mode":"include","leads":[{"externalId":"abc123"}]}' SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -binary | xxd -p -c 256) curl -X POST https://chat.trysetter.com/api/v1/webhooks/campaigns/audience-filter \ -H "Content-Type: application/json" \ -H "X-Setter-Signature: sha256=$SIG" \ --data-raw "$BODY" ``` ### Bearer API key ```bash theme={null} curl -X POST https://chat.trysetter.com/api/v1/webhooks/campaigns/audience-filter \ -H "Authorization: Bearer your_api_key" \ -H "Content-Type: application/json" \ -d '{ "campaignId": 42, "sendId": 137, "mode": "exclude", "leads": [ { "phoneE164": "+15551234567" }, { "phoneE164": "+15557654321" } ] }' ``` # Lead Events Source: https://docs.trysetter.com/campaigns/lead-events Stream per-phone events into Setter so future sends can include or exclude leads based on what they did For the endpoint spec (URL, auth, request/response shapes, examples), see [Send Lead Event](/campaigns/send-lead-event). This page covers when to send events, how to configure a campaign send to consume them, and the patterns the time-window filter is designed for. ## Why Some sends should depend on what a lead has *done*, not just which audience they're in: * *"Don't send the May 17 'introducing Mastery' message to anyone who already purchased it."* * *"For the +2hr 'you can still join' reminder, skip phones currently in the live event."* You record those signals as **lead events** — small per-phone records like `mastery_purchase` or `webinar_attended`, each with a timestamp. At send-fire time, the campaign send filters its audience based on those events. ## Real-time vs bulk The endpoint accepts either pattern — both produce the same rows, the filter logic doesn't care. * **Real-time stream** — POST one event at a time as it happens (a purchase completes, a phone joins the live event). Best when you want the freshest possible data without a polling loop. * **Bulk batch** — POST up to 50,000 events in one call. Best when your source system aggregates and you'd rather push periodically than per-event. If you POST the same `(phoneE164, eventType, occurredAt)` more than once, the duplicate is silently dropped. Retries are safe. ## Configuring a send to consume events When adding a send to your campaign sequence, enable **Event filter** and pick: * **Mode** — `exclude` (skip leads that have the event) or `include` (only send to leads that have the event). * **Event type** — must match the `eventType` strings you POST (case-sensitive). * **Within last (minutes, optional)** — only consider events whose `occurredAt` is within this many minutes of the send firing. The filter is applied at send-materialize time, \~60 seconds before the scheduled fire time. ## Sticky vs windowed events Whether to use the time window depends on the event's meaning: | Pattern | Filter config | Use when | | - | - | - | | **Sticky** (no window) | `{ mode: "exclude", eventType: "mastery_purchase" }` | The event is permanent — once it happens, the lead is "done" forever. | | **Windowed** (with `within.minutes`) | `{ mode: "exclude", eventType: "webinar_attended", within: { minutes: 120 } }` | The event is temporary — "currently attending" only matters for \~2hrs. | Without a window, "ever happened" matches. With a window, only events whose `occurredAt` falls inside the last N minutes from send-fire time match. ## Common patterns **Exclude prior purchasers across a multi-day campaign:** ```json theme={null} { "mode": "exclude", "eventType": "mastery_purchase" } ``` No window — once a lead purchases, they stop receiving the upsell sequence on every subsequent day. **Skip people in the live event for the "you can still join" reminder:** ```json theme={null} { "mode": "exclude", "eventType": "attended", "within": { "minutes": 120 } } ``` Window matches today's session only. Yesterday's attendees who haven't joined today still receive the reminder. **Only message engaged leads (opt-in confirmation campaign):** ```json theme={null} { "mode": "include", "eventType": "double_opt_in_confirmed" } ``` Sends only to leads who completed the confirmation step. ## Combining with audience filtering A send can have **both** an event filter (this page) **and** an [audience filter](/campaigns/audience-filtering) configured. Both must keep a recipient for them to receive the message — the filters are ANDed. ## Phone normalization `phoneE164` values you POST go through libphonenumber. Both `+15551234567` and `15551234567` parse to the same canonical E.164. Numbers that don't parse are reported per-row in the response's `rejects[]` rather than failing the whole batch. # Campaigns Source: https://docs.trysetter.com/campaigns/overview Schedule WhatsApp marketing blasts to uploaded audiences ## What it is Campaigns is the workspace for scheduled, audience-targeted WhatsApp blasts. It uses **two** Meta APIs depending on the send's category: * **MARKETING** sends route through the [Marketing Messages Lite API](https://developers.facebook.com/documentation/business-messaging/whatsapp/marketing-messages/overview) — high-volume optimized, opt-in-required, US recipients blocked. * **UTILITY** sends route through the standard [WhatsApp Cloud API](https://developers.facebook.com/docs/whatsapp/cloud-api) — for transactional/account-related notifications. Different pricing category, fewer geographic restrictions. You pick the category per send. The recipient receives the same kind of WhatsApp message either way; the difference is server-side routing, billing category, and policy gates. A **campaign** has: * One **audience** (uploaded as CSV — phone numbers + arbitrary template variables) * One or more **sends** scheduled in chronological order (think of them as messages in a drip sequence) * One **WhatsApp number** to send from (any active WABA phone number in your org) Each send fires its assigned template at its scheduled time, to its audience (optionally narrowed by an inbound payload — see [Audience Filtering](/campaigns/audience-filtering) and [Lead Events](/campaigns/lead-events)). ## Send categories | Category | API routed through | Template category | Typical use | Geographic restrictions | | - | - | - | - | - | | `marketing` | Marketing Messages Lite (`/marketing_messages`) | `MARKETING` | Promotions, announcements, drip campaigns | US blocked; EEA/UK/JP/KR have limited reporting | | `utility` | Cloud API (`/messages`) | `UTILITY` | Account notifications, status updates, reminders | Standard Cloud API rules apply (broader geo support) | Pick category per send when adding it to the sequence. The campaign editor only lets you pick templates whose Meta-side category matches the send category — switching the send category clears your template pick. **Why mix them?** A common pattern: send 1–3 are MARKETING (engagement push), send 4 is UTILITY (the actual confirmation/receipt with no marketing content). Keeping them in one campaign keeps audience handling consistent without forcing you to spin up a parallel campaign just to swap APIs. Replies to campaign messages flow back through your existing bot — the bot attached to the chosen WhatsApp number handles conversations as it normally would. ## Lifecycle A campaign moves through these states: | Status | Meaning | | - | - | | `draft` | Editable. Sequence can be modified. No sends will fire. | | `scheduled` | Locked. Sends will fire at their scheduled times. | | `paused` | Toggled off. Materializer skips this campaign entirely. Reversible — turn back on anytime. | | `running` | At least one send is currently firing. | | `completed` | All sends have fired (or terminally failed). Final state. | | `cancelled` | Permanently stopped. Pending sends won't fire. Final state. | ## Sends within a campaign Each send is a single blast. Per-send config: * **Scheduled time** + IANA time zone (DST-aware — the saved UTC instant respects the picked zone's rules at that exact moment) * **Template** — Meta-approved MARKETING-category template (created in WhatsApp Business Manager) * **Audience filter** — off (full audience, minus opt-outs) or on (narrowed by inbound webhook payload) Sends fire one at a time per campaign. Throughput within a single send is rate-limited to your campaign's `max_messages_per_second` (default 20 — tune up after a successful dry run). Per-recipient delivery, read, and failure events flow back from Meta's webhook and are recorded for analytics. ## Geographic eligibility Two policy realities Meta enforces for **MARKETING sends**, which Campaigns surfaces at upload time: * **US recipients are blocked** with error 131049 across all WhatsApp marketing APIs. We mark them `ineligible_geo` at audience ingest and skip them at send time. * **EEA / UK / Japan / South Korea** — sends deliver, but Meta does not return read/click metrics through standard webhooks for these regions. The audience detail page surfaces the affected count so you don't misread their analytics. **UTILITY sends are not subject to the US block** — the Cloud API path doesn't have that policy gate. If you need to reach US recipients, ensure those sends are categorized utility AND that the template content is genuinely transactional (Meta enforces this on the template approval side). ## Opt-outs When a recipient replies with a STOP-style keyword (`stop`, `unsubscribe`, `unsub`, `cancel`, `end`, `quit`, `remove me`, `opt out`, `opt-out`), an opt-out is recorded for that organization + phone. The materializer skips opted-out numbers on subsequent sends, automatically. Match is conservative — only when the keyword is the entire message or a leading keyword followed by punctuation. We don't match phrases like *"please don't stop sending these"*. Opt-outs are per-organization. The same phone replying STOP to org A is not opted out from org B's campaigns. ## Onboarding gates Before your first send actually goes through: **For MARKETING sends:** * Your **WhatsApp Business Account (WABA) must accept the MM Lite Terms of Service** in Meta's App Dashboard. There's no API to do this on your behalf — manual one-time step per WABA. * You need at least one **approved MARKETING-category template** in your WABA. * For 80k-recipient sends, your WABA needs **TIER\_100K or higher** messaging tier (visible via `GET /{phone-number-id}?fields=messaging_limit_tier`). * Recipients must be **opted in to receive WhatsApp marketing messages from your business** — required by Meta's marketing message policy. You confirm this at campaign creation time (`product_policy` flag, sent on every API call). **For UTILITY sends:** * You need at least one **approved UTILITY-category template** in your WABA. * No MM Lite ToS or `product_policy` flag required. * Standard Cloud API messaging-limit tiers apply. # Send Lead Event Source: https://docs.trysetter.com/campaigns/send-lead-event POST /api/v1/webhooks/lead-events Record a per-phone event so future campaign sends can include or exclude that lead ## Overview Generic per-phone event stream. Use this to tell Setter "this phone number did event X at time T" so future campaign sends can include or exclude that lead based on whether the event happened (optionally within a time window). Typical event types: `mastery_purchase`, `webinar_attended`, `trial_started`, `cart_abandoned`. You choose the names — they're free strings scoped to your organization. > [!NOTE] > > **Shape-agnostic**: this endpoint accepts either real-time per-event POSTs (one event per call) or bulk batches (up to 50,000 events per call). Both produce the same rows; the filter logic doesn't care which shape was used. ## Authentication Pick the auth mode for inbound webhooks once per organization, in **Settings → Webhooks**: * **API key** (default) — Bearer-token auth using any active org-level API key. * **HMAC** — generate a signing key, sign the raw request body with HMAC-SHA256, send as `X-Setter-Signature: sha256=`. Multiple signing keys can be active concurrently for rotation. ## How sends consume these events When configuring a send under Campaigns → Sequence → Add a send, enable **Event filter** and pick: * **Mode** — `exclude` (skip leads that have the event) or `include` (only send to leads that have the event). * **Event type** — must match the `eventType` you POST. * **Within last (minutes, optional)** — only consider events whose `occurredAt` is within this many minutes of the send firing. Examples: * Skip anyone who's ever purchased Mastery: `{ mode: "exclude", eventType: "mastery_purchase" }` (no window — sticky event) * Skip anyone currently in the live event: `{ mode: "exclude", eventType: "webinar_attended", within: { minutes: 120 } }` (windowed — "currently attending") The filter is applied at send-materialize time alongside any audience-filter event. Both filters can be active on the same send and are ANDed. ## Idempotency and validation The unique key `(organizationId, phoneE164, eventType, occurredAt)` makes retries safe — re-POSTing the same batch returns `duplicates = received` and `inserted = 0`. Invalid rows (bad phone, missing/invalid `occurredAt`, oversize metadata) are rejected per-row, not per-batch — you get a structured `rejects[]` array back rather than a 400 for the whole call. The first 50 rejection reasons are returned for debugging. ## Phone normalization `phoneE164` is parsed via libphonenumber. Accepts the value with or without leading `+` and tolerates common formatting variants. Numbers that don't parse are reported in `rejects[]` with reason `invalid phoneE164`. ## Caps | Limit | Value | | - | - | | Events per request | 50,000 | | Request body size | 10 MB | | `eventType` length | 128 chars | | `metadata` per event (encoded) | 8 KB | ## Example Usage ### Real-time single event (Bearer API key) ```bash theme={null} curl -X POST https://chat.trysetter.com/api/v1/webhooks/lead-events \ -H "Authorization: Bearer your_api_key" \ -H "Content-Type: application/json" \ -d '{ "organizationId": 42, "eventType": "mastery_purchase", "events": [ { "phoneE164": "+15551234567", "occurredAt": "2026-05-12T18:34:00Z", "metadata": { "orderId": "ord_9F2", "amountUsd": 297 } } ] }' ``` ### Bulk batch (HMAC signature) ```bash theme={null} SECRET="your-signing-secret" BODY='{"organizationId":42,"eventType":"webinar_attended","events":[{"phoneE164":"+15551234567","occurredAt":"2026-05-15T13:00:00Z"},{"phoneE164":"+447700900123","occurredAt":"2026-05-15T13:05:11Z"}]}' SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -binary | xxd -p -c 256) curl -X POST https://chat.trysetter.com/api/v1/webhooks/lead-events \ -H "Content-Type: application/json" \ -H "X-Setter-Signature: sha256=$SIG" \ --data-raw "$BODY" ``` # Introduction Source: https://docs.trysetter.com/index Your complete guide to AI appointment setting with Setter AI Welcome to the **Setter AI Help Center and API Documentation**! This is your comprehensive resource for everything you need to know about Setter AI, the intelligent appointment booking assistant that automates customer conversations and streamlines your scheduling process. ## What is Setter AI? Setter AI is an advanced conversational AI system designed to handle customer interactions and automate appointment booking across multiple channels including WhatsApp, SMS, and web chat. Our AI assistants understand customer intent, engage in natural conversations, and seamlessly guide prospects through scheduling appointments with your business. ## What You'll Find Here > **[API Reference](/setter-ai/api-reference)** > > Complete API documentation with interactive playground to integrate Setter AI into your applications. > **[Calendly Scheduling](/calendly-scheduling/introduction)** > > Automate Calendly event scheduling with our direct integration API. ## Key Features * **24/7 Availability**: Your AI assistant works around the clock * **Multi-Channel Support**: WhatsApp, SMS, web chat, and more * **Natural Conversations**: Advanced AI that understands context and intent * **Automatic Booking**: Real-time calendar integration and instant confirmations * **Contact Management**: Automatic contact creation and conversation tracking * **Custom Workflows**: Configurable rules and prompts for your business needs ## Need Help? > [!NOTE] > > If you need assistance or have questions that aren't covered in this documentation, please reach out to our support team at [support@trysetter.com](mailto:support@trysetter.com). Ready to get started? Check out our [API Reference](/setter-ai/api-reference) to begin integrating Setter AI into your applications, or explore the guides to learn more about our platform capabilities. # Send Message Source: https://docs.trysetter.com/setter-ai/api-reference POST /api/v1/bot-integrations/{botIntegrationId}/messages/send Send a message to initiate a conversation with a contact ## Overview This endpoint allows you to send a message to initiate a conversation with a contact. It supports both WhatsApp and SMS platforms and automatically handles contact creation and conversation management. > [!NOTE] > > **Rate Limiting**: You cannot send another bot-initiated message to the same phone number within 30 minutes. ## Bot Integration ID The `botIntegrationId` in the URL path identifies **which channel of which bot** the message is sent through. It is **not** the same as the bot ID. | Identifier | What it is | Where to find it | | - | - | - | | **Bot ID** | Identifies the bot itself. A single bot can run on multiple channels (WhatsApp, SMS, web chat). | In the dashboard URL when you open a bot, e.g. `…/bots/700/…` → bot ID is `700`. | | **Bot Integration ID** | Identifies one specific channel connection of a bot (e.g. that bot's WhatsApp integration, or its SMS integration). Each channel has its own Bot Integration ID. | In the bot's **Integrations** settings, open the **WhatsApp** or **Twilio (SMS)** integration. The **Bot Integration ID** is displayed as a read-only field at the top of the integration details. | Because a bot can have both a WhatsApp and an SMS integration, each with its own Bot Integration ID, you use the Bot Integration ID — not the bot ID — to tell this endpoint which channel to send through. > [!NOTE] > > Open your bot → **Integrations** → **WhatsApp** or **Twilio**, and copy the **Bot Integration ID** shown in the integration details. ## Platform Support ### WhatsApp For WhatsApp integrations, you'll need to specify: * `templateName` - The approved WhatsApp message template * `language` - Language code (e.g., "en\_US") * `bodyParameters` - Parameters to fill template placeholders ### SMS (Twilio) For SMS integrations, you'll need to specify: * `message` - The text message to send ## Important Notes * **Authentication**: All requests require a Bearer token in the Authorization header * **Phone Format**: Always use international format (e.g., 1234567890) * **Contact Management**: Contacts are automatically created or updated * **Conversation Tracking**: Conversations are automatically created and linked * **Calendar Integration**: Optionally link conversations to specific calendar integrations ## 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. # Create Booking Source: https://docs.trysetter.com/setter-ai/bookings POST /api/v1/bookings Record an externally-booked appointment so the bot stops asking the contact to book again ## 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. > [!NOTE] > > **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](/setter-ai/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 ```bash theme={null} curl -X POST https://chat.trysetter.com/api/v1/bookings \ -H "Authorization: Bearer your_api_key" \ -H "Content-Type: application/json" \ -d '{ "bot_id": 700, "phone": "+447813194799", "start_time": "2026-05-25T14:00:00Z", "end_time": "2026-05-25T15:00:00Z", "time_zone": "Europe/London", "source": "calendly", "external_id": "calendly-invitee-abc" }' ``` ### Create by WhatsApp ID ```bash theme={null} curl -X POST https://chat.trysetter.com/api/v1/bookings \ -H "Authorization: Bearer your_api_key" \ -H "Content-Type: application/json" \ -d '{ "bot_id": 700, "wa_id": "447813194799", "start_time": "2026-05-25T14:00:00Z", "time_zone": "Europe/London", "source": "manual" }' ``` # Cancel Booking Source: https://docs.trysetter.com/setter-ai/cancel-booking POST /api/v1/bookings/{id}/cancel Soft-delete a previously recorded booking so the bot stops seeing it ## Overview This endpoint soft-deletes a previously recorded booking. Use the `id` returned by [Create Booking](/setter-ai/bookings). The bot will stop seeing this booking in its context from the next message onwards. > [!NOTE] > > **Authentication**: All requests require a Bearer token in the Authorization header. ## Important Notes * **Authentication**: All requests require a Bearer token in the Authorization header * **Idempotency**: Re-cancelling an already-cancelled booking is a no-op * **Access Control**: You can only cancel bookings owned by your organization ## 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 ```bash theme={null} curl -X POST https://chat.trysetter.com/api/v1/bookings/555/cancel \ -H "Authorization: Bearer your_api_key" ``` # Get Conversation History Source: https://docs.trysetter.com/setter-ai/conversation-history GET /api/v1/bot-integrations/{botIntegrationId}/conversations Retrieve the full message history of a conversation programmatically ## Overview This endpoint returns the complete message history for a contact's conversation with your bot — every message sent by both the user and the bot, in chronological order, along with delivery status details. Use this to capture lead data, sync conversations to your CRM, or trigger downstream automations (e.g. in n8n or Make) whenever a conversation completes. > [!NOTE] > > **Authentication**: Requires a Bearer token. Pass your API key in the `Authorization` header as `Bearer `. > [!NOTE] > > **Bot Integration ID**: The `botIntegrationId` in the path identifies a specific channel of a bot (its WhatsApp or SMS integration) — it is not the bot ID. Find it in the bot's **Integrations** settings under the **WhatsApp** or **Twilio** integration. See [Send Message](/setter-ai/api-reference#bot-integration-id) for details. ## Platform-specific parameters The query parameter you need depends on your bot's platform: | Platform | Required parameter | | - | - | | WhatsApp | `userNumber` — the contact's phone number | | SMS (Twilio) | `userNumber` — the contact's phone number | | Playground / Embed | `sessionId` — the session ID | ## Example request (WhatsApp) ```bash theme={null} curl -X GET \ "https://chat.trysetter.com/api/v1/bot-integrations/123/conversations?userNumber=1234567890" \ -H "Authorization: Bearer " ``` ## Response Each item in the `data` array is a single message: * `senderType` — `"user"` or `"bot"` * `content` — the message text * `createdAt` — ISO 8601 timestamp * `latestStatus` — delivery status (e.g. `sent`, `delivered`, `read`, `failed`) * `failureReason` / `errorCode` / `errorMessage` — populated only when `latestStatus` is `failed` The `metadata.contextStartsAt` field indicates when the bot's active context window begins. Messages before this timestamp are still returned in full but fall outside the bot's current 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. # Update Contact Source: https://docs.trysetter.com/setter-ai/update-contact PUT /api/v1/contacts Update an existing contact information ## Overview This endpoint allows you to update an existing contact's information in your Setter AI account. You can update contact details like name, email, phone number, timezone, and custom metadata fields. > [!NOTE] > > **Contact Identification**: You must provide at least one identifier (ID, WhatsApp ID, or SMS phone number) to locate the contact. ## Contact Identification You can identify a contact using any of these methods: ### By Contact ID Use the internal contact ID for direct lookup: ```json theme={null} { "id": 123, "firstName": "John" } ``` ### By WhatsApp ID Use the WhatsApp ID for contacts from WhatsApp integrations: ```json theme={null} { "waId": "1234567890", "email": "john@example.com" } ``` ### By SMS Phone Number Use the SMS phone number for contacts from SMS integrations: ```json theme={null} { "smsPhoneNumber": "1234567890", "fullName": "John Doe" } ``` ## Updatable Fields All contact fields are optional in the update request. Only provided fields will be updated: * **firstName** - Contact's first name * **lastName** - Contact's last name * **fullName** - Contact's full name * **phoneNumber** - Contact's phone number * **email** - Contact's email address (must be valid format) * **defaultTimeZone** - Contact's default timezone (IANA format) * **metadata** - Custom key-value pairs for additional contact data ## Important Notes * **Authentication**: All requests require a Bearer token in the Authorization header * **Unique Contact**: If multiple contacts match the identifier, the operation fails with a 409 error * **Access Control**: Only contacts that your organization has access to can be updated * **Validation**: Email addresses are validated for proper format * **Metadata**: The metadata field supports custom key-value pairs for storing additional contact information ## Error Handling The endpoint provides specific error responses for different scenarios: * **400**: Missing identifier or invalid field format * **404**: No contacts found with the provided identifier * **409**: Multiple contacts matched the identifier * **401/403**: Authentication or authorization errors ## 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 ### Update Contact Name and Email ```bash theme={null} curl -X PUT https://chat.trysetter.com/api/v1/contacts \ -H "Authorization: Bearer your_api_key" \ -H "Content-Type: application/json" \ -d '{ "id": 123, "firstName": "John", "lastName": "Smith", "email": "john.smith@example.com" }' ``` ### Update Contact Metadata ```bash theme={null} curl -X PUT https://chat.trysetter.com/api/v1/contacts \ -H "Authorization: Bearer your_api_key" \ -H "Content-Type: application/json" \ -d '{ "waId": "1234567890", "metadata": { "source": "updated_via_api", "campaign": "winter2024", "last_interaction": "2024-01-15" } }' ``` # Webhooks Source: https://docs.trysetter.com/setter-ai/webhooks Receive real-time notifications for important events in your Setter AI integration ## Overview Setter AI sends webhook notifications to your server when important events occur, allowing you to build real-time integrations and automate workflows. ## Setting Your Webhook URL Configure your webhook URL in the Setter AI dashboard: 1. Navigate to **Settings > General** 2. Enter your webhook endpoint URL in the "Webhook URL" field 3. Save your settings Alternatively, you can configure it via API: ```bash theme={null} PUT /api/v1/organizations/current/settings Content-Type: application/json Authorization: Bearer YOUR_API_KEY { "webhookUrl": "https://api.example.com/webhook" } ``` > [!NOTE] > > Your webhook endpoint must accept POST requests with `Content-Type: application/json`. ## Webhook Events ### Appointment Booked Triggered when a contact successfully books an appointment through any connected calendar integration. **Event Type:** `appointment_booked` #### Payload Example ```json theme={null} { "type": "appointment_booked", "timestamp": "2025-12-04T10:30:00.000Z", "startTime": "2025-12-05T14:00:00.000Z", "startTimeInTz": "2025-12-05T09:00:00-05:00", "endTime": "2025-12-05T15:00:00.000Z", "timeZone": "America/New_York", "contactEmail": "user@example.com", "contactWhatsappId": "1234567890", "contactPhoneNumber": "+1234567890", "contactFullName": "John Doe", "contactFirstName": "John", "contactLastName": "Doe", "contactMetadata": {}, "concatenatedConversation": "Full conversation history...", "botId": 123, "botIntegrationId": 456 } ``` ### Conversation Inactive Triggered 23 hours after the last user message in a conversation. **Event Type:** `conversation_inactive` #### Payload Example ```json theme={null} { "type": "conversation_inactive", "timestamp": "2025-12-04T10:30:00.000Z", "lastUserMessageSentAt": "2025-12-03T11:30:00.000Z", "inactiveForDuration": "PT23H", "conversationStatus": ["replied"], "contactEmail": "user@example.com", "contactWhatsappId": "1234567890", "contactPhoneNumber": "+1234567890", "contactFullName": "John Doe", "contactFirstName": "John", "contactLastName": "Doe", "contactMetadata": {}, "concatenatedConversation": "Full conversation history...", "botId": 123, "botIntegrationId": 456 } ``` ### Message Delivery Failed Triggered when a WhatsApp message fails to deliver. Use this to implement fallback workflows — for example, triggering an SMS via Zapier when a WhatsApp message can't be delivered. **Event Type:** `message_delivery_failed` #### Payload Example ```json theme={null} { "type": "message_delivery_failed", "timestamp": "2025-12-04T10:30:00.000Z", "platformResourceId": "wamid.HBgLNDQ3...", "errorCode": 131026, "errorTitle": "Message undeliverable", "errorMessage": "Message failed to send because there were one or more errors related to your phone number.", "errorDetails": "The message could not be delivered.", "contactWhatsappId": "447911123456", "contactPhoneNumber": "+447911123456", "contactFullName": "John Doe", "contactFirstName": "John", "contactLastName": "Doe", "contactEmail": "john@example.com", "contactMetadata": {}, "botIntegrationId": 456 } ``` #### Use case: SMS fallback via Zapier If a WhatsApp message fails to deliver, you can use this webhook to trigger an SMS to the same contact: 1. Create a Zap with **Webhook by Zapier** as the trigger (Catch Hook) 2. Set your Zapier webhook URL as the **Webhook URL** in your Setter AI settings 3. Filter on `type === "message_delivery_failed"` 4. Use `contactPhoneNumber` to send an SMS via Twilio or another SMS provider ## Payload Fields ### Common Fields | Field | Type | Description | | - | - | - | | `type` | string | Event type identifier (`appointment_booked`, `conversation_inactive`, or `message_delivery_failed`) | | `timestamp` | ISO 8601 | When the event occurred (UTC) | | `contactEmail` | string \| null | Contact's email address | | `contactWhatsappId` | string \| null | WhatsApp user ID | | `contactPhoneNumber` | string \| null | Contact's phone number | | `contactFullName` | string \| null | Contact's full name | | `contactFirstName` | string \| null | Contact's first name | | `contactLastName` | string \| null | Contact's last name | | `contactMetadata` | object \| null | Custom metadata associated with the contact | | `botId` | number \| null | Bot identifier (shown in the dashboard URL, e.g. `…/bots/700/…`) | | `botIntegrationId` | number | Bot Integration ID — identifies the specific channel (WhatsApp or SMS integration) the event belongs to. Different from `botId`; found in the bot's Integrations settings. Use this value when calling the [Send Message](/setter-ai/api-reference) and [Conversation History](/setter-ai/conversation-history) APIs. | ### Appointment-Specific Fields | Field | Type | Description | | - | - | - | | `startTime` | ISO 8601 | Appointment start time (UTC) | | `startTimeInTz` | ISO 8601 | Appointment start time in the invitee's timezone | | `endTime` | ISO 8601 | Appointment end time (UTC) | | `timeZone` | string | IANA timezone identifier (e.g., "America/New\_York") | ### Conversation Inactive Fields | Field | Type | Description | | - | - | - | | `lastUserMessageSentAt` | ISO 8601 | Timestamp of the last user message | | `inactiveForDuration` | ISO 8601 Duration | Duration of inactivity (e.g., "PT23H" = 23 hours) | | `conversationStatus` | string\[] | Array of conversation status tags (e.g., \["appointment\_booked", "replied"]) | | `concatenatedConversation` | string \| null | Complete conversation history | ### Message Delivery Failed Fields | Field | Type | Description | | - | - | - | | `platformResourceId` | string | The WhatsApp message ID (wamid) that failed to deliver | | `errorCode` | number \| null | WhatsApp error code (see [Meta error codes](https://developers.facebook.com/docs/whatsapp/cloud-api/support/error-codes)) | | `errorTitle` | string \| null | Short error title | | `errorMessage` | string \| null | Detailed error message | | `errorDetails` | string \| null | Additional error context | ## Best Practices > [!TIP] > > **Implement Idempotency**: Your webhook endpoint should handle duplicate events gracefully. Use the `timestamp` and event-specific fields to deduplicate requests. * **Respond Quickly**: Return a 2xx status code within 5 seconds to acknowledge receipt * **Process Asynchronously**: Queue webhook processing for longer operations * **Secure Your Endpoint**: Use HTTPS and validate webhook signatures (if implemented) * **Handle Failures**: Implement retry logic with exponential backoff on your side # A2P 10DLC Registration Guide Source: https://docs.trysetter.com/sms-integration/a2p-registration Successfully register your business messaging campaign with Twilio for US and Canada SMS. > [!NOTE] > > **Last updated:** July 22, 2025 ## Overview If you're planning to send business SMS messages in the US or Canada, you must complete A2P (Application-to-Person) 10DLC registration with Twilio. This guide walks you through filing a compliant campaign registration to avoid rejections and ensure your messaging gets approved. > [!WARNING] > > **Required for US & Canada**: A2P 10DLC registration is mandatory before sending any application-generated messages to US or Canadian phone numbers. Start this process early as approval can take several weeks. ## What You Need Before Starting Before beginning your A2P registration, ensure you have: * A registered business with Twilio * A clear opt-in process for collecting SMS consent * Compliant message samples * Privacy policy and terms of service * Screenshots of your consent forms *** ## Step 1: Set Up Compliant Opt-In Forms Your lead form must meet Twilio's strict requirements to ensure compliance. ### Required Elements **1. Clear Opt-In Language** Use explicit language that explains what users are agreeing to receive: ``` "Do you agree to receive SMS notifications about appointments and offers?" ☐ Yes, I agree to receive SMS messages from [Company Name] ``` **2. Separate Consent Checkbox** > [!WARNING] > > **Critical**: Do NOT bundle SMS consent with Terms & Conditions or Privacy Policy. SMS consent must be a separate, unchecked checkbox. **3. Visible Policy Links** Include direct links to your Privacy Policy and Terms of Service on the form. Your Privacy Policy must explicitly state: > "Mobile information will not be shared with third parties/affiliates for marketing/promotional purposes." ### Form Checklist * Separate SMS consent checkbox (unchecked by default) * Clear description of what messages users will receive * Privacy Policy link visible on form * Terms of Service link visible on form * Privacy Policy includes third-party sharing language *** ## Step 2: Describe Your Opt-In Process In the **"How do end-users consent to receive messages?"** section of your Twilio application, provide a clear description of your opt-in process. ### Example Description ``` Users opt in via our website [yourdomain.com] and provide explicit consent to receive SMS communications from our company through a separate, unchecked checkbox on our lead form. ``` ### What to Include > **Platform Details** > > Specify where opt-in happens (website, app, checkout page, etc.) > **Consent Method** > > Describe how consent is collected (checkbox, form field, etc.) > **Form Evidence** > > Provide either a direct link to your opt-in form OR screenshots > **Supporting Documentation** > > Additional images or files that demonstrate your consent process ### Supporting Form Evidence for Your Application When submitting your A2P campaign, you'll need to provide evidence of your compliant opt-in process in this field of your Twilio application. This should be a link in the **"How do end-users consent to receive messages?"** field. #### Documentation to Include * **Either** screenshots of your complete opt-in form **OR** a direct link to the live form > [!NOTE] > > **File Sharing**: Use a public file-sharing service like Google Drive, OneDrive, or Dropbox to host your documentation folder, then provide the link in your Twilio application. *** ## Step 3: Create Message Samples You'll need to provide two sample messages that represent the type of content you'll send. ### Sample Message Guidelines > **Conversational Tone** > > Write messages as if speaking to a friend or customer > **Clear Purpose** > > Make it obvious why the recipient is receiving the message > **Professional Content** > > Avoid excessive emojis or informal language > **Relevant Links** > > Include only business-relevant URLs ### Example Messages **Message Sample #1:** ``` Hi [Name]! Your appointment is confirmed for tomorrow at 2 PM. Please arrive 5 minutes early. Looking forward to meeting you! ``` **Message Sample #2:** ``` [Name], new time slots are now available! Book your session at our [location] by clicking here: https://yourlink.com ``` *** ## Pre-Submission Checklist Before submitting your A2P campaign, verify all requirements are met: > **Opt-In Compliance** > >
    >
  • ☐ Separate SMS consent checkbox (unchecked by default)
  • >
  • ☐ Clear opt-in language explaining message types
  • >
  • ☐ Privacy Policy and Terms visible on form
  • >
  • ☐ Privacy Policy includes no third-party sharing clause
  • >
> **Message Samples** > >
    >
  • ☐ Two compliant message examples provided
  • >
  • ☐ Messages use conversational, professional tone
  • >
  • ☐ Content aligns with your business purpose
  • >
> **Documentation** > >
    >
  • ☐ Screenshots of opt-in form linked OR direct form link provided
  • >
*** ## Next Steps Once your A2P campaign is approved: > **[Start SMS Integration](/sms-integration/introduction)** > > Begin your SMS integration setup process > **[Configure Twilio Webhook](/sms-integration/twilio-setup)** > > Set up your Twilio integration with Setter AI ## Need Help? > **Technical Support** > > Contact [support@trysetter.com](mailto:support@trysetter.com) for A2P registration questions # SMS Integration Overview Source: https://docs.trysetter.com/sms-integration/introduction Enable AI-powered SMS conversations through Twilio integration. ## Welcome to SMS Integration The AI Setter SMS integration allows you to automatically handle SMS conversations with leads and prospects through Twilio. You can now **set up the integration entirely through our self-serve integration UI** - no need to coordinate with our team or share credentials back and forth. ## How It Works > **Connect Twilio** > > Enter your Twilio credentials directly in our integration UI > **Configure Webhook** > > Set up the webhook URL in your Twilio console to route messages > **You're Ready** > > Start sending SMS conversations via our API immediately > **AI Takes Over** > > AI Setter handles conversations automatically ## What You Need to Set Up To get started, you'll need to have the following information ready: ### 1. Twilio Account Details * **Account SID** (found in your Twilio Console) * **Account Auth Token** (found in your Twilio Console) * **Phone Number** (the Twilio number you want to use for SMS) ### 2. Access to Your Bot * Navigate to your bot's integrations page in the Setter AI dashboard * You'll enter the Twilio credentials directly in the integration form > [!NOTE] > > **Finding your integration page**: In your dashboard, go to your bot → Integrations → Twilio to access the self-serve setup form. ### 3. A2P 10DLC Registration (only US & Canada phone numbers) > [!WARNING] > > **US & Canada**: A2P 10DLC registration is mandatory before sending application-generated messages. Ensure your brand and campaign are fully approved before setting up the integration. > **[A2P 10DLC Registration Guide](/sms-integration/a2p-registration)** > > Complete guide to filing a successful A2P campaign with Twilio ## Getting Started Ready to set up your SMS integration? Follow these simple steps: > **[Integration Setup Guide](/sms-integration/twilio-setup)** > > Complete step-by-step guide to set up SMS integration through our UI > **[Need Help?](https://calendly.com/setter-ai/ai-appointment-setter-15min)** > > Book a demo if you need assistance with the integration setup ## What You'll Get After completing the self-serve integration setup, you'll have: * **Bot Integration ID** - Automatically generated and displayed in the UI for use in API calls * **Instant setup** - Integration is active immediately after configuration * **Ready to use** - Start sending SMS conversations via our API right away ## Key Features > **Automated Conversations** > > AI Setter automatically handles incoming SMS messages and responds intelligently > **Lead Qualification** > > Qualify leads through natural conversation flow > **Appointment Scheduling** > > Schedule appointments directly through SMS conversations > **Real-time Processing** > > Instant response to incoming messages via Twilio webhooks ## Supported Regions SMS integration is available in any region where a SMS-capable phone number can be purchased from Twilio that can receive inbound messages and send outbound messages. > [!NOTE] > > **US & Canada**: A2P 10DLC registration is mandatory before sending application-generated messages. Ensure your brand and campaign are fully approved before initiating conversations. [Learn how to complete A2P registration →](/sms-integration/a2p-registration) > [!NOTE] > > Need help acquiring a suitable phone number from Twilio? Contact [support@trysetter.com](mailto:support@trysetter.com) for assistance. ## Integration Workflow 1. **Enter Credentials** - Input your Twilio details directly in our integration UI 2. **Configure Webhook** - Set up the webhook URL in your Twilio console 3. **Get Bot Integration ID** - Automatically generated and displayed in the UI 4. **Start Conversations** - Begin sending SMS via our API immediately 5. **AI Handles Everything** - Automated responses and scheduling ## Next Steps > **[Complete Your SMS Integration Setup](/sms-integration/twilio-setup)** > > Follow our step-by-step guide to set up SMS integration through the self-serve UI # Twilio SMS Setup Source: https://docs.trysetter.com/sms-integration/twilio-setup Set up SMS integration through our self-serve integration UI. > [!NOTE] > > **Author:** Josef Büttgen\ > **Last updated:** September 20, 2025 ## Overview This guide walks you through setting up SMS integration with Twilio using our **completely self-serve integration UI**. You can now connect your Twilio account directly through our dashboard without any manual coordination with our team. ## Pre-requisites > [!WARNING] > > **A2P 10DLC registration (only US & Canada)** – US long-code numbers must have a fully approved A2P (brand & campaign) before any application-generated messages can be sent. [Complete the A2P registration process →](/sms-integration/a2p-registration) **What you'll need:** * Your Twilio Account SID * Your Twilio Auth Token * Your Twilio phone number * Access to your Twilio Console for webhook configuration *** ## Step 1: Connect Twilio in Integration UI 1. **Navigate to Integrations** * Go to your bot dashboard * Click on **Integrations** in the navigation * Select **Twilio** from the integration options 2. **Enter Your Twilio Credentials** * **Phone Number**: Enter your Twilio phone number (e.g., 1234567890, no '+' symbol at the start) * **Account SID**: Found in your Twilio Console dashboard * **Auth Token**: Found in your Twilio Console dashboard (will be hidden for security) 3. **Save Integration** * Click **Save** to create the integration * Your **Bot Integration ID** will be automatically generated and displayed * Copy this ID - you'll need it for API calls > [!NOTE] > > **Bot Integration ID**: This unique identifier is automatically created when you save your integration. You'll use this ID in API calls to send SMS messages. *** ## Step 2: Configure AI Setter Webhook in Twilio Now that your integration is set up, you need to configure your Twilio phone number or Messaging Service to route incoming SMS messages to the AI Setter webhook: ![Messaging Configuration in Twilio](https://mintcdn.com/setterai/AV6yna-vayQT6nGM/images/twilio_messaging_configuration_setter_ai.png?fit=max\&auto=format\&n=AV6yna-vayQT6nGM\&q=85\&s=eefde42bb5979ed89f27641aafb86662) *Example: Messaging Configuration in Twilio (Messaging Service can differ to your configuration).* ### Setup Steps 1. **Navigate to your Twilio Console** * For **Phone Numbers**: Go to **Phone Numbers → Manage → Active numbers** → Select your number * For **Messaging Services**: Go to **Messaging → Services** → Select your service 2. **Configure the Incoming Message Handler** Set the following fields exactly as shown: * **Messaging Service**: Select your A2P messaging service (e.g., "Low Volume Mixed A2P Messaging Service") * **Configure with**: Select **"Webhook, TwiML Bin, Function, Studio Flow, Proxy Service"** * **A message comes in**: * Type: **"Webhook"** * URL: `https://chat.trysetter.com/api/v1/webhooks/twilio` * HTTP Method: **"HTTP POST"** * **Primary handler fails**: * Type: **"Webhook"** * HTTP Method: **"HTTP POST"** * URL: *leave empty* 3. **Save Configuration** > [!NOTE] > > Once the webhook is configured, you can initiate SMS conversations using the Bot Integration ID from your integration UI. ## Step 3: Testing Your Setup After saving the webhook configuration, test your integration: 1. **Send a test message** to your Twilio phone number from your personal phone 2. **Check for an AI response** - You should receive an automated reply from AI Setter 3. **Verify in dashboard** - Check your bot's conversation history to see the test message 4. **Contact support** if you don't receive a response within a few minutes ## Troubleshooting ### Integration Not Working - Bad Request Responses If you've followed all the setup steps but your SMS integration isn't working and you're seeing **'Bad Request'** responses from Setter AI in your Twilio logs: > [!WARNING] > > **Double-check your Auth Token** - The most common cause of Bad Request errors is an incorrectly entered Twilio Auth Token in the integration settings. **Steps to resolve:** 1. **Verify Auth Token** * Go back to your Twilio Console dashboard * Copy your Auth Token again (make sure to get the complete token) * Navigate to your Setter AI Integrations page * Re-enter the Auth Token exactly as copied from Twilio * Save the integration settings 2. **Test the integration** * Send a test message to your Twilio phone number * Check if you receive an AI response 3. **Still not working?** * Contact our support team with your integration details * Include your Bot Integration ID and any error messages from Twilio logs > **Email Support** > > Send details to [support@trysetter.com](mailto:support@trysetter.com) *** ## What You'll Need for API Calls To start sending SMS conversations, you'll need: * **Bot Integration ID** (displayed in your integration UI after saving) * **API Key** (from your Setter AI dashboard) ## Next Steps > **[Start SMS Conversation](/setter-ai/api-reference)** > > Learn how to initiate SMS conversations via API ## Need Help? > **Technical Support** > > Contact [support@trysetter.com](mailto:support@trysetter.com) for integration issues > **Book a Call** > > Schedule a call at [calendly.com/setter-ai](https://calendly.com/setter-ai/ai-appointment-setter-15min) for setup assistance ## Summary With the new self-serve integration UI, setting up SMS is now completely streamlined: 1. **Enter credentials** directly in the Twilio integration page 2. **Configure webhook** in your Twilio console 3. **Start using** your Bot Integration ID for API calls immediately No more back-and-forth with our team or waiting for manual setup! # WhatsApp Meeting Reminders Setup Source: https://docs.trysetter.com/whatsapp-reminders/setup Automatically send WhatsApp reminders to your invitees before a Calendly event starts. > **TL;DR:** > > 1. Ensure your bot has Calendly and WhatsApp integrations already connected. > 2. Create a **Reminder Configuration** that links the two integrations and points to an approved WhatsApp template.\ > That's it – Setter AI will now notify your invitees on WhatsApp \~2 h before their meeting. *** ## 1. Prerequisites 1. **Setter AI account** with at least one *bot*. 2. **Calendly account already connected** to your bot (via the bot's Calendly integrations section). 3. **WhatsApp integration already set up** for your bot with a valid access token and phone number. 4. **Meta WhatsApp Business** account with an *approved* message template (e.g. `meeting_reminder`). 5. **Calendly event type configured to collect phone numbers** - your event type must include a required phone number field in the booking form. > [!NOTE] > > **Important:** Setter AI currently sends reminders **2 hours** before each event. If you need a different schedule, [contact support](mailto:support@trysetter.com). > > **Phone Number Required:** Reminders will only be sent to invitees who provide a phone number during booking. Make sure your Calendly event type includes a required phone number field. *** ## 2. Create a Reminder Configuration With both your Calendly account and WhatsApp integration already set up, you can now link them together through the Setter AI dashboard. ### Step 1: Navigate to Meeting Reminders 1. Go to your bot's dashboard in Setter AI 2. Navigate to **Settings > Reminders** 3. Click **"Create New Reminder"** ![Meeting Reminders Dashboard](https://mintcdn.com/setterai/AV6yna-vayQT6nGM/images/meeting-reminders-dashboard.png?fit=max\&auto=format\&n=AV6yna-vayQT6nGM\&q=85\&s=46a58fd1d24c9ac37c220490fb1340fc) *Screenshot: Meeting reminders section in the bot dashboard* ### Step 2: Configure Calendar Integration 1. Select **Calendly** as your calendar provider 2. Choose the Calendly account you want to use from the dropdown 3. Select the specific **Event Type** that should trigger reminders (ensure this event type collects phone numbers from invitees) ![Calendar Integration Setup](https://mintcdn.com/setterai/AV6yna-vayQT6nGM/images/reminder-calendar-setup.png?fit=max\&auto=format\&n=AV6yna-vayQT6nGM\&q=85\&s=69d2d1e457ba1be8866b70815769d147) *Screenshot: Selecting Calendly account and event type* ### Step 3: Configure WhatsApp Messaging 1. Select **WhatsApp** as your messaging platform 2. Choose your approved **Message Template** from the dropdown 3. Configure the template variables - these are the placeholders you defined when creating your WhatsApp message template > [!TIP] > > Need help creating message templates? Check out this [video guide](https://www.youtube.com/watch?v=rLv_h95svBI) for step-by-step instructions. ![WhatsApp Template Configuration](https://mintcdn.com/setterai/AV6yna-vayQT6nGM/images/reminder-whatsapp-template.png?fit=max\&auto=format\&n=AV6yna-vayQT6nGM\&q=85\&s=14b59b5e977cf65626f2857a867fe098) *Screenshot: WhatsApp template selection and variable configuration* ### Step 4: Preview and Save 1. Review the reminder configuration summary 2. Preview how the message will look to customers 3. Click **"Save"** to activate the reminders ![Reminder Preview and Save](https://mintcdn.com/setterai/AV6yna-vayQT6nGM/images/reminder-preview-save.png?fit=max\&auto=format\&n=AV6yna-vayQT6nGM\&q=85\&s=eaafb60e3fa226c3a9bb51c3875aafdf) *Screenshot: Final preview and save screen* *** ## 3. Managing Reminder Configurations ### View Existing Configurations 1. In your bot dashboard, go to **Settings > Reminders** 2. All active reminder configurations will be displayed in a list 3. You can see which calendar accounts and event types have reminders enabled ### Edit or Disable Configurations 1. Click the **"Edit"** button next to any configuration 2. Modify the template, variables, or other settings as needed 3. Use the **"Enable/Disable"** toggle to turn reminders on or off 4. Click **"Update"** to save your changes *** ## 4. How it Works Behind the Scenes 1. **Every few minutes** Setter AI scouts your Calendly account for events starting *\~2 h* in the future (5 min grace window). 2. For each invitee we look up a phone number in Calendly's questions & answers (if no phone number was provided during booking, no reminder will be sent). 3. A WhatsApp template message is sent via the bot channel. *** ## 5. Troubleshooting | Issue | Fix | | - | - | | No reminders are being sent | Verify the reminder configuration is enabled and that your Calendly event type collects phone numbers from invitees. | | Invitee didn't receive a message | Ensure the invitee provided a phone number during booking. The phone number should be in international format (e.g., +1234567890). | | "Template rejected" error | The template name or language code does not match an *approved* template in your WhatsApp Business account. | | Some invitees get reminders, others don't | Check that all invitees provided phone numbers during booking - reminders are only sent to those with valid phone numbers. | Need more help? Reach out at [support@trysetter.com](mailto:support@trysetter.com).