List TFU Live Brain templates
Lists ready-made TFU Live agent templates (Brain templates) that suit many industries. Pass a template’s id as brainTemplateId to POST /api/tfu-live-agents. Each template has its workflows, which always include Schedule a callback and Stop contact, its tools (texting is off), and a short starting prompt. The prompt uses call variables such as and , and holds no business facts or placeholders. Each also gives the call direction it suits, its business logic in a few values (logic), and toFill: the settings the user fills, optional at creation, each with its JSON Schema and the settings it fills. The full workflow reference is in Workflows contract.
Required scope: agents:read.
Required API key scope: agents:read.
GET
/
api
/
tfu-live-agents
/
brain-templates
cURL
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",
"search_call_history"
],
"workflows": {
"book": {
"name": "Book appointment",
"description": "Use when the caller wants to book an appointment, asks what times are available, or wants 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": "schedule",
"type": "schedule_ai_call",
"config": {}
}
]
},
"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": "dnd",
"type": "dnd",
"config": {}
}
]
}
},
"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\nFollow the person's current intent. Stay with questions or concerns while they explore them; answer directly and clarify when useful. Do not automatically append a scripted question, invent discovery or ask whether every answer was satisfactory. Resume relevant unfinished steps when their response supports moving forward. Use known facts: skip answered questions and completed objectives, revisiting only when information changes. Preserve settled agreements; ask only what's missing. After an invitation, address questions without repeating the pitch. If undecided, continue briefly in context; acknowledgement alone isn't acceptance. Repeat details only when requested or needed for clarity. Ask one question, then wait. Use the script naturally, with exact wording only where required and applicable. Never speak instruction labels.\n\n## Opening\n\nAuthored openings and introductory connection questions are first contact defaults, not a restart on every call. Use the current call context/steering and established history to decide where to begin. For callbacks, returning callers or interrupted conversations, use the specific current call start and continue the relevant unfinished objective; skip introductions, identity checks and questions already resolved. An unanswered attempt or a saved contact alone does not prove a previous conversation. If context is missing or conflicting, clarify only what is needed; never invent prior contact, its outcome or why a call ended. On a new inbound call, do not recite outbound enquiry claims: establish the caller's purpose only if unknown, then follow the relevant objective. Keep required disclosures when applicable. Once you ask the opening question, stop and wait for the reply.\n\n### Hook\nPurpose: Hook\nApproach: Use the matching opening below for first contact. Otherwise follow the current call context and history to resume the relevant unfinished objective. Stop and wait for the person to answer. Do not stack later questions into this turn.\nOutbound: Hey, is this {{first_name}}?\nInbound: Hey, thanks for calling {{business_name}}, this is {{agent_name}}. How can I help?\nComplete when: they confirm who they are, or say why they called.\n\n## Establish context\n\n### Discovery\nPurpose: Discovery\nApproach: This is {{agent_name}} with {{business_name}}. What can we help you with?\nComplete when: they say what they need.\n\n## Fulfill purpose\n\n### Value proposition\nPurpose: Value proposition\nApproach: Let's get you booked in so the team can take care of it. What day usually works best for you?\nComplete when: they choose a time and it's booked.\n\n### Downsell (in order; each only when the one before didn't happen)\nPurpose: Downsell (in order; each only when the one before didn't happen)\n1. They're not ready to book: offer a callback.\nApproach: No problem. When would be a better time for us to give you a call?\nComplete when: they agree a time, or say no.\n\n## Wrap up\n\n### Wrap up\nPurpose: Wrap up\nApproach: Perfect, you're all set, and you'll get a confirmation with the details. Anything else I can help with?\nComplete when: 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
Query Parameters
⌘I
cURL
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",
"search_call_history"
],
"workflows": {
"book": {
"name": "Book appointment",
"description": "Use when the caller wants to book an appointment, asks what times are available, or wants 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": "schedule",
"type": "schedule_ai_call",
"config": {}
}
]
},
"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": "dnd",
"type": "dnd",
"config": {}
}
]
}
},
"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\nFollow the person's current intent. Stay with questions or concerns while they explore them; answer directly and clarify when useful. Do not automatically append a scripted question, invent discovery or ask whether every answer was satisfactory. Resume relevant unfinished steps when their response supports moving forward. Use known facts: skip answered questions and completed objectives, revisiting only when information changes. Preserve settled agreements; ask only what's missing. After an invitation, address questions without repeating the pitch. If undecided, continue briefly in context; acknowledgement alone isn't acceptance. Repeat details only when requested or needed for clarity. Ask one question, then wait. Use the script naturally, with exact wording only where required and applicable. Never speak instruction labels.\n\n## Opening\n\nAuthored openings and introductory connection questions are first contact defaults, not a restart on every call. Use the current call context/steering and established history to decide where to begin. For callbacks, returning callers or interrupted conversations, use the specific current call start and continue the relevant unfinished objective; skip introductions, identity checks and questions already resolved. An unanswered attempt or a saved contact alone does not prove a previous conversation. If context is missing or conflicting, clarify only what is needed; never invent prior contact, its outcome or why a call ended. On a new inbound call, do not recite outbound enquiry claims: establish the caller's purpose only if unknown, then follow the relevant objective. Keep required disclosures when applicable. Once you ask the opening question, stop and wait for the reply.\n\n### Hook\nPurpose: Hook\nApproach: Use the matching opening below for first contact. Otherwise follow the current call context and history to resume the relevant unfinished objective. Stop and wait for the person to answer. Do not stack later questions into this turn.\nOutbound: Hey, is this {{first_name}}?\nInbound: Hey, thanks for calling {{business_name}}, this is {{agent_name}}. How can I help?\nComplete when: they confirm who they are, or say why they called.\n\n## Establish context\n\n### Discovery\nPurpose: Discovery\nApproach: This is {{agent_name}} with {{business_name}}. What can we help you with?\nComplete when: they say what they need.\n\n## Fulfill purpose\n\n### Value proposition\nPurpose: Value proposition\nApproach: Let's get you booked in so the team can take care of it. What day usually works best for you?\nComplete when: they choose a time and it's booked.\n\n### Downsell (in order; each only when the one before didn't happen)\nPurpose: Downsell (in order; each only when the one before didn't happen)\n1. They're not ready to book: offer a callback.\nApproach: No problem. When would be a better time for us to give you a call?\nComplete when: they agree a time, or say no.\n\n## Wrap up\n\n### Wrap up\nPurpose: Wrap up\nApproach: Perfect, you're all set, and you'll get a confirmation with the details. Anything else I can help with?\nComplete when: 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": []
}
]
}
}