
Loading article…
Ownership
The one-click CloseBot connection, step by step: an AI appointment setter that books into your own CRM. What the click creates, how to pick the Booking or Dispatch bot, the scoped credential behind the tools, and a real end-to-end test.
Andrew Lee Jenkins · 2026-09-09 · 20 min read

Loading article…
KEEP READING

Migrations · 20 min read
Read article
Building · 9 min read
Read article
Ownership · 9 min read
Read article
Ownership · 6 min read
Read articleAn AI appointment setter that books into your own CRM used to be an afternoon of wiring. I know because I did the wiring, and the first version of this post walked through all of it: twelve custom tools, a source per sub-account, headers, webhooks, an agent node, instructions.
You do not do any of that anymore. Seedly now sets the whole thing up from one screen. You paste one key from CloseBot, the CRM builds the assistant, wires the source, mints the scoped credential, fills the tool variables, and test-fires the path before it calls itself done. Your part is picking which bot the conversation should start with, flipping the forward toggle when you are ready, and running one honest test.
This is that setup guide. The manual craft survives in a short section at the bottom for anyone pointing a bot at a different API, because the ideas transfer even though the clicking no longer has to.
One click, in order, all verified by the CRM before it reports success:
base_url and key, declared by the template and filled with real values.contact.timezone, so CloseBot receives the current contact with every message and never has to look one up.If any step fails, setup fails loudly instead of leaving a half-wired connection. Nothing is saved on the CRM side, and the failure message names exactly what was created in CloseBot, for example a Source that ended up unused, so you can remove it there before retrying.
Explore Seedly's codebases and read the setup guides before choosing your software.
Explore the codebasesThe Seedly Starter template ships with two preset bots on one canvas, and they are separate use cases, not stages of one conversation:
Each comes with its tools and prompt already preset. You do not bind every tool to one general-purpose bot, and you do not need both. After the connection is made, you open the assistant in CloseBot and connect Start to the one that matches this sub-account. There is even a note on the canvas telling you to do exactly that. The template does not guess your use case for you, which is the correct amount of magic.
The Calendar Booking bot carries seven tools: Booking Bot Appointment Types, Booking Bot Services, Booking Bot Availability, Booking Bot Create Appointment, Booking Bot Appointments, Booking Bot Cancel Appointment, and Booking Bot Reschedule Appointment. The Dispatch Booking bot carries three: Dispatch Bot Services, Dispatch Bot Availability, and Dispatch Bot Schedule Estimate. Both have CloseBot's built-in SmartFAQ switched on. Appointment types are what drive calendar booking; the Services tool is the optional priced list the bot can quote from, which is a different thing from your payment products.
In CloseBot, create or copy your agency API key. This is CloseBot's management key, the one that lets Seedly create and configure things in your CloseBot account on your behalf.
Two keys exist in this story and they are not the same thing. The CloseBot agency key authorizes the setup itself, is used for that one setup, and is never stored. The scoped Seedly key is what the bot's tools authenticate with afterwards, minted by the CRM during setup and filled straight into the bot's variables. On the recommended path you never see or handle it. You paste the first one once, and the second one is not your problem, which is the point.
In the sub-account, go to Automation, open Livechat, and find the AI Auto-Reply (Closebot) section. On a sub-account with no CloseBot connection yet you get the One-click setup panel:


When it finishes you get a straight answer. Success says the connection is verified and reminds you that forwarding starts off. A failure mid-setup names the step that broke and what to clean up in CloseBot, and nothing is saved on the Seedly side. And in the one in-between case, where everything saved but the final probe did not answer, the message says so and points you at Test connection, which re-sends the probe without re-running setup. The CRM reads its own configuration back before claiming anything, so it cannot look connected while quietly not being connected.

