Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.poly.ai/llms.txt

Use this file to discover all available pages before exploring further.

This recipe covers the complete SMS consent-and-send pattern: confirm the number, ask for consent, send the message, and confirm delivery — all without the agent making promises it can’t keep.

When to use this

Use this pattern when:
  • You need to send a follow-up (link, confirmation, summary) after a call interaction
  • Compliance or brand requirements mean you must collect explicit consent before sending
  • You want a hard confirmation step so the agent never sends SMS without the user agreeing

The complete pattern

Step 1 – Collect the phone number

def collect_phone_number(conv, flow, phone_number: str) -> str:
    # Store the number; validation happens in the next step
    conv.state["sms_phone"] = phone_number
    flow.goto_step("confirm_consent")
    return f"Phone number {phone_number} noted."
Step prompt: “Ask the caller for the phone number they’d like the message sent to. Once they provide it, call collect_phone_number.”
def record_consent(conv, flow, consented: bool) -> str:
    if consented:
        conv.state["sms_consent"] = True
        flow.goto_step("send_sms")
        return "Consent given."
    else:
        # Respect the refusal and exit the flow gracefully
        flow.exit_flow()
        return "The caller declined SMS. Do not attempt to send."
Step prompt: “Ask the caller to confirm they consent to receiving an SMS at the number they provided. Call record_consent with consented=True if they agree, consented=False if they decline.”
Never send an SMS if consented is False. If the model calls record_consent(consented=False), exit the flow — do not loop back to ask again.

Step 3 – Send and confirm

import requests

def send_confirmation_sms(conv, flow) -> dict:
    phone = conv.state.get("sms_phone")
    consent = conv.state.get("sms_consent")

    if not consent:
        # Defensive check — should not reach here without consent
        flow.exit_flow()
        return {"content": "No consent on record. SMS not sent."}

    # Replace with your real SMS provider call
    response = requests.post(
        "https://your-sms-provider.com/send",
        json={"to": phone, "body": "Here's the information you requested: ..."},
        timeout=5,
    )

    if response.status_code == 200:
        flow.exit_flow()
        return {"content": f"SMS sent successfully to {phone}."}
    else:
        return {"content": f"SMS delivery failed (status {response.status_code}). Tell the caller there was a problem and offer to try again or provide the information verbally."}
Step prompt: “The caller has consented. Call send_confirmation_sms to send the message and confirm delivery.”

Flow structure

Key decisions

Each flow step runs in a separate LLM request. The phone number collected in Step 1 must be stored in conv.state to be accessible in Step 3 — the LLM does not carry it forward automatically.
If the caller declines consent, flow.exit_flow() returns control to the LLM, which can continue the conversation naturally. Do not loop back to the consent step — that would feel coercive.

Check your understanding


← Back to Recipes

All recipes

Retry with handoff →

Next recipe
Last modified on May 7, 2026