SMS link with transfer fallback¶
A common pattern in voice agents: offer to send the caller a link by SMS, but transfer to a live agent if SMS isn't an option or the caller asks for it. The decision lives in a function so it is deterministic — not subject to LLM interpretation.
Files involved¶
functions/start_function.py ← stash caller_number
functions/send_link_or_transfer.py ← SMS or handoff decision
config/sms_templates.yaml ← SMS template (alongside other templates)
config/handoffs.yaml ← transfer destination (alongside other handoffs)
topics/Get Booking Link.yaml ← triggers the pattern
send_link_or_transfer.py¶
from _gen import * # <AUTO GENERATED>
@func_description(
"Called when the caller has been offered the booking link by SMS or by speaking to an agent. "
"wants_sms: True if they want the link by text, False if they want to speak to someone."
)
@func_parameter("wants_sms", "True if the caller wants the SMS link, False if they want to speak to an agent")
def send_link_or_transfer(conv: Conversation, wants_sms: bool):
if wants_sms:
to_number = conv.state.caller_number
if not to_number:
return (
"Tell the caller we were unable to send the SMS because we do not have their number. "
"Offer to transfer them to an agent instead or ask for a number to send to."
)
conv.send_sms_template(to_number=to_number, template="booking_link")
return "Tell the caller the link has been sent and ask if there is anything else you can help with."
else:
conv.call_handoff(
destination="agent_queue",
reason="caller_requested_agent",
utterance="Let me connect you with a member of the team now.",
)
Get Booking Link.yaml¶
enabled: true
example_queries:
- Can you send me a link to book?
- How do I book online?
- I want to make a reservation online
- Send me a booking link
- Can I speak to someone about booking?
content: |-
Bookings can be made online at book.example.com, or by speaking with a team member.
actions: |-
Ask the caller if they would like the link sent by text message, or if they would prefer to speak to someone.
Use {{fn:send_link_or_transfer}} once they respond.
Testing via poly chat: caller_number will be empty
conv.state.caller_number is populated from inbound caller ID, which is only available on a real voice call. When testing with poly chat, caller_number is always empty regardless of --channel — wants_sms: True will always hit the "unable to send" branch.
To exercise the SMS path locally, mock the value in start_function.py:
config/handoffs.yaml¶
The destination value passed to conv.call_handoff must match the name of a handoff defined in config/handoffs.yaml. All handoffs are defined in a single file under the handoffs key.
handoffs:
- name: agent_queue
description: Transfer to live agent queue
is_default: true
sip_config:
method: refer
phone_number: "+441234567890"
See the handoffs reference for all SIP method options and field details.
Per-environment sender number¶
If the sender number differs between environments, the simplest approach is to configure env_phone_numbers directly in config/sms_templates.yaml — no code required:
sms_templates:
- name: booking_link
text: "Here's your booking link: https://book.example.com"
env_phone_numbers:
sandbox: "+441111111111"
pre_release: "+442222222222"
live: "+443333333333"
The platform selects the right number automatically when conv.send_sms_template() is called. See the SMS setup reference for full template configuration options.
If you need more control — for example, when using conv.send_sms() to send free-form content rather than a template — you can read conv.env directly:
ENV_SENDER_NUMBERS = {
"sandbox": "+441111111111",
"pre-release": "+442222222222",
"live": "+443333333333",
}
def send_link_or_transfer(conv: Conversation, wants_sms: bool):
if wants_sms:
from_number = ENV_SENDER_NUMBERS.get(conv.env, ENV_SENDER_NUMBERS["sandbox"])
conv.send_sms(
to_number=conv.state.caller_number,
from_number=from_number,
content="Here's your booking link: https://book.example.com",
)
return "Tell the caller the link has been sent."
...
Use secrets for sender numbers in production
Avoid hardcoding phone numbers in function code. Store them as secrets and retrieve with conv.utils.get_secret("sms_sender_live").
Related pages¶
-
SMS templates
Structure and variable substitution for SMS templates. Open SMS templates
-
Handoffs
Configure transfer destinations used by
conv.call_handoff. Open handoffs -
Functions
Return values, conv API, and function structure. Open functions
-
Conversation object reference
Full reference for
conv.send_sms_template,conv.call_handoff,conv.env, and all otherconvattributes. Open conv object reference -
Secrets (platform)
Store sensitive values like sender numbers and retrieve them at runtime with
conv.utils.get_secret. Open secrets reference -
SMS setup (platform)
Configuring SMS channels, sender numbers, and template structure. Open SMS setup