Dialling into the Future: Building an AI-Powered Appointment Booking Agent with Fetch.AI,
3
0
Dialling into the Future: Building an AI-Powered Appointment Booking Agent with Fetch.AI, ElevenLabs, andĀ Twilio

The days of wrestling with phone menus or waiting on hold to book an appointment are inching closer to obsolescenceāāāand Iām thrilled to be part of that shift. Imagine typing a quick request into a webpage, and moments later, your phone rings with an AI assistant ready to chat, all in real time. This isnāt a distant dreamāāāitās a milestone Iāve hit in an ongoing project using Fetch.AIās AI agents, ElevenLabsā conversational magic, and Twilioās telephony backbone, tied together with a sprinkle of ngrok forĀ testing.
In this blog, Iāll walk you through the architecture, share the code, and highlight the āaha!ā moments that got me here. This is a work in progressāāāa snapshot of where Iām at in a broader development journey. Whether youāre a dev itching to automate or just curious about AIās next steps, letās diveĀ in!
Whatās This AllĀ About?
The aim is straightforward: let users book appointments hands-free with a prompt and their phone number. Where Iāve landed so far is a system where an AI agent calls you, chats naturally, and books a slotāāāno human required. Hereās the currentĀ flow:
- A frontend captures the userāsĀ request.
- Fetch.AIās agent ecosystem, the core foundation, analyzes the userās request, finds the right agent within the ecosystem, and assigns the task to itāāālike the āAppointment Booking Agentā for booking requests.
- Twilio dials the user and ElevenLabs powers a live conversation.
Itās automation that feels personal, and Fetch.AI is the bedrock making it all possible. Letās break itĀ down.
System Architecture: The Blueprint
The system is made up of different components that each play a specific role. Fetch.AI acts as the central hub, connecting everything together. It manages how data flows through the system, ensuring that user requests are properly handled by the right agents, like the āAppointment Booking Agentā for scheduling tasks. Hereās the architecture:
Components
- Frontend: A basic web interface where users enter a prompt (e.g., āBook an appointment at City Clinicā) and their phoneĀ number.
- Primary Fetch.AI Agent (Search Agent): Picture this as the projectās helpful guide. It lives in Fetch.AIās agentverseāāāa busy online hub for AI helpersāāāwhere it reads the userās request (like āBook an appointment!ā) and hands it off to my custom āAppointment Booking Agentā to get the job done. Itās the one keeping everything moving!
- Appointment Booking Agent: My AI Agent, built with the Fetch.ai SDK, running locally via ngrok during development and eventually hosted in the agentverse, managing calls andĀ audio.
- ngrok: Tunnels my local server (e.g., https://localhost:8000) to a public URL (e.g., https://abc123.ngrok.io) for external access duringĀ testing.
- Twilio: Handles outbound calls and real-time audio streaming.
- ElevenLabs: Delivers the conversational AI, chatting with users via WebSocket.
Flowchart
Hereās how data flows through theĀ system:


- Step 1: User submits prompt and number via frontend.
- Step 2: Primary AI Agent (Search Agent)āāāthe systemās foundationāāāanalyzes and routes the task to the BookingĀ Agent.
- Step 3: Booking Agent, hosted on Fetch.AIās agentverse (and ngrok-exposed locally), tells Twilio to call theĀ user.
- Step 4: Twilio connects the call to ElevenLabs for real-time dialogue.
- Step 5: Agent books the appointment, and the callĀ ends.
The Code: Bringing It to Life (SoĀ Far)
The Appointment Booking Agent is a key player, built with the Fetch.AI SDK and hosted on Fetch.AIās agentverse. This ecosystem is the foundation that initiates and coordinates everything. Hereās how it works, with key snippets to illustrate.
Setup and Registration
First, I load environment variables and register the agent with Fetch.AIās agentverse:
load_dotenv()
ELEVENLABS_AGENT_ID = os.getenv('ELEVENLABS_AGENT_ID')
TWILIO_PHONE_NUMBER = os.getenv('TWILIO_PHONE_NUMBER')
AGENTVERSE_KEY = os.getenv('AGENTVERSE_KEY')
app = FastAPI()
@app.get("/register")
async def registerAgent():
ai_identity = Identity.from_seed("It used to book appointment!", 0)
name = "Appointment Booking Agent"
ai_webhook = os.getenv('ngrok_URL', "https://0.0.0.0:8000/make-call")
register_with_agentverse(ai_identity, ai_webhook, AGENTVERSE_KEY, name, readme)
return {"status": f"{name} got registered"}
ngrokās public URL (e.g., https://abc123.ngrok.io/make-call) is used during local development, but once registered, the agent lives in the agentverse, ready to receiveĀ tasks.
Setting Up ElevenLabs
Before the magic happens, youāll need to configure ElevenLabsā Conversational AI:
- Sign up at ElevenLabs, create an agent, and grab your ELEVENLABS_AGENT_ID.
- Customize the Agent for appointment booking (e.g., āHello! Iām here to help you book an appointment. What time works forĀ you?ā).
- Add the ID to yourĀ .env file. This powers the real-time voice interaction via WebSocket.
Initiating theĀ Call
When the Primary Fetch.AI Agent assigns a task, the /make-call endpoint fires upĀ Twilio:
@app.post("/make-call")
async def make_outbound_call(request: Request):
body = await request.json()
message = parse_message_from_agent(json.dumps(body))
payload = message.payload
to = payload.get("to")
call = twilio_client.calls.create(
url=f"https://{request.headers['host']}/incoming-call-eleven",
to=to,
from_=TWILIO_PHONE_NUMBER
)
return {"message": "Call initiated", "callSid": call.sid, "status": "success"}The url points to my ngrok-exposed /incoming-call-eleven route during testing, which Twilio uses to connect theĀ call.
Real-Time AudioĀ Magic
The /media-stream WebSocket bridges Twilio and ElevenLabs:
@app.websocket("/media-stream")
async def media_stream(websocket: WebSocket):
await websocket.accept()
async with websockets.connect(f"wss://api.elevenlabs.io/v1/convai/conversation?agent_id={ELEVENLABS_AGENT_ID}") as elevenlabs_ws:
async def handle_twilio_messages():
async for message_str in websocket.iter_json():
if message_str['event'] == 'media':
audio_chunk = base64.b64decode(message_str['media']['payload'])
await elevenlabs_ws.send(json.dumps({
'user_audio_chunk': base64.b64encode(audio_chunk).decode('utf-8')
}))
async def handle_elevenlabs_messages():
async for message_str in elevenlabs_ws:
message = json.loads(message_str)
if message['type'] == 'audio':
await websocket.send_json({
'event': 'media',
'media': {'payload': message['audio_event']['audio_base_64']}
})
await asyncio.gather(handle_twilio_messages(), handle_elevenlabs_messages())User speech flows to ElevenLabs, and AI responses come backāāāall in realĀ time.
Why Itās a BigĀ Deal
This isnāt just a proof-of-conceptāāāitās a stepping stone toward smarter automation, with Fetch.AI as the backbone. The current milestone shows promise: ngrok simplifies local testing, and Fetch.AIās agentverse, Twilio, and ElevenLabs handle the heavy lifting. Itās not perfect yet, but itās a glimpse of whatās possible.
Whatās Next?
This is an ongoing journey, and Iām exploring practical next steps beyond clinic scheduling (which, while cool, needs more polish to be truly feasible). Here are some realistic use cases IāmĀ eyeing:
- Customer Support Triage: Route incoming requests to the right team with a quick AIĀ call.
- Event RSVPs: Let users confirm attendance via voice, no formsĀ needed.
- Personal Task Assistants: Schedule reminders or follow-ups with a conversational nudge.
Wrapping Up
From a prompt to a live call, this projectāāābuilt on Fetch.AIās SDKāāāis a milestone in reimagining everyday automation. Itās not flawless: determinism (ensuring consistent outcomes) is a work in progress, and latency can still hiccup. But thatās the fun partāāāIām inviting devs to jump in! Check out the full code on GitHub, grab the fetch.ai SDK, fire up ngrok, and help solve the quirks. Together, we can dial further into theĀ future.
Dialling into the Future: Building an AI-Powered Appointment Booking Agent with Fetch.AI, was originally published in Fetch.ai on Medium, where people are continuing the conversation by highlighting and responding to this story.
3
0
Securely connect the portfolio youāre using to start.