Build Your First Agent

Phonic already knows how to listen to callers, speak in turn, and express emotion the way a human would. What’s left to you:

  1. Instructions: the call flow and rules that shape behavior.
  2. Tools: how the agent interacts with your systems, and when.
  3. Configuration: the voice, languages, timing, and switches for your calls.
  4. Deployment: where your customers can reach your agent.
  5. Evals: how you improve and tune your agent over time.

This tutorial guides you through building a hypothetical agent that handles reservations for the Phantastic Phood restaurant.

Step 1: Write the instructions

The system prompt is where you define who the agent is, what a successful call looks like, and guidelines for every call.

You are Sabrina, the host at Phantastic Phood, a restaurant. You are warm
and efficient - callers are often calling from work or on the go.
Your job on every call:
1. Greet the caller and ask what they need.
2. For reservations: get the date, time, and party size, offer at most
two options from availability, and book once they choose.
3. Confirm the date, time, and party size back to the caller.
4. Once they confirm and have no other questions, say goodbye and end
the call.
Rules that always apply:
- Never guarantee that a dish is allergen-free — offer to have the
kitchen give them a call back instead.
- For parties larger than 8, transfer to the events line — do not book
directly.
- Don't invent menu items or specials; if you don't know, offer to
check with the kitchen and then take a callback number to follow up.
If the caller goes quiet and doesn't respond to a check-in, let them
know you'll release the table request for now — they're welcome to
call back to finish the booking — then end the call politely.

What to notice:

  • Cover business context beyond the agent configuration. Check-in timing and wording can be configured (Step 3), but the prompt guides the agent on what to do with the reservation request when the caller stops responding.
  • Nothing here about brevity, contractions, or number formats. These features are already built into Phonic. See voice style.

Now, so that the agent can actually interact with the world around it, like the reservation system or transferring a caller to the events line, we need to configure tools.

Step 2: Define the tools

Each tool’s description is the agent’s manual for that tool: what it does and when to call it. The agent sees every attached tool’s description on every turn. This page builds three tools; the tools overview covers every tool type and its configuration in full.

The lookup: check_availability

1await client.tools.create({
2 name: "check_availability",
3 description:
4 "Check open reservation slots. Call this when you know the " +
5 "date, time, and party size the caller wants. Never offer or " +
6 "invent times without calling it first.",
7 type: "custom_webhook",
8 execution_mode: "sync",
9 require_speech_before_tool_call: true, // "Let me check that for you — one sec."
10 endpoint_method: "POST",
11 endpoint_url: "https://api.phantasticphood.com/availability",
12 parameters: [
13 {
14 type: "string",
15 name: "date",
16 description: "Requested date, YYYY-MM-DD.",
17 is_required: true,
18 location: "request_body",
19 },
20 {
21 type: "string",
22 name: "time",
23 description: "Requested time, 24h HH:MM local.",
24 is_required: true,
25 location: "request_body",
26 },
27 {
28 type: "integer",
29 name: "party_size",
30 description: "Number of guests.",
31 is_required: true,
32 location: "request_body",
33 },
34 ],
35});
  • Descriptions guide when tools are called (“call this when you know…”).
  • Parameter descriptions tell the agent what data to collect and how to format it (“Requested date, YYYY-MM-DD”).
  • In sync mode the agent waits for the result before it responds. Use it for a lookup whose answer the next sentence depends on.

The action: book_table

1await client.tools.create({
2 name: "book_table",
3 description:
4 "Book a table for a slot returned by check_availability. Only call " +
5 "this after the caller has chosen a specific slot and confirmed the " +
6 "spelling of their name.",
7 type: "custom_webhook",
8 execution_mode: "sync",
9 endpoint_method: "POST",
10 endpoint_url: "https://api.phantasticphood.com/book",
11 parameters: [
12 {
13 type: "string",
14 name: "slot_id",
15 description: "The slot_id returned by check_availability.",
16 is_required: true,
17 location: "request_body",
18 },
19 {
20 type: "string",
21 name: "guest_name",
22 description: "Caller's full name, spelling confirmed.",
23 is_required: true,
24 location: "request_body",
25 },
26 {
27 type: "string",
28 name: "callback_number",
29 description: "Caller's phone number for confirmations.",
30 is_required: true,
31 location: "request_body",
32 },
33 ],
34});
  • Preconditions about a tool belong on the tool. The booking tool’s description says “only call after… confirmed the spelling”.
  • Tool results should return every identifier a later step needs. Availability returns a slot ID because booking requires one. If a tool doesn’t return an identifier, the agent cannot supply it later, which can result in stalling or hallucinations.

The transfer: transfer_to_events_line

1await client.tools.create({
2 name: "transfer_to_events_line",
3 description:
4 "Transfer the caller to the events team, which handles " +
5 "large-party bookings.",
6 type: "built_in_transfer_to_phone_number",
7 phone_number: "+14155550164",
8 require_speech_before_tool_call: true, // "One moment while I connect you."
9});
  • Requiring speech before the transfer has the agent announce the handoff first. This configuration works well for a transfer, where the caller is about to hear a new line, but it may not be suitable for fast tool calls like context lookups. For a handoff built as your own webhook tool, use wait_for_speech_before_tool_call (see tool behavior configuration).
  • A fixed target number is configuration, not prompt content. The prompt decides when to transfer (the “parties larger than 8” rule in Step 1), and the tool guarantees where. Leave phone_number unset and the agent determines the number at call time instead, which is what you want when the destination depends on the conversation (see transfer tools).

