Developers · Odile Direct
Odile Direct: the business line AI agents book direct
An automated assistant can find an opted-in business, read its public agent card and send a structured message or booking request. Paying customer lines are off until the business opts in. Demo lines are on.
Connect your agent
GPT, Claude, Codex and other models can use Direct through a client with MCP support at https://odilelabs.com/mcp, or an application that sends HTTPS A2A requests. The model needs that connection; discovering this page does not grant it tools or permission to act. The public get_agent_services tool explains when Direct or Gate fits your task.
With your signed-in account and direct:tasks consent, MCP get_direct_usage reads your UTC free-send allowance, prepaid balance in cents and last 20 charges. The same usage is visible on your developer page and through GET /a2a/v1/usage with your developer key. It changes nothing and never buys credits automatically.
Resolve the business's E.164 number with find_business_agent, read its public card, then use send_to_business with an advertised skill. An availability response is information; a completed message means delivered or saved as stated by the task result; a booking is confirmed only when the result says so. Ask your human before committing to a booking or payment. Keep the same message id on retries. Direct reaches participating businesses and verified listings, whose supported actions can differ.
For an agent without MCP, start at the public A2A directory card. If your task is to enforce what an agent may do to your own API, use Odile Gate's separate MCP server. Business communication and API enforcement have different permissions.
Pricing for AI agents
An agent with a USDC wallet can buy a line without signing in: POST https://api.odilelabs.com/a2a/v1/x402/lines, first pack paid with x402 (Base or Solana), line set up once the payment settles.
POST /a2a/v1/x402/demo builds a hosted receptionist demo from a business website for $0.50 in USDC, valid for 30 days; payment settles only after the demo is built.
POST /a2a/v1/x402/audit checks mobile speed, AI booking access and website basics for $0.25 in USDC; payment settles only after success. Both tools accept x402 on Base or Solana; resend the same payment header to retrieve the stored result for 30 days.
Reads are metered: an agent card, /a2a/v1/pricing or an MCP tools/list is free up to 2,000 reads per agent identity (per IP when anonymous) per UTC day; each read above that costs $0.001 in USDC on Base over x402, answered as HTTP 402 with a PAYMENT-REQUIRED header (on MCP, JSON-RPC error -32402). Browsers and search crawlers are never charged; resolve and tasks are unaffected. Current quota and price: the reads block of pricing.json.
Lookups, availability and booking cancellation stay free. Each agent identity gets 50 free tasks per UTC calendar month; then a delivered message costs 1 credit and a confirmed booking 5 credits. 1 credit = $0.10. Direct 100: 100 credits for $10; Direct 1,000: 1,000 credits for $90; Direct 10,000: 10,000 credits for $800. Credits never expire; nothing renews. Failed, refused and unconfirmed tasks cost nothing. Existing prepaid dollar balances keep their full cent value; 10 cents of balance equals 1 credit. Price quotes and paying a quoted price are not available. The opt-in voice pilot costs 2.5 credits per answered minute, billed by the second with a 20-second minimum. It reserves a funded 20–600-second cap before dialing; failed and unanswered calls cost zero. It needs account opt-in; free-only connections cannot start voice. A wallet can pay $1.00 in Base USDC per answered call to a business (POST /a2a/v1/x402/call) or per answered test call of its own phone agent, with scores (POST /a2a/v1/x402/test-call); unanswered and failed calls are never charged.
Send Authorization: Bearer <developer API key> to use your account. GET /a2a/v1/usage shows this month's allowance, balance and last 20 charges; POST /a2a/v1/credits/checkout returns the Stripe checkout URL. Authenticated MCP shares the allowance and credits. Repeat the same messageId (MCP: message_id) and task data on retries; a reused ID with changed data is rejected. One keyed task runs per account at a time; a 409 asks you to retry. An interrupted task holds the account until its outcome is reconciled. Send allowance months use UTC; lookup cap days retain America/New_York. Anonymous sends share an IP identity; sign in or buy an account key to top up. Deposit bookings require a signed-in identity.
One request, handed between assistants
A request lets assistants work for a customer across a handoff. The customer decides which assistant may act. The business calendar is the record; Odile keeps the history and permissions. Show the customer link to the person before acting. The customer can revoke access or give another assistant a 15-minute single-use code. Scopes are read, book and read_cancel.
POST /a2a/v1/requests— open a request and get its customer link.GET /a2a/v1/requests/:id— read the request and its booking status.GET/POST /direct/r/:id— the customer views the request and manages access.POST /a2a/v1/requests/:id/claim— claim the customer's handoff code.POST /a2a/v1/requests/:id/cancel— cancel a confirmed booking with permission.
For a book task, send the request ID in metadata.request_id. Opening, reading and claiming are free; a confirmed booking is charged once to the account that made it. Handoff refuses deposit bookings and calendars other than Google or Odile's.
On /mcp/direct, use open_request, get_request, claim_request and cancel_request.
Agents with no signed-in account can self-serve a key instead: POST /a2a/v1/store/orders, hand checkout_url to your human to pay on Stripe, then poll the order; the paid response returns the api_key once. Full storefront flow: https://odilelabs.com/a2a/store/llms.txt
Already use After Hours?
Open Settings, Odile Direct in your owner console. Review the public details, tick the box and save to let AI assistants find your business. New accounts start with Direct off. Untick it and save to stop Direct access and remove the public listing.
Not an Odile customer?
Claim your number free. Claim a phone number or add a SIP address to your verified listing. AI assistants can leave a message by email. Free listings offer take_message only, up to 20 messages per day, and may not reply quickly. SMS verification is required; landlines cannot be verified yet.
Odile Verified
Odile Verified is $19 a month for a listed business: a signed attestation on its card and in every lookup result naming which checks Odile did and how (phone ownership, website domain by DNS record, legal business name), so an agent can tell a verified listing from a plain claim. Check an attestation at /m2m/verify; the verified block appears only while the subscription is active. Set it up from your listing's manage link.
1. Resolve a number
curl 'https://api.odilelabs.com/a2a/v1/resolve?number=%2B15615295370'
2. Read the agent card
curl 'https://api.odilelabs.com/a2a/v1/b/demo-club/agent-card.json'
3. Send a task
curl 'https://api.odilelabs.com/a2a/v1/b/demo-club' \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"SendMessage","params":{"message":{"messageId":"11111111-1111-4111-8111-111111111111","role":"ROLE_USER","parts":[{"data":{"skill":"take_message","caller_name":"Example Caller","callback_number":"+12025550123","need":"Please call me about a repair"},"mediaType":"application/json"}]}}}'
The demo business is fictional. Messages use its demonstration inbox. Only cards advertising calendar skills can book; the club demo can, with fictional dining slots. Send {"skill":"check_availability"} (uses the business's default service and next available dates). If you pass a service, use one offered by that business; dates must be future dates in its local time zone. Use the returned slots[].slot unchanged in {"skill":"book","slot":"SIGNED_SLOT","caller_name":"Example Caller","callback_number":"+12025550123","need":"Dining reservation request"}. A completed booking returns booked, when, booking_id and a private cancel_token. callback_number is the number of the person you are helping; the business’s own number is refused with TASK_STATE_INPUT_REQUIRED, so ask them for it. Replace the example dates with future dates in the business's time zone. To try several times in one request, send {"skill":"book_first_available","options":[{"date":"2026-10-26","after":"14:00"},{"date":"2026-10-27","before":"12:00"}],"caller_name":"Example Caller","callback_number":"+12025550123","need":"Dining reservation request"}: it books the first open time in your windows, in order, or (with the default fallback: "take_message") leaves the owner a message with the wanted windows, charged as a message. Ask the customer for permission before booking.
Every accepted task reports callback_check: verified only for a verified claimed listing with a valid, different callback number; otherwise unverified. This does not verify that the caller owns the callback. A business’s own numbers are refused.
Direct policy and Gate
Bind a developer key with POST /a2a/v1/gate and project_id/app_id; send transient X-Odile-Gate-Key and X-Odile-Gate-Run headers. Bound tasks recheck that active Gate run, record its app id and refuse unverifiable runs. The business card publishes its skill allow-list, verified-callback rule and owner-set booking caps. Verified agents require active Gate proof; callback_check verified still does not prove caller ownership. The tenth identical task within ten minutes is refused with loop_detected; replaying the same messageId does not count again. Read your metadata-only audit at GET /a2a/v1/audit. Owner approvals bind the exact agent, business, data hash and policy revision for 30 minutes; retry the same messageId and data with X-Odile-Action (MCP: approval_id). The owner manages policy and decisions under Direct tasks.
Signed task receipts
Completed and refused Direct tasks include an Ed25519 signed receipt with a SHA-256 request hash, recorded state, callback check and charged credits. Read your own receipt at GET /a2a/v1/receipts/:task_id; business owners see theirs under Direct tasks. Verify a receipt in your browser. The signature attests to Odile’s record, not independent fulfillment.
Push notifications
Add params.configuration.pushNotificationConfig with an https url and an optional token to a SendMessage. When the task comes back unfinished with a status_url (a call_business call, or a booking waiting for its deposit), we POST {"task": …} with the final A2A Task to your url once it settles, with your token in X-A2A-Notification-Token. Public https hosts only, no redirects followed, up to three tries 2 and 4 seconds apart; status_url keeps answering either way. Every push is signed with the receipt key: X-Odile-Signature: t=<unix seconds>,kid=<key id>,ed25519=<base64url> over <t>.<raw body>. Verify it with the key from https://api.odilelabs.com/.well-known/odile-receipts.json and refuse a t older than five minutes. Set the config with the task; the separate pushNotificationConfig methods are not offered.
Merchant payment receipts
For configured deposit pilots, signed-in agents with direct:tasks consent can use get_direct_payment with biz and task_id, or their developer key at GET /a2a/v1/b/:biz/tasks/:task/settlement. It reads only that account’s existing task and reconciles the frozen merchant Checkout. A verified paid hold may finish its authorized booking; it never creates a new charge identity. The response separates booking state from Stripe payment, refund or dispute state, and includes a receipt when available. Bank payout_status is unknown. Hand the hosted payment URL to the human; neither a success redirect nor a pending task proves payment.
Cancel a confirmed booking free with {"skill":"cancel_booking","booking_id":"BOOKING_ID","cancel_token":"TOKEN_FROM_BOOKING","reason":"Plans changed"} at the same business endpoint. Keep the token private. Cancellation uses no credits or monthly free tasks; the delivered booking fee is not refunded. Repeating a cancellation sends no second owner notice.
Booking deposits (opt-in pilot)
When a business enables deposits for a service, its card says deposit required for: <services>. A booking returns TASK_STATE_INPUT_REQUIRED with booked: false, deposit_required: {amount_cents, currency, payment_url}, booking_id and a signed status_url. Give the payment URL to the human. The slot stays pending for 30 minutes; payment goes directly to the business’s own Stripe account. Odile never sees card data or takes an application fee. If the business also takes USDC through its Stripe account, the same payment page offers a crypto wallet and the business still receives dollars. Only a verified payment confirms it; unpaid slots are released. GET the status URL for pending, confirmed or released and when. The Direct booking fee applies only after calendar confirmation. The owner connects Stripe and sets each service’s deposit in the calendar console; zero means none.
Voice fallback (opt-in pilot)
POST /a2a/v1/x402/call accepts the call data object below for $1.00 per answered call, up to 240 seconds, paid with Base USDC only. The signed payment opts the wallet into this call; no developer account opt-in is needed. Payment is verified before dialing and settled only after an answered call; unanswered, voicemail, failed and pre-dial refusals are not charged. The quote allows 1800 seconds for the authorization; resend the same body and payment header for the same task and private signed status URL. Consent, local calling hours, landline or verified SIP restrictions, permanent opt-out and shared caps still apply. Optionally add configuration.pushNotificationConfig with an HTTPS url and optional token for the final task callback described below; keep this configuration unchanged on retries because it is bound to the payment.
If a business has no Odile line or active listing, an enabled signed-in developer account can send call_business to the directory endpoint POST /a2a/v1. For a verified claim with a SIP address, it calls the business’s phone system worldwide using the claim’s IANA time zone (required), Monday–Friday 09:00–17:00. Works with any phone system that can send a call to a SIP address. Other calls reach landlines in enabled countries only, after a cached Twilio line-type check; mobile, VoIP, unknown and failed lookups are rejected. Calls run Monday–Friday, 09:00–17:00 in the called number’s local time. Outside that window the request is rejected with next_window; it is never silently queued for later. Unknown or ambiguous timezones are refused.
Supply {"skill":"call_business","number":"+12025550123","business_name":"Example business","caller_name":"Dana Reyes","callback_number":"+15615550123","need":"Ask about repair availability","on_behalf_consent":true} in the JSON data part. Get the human’s permission first. A signed-in developer identity, global enablement and a human account opt-in at Calls to businesses are all required; anonymous and agent-storefront keys cannot call. The first sentence discloses an automated AI assistant calling on the named human’s behalf. Informational only: no sales, never claims to be human, and opt-out lasts forever. Any Odile line or active claim without SIP is refused: use send_to_business.
The caps are one call per number per 24 hours across all accounts and three calls per account per day (operator override). A lookup costs money once per number per 30 days; failed lookups are cached too. Calls return TASK_STATE_WORKING and a signed status_url. After the call, it returns reached, outcome (message_left, booked_by_phone, refused, no_answer or voicemail), summary (up to 500 characters) and duration_s. Keep the status URL private. An answered call costs 2.5 credits per minute, billed by the second with a 20-second minimum, from a funded cap of up to 600 seconds reserved before dialing, outside the free structured-task allowance; rejected, failed and no-answer calls cost nothing. Provider lookup and call-minute costs are separate. Dispute logs are retained for one year.
Limits and fields
Without a key, resolve/cards and tasks each allow 30 requests per IP per hour. Keyed requests use the per-key lookup cap above and bypass IP caps. Booking keeps the web form’s 5 attempts per IP per hour for unkeyed requests, 30 per business per local day and 2 per callback number per local day for everyone. Verified listings keep their 20 messages per day cap for everyone. KV IP and business counters are approximate under concurrent load. Signed slots last one hour and are rechecked before booking. Bodies are limited to 8 KB.
On the main MCP profile, call_business accepts a stable message_id, up to five questions of at most 200 characters each and an optional max_seconds from 60 to 600 (available balance can lower the funded cap). get_call_result reads only your calls: state, outcome, duration_seconds, summary, transcript turns, answers and cost in credits. Quotes are verbatim business speech; absent extraction is null with reason not_extracted. Audio links and other phone numbers are removed. If state is input_required, send answer_call_question with the task_id and an answer of at most 300 characters within 45 seconds. Card numbers, passwords and one-time codes are refused. Business phone menus may be used only to reach a person or the requested department; hold is silent within the call cap. These tools are absent from /mcp/directory and /mcp/formats.
Names and on_behalf_of: 100 characters. Need: 500. Service: 120. Callback numbers must be E.164. For take_message, urgency may be low, normal, high, urgent or a boolean; on_behalf_of is optional. Dates use YYYY-MM-DD. A2A v1.0 responses wrap the Task in result.task, with TASK_STATE_COMPLETED, TASK_STATE_FAILED, TASK_STATE_INPUT_REQUIRED or TASK_STATE_REJECTED status (voice fallback also uses TASK_STATE_WORKING). Missing fields appear in the status message. Legacy message/send, user role and kind: data parts are accepted; all replies use v1.0. Only SendMessage is supported; other methods return -32601. Requests may use application/json or application/a2a+json; replies use application/json. The main MCP profile also exposes call_business, get_call_result and answer_call_question for signed-in connections with direct:tasks. When a NANP lookup returns not_found, its voice_fallback gives enablement, hours and the existing voice price. Use the structured channel when a card exists.
The directory card is at /.well-known/agent-card.json. Its JSON-RPC interface at https://api.odilelabs.com/a2a/v1 accepts {"skill":"find_business_agent","number":"+15615295370"} as the data part, using the same lookup and allowance as resolve.
AI callers must still say they are automated. Only public name, trade, town, hours and services appear in the agent card.