DEV Community

Tolga Coskun
Tolga Coskun

Posted on Fully Autonomous

How an AI agent reaches a real business by its phone number

Your agent can search the web, write code and fill forms. Ask it to leave a message for the plumber down the road and it stops: most small businesses have no API. What they all have is a phone number.

Odile Direct makes that number addressable. An agent looks a business up by its number, reads what that business accepts, and leaves a message or books an open slot. The business gets it as a text or an email, with the person's callback number.

Try it in one line (no key, no card)

curl -fsS https://odilelabs.com/m2m-quickstart.sh | sh
Enter fullscreen mode Exit fullscreen mode

It runs four tasks against a fictional demo business with an in-memory inbox and calendar: find it, check open times, book the first available slot, leave a message. Nobody is contacted and nothing is charged. Output:

find_business_agent: task_id=... state=TASK_STATE_COMPLETED callback_check=unverified
check_availability: task_id=... state=TASK_STATE_COMPLETED callback_check=unverified
book_first_available: task_id=... state=TASK_STATE_COMPLETED callback_check=unverified
take_message: task_id=... state=TASK_STATE_COMPLETED callback_check=unverified
Enter fullscreen mode Exit fullscreen mode

Step 1: look the number up

Lookups are free (30 an hour per IP without a key):

curl -s "https://api.odilelabs.com/a2a/v1/resolve?number=%2B15613752995"
Enter fullscreen mode Exit fullscreen mode
{"agent_card": "https://api.odilelabs.com/a2a/v1/b/odile-labs/agent-card.json",
 "business": "Odile Labs", "trade": "AI receptionist and AI agent tools", "town": "West Palm Beach, Florida"}
Enter fullscreen mode Exit fullscreen mode

A number that isn't on the network returns nothing. A phone number alone does not mean a business takes part; your agent should say so and stop, not guess.

Step 2: read the card, then act

The agent card lists the skills that business accepts (take_message, check_availability, book, book_first_available). Use only what the card lists. From an MCP client the same flow is two tools on the hosted server https://odilelabs.com/mcp: find_business_agent, then send_to_business.

Step 3: read the result, not the HTTP status

A 200 is not a delivered message. Read task.status.state: only TASK_STATE_COMPLETED is done, and a booking is confirmed only when the result says booked: true with a booking id. The sending agent can fetch a signed receipt for each task at /a2a/v1/receipts/{task_id} and check it at odilelabs.com/m2m/verify.

callback_check: verified means the listing is verified and the callback number is valid and distinct from the business. It does not prove who owns the caller's number.

The rules your agent must follow

  • Ask the person before every send, and show them what will be shared.
  • Say it is an automated assistant writing for the person. Never imply a human.
  • Use the person's own callback number, never the business's.
  • On a timeout, don't retry on your own; reuse the same message_id if the person retries.

What it costs

Lookups and availability checks are free. Each agent gets 50 free tasks a month. After that a message is 1 credit and a booking 5; credits are 10 cents (100 for $10, 1,000 for $90), sold as one-time packs; nothing renews. Live prices are machine-readable at https://api.odilelabs.com/a2a/v1/pricing. When the free tasks run out, the 402 answer lists the packs and the exact checkout call; a person approves the Stripe payment, nothing is charged without that.

Not available yet, and the API says so: quotes, payment settlement, and agent-to-agent voice.

For businesses

Any business can claim its number for free at odilelabs.com/direct/claim, or by calling (561) 375-2995 and asking Odile to claim the number it is calling from (a six-digit code is texted to that number), and choose whether to appear in the public directory. Messages arrive by email; businesses with a calendar-enabled line can also take bookings.

Docs and OpenAPI: https://odilelabs.com/m2m

Top comments (1)

Collapse
 
tercelyi profile image
tercel •

The interesting line for me is your output example with callback_check=unverified on all four tasks. That alone implies a client can’t safely assume the caller identity is tied to the number they provided, even when the task is TASK_STATE_COMPLETED. It pushes the agent to reason about two things separately: “did the task finish?” vs “how much can I trust the callback data?”.

A few things I’m curious about / would want to check from an integration point of view:

  • If callback_check flips to verified, is that strictly a phone ownership check (SMS code, call-back) or something else?
  • Do you expose any machine-readable policy hints in the agent card like “only accept verified callbacks”, or is that up to the consuming agent to enforce?
  • For multi-tenant agents: is there a rate or quota signal in the lookup response so they can preemptively throttle before hitting the “30/hour per IP” wall?

Also, the distinction you draw in Step 3 matters a lot in practice: 200 vs TASK_STATE_COMPLETED vs booked: true. This is very much in line with how async job queues work, but people are used to webhooks, not polling receipts. Have you seen agents actually fetch /receipts/{task_id} and verify signatures yet, or is that still aspirational?

Either way, “phone number as agent address” plus the explicit rules section feels like a clean mental model to bolt onto existing MCP clients.