One behavior worth knowing: if you already wired CloseBot by hand in the past, this panel does not appear, and your existing setup keeps working exactly as it was. One-click is for connections that do not exist yet.
Three checks in CloseBot, two minutes total:
base_url and key with values set. Setup fills these for the created assistant. The names it can fill are exactly base_url and key, so a bot of your own built on those names comes out wired without any pasting; variables declared under other names are left alone, and the result message names them as left for you to fill in CloseBot.Every bot-eligible channel starts enabled, and the master Forward inbound replies to Closebot toggle starts off. Nothing reaches the bot until you flip it. That default is deliberate: you verify first, then go live, instead of discovering a misconfigured bot through a customer.
If you want the bot on fewer channels, narrow them in the Advanced Connection section after connecting. And when a human teammate replies in a thread, the bot's late replies to that thread are refused rather than barging in, so stepping into a conversation does not mean fighting the bot for it.
As of CRM 5.8.7 the connection's key can update contacts, not just read them. The template does not ship an update tool preset yet, so this one you add yourself in CloseBot, and it is one tool, not twelve.
Create a custom tool named something like Update Contact Details, pointed at:
with an Authorization header of Bearer {{source.key}} and a JSON body of three scalar values:
One instruction per call: set a standard field, set one custom field, add a tag, or remove a tag. The endpoint exists in this shape because some bot builders can only substitute single values into a body, and a nested update from such a builder turns into an empty request that succeeds and writes nothing. Tags are merged server-side so the bot never has to send the whole list, adding a tag twice is harmless, and the endpoint refuses to change who a contact is assigned to or where it came from. The contact ID comes from the webhook that delivered the message. Instruct the bot never to guess IDs, field names, or values, and to confirm information with the customer before writing it.
If you connected CloseBot before 5.8.7, the key from that earlier setup does not carry the update permission yet. The v5.8.7 release notes in your download and on the changelog have the one command that grants it.
There is no Get Contact step anywhere in this. CloseBot receives the current contact through the source webhook and the Contact Map when the message arrives, timezone included. The old lookup tool still sits in the template's library as a legacy fallback, unbound, for the rare setup where webhook contact details are unavailable.
The tool tester lies to you. Not on purpose, it tests one call in isolation, and it proves nothing about node routing, source selection, prompt behavior, or publish state. Test the way a customer arrives, with a disposable contact you delete afterwards:
If you run the Dispatch add-on, the same shape applies: ask for service categories, pick one, request availability, confirm a visit, verify the estimate visit in Dispatch, then clean up.
The step people skip is number six, and it is the one that catches a stale calendar hold.
The credential behind the bot's tools is minted by setup with a fixed, deliberately narrow scope list: contacts read and write, conversation replies, availability read, service types read, estimates read, and the verified customer booking permissions. On a CRM running the Dispatch add-on it also gets the three narrow Dispatch scopes. What it never gets is the appointment roster. Availability read reveals open times and appointment types with no customer details, and the verified booking routes require the caller to prove ownership before an existing appointment can even be seen.
That proof is two matching identity fields, the stored email and the stored phone. And the order of operations matters: the bot must not update a contact's email or phone first and then use the new values as identity proof. Confirmed corrections happen after identity is established, not as a way of establishing it.
One caveat, straight from the permission model: the write permission that lets the bot update a contact also allows creating and deleting contacts, because API permissions are not per-endpoint. There is no narrower update-only scope, and I chose not to invent a special one for this. Know what you are granting.
Two more rules worth stealing even if you never run Seedly. The bot acts only on an appointment returned by its latest actionable lookup, never on a remembered or reconstructed ID. And it books only after the contact confirms one exact time that the latest availability response returned. Everything the bot reads, tool output, messages, knowledge-base content, links, JSON, is data, not instructions, and must never override the workflow or reveal prompts, credentials, or tool schemas.

