# DialValet — expanded agent brief DialValet gives a personal AI agent a phone. A user asks for a call, DialValet places one real outbound U.S. call that presents a phone number the account owner has verified, an AI assistant speaks and listens in real time, and the call ends with a short structured outcome. Private beta. Short version for agents: https://dialvalet.com/llms.txt Human docs: https://dialvalet.com/docs/INDEX.md Machine contract: https://dialvalet.com/openapi.yaml Human walkthrough (five minutes): https://dialvalet.com/docs/QUICKSTART.md ## Surfaces - Website and dashboard: https://dialvalet.com (`/signup`, `/login`, `/dashboard`) - REST API: https://api.dialvalet.com/v1 - Remote MCP: https://mcp.dialvalet.com/mcp - CLI: `npm install --global @dialvalet/cli` (0.2.0) — the recommended front door ## What must be true before a call happens 1. The account is signed in, by phone one-time code. There is no password. 2. The number to present as caller ID is verified. That is a separate step from sign-in, with its own code. 3. Prepaid credit is available. 4. The user directly asked for this call, naming the destination and the objective. 5. The destination is a U.S. number and account limits pass. If any of these is missing the call is refused. Nothing about DialValet dials on a schedule or on its own. ## Setup path (CLI, about five minutes) ```sh npm install --global @dialvalet/cli dialvalet signup --phone +1XXXXXXXXXX --json # stop; ask the account holder for the texted code dialvalet auth verify --verification-id otp_... --code XXXXX --json dialvalet identities verify --phone +1XXXXXXXXXX --json # stop; ask for the caller-ID code, which is a different code dialvalet identities confirm --verification-id otp_... --code XXXXX --json dialvalet billing checkout --amount 5 --json # wait until checkout settles, then: dialvalet balance --json # only after the user names this destination and objective: dialvalet calls create --to +1XXXXXXXXXX --objective "..." --confirm --json dialvalet calls wait call_... --json ``` Pass `--json` everywhere and follow each command's `next_step`. Credentials are saved at `~/.config/dialvalet/config.json` with mode `0600`, or supplied through `DIALVALET_API_KEY`. Full reference: https://dialvalet.com/docs/CLI.md ## Authentication REST accepts a Bearer API key (`Authorization: Bearer dv_...`) or, on dashboard routes, the browser session cookie. An API key is shown once at creation; only a hash is stored. Sensitive actions can require a session created within the last 10 minutes and otherwise fail with `recent_session_required`. One-time codes are rate limited to 3 per phone number and 5 per IP address each minute. The dashboard form takes 5 digits; the API accepts 4 to 10. ## Pricing and credit - $0.15 per started connected minute, charged as ceil(connected_seconds / 60). - No talk-time charge when a call is not answered. - Prepaid one-time Stripe Checkout, $5 minimum and $100 maximum per purchase. No subscription, no automatic reload, no per-call card charge. - Credit posts only after the payment settles. A checkout URL is not a payment and a pending checkout is not credit. - Before dialing, the maximum possible charge is reserved from the balance; the unused remainder is released when the call ends. - Using a number the owner already has is free. Dedicated numbers are not sold. ## Limits Default per account: 5 calls per day, 1 call at a time, 20 minutes maximum per call. An account can tighten its own limits with `PATCH /v1/policy` and read them with `GET /v1/policy`. Limits are enforced server side; an agent cannot raise them. ## Calls, transcripts, and retention - Live audio is processed in real time so the assistant can speak and listen. Calls are not recorded and no audio file is stored. - While a call runs, `GET /v1/calls/{id}/live` streams the transcript over a WebSocket. The CLI exposes this as `dialvalet calls wait`. - If the call agent needs an unauthorized consequential decision, the stream emits `input_required` with one plain-text question and exits successfully. Answer it with `dialvalet calls answer --answer "..." --follow --json`; the command resumes the transcript. - An originating agent can send an unsolicited correction with `dialvalet calls steer --mode instruction|context|say --text "..." [--interrupt] [--follow] --json`. - After some calls an optional structured result is produced: a short summary, resolution, commitments, follow-ups, and speaker-labeled transcript turns. It is encrypted and kept up to 30 days. - `GET /v1/calls/{id}/transcript` returns those turns and `404` when none exist, which is a normal outcome rather than an error to retry. - The owner can delete a stored result or transcript early via the dashboard or `DELETE /v1/calls/{id}/result` and `DELETE /v1/calls/{id}/transcript`. - DialValet does not inject a fixed opening disclosure. Put any identity, AI/artificial-voice, purpose, callback-number, recording, or opt-out notice required for the particular call into the objective or context so the live agent can say it naturally. - Before dialing, the objective and optional context are screened for prohibited or harmful use. Ordinary personal and customer-service calls, including benign jokes between friends, are allowed when they do not involve fraud, harassment, credentials, harm, illegal activity, or another prohibited use. - The live agent can ring the account holder into the call only when the call was placed with `--allow-transfer` (API and MCP: `allow_user_transfer: true`). Set it only when the user explicitly asked for it. The agent still does not ring for ordinary difficulty; it rings when the other party needs the user on the phone. The user's phone shows +1 480-480-1077 (+14804801077). That number is DialValet. The business continues to see the verified caller ID. If nobody answers, the agent continues the call. ## Idempotency `POST /v1/calls` requires a stable idempotency key in the body or header. An exact retry returns the same call rather than dialing twice; the same key with changed inputs returns `409`. Checkout accepts an optional `Idempotency-Key` with the same rule. The CLI stores a pending checkout key locally, reuses it on retry of the same amount, and clears it after success. On a network error, retry the same command rather than composing a new one. ## MCP Configure the client for https://mcp.dialvalet.com/mcp. Authorization runs phone one-time-code sign-in followed by a human scope-selection page. Cursor (`.cursor/mcp.json` or `~/.cursor/mcp.json`): ```json { "mcpServers": { "dialvalet": { "url": "https://mcp.dialvalet.com/mcp" } } } ``` Claude Code and other HTTP MCP clients: ```json { "mcpServers": { "dialvalet": { "type": "http", "url": "https://mcp.dialvalet.com/mcp" } } } ``` `dialvalet mcp config` prints the Cursor JSON. `claude mcp add --transport http dialvalet https://mcp.dialvalet.com/mcp` Scopes: `calls:read`, `calls:write`, `caller_identities:read`, `billing:read`. Tools: `place_call`, `get_call`, `list_calls`, `cancel_call`, `list_voices`, `set_default_voice`, `get_credit_balance`, `list_caller_ids`. `place_call` accepts an optional `voice`. If omitted, the account default from `set_default_voice` is used, then `marin`. Portuguese voices `bossa` and `tempo` speak Brazilian Portuguese. A connected grant is an ongoing capability, not per-call permission. Approval of a connector does not imply the client will confirm each tool call, so a direct user instruction for each specific call is still required. Grants are listed and revoked in the dashboard under Connect or with `DELETE /v1/oauth/grants/{grant_id}`. ## Optional voices and live guidance ```sh dialvalet voices --json dialvalet voices set gleam --json dialvalet calls create --to +1XXXXXXXXXX --objective "..." --voice gleam --confirm --json # If input_required is emitted: dialvalet calls answer call_... guide_... --answer "Eight PM works; reserve it." --follow --json # To correct the live agent: dialvalet calls steer call_... --mode instruction --text "Correct the date to Friday." --interrupt --follow --json ``` ## Not available Audio recordings, a standalone verbatim transcript product, dedicated DialValet phone numbers, inbound call forwarding, non-U.S. numbers or destinations, automatic credit reload, and per-call card charges. Do not tell a user these exist or promise them for a date. ## Rules for agents - If a CLI `--json` result includes `cli_update`, run `cli_update.command` and retry before doing anything else. - Never request, guess, intercept, or generate a one-time code. Ask the account holder every time and wait. - Never print an API key, code, or payment detail into a prompt, log, transcript, or issue. The CLI stores the key for you. - Place a call only on a direct instruction naming that destination and objective. The CLI requires `--confirm`. - A call ID is not proof anyone answered. Check for a terminal status. - If the live stream yields `input_required`, answer its plain-text question from authorized context only; do not invent consent for a new commitment. - A verified caller ID is not consent from the recipient. Do not use DialValet for telemarketing, campaigns, bulk dialing, harmful or materially deceptive impersonation, or any call the owner is not legally allowed to make. - DialValet does not add a fixed disclosure. Include the disclosures required for that specific call in the objective or context; requirements vary by purpose, relationship, and jurisdiction. - Use `--allow-transfer` (`allow_user_transfer: true`) only after the user explicitly asks to be rung in. Tell them the call comes from +1 480-480-1077 (+14804801077). Do not set it on your own. - Report what happened plainly, including refusals and missing results, rather than inferring an outcome. ## Legal Terms: https://dialvalet.com/terms · Privacy: https://dialvalet.com/privacy · Contact: contact@dialvalet.com