curl --request GET \
--url https://api.teamfollowup.ai/api/tfu-live-agents/brain-templates \
--header 'Authorization: Bearer YOUR_API_KEY'import requests
url = "https://api.teamfollowup.ai/api/tfu-live-agents/brain-templates"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.teamfollowup.ai/api/tfu-live-agents/brain-templates', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.teamfollowup.ai/api/tfu-live-agents/brain-templates",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.teamfollowup.ai/api/tfu-live-agents/brain-templates"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.teamfollowup.ai/api/tfu-live-agents/brain-templates")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.teamfollowup.ai/api/tfu-live-agents/brain-templates")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"brainTemplates": [
{
"id": "booking_one_calendar",
"name": "Appointment booking, one calendar",
"direction": "either",
"typicalFor": [
"outbound"
],
"description": "For a business that books appointments on one calendar, on inbound or outbound calls. The AI speaks for the business, finds out what the lead needs, offers open times from that one calendar and books the time the lead picks; a lead who already has an appointment can move it or cancel it there. There is no live transfer: a lead who wants a person later or is busy now is offered an AI callback. A lead who asks not to be contacted is put on do not disturb. Texting is off.",
"logic": {
"booking": "single",
"cancel": true,
"transfer": "none",
"direction": "either",
"texting": false
},
"tools": [
"respond_to_voice",
"end_call",
"resume_call_after_drop",
"search_call_history"
],
"workflows": {
"book": {
"name": "Book appointment",
"description": "Use when the caller wants to book an appointment, or to move one they already have.",
"steps": [
{
"id": "slots",
"type": "find_slots",
"config": {
"calendarId": {
"$fill": "calendar"
}
}
},
{
"id": "book",
"type": "book_appointment",
"config": {
"mode": "book_or_move"
},
"outputs": {
"booked": [],
"rescheduled": []
}
}
]
},
"cancel": {
"name": "Cancel appointment",
"description": "Use when the caller wants to cancel an appointment they have.",
"steps": [
{
"id": "cancel",
"type": "cancel_appointment",
"config": {
"calendarIds": {
"$fill": "calendar",
"as": "list"
}
},
"outputs": {
"cancelled": []
}
}
]
},
"callback": {
"name": "Schedule a callback",
"description": "Use when the lead wants the AI to call them back later, including a busy lead who agrees to talk at another time. This is not a business appointment.",
"steps": [
{
"id": "time",
"type": "collect_information",
"label": "When to call back",
"config": {
"items": [
{
"id": "callback_time",
"label": "When to call back",
"question": "When would be a good time for us to call you back?",
"type": "text"
}
]
}
},
{
"id": "schedule",
"type": "schedule_ai_call",
"config": {
"timeFrom": "callback_time"
}
}
]
},
"stop": {
"name": "Stop contact",
"description": "Use when the lead asks not to be contacted again, is clearly not interested, or the conversation is spam or a bot. This ends every call and message to them.",
"steps": [
{
"id": "reason",
"type": "collect_information",
"label": "Why they are leaving",
"config": {
"items": [
{
"id": "reason",
"label": "Why the lead is leaving the journey, in their own words where they gave them (an opt-out, no interest, spam or a bot)",
"type": "text",
"required": false
}
]
}
},
{
"id": "dnd",
"type": "dnd",
"config": {
"reason": "{{collected.reason}}"
}
}
]
}
},
"prompt": "# Identity\n\n## Who you are\nYou're {{agent_name}}, speaking for {{business_name}}. You help people get the appointment they need booked in.\n\n## How you carry yourself\nYou believe the quickest way to help someone is to get them in front of the team, so you make booking easy and never pushy. You'd rather hear a clear no than book someone who won't turn up. You say plainly when something is for the team to answer.\n\n## This call\nLead: {{full_name}}\nPhone: {{phone}}\nEmail: {{email}}\nDirection: {{direction}}\nNow: {{current_time}}, timezone {{timezone}}\n\n## Don't\n- Don't keep pushing for a booking after a clear no.\n\n# Steps to follow\n\n## 1. Hook\nOutbound: Hey, is this {{first_name}}?\nInbound: Hey, thanks for calling {{business_name}}, this is {{agent_name}}. How can I help?\nGoal: they confirm who they are, or say why they called.\n\n## 2. Discovery\nLine: This is {{agent_name}} with {{business_name}}. What can we help you with?\nGoal: they say what they need.\n\n## 3. Value proposition\nLine: Let's get you booked in so the team can take care of it. What day usually works best for you?\nGoal: they choose a time and it's booked.\n\n## 4. Downsell (in order; each only when the one before didn't happen)\n1. They're not ready to book: offer a callback.\n Line: No problem. When would be a better time for us to give you a call?\n Goal: they agree a time, or say no.\n\n## 5. Wrap up\nLine: Perfect, you're all set, and you'll get a confirmation with the details. Anything else I can help with?\nGoal: nothing is left to handle. Then close the conversation.\n\n# Conversational FAQ\n\n**Can I move or cancel my appointment?**\nOf course. Tell me which appointment, and I'll sort it out for you.\n\n**I'm not interested.**\nNo problem at all. Is it the timing, or just not something you need right now?\n\n**Now's not a good time.**\nNo worries. When's a better time for a quick call?\n\n**Can you just send me some info?**\nHappy to help with that. Honestly, a quick chat with the team is the fastest way to get answers that fit you. Want me to set that up?",
"toFill": [
{
"id": "calendar",
"label": "The calendar appointments are booked on",
"kind": "calendar",
"value": {
"type": "string",
"pattern": "^[a-zA-Z0-9_-]{1,200}$",
"description": "A calendar id from the sub-account’s calendars lookup."
},
"settings": [
{
"workflow": "book",
"step": "slots",
"setting": "calendarId"
},
{
"workflow": "cancel",
"step": "cancel",
"setting": "calendarIds"
}
]
}
],
"placeholders": []
}
]
}
}List TFU Live Brain templates
TFU Live only. The Brain templates: ready-made agents, niche agnostic, to create an agent from (Create agent with brainTemplateId). Each has its workflows (composed of the workflow templates; every one holds Schedule a callback and Stop contact), the tools it equips (texting off), a short starting prompt that speaks with the Layer 1 variables and keeps placeholders only for business facts, the campaign direction it suits, logic (its business logic in a few values) and toFill: the settings the client fills, optional at create, each with its JSON Schema and the settings it fills. See the workflows contract guide.
Required scope: agents:read.
Required API key scope: agents:read.
curl --request GET \
--url https://api.teamfollowup.ai/api/tfu-live-agents/brain-templates \
--header 'Authorization: Bearer YOUR_API_KEY'import requests
url = "https://api.teamfollowup.ai/api/tfu-live-agents/brain-templates"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.teamfollowup.ai/api/tfu-live-agents/brain-templates', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.teamfollowup.ai/api/tfu-live-agents/brain-templates",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.teamfollowup.ai/api/tfu-live-agents/brain-templates"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.teamfollowup.ai/api/tfu-live-agents/brain-templates")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.teamfollowup.ai/api/tfu-live-agents/brain-templates")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"brainTemplates": [
{
"id": "booking_one_calendar",
"name": "Appointment booking, one calendar",
"direction": "either",
"typicalFor": [
"outbound"
],
"description": "For a business that books appointments on one calendar, on inbound or outbound calls. The AI speaks for the business, finds out what the lead needs, offers open times from that one calendar and books the time the lead picks; a lead who already has an appointment can move it or cancel it there. There is no live transfer: a lead who wants a person later or is busy now is offered an AI callback. A lead who asks not to be contacted is put on do not disturb. Texting is off.",
"logic": {
"booking": "single",
"cancel": true,
"transfer": "none",
"direction": "either",
"texting": false
},
"tools": [
"respond_to_voice",
"end_call",
"resume_call_after_drop",
"search_call_history"
],
"workflows": {
"book": {
"name": "Book appointment",
"description": "Use when the caller wants to book an appointment, or to move one they already have.",
"steps": [
{
"id": "slots",
"type": "find_slots",
"config": {
"calendarId": {
"$fill": "calendar"
}
}
},
{
"id": "book",
"type": "book_appointment",
"config": {
"mode": "book_or_move"
},
"outputs": {
"booked": [],
"rescheduled": []
}
}
]
},
"cancel": {
"name": "Cancel appointment",
"description": "Use when the caller wants to cancel an appointment they have.",
"steps": [
{
"id": "cancel",
"type": "cancel_appointment",
"config": {
"calendarIds": {
"$fill": "calendar",
"as": "list"
}
},
"outputs": {
"cancelled": []
}
}
]
},
"callback": {
"name": "Schedule a callback",
"description": "Use when the lead wants the AI to call them back later, including a busy lead who agrees to talk at another time. This is not a business appointment.",
"steps": [
{
"id": "time",
"type": "collect_information",
"label": "When to call back",
"config": {
"items": [
{
"id": "callback_time",
"label": "When to call back",
"question": "When would be a good time for us to call you back?",
"type": "text"
}
]
}
},
{
"id": "schedule",
"type": "schedule_ai_call",
"config": {
"timeFrom": "callback_time"
}
}
]
},
"stop": {
"name": "Stop contact",
"description": "Use when the lead asks not to be contacted again, is clearly not interested, or the conversation is spam or a bot. This ends every call and message to them.",
"steps": [
{
"id": "reason",
"type": "collect_information",
"label": "Why they are leaving",
"config": {
"items": [
{
"id": "reason",
"label": "Why the lead is leaving the journey, in their own words where they gave them (an opt-out, no interest, spam or a bot)",
"type": "text",
"required": false
}
]
}
},
{
"id": "dnd",
"type": "dnd",
"config": {
"reason": "{{collected.reason}}"
}
}
]
}
},
"prompt": "# Identity\n\n## Who you are\nYou're {{agent_name}}, speaking for {{business_name}}. You help people get the appointment they need booked in.\n\n## How you carry yourself\nYou believe the quickest way to help someone is to get them in front of the team, so you make booking easy and never pushy. You'd rather hear a clear no than book someone who won't turn up. You say plainly when something is for the team to answer.\n\n## This call\nLead: {{full_name}}\nPhone: {{phone}}\nEmail: {{email}}\nDirection: {{direction}}\nNow: {{current_time}}, timezone {{timezone}}\n\n## Don't\n- Don't keep pushing for a booking after a clear no.\n\n# Steps to follow\n\n## 1. Hook\nOutbound: Hey, is this {{first_name}}?\nInbound: Hey, thanks for calling {{business_name}}, this is {{agent_name}}. How can I help?\nGoal: they confirm who they are, or say why they called.\n\n## 2. Discovery\nLine: This is {{agent_name}} with {{business_name}}. What can we help you with?\nGoal: they say what they need.\n\n## 3. Value proposition\nLine: Let's get you booked in so the team can take care of it. What day usually works best for you?\nGoal: they choose a time and it's booked.\n\n## 4. Downsell (in order; each only when the one before didn't happen)\n1. They're not ready to book: offer a callback.\n Line: No problem. When would be a better time for us to give you a call?\n Goal: they agree a time, or say no.\n\n## 5. Wrap up\nLine: Perfect, you're all set, and you'll get a confirmation with the details. Anything else I can help with?\nGoal: nothing is left to handle. Then close the conversation.\n\n# Conversational FAQ\n\n**Can I move or cancel my appointment?**\nOf course. Tell me which appointment, and I'll sort it out for you.\n\n**I'm not interested.**\nNo problem at all. Is it the timing, or just not something you need right now?\n\n**Now's not a good time.**\nNo worries. When's a better time for a quick call?\n\n**Can you just send me some info?**\nHappy to help with that. Honestly, a quick chat with the team is the fastest way to get answers that fit you. Want me to set that up?",
"toFill": [
{
"id": "calendar",
"label": "The calendar appointments are booked on",
"kind": "calendar",
"value": {
"type": "string",
"pattern": "^[a-zA-Z0-9_-]{1,200}$",
"description": "A calendar id from the sub-account’s calendars lookup."
},
"settings": [
{
"workflow": "book",
"step": "slots",
"setting": "calendarId"
},
{
"workflow": "cancel",
"step": "cancel",
"setting": "calendarIds"
}
]
}
],
"placeholders": []
}
]
}
}Authorizations
Send your API key as Authorization: Bearer YOUR_API_KEY.
Query Parameters
Sub-account belonging to the authenticated agency and any narrower credential location binding.
