Appointment Call Confirm
Why this exists
Any service business that books time slots — clinics, salons, repair
shops, tutoring, veterinary practices, small logistics/delivery
windows — loses revenue to no-shows. The standard mitigation is a
person on staff spending part of every afternoon manually phoning
tomorrow's appointment list to confirm, reschedule, or free up a slot.
It is repetitive, easy to skip on a busy day, and does not scale past a
handful of bookings.
appointment-call-confirm automates exactly that one workflow — not a
general-purpose "AI that makes phone calls." Given a list of upcoming
appointments (recipient, phone, appointment time, business/task
context), it places one outbound CALL-E call per appointment, asks the
recipient to confirm, reschedule, or cancel, and returns a structured
result per call that a host can write back to wherever appointments
already live (a spreadsheet, a calendar, a CRM, a CSV).
This is a workflow skill, not a new CALL-E backend API. It does not
add call-scheduling, recurrence, or provider-side state — it wraps
CALL-E's existing one-off POST /v1/calls / GET /v1/calls/{id}
Developer API in a batch-confirmation shape and hands the caller a
consistent result contract.
When To Use
Use this skill when:
- a user has a list of upcoming appointments/bookings and wants each
recipient called to confirm, reschedule, or cancel before the slot
- a user asks something like "call everyone on tomorrow's schedule and
confirm they're still coming" or "phone these 12 customers and ask
if 2pm still works"
- the result of each call needs to be written back somewhere
structured (a sheet, a file, a downstream system) rather than just
read aloud in chat
When Not To Use
Do not use this skill to:
- place a single one-off call with no confirm/reschedule/decline
structure — use CALL-E's plain call API directly instead
- create a recurring/scheduled calling job — see the
call-reminder
skill in this repository for scheduler-wrapped recurring calls
- call any recipient who has not already been given a specific
appointment/booking with the caller's business — this skill is for
confirming existing appointments, not cold outreach or lead
generation
- guess a recipient's phone number, region, or language from anything
other than what the caller/host explicitly provided
- place a call before the user has explicitly confirmed the appointment
list is correct and that the calls should go out
Core Workflow
- Collect the appointment batch. Each entry needs, at minimum:
recipient_name, phone (E.164), appointment_time (ISO 8601,
with timezone), and a short context string (what the appointment
is for — e.g. "annual checkup with Dr. Rao", "car pickup for
invoice #4021"). Ask for any missing required field rather than
inferring it.
- Dry-run the batch before calling anyone. Print the full list
(name, masked phone, time, context) and require explicit
confirmation before any call is placed — see
references/safety.md. This mirrors CALL-E's own guidance that
phone-call workflows must be safe to preview without a real call.
- Build the CALL-E task per recipient using
references/result-schema.md's result_schema, so CALL-E returns
a structured status (confirmed / needs_reschedule /
declined / no_answer / voicemail) and an optional
requested_new_time instead of free text that has to be
re-parsed.
- Place calls serially, not in parallel. One call in flight per
recipient at a time (see
scripts/place_confirmation_calls.py).
This keeps behavior predictable, keeps a single failing call from
masking others, and avoids surprising a business with a burst of
simultaneous outbound calls.
- Require a separate, explicit authorization record per number.
--confirm says the batch as a whole should place real calls;
a distinct --authorized-numbers file is the record of which
specific numbers consent has actually been confirmed for. A
recipient missing from that file is never called, even with
--confirm set — see references/safety.md.
- Poll each call to a terminal state using CALL-E's
GET /v1/calls/{call_id} before moving to the next recipient (or
asynchronously, if the host has its own webhook/queue — see the
script's --webhook-url option). If a call's outcome is ever
ambiguous — a local/network error, a missing call id, or a poll
that times out — halt the entire batch immediately rather than
guessing or advancing to the next recipient; a call CALL-E may or
may not have actually placed must be reconciled by a human before
anything else is dialed.
- Write back one structured row per recipient: name, masked
phone, appointment time, call status, structured result, and the
CALL-E
call_id for auditability — to CSV by default
(scripts/place_confirmation_calls.py --out results.csv), or
forward each result to a host-provided sink (webhook, sheet,
ticketing system).
- Never claim a call happened if CALL-E rejected the request.
Report the rejection reason from the API and halt rather than
retrying silently or moving on as if nothing happened.
Required Fields (per appointment)
recipient_name
phone — E.164, e.g. +14155550101
appointment_time — ISO 8601 with timezone, e.g.
2026-09-05T15:00:00-04:00
context — one sentence describing what the appointment is for,
used to build the call's task
Optional: region (CALL-E region code, defaults to inferring from the
phone country code if omitted — see references/result-schema.md),
locale, business_name (used in the call script), metadata
(free-form, echoed back with the result).
Safety Rules
Read references/safety.md for the full contract. In short:
- This skill places real phone calls with real consequences — never
run the batch without the user explicitly reviewing and approving
the dry-run list first.
- Only call the phone numbers explicitly provided for this batch —
never a number pulled from an unrelated contact list or guessed.
- Mask phone numbers in every user-facing summary (
+1415•••0101);
the full number is only ever sent to CALL-E's API, never printed to
a log a bystander could read over someone's shoulder.
- Do not fabricate a
confirmed / declined / etc. result if CALL-E's
response doesn't clearly support it — report unclear and surface
the raw summary instead of guessing.
- Do not retry a failed call automatically more than once per
recipient per run; repeated unwanted calls are a real-world harm,
not just a technical annoyance. If any call's outcome is ambiguous,
halt the whole batch rather than continuing — see
references/safety.md.
- Never expose the CALL-E API key in output, logs, or the results
file, and never send it to a CALL-E origin outside the script's
explicit allowlist even if
CALLE_BASE_URL is overridden.
- Treat any appointment context that reads as medical, legal, or
financial as logistics-only — the call confirms a time, it does not
discuss the underlying medical/legal/financial matter.
- CALL-E does not currently expose a call-cancellation endpoint.
Stopping this script prevents further calls in the batch, but
cannot cancel a call already created — see the "Cancellation"
section of
references/safety.md.
Output Format
After a batch run, report per recipient:
- masked phone, appointment time, and CALL-E
call_id
- final status:
confirmed / needs_reschedule (with the requested
new time, if any) / declined / no_answer / voicemail /
unclear / failed (with the rejection reason)
And a one-line batch summary: N confirmed, N to reschedule, N declined, N no answer, N failed — so a business can act on the
exceptions first instead of re-reading every row.
Never state a call was completed unless CALL-E's own status for that
call_id reached a terminal state.
Files
scripts/place_confirmation_calls.py — standalone runner: reads a
CSV/JSON batch, dry-runs it (stdlib only, no install needed), then
requires both --confirm and --authorized-numbers to place real
calls through CALL-E's Developer API with the shared
result_schema, polls to completion, halts the whole batch on any
ambiguous outcome, and writes a results CSV.
requirements.txt — the one dependency (requests) needed only
for live calls; dry-run needs nothing beyond it being present in
the repo so --confirm runs can install it.
assets/authorized_numbers.example.txt — format reference for the
required --authorized-numbers file; copy it, don't commit your
real one.
references/result-schema.md — the exact result_schema sent to
CALL-E and how each field maps to the output above.
references/safety.md — the full safety contract this skill
follows, aligned with this repository's repo-wide safety patterns,
including the authorization gate, halt-on-ambiguity behavior, and
CALL-E's current lack of a cancellation endpoint.
1---2name: appointment-call-confirm3description: Places outbound CALL-E confirmation calls for a batch of upcoming appointments or bookings and returns a structured confirmed / needs-reschedule / declined / no-answer result per recipient, so a business can close its next-day no-show gap without a staff member manually dialing down the list.4license: MIT5---67# Appointment Call Confirm89## Why this exists1011Any service business that books time slots — clinics, salons, repair12shops, tutoring, veterinary practices, small logistics/delivery13windows — loses revenue to no-shows. The standard mitigation is a14person on staff spending part of every afternoon manually phoning15tomorrow's appointment list to confirm, reschedule, or free up a slot.16It is repetitive, easy to skip on a busy day, and does not scale past a17handful of bookings.1819`appointment-call-confirm` automates exactly that one workflow — not a20general-purpose "AI that makes phone calls." Given a list of upcoming21appointments (recipient, phone, appointment time, business/task22context), it places one outbound CALL-E call per appointment, asks the23recipient to confirm, reschedule, or cancel, and returns a structured24result per call that a host can write back to wherever appointments25already live (a spreadsheet, a calendar, a CRM, a CSV).2627This is a **workflow skill**, not a new CALL-E backend API. It does not28add call-scheduling, recurrence, or provider-side state — it wraps29CALL-E's existing one-off `POST /v1/calls` / `GET /v1/calls/{id}`30Developer API in a batch-confirmation shape and hands the caller a31consistent result contract.3233## When To Use3435Use this skill when:3637- a user has a list of upcoming appointments/bookings and wants each38 recipient called to confirm, reschedule, or cancel before the slot39- a user asks something like *"call everyone on tomorrow's schedule and40 confirm they're still coming"* or *"phone these 12 customers and ask41 if 2pm still works"*42- the result of each call needs to be written back somewhere43 structured (a sheet, a file, a downstream system) rather than just44 read aloud in chat4546## When Not To Use4748Do not use this skill to:4950- place a single one-off call with no confirm/reschedule/decline51 structure — use CALL-E's plain call API directly instead52- create a recurring/scheduled calling job — see the `call-reminder`53 skill in this repository for scheduler-wrapped recurring calls54- call any recipient who has not already been given a specific55 appointment/booking with the caller's business — this skill is for56 confirming existing appointments, not cold outreach or lead57 generation58- guess a recipient's phone number, region, or language from anything59 other than what the caller/host explicitly provided60- place a call before the user has explicitly confirmed the appointment61 list is correct and that the calls should go out6263## Core Workflow64651. **Collect the appointment batch.** Each entry needs, at minimum:66 `recipient_name`, `phone` (E.164), `appointment_time` (ISO 8601,67 with timezone), and a short `context` string (what the appointment68 is for — e.g. "annual checkup with Dr. Rao", "car pickup for69 invoice #4021"). Ask for any missing required field rather than70 inferring it.712. **Dry-run the batch before calling anyone.** Print the full list72 (name, masked phone, time, context) and require explicit73 confirmation before any call is placed — see74 `references/safety.md`. This mirrors CALL-E's own guidance that75 phone-call workflows must be safe to preview without a real call.763. **Build the CALL-E task per recipient** using77 `references/result-schema.md`'s `result_schema`, so CALL-E returns78 a structured `status` (`confirmed` / `needs_reschedule` /79 `declined` / `no_answer` / `voicemail`) and an optional80 `requested_new_time` instead of free text that has to be81 re-parsed.824. **Place calls serially, not in parallel.** One call in flight per83 recipient at a time (see `scripts/place_confirmation_calls.py`).84 This keeps behavior predictable, keeps a single failing call from85 masking others, and avoids surprising a business with a burst of86 simultaneous outbound calls.875. **Require a separate, explicit authorization record per number.**88 `--confirm` says the batch as a whole should place real calls;89 a distinct `--authorized-numbers` file is the record of which90 specific numbers consent has actually been confirmed for. A91 recipient missing from that file is never called, even with92 `--confirm` set — see `references/safety.md`.936. **Poll each call to a terminal state** using CALL-E's94 `GET /v1/calls/{call_id}` before moving to the next recipient (or95 asynchronously, if the host has its own webhook/queue — see the96 script's `--webhook-url` option). If a call's outcome is ever97 ambiguous — a local/network error, a missing call id, or a poll98 that times out — **halt the entire batch immediately** rather than99 guessing or advancing to the next recipient; a call CALL-E may or100 may not have actually placed must be reconciled by a human before101 anything else is dialed.1027. **Write back one structured row per recipient**: name, masked103 phone, appointment time, call status, structured result, and the104 CALL-E `call_id` for auditability — to CSV by default105 (`scripts/place_confirmation_calls.py --out results.csv`), or106 forward each result to a host-provided sink (webhook, sheet,107 ticketing system).1088. **Never claim a call happened if CALL-E rejected the request.**109 Report the rejection reason from the API and halt rather than110 retrying silently or moving on as if nothing happened.111112## Required Fields (per appointment)113114- `recipient_name`115- `phone` — E.164, e.g. `+14155550101`116- `appointment_time` — ISO 8601 with timezone, e.g.117 `2026-09-05T15:00:00-04:00`118- `context` — one sentence describing what the appointment is for,119 used to build the call's `task`120121Optional: `region` (CALL-E region code, defaults to inferring from the122phone country code if omitted — see `references/result-schema.md`),123`locale`, `business_name` (used in the call script), `metadata`124(free-form, echoed back with the result).125126## Safety Rules127128Read `references/safety.md` for the full contract. In short:129130- This skill places real phone calls with real consequences — never131 run the batch without the user explicitly reviewing and approving132 the dry-run list first.133- Only call the phone numbers explicitly provided for this batch —134 never a number pulled from an unrelated contact list or guessed.135- Mask phone numbers in every user-facing summary (`+1415•••0101`);136 the full number is only ever sent to CALL-E's API, never printed to137 a log a bystander could read over someone's shoulder.138- Do not fabricate a `confirmed` / `declined` / etc. result if CALL-E's139 response doesn't clearly support it — report `unclear` and surface140 the raw summary instead of guessing.141- Do not retry a failed call automatically more than once per142 recipient per run; repeated unwanted calls are a real-world harm,143 not just a technical annoyance. If any call's outcome is ambiguous,144 halt the whole batch rather than continuing — see145 `references/safety.md`.146- Never expose the CALL-E API key in output, logs, or the results147 file, and never send it to a CALL-E origin outside the script's148 explicit allowlist even if `CALLE_BASE_URL` is overridden.149- Treat any appointment context that reads as medical, legal, or150 financial as logistics-only — the call confirms a time, it does not151 discuss the underlying medical/legal/financial matter.152- CALL-E does not currently expose a call-cancellation endpoint.153 Stopping this script prevents further calls in the batch, but154 cannot cancel a call already created — see the "Cancellation"155 section of `references/safety.md`.156157## Output Format158159After a batch run, report per recipient:160161- masked phone, appointment time, and CALL-E `call_id`162- final status: `confirmed` / `needs_reschedule` (with the requested163 new time, if any) / `declined` / `no_answer` / `voicemail` /164 `unclear` / `failed` (with the rejection reason)165166And a one-line batch summary: `N confirmed, N to reschedule, N167declined, N no answer, N failed` — so a business can act on the168exceptions first instead of re-reading every row.169170Never state a call was completed unless CALL-E's own status for that171`call_id` reached a terminal state.172173## Files174175- `scripts/place_confirmation_calls.py` — standalone runner: reads a176 CSV/JSON batch, dry-runs it (stdlib only, no install needed), then177 requires both `--confirm` and `--authorized-numbers` to place real178 calls through CALL-E's Developer API with the shared179 `result_schema`, polls to completion, halts the whole batch on any180 ambiguous outcome, and writes a results CSV.181- `requirements.txt` — the one dependency (`requests`) needed only182 for live calls; dry-run needs nothing beyond it being present in183 the repo so `--confirm` runs can install it.184- `assets/authorized_numbers.example.txt` — format reference for the185 required `--authorized-numbers` file; copy it, don't commit your186 real one.187- `references/result-schema.md` — the exact `result_schema` sent to188 CALL-E and how each field maps to the output above.189- `references/safety.md` — the full safety contract this skill190 follows, aligned with this repository's repo-wide safety patterns,191 including the authorization gate, halt-on-ambiguity behavior, and192 CALL-E's current lack of a cancellation endpoint.