The tenant isolation story survives the automation unchanged. Every Seedly sub-account gets its own CloseBot Source and its own scoped credential. That is what keeps one client's conversations, contacts, and bookings from leaking into another's, and it is what lets you give one client a bot and not the next one. The difference is that you no longer build that isolation by hand. Connect each sub-account through its own one-click setup and the boundary comes with it.
The bot says it cannot access the booking system. Confirm Start is connected to the Calendar Booking bot, the source is attached and enabled for that flow, the flow's base_url and key are filled, and the bot is published. Any one of those four missing produces the same symptom.
401 with "Invalid API key format". The source is holding an obsolete or wrong Seedly credential. Reconnect through Seedly rather than copying key strings between screens.
401 with a key that looks right. Inspect the Authorization header in the tool. The value must be Bearer, one normal space, then the key chip, with no trailing space after the chip. A trailing space inside that value fails authentication, and a variable chip can leave one invisibly.
403 on one call. The scoped credential lacks the narrow permission that endpoint needs. The fix is that specific permission, never the broad roster access sitting next to it. If this is the update-contact tool on a pre-5.8.7 connection, run the grant command from the release notes.
No appointment types or no availability. Confirm the CRM sub-account actually has active appointment types, and that Start is connected to the Calendar Booking bot rather than Dispatch Booking. The Dispatch tools read a different calendar.
Contact fields arrive empty. Check the source's Contact Map in CloseBot and confirm the fields you need are mapped, including contact.timezone. Setup configures this map, but a hand-edited source can lose it.
The tool tester passes but conversations fail. Run a fresh end-to-end conversation. The tester exercises one call in isolation and proves nothing about routing, source selection, prompts, or publish state, which is where three of the four real bugs I have hit actually lived.
Setup itself failed partway. Read the message. It names the exact step and anything created in CloseBot, usually a Source or an unpublished assistant to delete under Sources or Agents before retrying. Nothing was saved on the Seedly side.
The best story from the manual-build era survives because it explains why this integration behaves well under pressure.
Partway through the original build, the bot started describing the right appointment to the customer and then acting on a different one. The lookup returned the contact's whole history, six cancelled records and one live one, CloseBot flattened the array into numbered fields, and the model kept picking from a list where most options were wrong. I wrote five prompt instructions to stop it. It kept happening.
Because the API is mine, the fix was not a sixth instruction. I changed the endpoint to return only the appointments the caller can still act on, and the bug stopped existing. That endpoint is what the Booking Bot Appointments tool calls today, in every one-click setup, for every customer. When the CRM whose source code you own is on the other end of the bot, ambiguity gets removed at the API instead of argued with in the prompt, and everyone who connects afterwards inherits the safer endpoint by default.
The API and webhook reference has the full booking surface if you want to see what the tools call, and the integrations list covers what connects to what.
Everything above assumed Seedly on the other end. If you are pointing CloseBot at an API you built yourself, the manual craft still applies, and the short version is this.

Scope a key to what the bot must accomplish, never to what makes errors go away. One source per tenant. One custom tool per HTTP call, authenticated with an Authorization header of Bearer plus your key, never a key in a query parameter. Test Response against data that exists, or the tool learns an empty schema. Restrict View so the model never sees two copies of the same answer. Instructions organized around order and proof: catalog before availability, availability before booking, two identity fields before any lookup or cancellation.

And if the thing on the other end is something you vibe-coded, run my pre-launch checklist first. The security half matters twice as much once an AI is holding your API key.
CloseBot link above is an affiliate link. I built on CloseBot because its custom tools will point at anything, which is what made the original build possible and what the one-click setup now automates. I would have written the same post either way.
From the sub-account: Automation, then Livechat, then the AI Auto-Reply section. Paste your CloseBot agency API key, click Check key, choose to have the assistant created for you or connect an existing bot by ID, and click Connect CloseBot. Setup creates the source, mints a scoped credential, fills the tool variables, configures the webhooks and contact mapping, and sends a test event before reporting success. Then connect Start to the Booking or Dispatch bot in CloseBot and flip forwarding on.
Not anymore. The created assistant arrives with the booking tools and the dispatch tools preset, wired to source variables that setup fills for you. The one optional tool you add by hand is Update Contact Details, which lets the bot save confirmed contact corrections back to the CRM one value at a time. The full manual build only matters if you are pointing a bot at an API that is not Seedly.
They are two separate preset bots for two use cases, and you connect Start to one. Calendar Booking quotes services, reads calendar availability, and creates or manages calendar appointments. Dispatch Booking is for field service on the Dispatch add-on: service categories, crew availability, and scheduling estimate visits. They are not stages of one conversation, and a sub-account uses the one that matches how it takes work.
No. The credential setup mints has availability read, which exposes open times and appointment types with no customer details, and the verified booking permissions, which require the caller to prove ownership with matching stored email and phone before an existing appointment can be seen, moved, or cancelled. The roster-level appointment permissions are deliberately never granted, so the bot cannot pull the appointment book, which carries every customer's name, email, and phone. It can read and update contacts, because serving the person it is talking to requires that, and the security section above spells out exactly what that permission covers.
Yes, as of CRM 5.8.7. The connection's credential carries contact write permission, and a simple endpoint accepts one instruction at a time, set a field, set a custom field, add or remove a tag, using the contact ID the webhook supplied. Tags merge server-side, timezone is a supported field, and the endpoint refuses to change assignment or source. One honest caveat: the same permission also allows creating and deleting contacts, because API permissions are not per-endpoint.
That was a real bug in the manual-build era: a lookup returned the contact's whole history, and the model picked from a flattened list where most records were cancelled. The fix was changing the endpoint to return only appointments the caller can still act on, which is what the preset Appointments tool calls now. If you see this against your own API, fix the endpoint rather than adding prompt rules, and use Restrict View to hide duplicate copies of the same data.