Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when the user wants phone-number intelligence (lookup, carrier, line type, SIM-swap / call-forwarding fraud signals), US/CA number provisioning (rent a phone number), or outbound AI voice calls (Bland.ai under the hood — schedule, confirm, follow-up). Pay per call in USDC.
.claude/skills/blockrunai-phone/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 99% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 108% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 21% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 132% | 0% |
| case-20 | ✗→✓ | ▲ Improved | 48% | 0% |
Two namespaces in one tool: /v1/phone/* for number intelligence + provisioning, /v1/voice/* for outbound AI calls. Pay per call in USDC.
Phone numbers use E.164 format — + followed by country code and subscriber digits (US: +1 + 10 digits; UK: +44 + 10 digits; etc.). The examples below use <+E.164-number> as a placeholder — the LLM should substitute the actual number from the user's request, not copy the literal placeholder.
tsconst targetNumber = "<+E.164-number-from-user>" // e.g. user said "call my doctor at 415-..." // Lookup carrier + line type blockrun_phone({ path: "phone/lookup", body: { phoneNumber: targetNumber } }) // Buy a 30-day US number blockrun_phone({ path: "phone/numbers/buy", body: { country: "US", areaCode: "415" } }) // Outbound AI call (requires `from` — see below) const r = await blockrun_phone({ path: "voice/call", body: { to: targetNumber, from: "<+E.164-number-you-own>", // from phone/numbers/buy task: "Confirm appointment for Friday at 3pm with Dr. Wong.", voice: "june" }}) // poll the result (free GET, no body) blockrun_phone({ path: `voice/call/${r.call_id}` })
/v1/phone/*)| Path | Body | Price | Effect | |---|---|---|---| | phone/lookup | { phoneNumber } | $0.0110 | Carrier, line type (mobile/landline/VoIP) | | phone/lookup/fraud | { phoneNumber } | $0.0510 | + SIM-swap signals, call-forwarding detection | | phone/numbers/buy | { country?: "US"\|"CA", areaCode? } | $5.001 | 30-day lease, US or CA | | phone/numbers/renew | { phoneNumber } | $5.001 | Extend lease 30 days | | phone/numbers/list | {} | $0.0020 | Your wallet-owned numbers | | phone/numbers/release | { phoneNumber } | free | Return to pool |
/v1/voice/*)| Path | Method | Body | Price | |---|---|---|---| | voice/call | POST | { to, task, from, voice?, max_duration?, language?, first_sentence?, wait_for_greeting? } | $0.5410 flat | | voice/call/{call_id} | GET (no body) | – | free poll |
> from is REQUIRED and must be a number your wallet owns. Provision one first with phone/numbers/buy ($5, 30-day lease). 400 errors from voice/call are almost always missing from.
| Field | Required | Default | Notes | |---|---|---|---| | to | yes | – | Destination E.164 number | | task | yes | – | What the AI should do on the call (10–4000 chars) | | from | yes | – | Your provisioned BlockRun caller-ID number (from phone/numbers/buy) | | voice | no | nat | nat / josh / maya / june / paige / derek / florian | | max_duration | no | 5 | Minutes, 1–30 | | language | no | en-US | Language code, BCP-47 | | first_sentence | no | – | Custom opening line for the AI | | wait_for_greeting | no | false | Let recipient speak first, then AI starts |
| Voice | Tone | |---|---| | nat | Neutral / professional male, default | | josh | Friendly male | | maya | Warm female | | june | Calm professional female | | paige | Energetic female | | derek | Deep male | | florian | European-accented male |
tsblockrun_phone({ path: "phone/lookup/fraud", body: { phoneNumber: "+14155550150" } })
Returns carrier, line type, SIM-swap indicator, call-forwarding state. Cost: $0.0510.
tsblockrun_phone({ path: "phone/numbers/buy", body: { country: "US", areaCode: "415" } }) // returns { phoneNumber: "+14155550199", expires_at: "..." }
Best-effort area code match. Cost: $5.001 for 30 days.
ts// Step 0 (one-time): provision a number you'll use as caller ID const { phoneNumber: myNumber } = await blockrun_phone({ path: "phone/numbers/buy", body: { country: "US", areaCode: "415" } }) // $5.001, 30-day lease // Step 1: place the call (from is REQUIRED) const r = await blockrun_phone({ path: "voice/call", body: { to: "+14155550100", from: myNumber, task: "Call Dr. Wong's office. Confirm the appointment for Sarah Chen on Friday May 24th at 3pm. If the time isn't available, ask for the next opening on Friday afternoon and report back.", voice: "june", max_duration: 5, wait_for_greeting: true }}) // returns { call_id: "call_abc..." } — call runs async // Poll until done while (true) { const status = await blockrun_phone({ path: `voice/call/${r.call_id}` }) if (status.status === "completed") { console.log(status.summary, status.transcript) break } await new Promise(r => setTimeout(r, 5000)) }
Cost: $0.5410 flat for the call. Status polling is free.
tsconst { numbers } = await blockrun_phone({ path: "phone/numbers/list", body: {} }) // Release the oldest await blockrun_phone({ path: "phone/numbers/release", body: { phoneNumber: numbers[0].phoneNumber } })
wait_for_greeting: true for human-answered calls (most cases). Set to false for known-IVR / known-bot destinations to skip the greeting wait.max_duration is a hard cap — the call ends regardless of conversation state. Default 5 min covers most scripted tasks.from matters for trust — using a provisioned BlockRun number you own (from numbers/buy) makes the call look less spammy than a random caller ID.numbers/buy provisions a number but inbound routing is not exposed via MCP; use Bland directlyphone/lookup is cheap reconnaissance; phone/lookup/fraud is 5× the price but adds SIM-swap + call-forwarding signals you can't get from a basic carrier lookupcall_id; the call runs in the background. Always poll voice/call/{call_id} to get the transcriptPOST /v1/phone/*POST /v1/voice/call and GET /v1/voice/call/{call_id}| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 6,014 | 6,251 | +4% | 1 | 1 | 0% | 944 | 2,739 | +190% | 0 | 0 | — |
case-02 | fail→fail | 19,748 | 12,487 | -37% | 1 | 1 | 0% | 1,631 | 2,548 | +56% | 0 | 0 | — |
case-03 | fail→fail | 9,495 | 5,643 | -41% | 1 | 1 | 0% | 1,635 | 2,435 | +49% | 0 | 0 | — |
case-04 | fail→pass | 8,279 | 4,644 | -44% | 1 | 1 | 0% | 1,448 | 2,877 | +99% | 0 | 0 | — |
case-05 | fail→pass | 7,553 | 3,782 | -50% | 1 | 1 | 0% | 1,372 | 2,851 | +108% | 0 | 0 | — |
case-06 | fail→pass | 17,159 | 5,694 | -67% | 1 | 1 | 0% | 2,455 | 2,959 | +21% | 0 | 0 | — |
case-07 | pass→pass | 10,983 | 3,462 | -68% | 1 | 1 | 0% | 1,915 | 2,765 | +44% | 0 | 0 | — |
case-08 | fail→fail | 9,913 | 8,435 | -15% | 1 | 1 | 0% | 1,624 | 2,655 | +63% | 0 | 0 | — |
case-09 | fail→fail | 8,424 | 5,402 | -36% | 1 | 1 | 0% | 870 | 2,400 | +176% | 0 | 0 | — |
case-10 | fail→pass | 6,817 | 4,075 | -40% | 1 | 1 | 0% | 1,269 | 2,950 | +132% | 0 | 0 | — |
case-11 | fail→fail | 6,501 | 6,459 | -1% | 1 | 1 | 0% | 933 | 2,494 | +167% | 0 | 0 | — |
case-12 | fail→fail | 6,663 | 7,637 | +15% | 1 | 1 | 0% | 1,072 | 2,577 | +140% | 0 | 0 | — |
case-13 | fail→fail | 3,932 | 6,916 | +76% | 1 | 1 | 0% | 564 | 2,580 | +357% | 0 | 0 | — |
case-14 | fail→fail | 6,141 | 6,648 | +8% | 1 | 1 | 0% | 944 | 2,520 | +167% | 0 | 0 | — |
case-15 | fail→fail | 5,783 | 7,077 | +22% | 1 | 1 | 0% | 865 | 2,546 | +194% | 0 | 0 | — |
case-16 | fail→fail | 8,145 | 7,314 | -10% | 1 | 1 | 0% | 1,336 | 2,609 | +95% | 0 | 0 | — |
case-17 | pass→fail | 7,686 | 7,505 | -2% | 1 | 1 | 0% | 1,378 | 2,596 | +88% | 0 | 0 | — |
case-18 | fail→fail | 5,757 | 6,200 | +8% | 1 | 1 | 0% | 979 | 2,497 | +155% | 0 | 0 | — |
case-19 | pass→fail | 8,320 | 7,130 | -14% | 1 | 1 | 0% | 1,494 | 2,666 | +78% | 0 | 0 | — |
case-20 | fail→pass | 9,427 | 8,747 | -7% | 1 | 1 | 0% | 1,934 | 2,855 | +48% | 0 | 0 | — |
case-21 | fail→pass | 5,278 | 4,011 | -24% | 1 | 1 | 0% | 874 | 2,908 | +233% | 0 | 0 | — |
case-22 | fail→fail | 6,537 | 6,496 | -1% | 1 | 1 | 0% | 1,054 | 2,506 | +138% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 7 counted toward the lift figure. The other 15 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +18 percentage points is the difference between those two pass rates over the 7 comparable cases. 7 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.