Phone & Voice API
AI-powered outbound voice calls (Bland.ai) and wallet-owned phone numbers (Twilio). Make conversational AI calls with real-time transcripts, buy/manage dedicated US/CA numbers, and perform carrier/fraud lookups. Outbound only, no SMS.
Base URL: https://api.jarvisclaw.ai/v1/marketplace/phone
Pricing
| Endpoint | Price | Description |
|---|---|---|
POST /voice/call | $0.54/call | Initiate AI voice call |
GET /voice/call/:call_id | Free | Retrieve call status/transcript |
POST /lookup | $0.01/request | Carrier identification |
POST /lookup/fraud | $0.05/request | Fraud risk assessment |
POST /numbers/buy | $5.00/number | Lease a phone number (30-day) |
POST /numbers/list | $0.001/request | List owned numbers |
Endpoints
POST /voice/call
Initiate an outbound AI voice call. The AI agent handles the conversation using the provided task/system prompt. Powered by Bland.ai.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
to | string | Yes | Destination phone number (E.164 format, e.g., +14155551234) |
from | string | No | Caller ID — must be a leased number from /numbers/buy |
task | string | Yes | Instructions for the AI voice agent (system prompt) |
voice | string | No | Voice preset. Default: nova |
max_duration | integer | No | Max call duration in seconds. Default: 1800 (30 min) |
webhook_url | string | No | URL for real-time call status events |
first_sentence | string | No | Override the AI's opening line |
wait_for_greeting | boolean | No | Wait for callee to speak first. Default: true |
Request Example
{
"to": "+14155551234",
"from": "+14155559876",
"task": "You are an appointment reminder assistant. Confirm the user's dental appointment for Tuesday June 17 at 2 PM. Be polite and concise.",
"voice": "nova",
"max_duration": 120,
"first_sentence": "Hi, this is a reminder call from Dr. Smith's office.",
"wait_for_greeting": true
}Response Example
{
"call_id": "call_abc123def456",
"status": "initiated",
"to": "+14155551234",
"from": "+14155559876",
"created_at": "2025-06-13T12:00:00Z"
}GET /voice/call/:call_id
Retrieve the full transcript, status, and metadata for a call.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
call_id | string | Yes | Call ID (path parameter) |
Response Example
{
"call_id": "call_abc123def456",
"status": "completed",
"duration_seconds": 45,
"to": "+14155551234",
"from": "+14155559876",
"transcript": [
{"role": "assistant", "content": "Hi, this is a reminder call from Dr. Smith's office."},
{"role": "user", "content": "Yes, hello?"},
{"role": "assistant", "content": "I'm calling to confirm your dental appointment for Tuesday June 17 at 2 PM. Can you confirm you'll be there?"},
{"role": "user", "content": "Yes, I'll be there. Thank you."},
{"role": "assistant", "content": "Great, you're all set. Have a wonderful day!"}
],
"summary": "User confirmed dental appointment for Tuesday June 17 at 2 PM.",
"created_at": "2025-06-13T12:00:00Z",
"ended_at": "2025-06-13T12:00:45Z"
}Call statuses: initiated, ringing, in_progress, completed, failed, no_answer, busy
POST /lookup
Identify the carrier and line type for a phone number.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
phoneNumber | string | Yes | Phone number in E.164 format |
Request Example
{
"phoneNumber": "+14155551234"
}Response Example
{
"phoneNumber": "+14155551234",
"carrier": "T-Mobile",
"line_type": "mobile",
"country": "US",
"country_code": "1"
}POST /lookup/fraud
Assess fraud risk and identify suspicious indicators for a phone number.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
phoneNumber | string | Yes | Phone number in E.164 format |
Request Example
{
"phoneNumber": "+14155551234"
}Response Example
{
"phoneNumber": "+14155551234",
"risk_score": 15,
"risk_level": "low",
"flags": [],
"carrier": "T-Mobile",
"line_type": "mobile",
"is_voip": false,
"is_prepaid": false
}Risk levels: low (0-25), medium (26-50), high (51-75), critical (76-100)
POST /numbers/buy
Lease a dedicated phone number for use as a caller ID on outbound calls.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
country | string | Yes | ISO country code (US or CA) |
area_code | string | No | Preferred area code (e.g., 415) |
Request Example
{
"country": "US",
"area_code": "415"
}Response Example
{
"number": "+14155559876",
"country": "US",
"capabilities": ["voice"],
"monthly_cost": 5.00,
"lease_start": "2025-06-13T12:00:00Z",
"expires_at": "2025-07-13T12:00:00Z"
}POST /numbers/list
List all phone numbers currently leased to your account.
Request Example
{}Response Example
{
"numbers": [
{
"number": "+14155559876",
"country": "US",
"capabilities": ["voice"],
"monthly_cost": 5.00,
"lease_start": "2025-06-01T12:00:00Z",
"expires_at": "2025-07-01T12:00:00Z",
"status": "active"
}
],
"total": 1
}Errors
| HTTP Code | Error Code | Description |
|---|---|---|
| 400 | invalid_phone_number | Phone number is not valid E.164 format |
| 404 | number_not_owned | The from number is not leased to your account |
| 404 | call_not_found | No call found with the specified call_id |
| 409 | number_unavailable | Requested number or area code has no availability |
| 500 | call_failed | Voice call could not be connected (carrier/network issue) |
Error Response Format
{
"error": {
"code": "invalid_phone_number",
"message": "The phone number '+1415555' is not valid E.164 format. Expected format: +14155551234"
}
}Code Examples
# Initiate a voice call
curl -X POST https://api.jarvisclaw.ai/v1/marketplace/phone/voice/call \
-H "Authorization: Bearer sk-your-api-key" \
-H "Content-Type: application/json" \
-d '{
"to": "+14155551234",
"task": "You are a friendly appointment reminder. Confirm the dental appointment for Tuesday at 2 PM.",
"voice": "nova",
"max_duration": 120
}'
# Get call transcript
curl https://api.jarvisclaw.ai/v1/marketplace/phone/voice/call/call_abc123def456 \
-H "Authorization: Bearer sk-your-api-key"
# Carrier lookup
curl -X POST https://api.jarvisclaw.ai/v1/marketplace/phone/lookup \
-H "Authorization: Bearer sk-your-api-key" \
-H "Content-Type: application/json" \
-d '{"phoneNumber": "+14155551234"}'
# Fraud risk check
curl -X POST https://api.jarvisclaw.ai/v1/marketplace/phone/lookup/fraud \
-H "Authorization: Bearer sk-your-api-key" \
-H "Content-Type: application/json" \
-d '{"phoneNumber": "+14155551234"}'
# Buy a phone number
curl -X POST https://api.jarvisclaw.ai/v1/marketplace/phone/numbers/buy \
-H "Authorization: Bearer sk-your-api-key" \
-H "Content-Type: application/json" \
-d '{"country": "US", "area_code": "415"}'
# List owned numbers
curl -X POST https://api.jarvisclaw.ai/v1/marketplace/phone/numbers/list \
-H "Authorization: Bearer sk-your-api-key" \
-H "Content-Type: application/json" \
-d '{}'import requests
BASE = "https://api.jarvisclaw.ai/v1/marketplace/phone"
HEADERS = {
"Authorization": "Bearer sk-your-api-key",
"Content-Type": "application/json",
}
# Initiate an AI voice call
resp = requests.post(f"{BASE}/voice/call", headers=HEADERS, json={
"to": "+14155551234",
"task": "You are an appointment reminder assistant. Confirm the dental appointment for Tuesday at 2 PM.",
"voice": "nova",
"max_duration": 120,
})
call = resp.json()
print(f"Call initiated: {call['call_id']}")
# Get transcript after call completes
resp = requests.get(
f"{BASE}/voice/call/{call['call_id']}",
headers={"Authorization": "Bearer sk-your-api-key"},
)
transcript = resp.json()
print(f"Status: {transcript['status']}, Duration: {transcript['duration_seconds']}s")
for turn in transcript["transcript"]:
print(f" {turn['role']}: {turn['content']}")
# Carrier lookup
resp = requests.post(f"{BASE}/lookup", headers=HEADERS, json={
"phoneNumber": "+14155551234",
})
info = resp.json()
print(f"Carrier: {info['carrier']}, Type: {info['line_type']}")
# Fraud risk assessment
resp = requests.post(f"{BASE}/lookup/fraud", headers=HEADERS, json={
"phoneNumber": "+14155551234",
})
risk = resp.json()
print(f"Risk: {risk['risk_level']} (score: {risk['risk_score']})")
# Buy a number
resp = requests.post(f"{BASE}/numbers/buy", headers=HEADERS, json={
"country": "US",
"area_code": "415",
})
print(f"Leased: {resp.json()['number']}")
# List owned numbers
resp = requests.post(f"{BASE}/numbers/list", headers=HEADERS, json={})
for num in resp.json()["numbers"]:
print(f" {num['number']} — expires {num['expires_at']}")from jarvisclaw import PhoneClient
# x402 Agent wallet — pays per-call via USDC
# Base chain (EVM)
phone = PhoneClient(private_key="0x<evm-private-key>")
# Or Solana
# phone = PhoneClient(private_key="<solana-bs58-keypair>")
# Initiate an AI voice call
call = phone.voice_call(
to="+14155551234",
task="You are an appointment reminder assistant. Confirm the dental appointment for Tuesday at 2 PM.",
voice="nova",
max_duration=120,
)
print(f"Call initiated: {call.call_id}")
# Get transcript
transcript = phone.get_call(call.call_id)
print(f"Status: {transcript.status}, Duration: {transcript.duration_seconds}s")
for turn in transcript.transcript:
print(f" {turn['role']}: {turn['content']}")
# Carrier lookup
info = phone.lookup("+14155551234")
print(f"Carrier: {info.carrier}, Type: {info.line_type}")
# Fraud risk assessment
risk = phone.lookup_fraud("+14155551234")
print(f"Risk: {risk.risk_level} (score: {risk.risk_score})")
# Buy a number
number = phone.buy_number(country="US", area_code="415")
print(f"Leased: {number.number}")
# List owned numbers
numbers = phone.list_numbers()
for num in numbers:
print(f" {num.number} — expires {num.expires_at}")package main
import (
"context"
"fmt"
jc "github.com/api-jarvisclaw/go-sdk"
)
func main() {
ctx := context.Background()
phone, _ := jc.NewPhoneClient(jc.WithAPIKey("sk-your-api-key"))
// Initiate an AI voice call
call, _ := phone.VoiceCall(ctx, &jc.VoiceCallRequest{
To: "+14155551234",
Task: "You are an appointment reminder. Confirm dental appointment Tuesday at 2 PM.",
Voice: "nova",
MaxDuration: 120,
})
fmt.Printf("Call initiated: %s\n", call.CallID)
// Get transcript
transcript, _ := phone.GetCall(ctx, call.CallID)
fmt.Printf("Status: %s, Duration: %ds\n", transcript.Status, transcript.DurationSeconds)
for _, turn := range transcript.Transcript {
fmt.Printf(" %s: %s\n", turn.Role, turn.Content)
}
// Carrier lookup
info, _ := phone.Lookup(ctx, "+14155551234")
fmt.Printf("Carrier: %s, Type: %s\n", info.Carrier, info.LineType)
// Fraud risk assessment
risk, _ := phone.LookupFraud(ctx, "+14155551234")
fmt.Printf("Risk: %s (score: %d)\n", risk.RiskLevel, risk.RiskScore)
// Buy a number
number, _ := phone.BuyNumber(ctx, &jc.BuyNumberRequest{
Country: "US",
AreaCode: "415",
})
fmt.Printf("Leased: %s\n", number.Number)
// List owned numbers
numbers, _ := phone.ListNumbers(ctx)
for _, num := range numbers {
fmt.Printf(" %s — expires %s\n", num.Number, num.ExpiresAt)
}
}package main
import (
"context"
"fmt"
jc "github.com/api-jarvisclaw/go-sdk"
)
func main() {
ctx := context.Background()
// x402 Agent wallet — pays per-call via USDC on Base
phone, _ := jc.NewPhoneClient(jc.WithPrivateKey("0x<evm-private-key>"))
// Initiate an AI voice call
call, _ := phone.VoiceCall(ctx, &jc.VoiceCallRequest{
To: "+14155551234",
Task: "You are an appointment reminder. Confirm dental appointment Tuesday at 2 PM.",
Voice: "nova",
MaxDuration: 120,
})
fmt.Printf("Call initiated: %s\n", call.CallID)
// Get transcript
transcript, _ := phone.GetCall(ctx, call.CallID)
fmt.Printf("Status: %s, Duration: %ds\n", transcript.Status, transcript.DurationSeconds)
// Carrier lookup
info, _ := phone.Lookup(ctx, "+14155551234")
fmt.Printf("Carrier: %s, Type: %s\n", info.Carrier, info.LineType)
// Fraud risk assessment
risk, _ := phone.LookupFraud(ctx, "+14155551234")
fmt.Printf("Risk: %s (score: %d)\n", risk.RiskLevel, risk.RiskScore)
// Buy a number
number, _ := phone.BuyNumber(ctx, &jc.BuyNumberRequest{
Country: "US",
AreaCode: "415",
})
fmt.Printf("Leased: %s\n", number.Number)
}Limitations
- Outbound only — inbound call handling and receiving calls is not supported
- No SMS — phone numbers are voice-only, SMS is not available
- 30-minute max call duration — calls are automatically terminated at 1800 seconds
- US/CA default — numbers outside US and Canada require KYC verification
- English only — voice AI currently supports English language conversations only
- 30-day lease — phone numbers auto-renew monthly unless cancelled
- E.164 format required — all phone numbers must include country code (e.g.,
+14155551234) - Caller ID — the
fromfield must be a number you've leased, or it will be omitted (calls show as unknown)