-
-
Dry-run mode: masked phone numbers, region inference, allowlist check — no call placed without explicit confirmation
-
Honest failure reporting: CALL-E rejected the call, and results.csv shows "failed" — never guessed as confirmed
-
Real bug caught and fixed: a duplicate call attempt is detected and skipped, preventing an accidental second dial
Inspiration
Every service business that books time slots loses money to no-shows. The usual fix is a person on staff spending part of every afternoon manually phoning down tomorrow's appointment list — repetitive, unglamorous, and the first thing to get skipped when the day gets busy. We already had a real, working CALL-E integration inside a broader personal-assistant agent that could place a goal-driven outbound call and get a structured result back. This hackathon was the reason to take that one capability, cut away everything else the agent does, and turn it into something the CALL-E community could actually install and use on its own.
What it does
appointment-call-confirm takes a batch of upcoming appointments
(name, phone, appointment time, and what the appointment is for) and:
- Dry-runs the whole batch first — prints every recipient with a masked phone number and requires explicit approval before any call goes out. No call is ever placed silently.
- Requires an exact-destination allowlist on every live run — no override exists to skip this. Any recipient not on the allowlist is skipped and reported as unauthorized, never dialed.
- Places one outbound CALL-E call per recipient, serially — never in parallel — asking them to confirm, reschedule, or cancel.
- Gets a structured result back, not free text:
confirmed/needs_reschedule(with the proposed new time) /declined/no_answer/voicemail/unclear, via CALL-E'sresult_schemasupport. - Treats any ambiguous outcome as an unconditional hard stop — a create-call timeout, a dropped connection, an accepted response with no call id, or a poll timeout all halt the batch immediately rather than being recorded as a clean failure.
- Writes back one row per recipient to a results CSV, with the
CALL-E
call_idkept for auditability, plus a one-line batch summary so a business can act on the exceptions first. - Never claims a call happened that didn't — every result field is sanitized (phone numbers in any common format, control characters, credentials) before it's ever displayed or stored.
It's a skill, not a new product surface: SKILL.md plus a
dependency-light Python runner (requests + a CALL-E API key,
nothing else), built to awesome-phone-call-agents' own skill folder
template.
How we built it
The skill wraps CALL-E's Developer API directly: POST /v1/calls to
place each call with a result_schema describing the exact JSON
shape we want back, then GET /v1/calls/{call_id} polled to a
terminal status. Region is inferred from the phone number's country
code against CALL-E's documented region list when not given
explicitly, and the run refuses to guess if it can't. Each call's
idempotency key is a stable hash of that appointment's own fields —
not a random value — so re-running an interrupted batch can't
double-dial someone already reached. The API base URL is hardcoded to
CALL-E's official host with no environment or flag override, so
credentials can never be sent anywhere else.
Technologies used: CALL-E Developer API (POST /v1/calls,
GET /v1/calls/{call_id}), Python, requests.
Challenges we ran into
- Scoping down instead of up. The tempting submission was a generalist agent that happens to have calling as one of many tools — but that doesn't answer "what specific phone-work problem does this solve," which is what's actually judged here.
- Never guessing a result. Anything that doesn't cleanly match
the
result_schema's enum is reported asunclear— a deliberately less impressive-looking but honest result. - Treating network ambiguity as ambiguity, not failure. A create timeout or dropped connection doesn't prove CALL-E didn't create the call — so those cases halt the batch for human reconciliation instead of being recorded as a clean "failed" row that lets the batch continue.
What we learned
- A hackathon's judging rubric is itself a design constraint: "does this solve a real, specific problem" pushed us toward narrowing scope, not adding features.
- Structured
result_schemaoutput turns "the agent talked to someone on the phone" into something a business can actually act on, instead of
Built With
- call-e-api
- cli
- python
- rest-api
Log in or sign up for Devpost to join the conversation.