{"version":"1.0","service":"agent-broker","tools":[{"name":"find_business","description":"Given criteria (vertical, location, capability, price band, availability window), return ranked candidate SMBs from the verified supply network. Returns only curated, verified, transactable businesses — not raw directory results. Use when: Use when an agent needs to identify which SMBs can fulfill a business task (booking, service, consultation) in a given location and vertical. Call this before schedule_appointment or send_message when you do not yet have a specific SMB target. Do NOT use when: Do not use as a general directory or browsing surface. Do not use when you already have a specific verified SMB identifier. Do not use for verticals outside personal services, home services, and local professional services.","input_schema":{"type":"object","required":["vertical","location"],"properties":{"vertical":{"type":"string","enum":["personal_services","home_services","professional_services"],"description":"Service vertical to search within"},"location":{"type":"object","required":["zip_or_city"],"properties":{"zip_or_city":{"type":"string"},"radius_miles":{"type":"number","default":10}}},"capability":{"type":"string","description":"Specific service capability required, e.g. 'haircut', 'plumbing', 'tax_consultation'"},"price_band":{"type":"object","properties":{"max_usd":{"type":"number"}}},"availability_window":{"type":"object","properties":{"start_iso":{"type":"string","format":"date-time"},"end_iso":{"type":"string","format":"date-time"}}},"max_results":{"type":"integer","default":5,"maximum":20}}}},{"name":"verify_business","description":"Confirm that an SMB is real, currently operating, and capable of the requested service. Performs a live capability probe against the business's channel. Use when: Use before sending communications or scheduling if you have an unverified SMB identifier, or if the agent's task requires confirmed capability (e.g., 'I need to be sure they do emergency plumbing'). Do NOT use when: Do not use if the SMB was returned from find_business within the last 24 hours — those results are already verified.","input_schema":{"type":"object","required":["smb_id"],"properties":{"smb_id":{"type":"string"},"capability_to_verify":{"type":"string"}}}},{"name":"send_message","description":"Send a message on behalf of an agent's user or an SMB across SMS, email, or voice. Five message types: transactional, reminder, follow_up, notification, marketing. Every send routes through a non-bypassable compliance gate (TCPA, GDPR, CASL, PDPL across 22 jurisdictions) that enforces opt-in consent for marketing/promotional content — marketing without recorded consent is rejected at runtime with a structured compliance_violation receipt. Channel is abstracted: specify intent and recipient; the service selects and falls back across channels. Use when: Use to: (a) confirm a booking the agent just made, (b) reply to a customer who messaged the SMB first, (c) follow up on a quote the user requested, (d) send appointment reminders the SMB owes its customer, (e) send marketing messages to recipients who have opted in (with consent_record_id). The gate verifies consent on every send. Do NOT use when: Do NOT use for OTPs or critical transactional confirmations — use send_transactional_confirmation. Do NOT attempt to send marketing without a consent_record_id pointing at a real opt-in — the gate will reject the send and log a compliance_violation. Do NOT attempt bulk / list-based / drip / cold outreach — those are out of scope and the rate limiter will throttle abuse. Execution: sync_fast — returns pending_async.","input_schema":{"type":"object","required":["recipient","message_type","content"],"properties":{"recipient":{"type":"object","required":["id_type","id_value"],"properties":{"id_type":{"type":"string","enum":["phone","email","smb_id","customer_id"]},"id_value":{"type":"string"},"country_code":{"type":"string","description":"ISO 3166-1 alpha-2, required for compliance routing"}}},"message_type":{"type":"string","description":"Intent tag for the message. Five permitted types. 'marketing' is allowed only when paired with a valid consent_record_id; the compliance gate verifies the consent at send time and rejects (compliance_violation receipt) if it's missing, expired, or revoked.","enum":["transactional","marketing","reminder","follow_up","notification"]},"content":{"type":"object","required":["body"],"properties":{"body":{"type":"string"},"subject":{"type":"string","description":"For email channel"},"template_id":{"type":"string"},"template_vars":{"type":"object"}}},"preferred_channel":{"type":"string","enum":["sms","email","voice","auto"],"default":"auto"},"send_at_iso":{"type":"string","format":"date-time","description":"Schedule for future delivery; omit for immediate"}}}},{"name":"capture_lead","description":"Structured intake of a prospect into an SMB's funnel with validation, enrichment hooks, and deduplication. Inserts into the SMB's CRM or direct-booking pipeline if available. Use when: Use when a potential customer has expressed interest in an SMB's service and you want to ensure they are registered in the SMB's pipeline for follow-up. Do NOT use when: Do not use for confirmed bookings — use schedule_appointment. Do not use for bulk list imports. Execution: sync_fast — returns pending_async.","input_schema":{"type":"object","required":["smb_id","prospect"],"properties":{"smb_id":{"type":"string"},"prospect":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"phone":{"type":"string"},"email":{"type":"string","format":"email"},"service_interest":{"type":"string"},"notes":{"type":"string"},"consent_record_id":{"type":"string","description":"Optional ID of a consent record proving the prospect asked to be contacted (e.g., they filled an SMB's intake form or requested a quote). Required when downstream send_message calls are anticipated."}}},"source":{"type":"string","description":"Where the consumer-initiated request originated (e.g., 'consumer_request', 'inbound_quote_form', 'agent_referral_from_find_business')."}}}},{"name":"schedule_appointment","description":"Availability lookup, hold, confirm, reschedule, or cancel appointments with an SMB. Routes through the SMB's native booking system if available, falls back to voice AI or web form. Use when: Use when an agent needs to book, reschedule, or cancel a specific appointment with a specific SMB. Requires a verified smb_id. Do NOT use when: Do not use for bulk scheduling. Do not use without a verified SMB — call find_business and verify_business first if needed. Execution: async_by_default — returns pending_async.","input_schema":{"type":"object","required":["smb_id","action"],"properties":{"smb_id":{"type":"string"},"action":{"type":"string","enum":["book","reschedule","cancel","check_availability"]},"service":{"type":"string"},"customer":{"type":"object","properties":{"name":{"type":"string"},"phone":{"type":"string"},"email":{"type":"string"}}},"requested_time":{"type":"object","properties":{"preferred_iso":{"type":"string","format":"date-time"},"window_start_iso":{"type":"string","format":"date-time"},"window_end_iso":{"type":"string","format":"date-time"},"duration_minutes":{"type":"integer"}}},"existing_appointment_id":{"type":"string","description":"Required for reschedule/cancel"},"notes":{"type":"string"}}}},{"name":"send_transactional_confirmation","description":"Idempotent transactional messages: OTPs, booking confirmations, payment receipts, cancellation notices. Guaranteed delivery via redundant channels. Use when: Use for any message that MUST be delivered reliably — OTPs, booking confirmations, receipts. Do not use for marketing. Do NOT use when: Do not use for marketing or promotional messages. Do not use for conversational messages. Execution: sync_fast — returns pending_async.","input_schema":{"type":"object","required":["recipient","confirmation_type","data"],"properties":{"recipient":{"type":"object","required":["phone_or_email"],"properties":{"phone_or_email":{"type":"string"},"name":{"type":"string"}}},"confirmation_type":{"type":"string","enum":["otp","booking_confirmation","payment_receipt","cancellation_notice","reminder"]},"data":{"type":"object","description":"Type-specific payload; e.g., {otp_code} for otp, {appointment_time, smb_name} for booking_confirmation"},"preferred_channel":{"type":"string","enum":["sms","email","auto"],"default":"sms"}}}},{"name":"handle_inbound","description":"Receive, classify, and route inbound messages on behalf of an SMB. Classifies intent (booking request, cancellation, inquiry, complaint), enriches with context, and routes to the appropriate handler or escalation path. Use when: Use when an SMB needs inbound message triage — classifying incoming contact-form submissions, SMS replies, voicemails, or email inquiries. Do NOT use when: Do not use for outbound communications. Do not use for compliance-flagged recipient lists without verified opt-in records. Execution: async_by_default — returns pending_async.","input_schema":{"type":"object","required":["smb_id","inbound_channel","raw_message"],"properties":{"smb_id":{"type":"string"},"inbound_channel":{"type":"string","enum":["sms","email","voice_voicemail","web_form","api"]},"sender":{"type":"object","properties":{"phone":{"type":"string"},"email":{"type":"string"},"name":{"type":"string"}}},"raw_message":{"type":"string"},"received_at_iso":{"type":"string","format":"date-time"},"routing_rules":{"type":"object","description":"Optional override routing policy for this SMB"}}}},{"name":"escalate_to_human","description":"Hand off an in-flight task to a human operator with a full context bundle: transcript, prior actions, identifiers, and a recommended next step. Use when: Use when automated resolution has failed after channel-fallback exhaustion, when the task requires human judgment, or when the customer has explicitly requested human contact. Do NOT use when: Do not use as a first resort. Escalate only after automated resolution attempts. Execution: async_by_default — returns pending_async.","input_schema":{"type":"object","required":["smb_id","reason","context"],"properties":{"smb_id":{"type":"string"},"reason":{"type":"string","enum":["automation_failed","customer_requested","compliance_hold","ambiguous_intent","exception_required"]},"context":{"type":"object","properties":{"original_operation":{"type":"string"},"operation_id":{"type":"string"},"transcript":{"type":"array","items":{"type":"object"}},"prior_actions":{"type":"array","items":{"type":"object"}},"recommended_next_step":{"type":"string"}}},"priority":{"type":"string","enum":["normal","urgent"],"default":"normal"}}}},{"name":"get_status","description":"Query the current state of any in-flight async operation by operation_id. Use when: Use to poll the state of a pending_async operation when no webhook callback has arrived or to check progress. Do NOT use when: Do not poll more frequently than once per 10 seconds — use webhook delivery for real-time updates instead.","input_schema":{"type":"object","required":["operation_id"],"properties":{"operation_id":{"type":"string"}}}},{"name":"get_outcome","description":"Retrieve the final OutcomeReceipt for a completed operation. Use when: Use after get_status returns success/failure/partial to retrieve the full result with cost and reason codes. Do NOT use when: Do not use for operations still in pending/executing state — use get_status first.","input_schema":{"type":"object","required":["operation_id"],"properties":{"operation_id":{"type":"string"}}}},{"name":"preview_cost","description":"Return an expected cost estimate, latency estimate, and success-probability estimate for a proposed call before execution. Accuracy SLO: actual cost within ±5% of preview. Use when: Use before any operation when the agent is operating under a budget constraint and needs to decide whether to proceed. Do NOT use when: Do not use in a hot loop — cache the result for at least 60 seconds if repeating the same preview.","input_schema":{"type":"object","required":["operation","params"],"properties":{"operation":{"type":"string"},"params":{"type":"object","description":"The same request body you would pass to the operation"}}}},{"name":"self_test","description":"Live capability probe that verifies the service is healthy, each claimed operation is reachable, and supply network size is current. Use to verify integration before production use. Use when: Use at agent startup, before high-stakes task sequences, or after receiving unexpected errors to check if the service is degraded. Do NOT use when: Do not call more than once per minute in production.","input_schema":{"type":"object","properties":{}}},{"name":"import_booking_url","description":"Turn ANY public booking URL (Cal.com, Calendly, Doctolib, Booksy, Fresha, OpenTable, Setmore, Square, Acuity, Schedulista, Squarespace, BookMyCity) into a callable smb_id you can immediately use with schedule_appointment, send_message, or capture_lead. Idempotent — calling twice returns the same smb_id. Use when: Call this FIRST whenever the user provides a specific booking URL (cal.com/handle, calendly.com/handle/event, doctolib.fr/..., booksy.com/..., opentable.com/r/..., etc.). User patterns that match: 'book me at https://cal.com/...', 'schedule with calendly.com/jane/intro', 'reserve a table at opentable.com/r/...', 'I want to book this dentist: https://www.doctolib.fr/...'. After importing, the returned smb_id can be passed straight to schedule_appointment. Do NOT use when: Do not use if the user only describes a business by name without a URL — call find_business instead. Do not use for arbitrary websites that are not on the supported booking-platform list (use /supply/platforms to see all 12). Cost: ~$0.005 per call.","input_schema":{"type":"object","required":["booking_url"],"properties":{"booking_url":{"type":"string","format":"uri","description":"Full URL the user supplied. Must point at one of the 12 supported booking platforms; auto-detected from the host."},"business_name":{"type":"string","description":"Optional override. If omitted, the business name is auto-extracted from the page's <title> or og:title."},"vertical":{"type":"string","enum":["personal_services","home_services","professional_services","restaurants","retail","healthcare","fitness"],"description":"Best-guess vertical. If omitted, inferred from the platform (e.g., Doctolib -> healthcare, OpenTable -> restaurants)."},"country_code":{"type":"string","description":"ISO 3166-1 alpha-2 (e.g. 'US', 'FR'). Used for compliance routing on later send_message calls."},"contact_phone":{"type":"string","description":"Optional. If omitted, the platform integration handles outreach."},"contact_email":{"type":"string","description":"Optional."},"capabilities":{"type":"array","items":{"type":"string"},"description":"Free-form capability tags (e.g., ['haircut','color','blowdry'])."}}}},{"name":"call_business","description":"Place a conversational voice-AI phone call to a business on a consumer's behalf and return a structured answer. THE differentiated capability: reach the ~60M long-tail SMBs that have NO API and NO booking page — only a phone number. An AI agent cannot pick up a phone and hold a conversation; this tool does. Give a plain-language objective; the voice AI navigates the call and extracts the answer. Business-directed (B2B), far less restricted than calling consumers — but the compliance gate still enforces recording consent per jurisdiction. Async: returns a call handle; poll get_outcome for the transcript + extracted fields. Use when: Use when the target business has NO booking URL and NO API — only a phone number — and the consumer asked the agent to reach them (e.g. 'call this plumber and ask if they can come Tuesday', 'ask the salon if they take walk-ins this afternoon'). Also use to confirm details a booking page doesn't expose (real-time availability, custom quotes). Do NOT use when: Do NOT use when the business has a booking URL — use import_booking_url + schedule_appointment (cheaper, faster, deterministic). Do NOT use for calls to consumers/individuals (this tool is for reaching businesses). Do NOT use for marketing or telemarketing — the compliance gate and the B2B-only framing reject that. Execution: async_by_default — returns pending_async.","input_schema":{"type":"object","required":["objective"],"properties":{"business_phone":{"type":"string","description":"Business phone in E.164 (e.g. +14045550123). Provide this OR smb_id."},"smb_id":{"type":"string","description":"Known SMB identifier with a phone on record. Provide this OR business_phone."},"objective":{"type":"string","description":"What the call should accomplish, in plain language."},"extract_fields":{"type":"array","items":{"type":"string"},"description":"Structured fields to pull from the answer, e.g. ['available_tomorrow','price_quote','earliest_slot']."},"country_code":{"type":"string","description":"ISO 3166-1 alpha-2 for compliance + recording-consent routing."},"on_behalf_of":{"type":"string","description":"Name of the consumer the call is placed for."},"max_duration_seconds":{"type":"integer","maximum":600,"default":180}}}}],"endpoint":"https://agent-broker-edge.basil-agent.workers.dev/ops/{tool_name}","auth_header":"X-Agent-Identity","mcp_endpoint":"https://agent-broker-edge.basil-agent.workers.dev/mcp"}