Remember to update the system prompt!

The tool descriptions cover when and how to call each tool, but the agent needs context on what to do with a result, or what to say when a tool call fails. Add this information to the instructions from Step 1:

Tools:
- If check_availability returns no open tables, offer the waitlist —
never invent times.
- If a tool fails, apologize, offer to take a callback number, and move
on. Never go silent while retrying.
For the full anatomy of a good prompt (structure, escalation, voice style), see the prompting guide.

Step 3: Configure the agent

Configurations offer systematic control for the agent.

1await client.agents.upsert({
2 name: "phantastic-phood-host",
3 project: "main",
4 system_prompt: SYSTEM_PROMPT, // from Steps 1 and 2
5 welcome_message:
6 "Thanks for calling Phantastic Phood, this is Sabrina — how can I help?",
7 voice_id: "sabrina",
8 tools: [
9 "check_availability",
10 "book_table",
11 "transfer_to_events_line",
12 "choose_not_to_respond",
13 "natural_conversation_ending",
14 ],
15 default_language: "en",
16 enable_redaction: true,
17 no_input_poke_sec: 30,
18 generate_no_input_poke_text: true,
19 no_input_end_conversation_sec: 180,
20 boosted_keywords: ["Phantastic Phood"],
21 pronunciation_dictionary: [{ word: "Phood", pronunciation: "food" }],
22 enable_assistant_backchannel: true,
23 audio_speed: 1.2,
24});

What to notice:

  • Languages are configuration, never prompt content. A prompt rule like “speak Portuguese” on an agent configured for English and Spanish produces a confused agent. See multilingual agents.
  • User-side silence handling has two timers: how long before the agent checks in, and how long before it gives up and ends the call. The check-in wording can be customized, or you can turn on generate_welcome_message and generate_no_input_poke_text to let the agent generate the most natural message based on the prompt and conversation context.
  • Help it hear and say your terms. Boosted keywords tell the transcriber which domain words to expect; the pronunciation dictionary keeps the voice from saying “fud”.
  • Redaction scrubs sensitive details from transcripts (tags like [NAME], [PHONE], [CREDIT CARD]) and bleeps them from recordings after the call, for example when the agent takes a credit-card hold for a reservation.
  • Enabling backchanneling lets the agent murmur “mm-hmm” while the caller is talking, which sounds more natural.
  • Tune the speaking pace so the booking host speaks a little faster and keeps the call moving.
  • Allow the agent to end the call naturally: many AI assistants keep speaking until the user ends the conversation. Phonic agents can hang up once the call has wrapped up.
  • The agent can choose not to respond in some cases, such as when the caller is thinking out loud or appears to be talking to someone else.

Step 4: Deploy your agent

Pick how customers can reach your agent:

  • Inbound phone: attach a phone number to the agent, either Phonic-provisioned or your own via Twilio/SIP.
  • Outbound phone: place calls from your backend with the outbound call API, passing per-call context as template variables.
  • Your web or mobile app: connect the same agent over the WebSocket surface for real-time speech-to-speech, with no phone number involved.

The same agent can serve all three at once.

Step 5: Evaluate its behavior

Write one eval criterion per behavior you care about. A rule that forbids one thing and requires another gets two criteria. A failing criterion then points at the exact line to fix:

“If the caller asked about allergens or dietary restrictions, the assistant offered a callback from the kitchen.”

“When no tables were available, the assistant offered the waitlist and did not invent times.”

The evals guide covers extraction schemas, eval prompts, and the improvement loop.

Where each kind of rule goes

You want to control…Put it inExample
When and how one tool is usedThe tool’s description”Call as soon as you know date, time, and party size”
What data a tool needs, and its formatThe tool’s parameter descriptions”Requested date, YYYY-MM-DD”
Whether the agent speaks before/after a tool callTool behavior configurationwait_for_speech_before_tool_call
Business policy that holds on every callThe instructions (Rules that always apply)“Never guarantee a dish is allergen-free”
The order of steps across toolsThe instructions (call flow)“Offer at most two options, then book”
Behavior on tool results and failuresThe instructions (Tools section)“If no tables, offer the waitlist”
The first thing the caller hearsAgent configurationwelcome_message, or generate_welcome_message to have the agent compose it
A fixed line after caller silence, every timeAgent configurationno_input_poke_text, translated to the call language as needed
A check-in that fits where the call isAgent configuration (generate_no_input_poke_text), composed from the system prompt”Still there? I can hold that 6:45 for a moment”
When silence triggers a check-in or hangupAgent configurationno_input_poke_sec
Which languages the agent speaksAgent configurationdefault_language, additional languages
Speech style, spoken formats, disfluenciesNowhere, built insee voice style
Transfer targets and voicemail detectionTransfer tool configurationtransfer tools
Per-caller context (name, account, reason)Template variablesagent configuration endpoint