Weekend Voice Concierge Starter Pack (5‑Intent Blueprint + Spend Guard)
Copy‑paste templates to deploy a five‑intent, after‑hours voice concierge with strict handoffs and a spend guard. Includes call‑flow JSON, Make/Zapier wiring, consent/escalation copy, and a metrics dashboard you can use on day one.
Use this pack to ship a bounded, after‑hours voice concierge in a weekend. Copy the JSON, wire the Make/Zapier blueprint to your calendar + CRM, paste the spend‑guard policy into your orchestrator, and drop in the consent/escalation copy. Fill in every [BRACKETED] field before going live, then test end‑to‑end with two phones on real network conditions.
Call‑Flow JSON: Five‑Intent Concierge (paste‑ready)
Paste into your voice agent config (or load at runtime) and replace all [BRACKETS]. This JSON scopes five intents only: book, reschedule, qualify, pricing deflection, voicemail. Guardrails cap turns, enforce low‑confidence handoffs, and route after‑hours to voicemail.
{
"meta": {
"version": "1.0",
"model": "[REALTIME_MODEL]",
"timezone": "[TZ]",
"business_hours_local": "[MON-SUN HH:MM-HH:MM]",
"primary_language": "[PRIMARY_LANG]",
"alt_languages": ["[ALT_LANG]"]
},
"guardrails": {
"max_turns": [MAX_TURNS],
"min_confidence": [CONFIDENCE_THRESHOLD],
"latency_budget_s": [LATENCY_BUDGET_S],
"vad_enabled": true,
"after_hours_to_voicemail": true
},
"consent": {
"opening_line": "[CONSENT_OPENING_LINE]",
"retry_if_no_ack": true,
"max_retries": 1
},
"functions": [
{"name":"book_slot","args":["name","phone","service","date","time","location","notes"],"webhook":"[BOOKING_WEBHOOK_URL]"},
{"name":"reschedule_slot","args":["booking_id","new_date","new_time","notes"],"webhook":"[RESCHEDULE_WEBHOOK_URL]"},
{"name":"create_lead","args":["name","phone","email","service","budget","timeline","utm"],"webhook":"[CRM_WEBHOOK_URL]"},
{"name":"lookup_pricing_page","args":[],"static_url":"[PRICING_URL]"},
{"name":"route_to_voicemail","args":["transcript","phone","utc"],"webhook":"[VOICEMAIL_WEBHOOK_URL]"},
{"name":"escalate_to_human","args":["reason","transcript","phone"],"dial":"[HUMAN_FALLBACK_NUMBER]"}
],
"intents": [
{
"id": "book",
"triggers": ["book","schedule","reservation","appointment"],
"on_match": {"call_function": "book_slot", "confirm_readback": true},
"handoff_if_confidence_below": [CONFIDENCE_THRESHOLD]
},
{
"id": "reschedule",
"triggers": ["reschedule","change time","move appointment"],
"on_match": {"call_function": "reschedule_slot", "confirm_readback": true},
"handoff_if_confidence_below": [CONFIDENCE_THRESHOLD]
},
{
"id": "qualify",
"triggers": ["quote","estimate","need service","project"],
"on_match": {
"ask": [
"Which service do you need?",
"When do you want this?",
"Where are you located?",
"What\u2019s the rough budget?"
],
"call_function": "create_lead",
"qualify_rules": {
"service_in": ["[SERVICE_1]","[SERVICE_2]","[SERVICE_3]"],
"geo_whitelist": ["[CITY]","[ZIP]"]
}
},
"handoff_if_confidence_below": [CONFIDENCE_THRESHOLD]
},
{
"id": "pricing_deflection",
"triggers": ["price","how much","cost","rates"],
"on_match": {
"say": "We price transparently online. I\u2019ll text you our current menu and can book a quick fit call.",
"link": "[PRICING_URL]",
"offer_callback": true,
"callback_minutes_window": 15
},
"handoff_if_confidence_below": [CONFIDENCE_THRESHOLD]
},
{
"id": "voicemail",
"triggers": ["after_hours","no_answer","network_issue"],
"on_match": {
"call_function": "route_to_voicemail",
"privacy_notice": true
}
}
],
"escalation": {
"rules": [
{"when":"confidence_below","threshold":[CONFIDENCE_THRESHOLD],"repeats":2,"action":{"call_function":"escalate_to_human","reason":"low_confidence"}},
{"when":"frustration_detected","action":{"call_function":"escalate_to_human","reason":"frustration_markers"}},
{"when":"turn_cap_reached","cap":[MAX_TURNS],"action":{"call_function":"escalate_to_human","reason":"turn_cap"}},
{"when":"latency_over_budget","threshold_s":[LATENCY_BUDGET_S],"repeats":2,"action":{"call_function":"escalate_to_human","reason":"latency"}}
]
},
"spend_guard": {
"per_call_usd_cap": [PER_CALL_USD_CAP],
"monthly_usd_cap": [MONTHLY_USD_CAP],
"disconnect_when_exceeded": true,
"log_to": "[OBSERVABILITY_WEBHOOK_URL]"
}
}
Recommended defaults to start: [REALTIME_MODEL]=gpt-realtime-mini, [MAX_TURNS]=8, [CONFIDENCE_THRESHOLD]=0.6, [LATENCY_BUDGET_S]=1.8, [PER_CALL_USD_CAP]=0.35, [MONTHLY_USD_CAP]=[YOUR_LIMIT]. Tune after your first 50 calls.
Make/Zapier Blueprint: Calendar + CRM wiring
Choose your tool (Make or Zapier). This blueprint routes function calls from your agent to calendar + CRM, handles idempotency, and logs outcomes.
- Trigger
- Event:
realtime.function_calledfrom your voice server/webhook. - Input:
{ "function": "[FUNCTION_NAME]", "args": { ... }, "call_id": "[CALL_ID]" }.
- Router (by function)
- book_slot → Create event on [CALENDAR_PROVIDER], upsert contact in [CRM], write activity "Booking Confirmed", send SMS confirm via [SMS_PROVIDER].
- reschedule_slot → Find event by [BOOKING_ID], update times, log activity "Booking Rescheduled", send SMS update.
- create_lead → Upsert contact, create deal/lead with stage "New", attach transcript summary.
- route_to_voicemail → Save recording/transcript to [STORAGE], create task "Callback: Voicemail" due in 24h.
- Idempotency
- Use
idempotency_key = hash([CALL_ID] + [FUNCTION_NAME] + stable_args)on all write ops.
- Error handling
- Exponential retry x3 on 5xx; on fail → Dead‑letter to [DLQ_WEBHOOK_URL] with payload.
- Observability
- POST summary to [OBSERVABILITY_WEBHOOK_URL] including
{call_id, intent, status, duration_s, turns, est_audio_cost_usd, escalated}.
Blueprint JSON (conceptual — import and map to your apps):
{
"trigger": "realtime.function_called",
"router": [
{
"if": "function=='book_slot'",
"actions": [
{"app": "[CALENDAR_PROVIDER]", "op": "CreateEvent", "input": {"title": "[SERVICE] for {{name}}", "start": "{{date}} {{time}}", "end": "{{date}} {{time_end}}", "location": "{{location}}", "notes": "{{notes}}"}},
{"app": "[CRM]", "op": "UpsertContact", "input": {"phone": "{{phone}}", "name": "{{name}}", "email": "{{email}}"}},
{"app": "[CRM]", "op": "CreateActivity", "input": {"type": "Booking Confirmed", "ref": "{{event_id}}", "call_id": "{{call_id}}"}},
{"app": "[SMS_PROVIDER]", "op": "Send", "input": {"to": "{{phone}}", "text": "[SMS_CONFIRM_TEMPLATE]"}}
]
},
{
"if": "function=='reschedule_slot'",
"actions": [
{"app": "[CALENDAR_PROVIDER]", "op": "UpdateEvent", "input": {"event_id": "{{booking_id}}", "start": "{{new_date}} {{new_time}}", "end": "{{new_date}} {{new_time_end}}"}},
{"app": "[CRM]", "op": "CreateActivity", "input": {"type": "Booking Rescheduled", "ref": "{{booking_id}}", "call_id": "{{call_id}}"}},
{"app": "[SMS_PROVIDER]", "op": "Send", "input": {"to": "{{phone}}", "text": "[SMS_RESCHEDULE_TEMPLATE]"}}
]
},
{
"if": "function=='create_lead'",
"actions": [
{"app": "[CRM]", "op": "UpsertContact", "input": {"phone": "{{phone}}", "name": "{{name}}", "email": "{{email}}"}},
{"app": "[CRM]", "op": "CreateLead", "input": {"service": "{{service}}", "budget": "{{budget}}", "timeline": "{{timeline}}", "utm": "{{utm}}", "notes": "[AI_SUMMARY: {{transcript}}]"}}
]
},
{
"if": "function=='route_to_voicemail'",
"actions": [
{"app": "[STORAGE]", "op": "SaveObject", "input": {"path": "/voicemail/{{call_id}}.mp3", "data": "{{recording}}"}},
{"app": "[CRM]", "op": "CreateTask", "input": {"title": "Callback: Voicemail", "due_in_hours": 24, "contact_phone": "{{phone}}"}}
]
}
],
"idempotency_key": "hash(call_id + function + stable_args)",
"on_error": {"retry": "exponential", "max_attempts": 3, "dead_letter": "[DLQ_WEBHOOK_URL]"},
"log": {"to": "[OBSERVABILITY_WEBHOOK_URL]"}
}
Notes
- Calendar sources: [CALENDAR_PROVIDER]=Google Calendar, Outlook, Calendly, or Acuity.
- CRM: HubSpot, Pipedrive, Close, Airtable base — pick one and standardize fields.
- Always store
call_id,transcript_excerpt, andintenton the CRM object for QA + revenue attribution.
Spend‑Guard Policy (per‑call + monthly caps with turn/latency budgets)
Drop this policy into your orchestrator or middleware. It caps per‑call and monthly spend, budgets latency, and escalates when limits are hit. Replace the pricing placeholders from your vendor’s current pricing page before launch.
// Spend Guard (pseudocode)
const PRICES = {
audio_in_per_million: [AUDIO_IN_PRICE_PER_MILLION], // e.g., 1000000-token rate for input audio
audio_out_per_million: [AUDIO_OUT_PRICE_PER_MILLION] // e.g., 1000000-token rate for output audio
};
const LIMITS = {
per_call_usd_cap: [PER_CALL_USD_CAP], // e.g., 0.35
monthly_usd_cap: [MONTHLY_USD_CAP], // your budget
max_turns: [MAX_TURNS], // e.g., 8
latency_budget_s: [LATENCY_BUDGET_S] // e.g., 1.8
};
let state = { inputMs: 0, outputMs: 0, turns: 0, estUsd: 0, ttfbBreaches: 0 };
function estUsd() {
const inUsd = (state.inputMs / 100) * (PRICES.audio_in_per_million / 1e6); // 1 token per 100ms in
const outUsd = (state.outputMs / 50) * (PRICES.audio_out_per_million / 1e6); // 1 token per 50ms out
return inUsd + outUsd; // excludes text tokens + telephony minutes
}
on('user.audio_frame', (ms) => { state.inputMs += ms; });
on('assistant.audio_frame', (ms) => { state.outputMs += ms; });
on('assistant.response.start', (ctx) => {
const ttfb = now() - ctx.userLastSpeechEnd; // time to first audio (s)
if (ttfb > LIMITS.latency_budget_s) state.ttfbBreaches += 1;
});
on('assistant.response.done', () => {
state.turns += 1;
state.estUsd = estUsd();
if (state.turns >= LIMITS.max_turns) return escalate('turn_cap');
if (state.estUsd >= LIMITS.per_call_usd_cap) return disconnect('per_call_cap');
if (state.ttfbBreaches >= 2) return escalate('latency');
});
on('billing.monthly_rollup', (usd) => {
if (usd >= LIMITS.monthly_usd_cap) pauseIngress('monthly_cap');
});
function escalate(reason) { callFunction('escalate_to_human', { reason }); }
function disconnect(reason) { endCall({ reason }); }
Implementation notes
- Add a
response.donelistener to recomputeestUsdevery turn and tag the transcript withestUsd_at_disconnectwhen applicable. - Enable VAD to avoid charging for silence; reject empty frames.
- For long calls or price‑sensitive use, pilot
[REALTIME_MODEL]=gpt-realtime-minifirst; upgrade only if quality demands it.
Consent + Escalation Copy (ready to paste)
Non‑legal, plain‑English copy you can paste and adapt. Confirm your jurisdiction’s consent rules before use.
Opening + consent (U.S. two‑party safe default)
- "Thanks for calling [BUSINESS_NAME]. This line uses AI to assist and record for quality. Do I have your permission to continue?"
- If yes → proceed.
- If no/unsure → "No problem. I can text our booking link or connect you to a person. Which do you prefer?"
Pricing deflection (link + callback)
- "We publish pricing at [PRICING_URL]. I’ll text it now. If you’d like a firm quote, I can book a 5‑minute fit call for [NEXT_OPEN_SLOT]."
Qualification micro‑script
- "To get you to the right person, what service do you need? And when are you hoping to get this done?"
Reschedule
- "I can help reschedule. What’s the name on the booking and the new time you prefer? I’ll confirm the change by text."
After‑hours → voicemail
- "We’re outside live support hours. I can take a message and send it to the team. What’s your name, number, and the reason for your call?"
Frustration/low confidence escalation
- "I want to get this right. I’m connecting you to a teammate now."
Do‑Not‑Call / opt‑out
- "Understood. I’ve marked your number as Do‑Not‑Contact. You won’t receive further calls or texts from us."
Multilingual fallback
- "Puedo ayudar en español. [I can help in Spanish.] ¿Prefiere continuar en español?"
SMS confirms (send via blueprint)
- Booking: "[BUSINESS_NAME]: Confirmed [SERVICE] on [DATE] [TIME] at [LOCATION]. Change anytime: [RESCHEDULE_LINK]."
- Reschedule: "[BUSINESS_NAME]: Updated to [NEW_DATE] [NEW_TIME]. Details: [APPT_LINK]."
- Pricing link: "[BUSINESS_NAME]: Pricing menu: [PRICING_URL]. Reply BOOK to schedule a fit call."
Escalation target
- Live handoff number: [HUMAN_FALLBACK_NUMBER]
- Live hours (local): [HOURS_LOCAL_TZ]
Disclaimer
- These snippets are non‑legal examples. Confirm consent, recording, and opt‑out language with counsel for your market.
Metrics Dashboard Template (ASR WER, booking rate, escalation rate)
Track outcomes from day one. Create a simple table (Notion/Airtable/Sheet) with these fields and formulas.
Core fields (one row per call)
- call_id (text)
- started_at (timestamp, UTC)
- duration_s (number)
- model (enum)
- intent_primary (enum: book | reschedule | qualify | pricing_deflection | voicemail | unknown)
- turns (number)
- ttfb_s (number)
- asr_wer (number, 0–1; sample 10 calls/week if needed)
- confidence_avg (0–1)
- escalated (boolean)
- outcome (enum: booking | rescheduled | lead_created | deflected_to_pricing | voicemail_left | abandoned)
- est_audio_cost_usd (number)
- telephony_minutes (number)
- country (ISO‑2)
Dashboard rollups (formulas)
- Booking rate = bookings / answered_calls
- Escalation rate = escalations / answered_calls
- Containment rate = (answered_calls − escalations) / answered_calls
- Avg turns = avg(turns)
- Avg TTFB (s) = avg(ttfb_s)
- ASR WER (weekly sample) = avg(asr_wer)
- Cost/call (audio only) = avg(est_audio_cost_usd)
- Cost/booking (audio only) = sum(est_audio_cost_usd where outcome=booking) / bookings
Instrumentation tips
- Log
response.donecount per call; later turns usually cost more — use this to justify your max_turns. - Tag every escalation with
reason(low_confidence | turn_cap | latency | caller_request) for QA. - Keep country on the call row so you can multiply telephony minutes by live per‑country rates outside this sheet.
QA + Launch Checklist (10 steps)
Run these before your first real caller.
- Replace all [BRACKETS] in JSON + blueprints and validate JSON with a linter.
- Pull current audio I/O prices and set [AUDIO_IN_PRICE_PER_MILLION] and [AUDIO_OUT_PRICE_PER_MILLION] in the spend guard.
- Fetch your telephony minute rates per country at deploy time; never assume a global rate.
# Twilio Voice Pricing API (example)
curl -u "[TWILIO_SID]:[TWILIO_AUTH_TOKEN]" \
"https://pricing.twilio.com/v1/Voice/Countries/[COUNTRY_ISO]"
- Set [PER_CALL_USD_CAP] and [MONTHLY_USD_CAP]; verify disconnect/escalate paths work.
- Test consent flow with a second phone; confirm opt‑out tags your CRM.
- Confirm Make/Zapier idempotency (replay webhook twice → 1 booking only).
- Simulate low confidence (mumble) and ensure escalation triggers.
- Place one after‑hours call; verify voicemail recording + next‑day task.
- Review your first 10 transcripts; update copy + triggers.
- Freeze v1 and turn on logging to [OBSERVABILITY_WEBHOOK_URL].