Tools
Seven capabilities. The same seven in every dialect: MCP, OpenAI and Anthropic tool schemas, and plain REST at POST /v1/tools/{name}.
create_task
Ask Handle It to get something done at a real business: a reservation, an appointment, or a delivery order. Returns the task id, the plan, and the chosen route. When a business can be reached more than one way (its own system, a delivery platform), the response carries `pending_action.chosen_channel`, `alternatives` and `why`. Show the user which channel was picked, the price and ETA, and the one-sentence reason, before you accept anything. They may prefer another one. For an AI-Ready business the first step is already done when this returns: a delivery order comes back `awaiting_developer` with the quote in `pending_action`, and an instant booking comes back `confirmed` with evidence. Read the result and tell the user. Only call wait_for_task if `status` is still `received`, `planned`, `routing` or `executing`. Prefer structured fields over prose. For an order, send `items` as [{"item_id": ..., "qty": ...}] using ids from get_capabilities, rather than describing the basket in words: quantities written as prose can be read wrong, and "2x karak" arriving as one karak costs the customer money. Always put the customer's phone in `on_behalf_of.phone` and their full address in `on_behalf_of.address`, even if they are also in the text; a delivery cannot be placed without both.
Start here. Pass plain language in request and we parse it, or pass structured fields if you already have them. Returns immediately: the task is worked in the background.
| Field | Type | ||
|---|---|---|---|
request | string | optional | Plain-language ask, e.g. 'order 2 karak to Cluster T JLT'. |
type | string (reservation, appointment, order) | optional | |
business | string | optional | Business name or hint. |
party_size | integer | optional | |
time_window | string | optional | e.g. 'tonight 9pm', 'Saturday morning'. |
notes | string | optional | |
items | array | optional | Order lines, when you already know them: [{"item_id": "karak", "qty": 2}]. Item ids come from get_capabilities. For an order, put what to order here or in `request`; `notes` is for the delivery instructions, not the basket. |
fulfilment_policy | string (balanced, cheapest, fastest) | optional | How to choose when a business can be reached more than one way (its own system, a delivery platform). Default balanced: price, ETA and reliability together. |
on_behalf_of | object | optional | Who it is for: {"first_name": "Faycel", "phone": "+9715...", "address": "Cluster T, Tower B, unit 1203, JLT"}. A delivery needs a phone and a full address including building and unit. |
mode | string (live, sandbox, dry_run) | optional | Execution mode; test keys always use the sandbox. |
sandbox_persona | string | optional | Sandbox business personality for test keys. |
get_task
Get a task's current status, outcome, evidence, and cost.
A point-in-time read. Use it when you already have another reason to poll; otherwise prefer wait_for_task, which is the same data without the polling loop.
| Field | Type | ||
|---|---|---|---|
task_id | string | required |
wait_for_task
Long-poll a task. Returns as soon as anything changes: the merchant advances a step (accepted -> preparing -> out_for_delivery -> delivered), the task needs a decision, or it reaches a terminal outcome. It does not wait for the end. Call it in a loop until `outcome` is set, and tell the user each change as it arrives. `merchant_status` is the latest step and `merchant_status_history` is every step so far: the kitchen can move twice while one call is returning, so narrate anything in the history you have not mentioned yet rather than only the latest. Never stop early and never ask the user to ask you for an update: following the order is the job. The only reasons to stop are a terminal outcome, an action_required you must answer, or the user telling you to stop. You do not need it immediately after create_task or respond_to_task, which already return the current state; start the loop from what they gave you.
Long-polls until the task finishes, needs a decision, or the merchant moves a step (accepted, preparing, out for delivery). Call it again after each return to follow an order all the way to the door.
| Field | Type | ||
|---|---|---|---|
task_id | string | required | |
timeout_seconds | integer | optional | Max 120. Returns the instant the task moves, so a longer value means fewer calls, not a longer wait. |
respond_to_task
Answer a task that is awaiting_developer, e.g. accept a delivery quote (choice_id 'accept_quote') or pick a slot. The pending_action on the task lists the valid choices. Accepting a quote spends the user's money: show them the price, the fee and the ETA, get an explicit yes, and only then call this with quote_id and total echoed back exactly as quoted. A call without them is refused. To use a different channel, pass `use_channel` with a channel_id from `pending_action.alternatives`: it re-quotes on that channel and returns a fresh decision to accept. The result is the task's new state, already up to date: after accepting a quote it comes back with merchant_status 'accepted' and the confirmation id. Tell the user that straight away, including how long they can still cancel (see `cancellation` on the result). Then call wait_for_task and keep following the order to its terminal outcome, narrating each step as it happens. Never ask the user to request an update.
Answers an action_required. The task tells you the legal choices in pending_action.choices; send one of those ids.
| Field | Type | ||
|---|---|---|---|
task_id | string | required | |
choice_id | string | required | |
use_channel | string | optional | Re-quote on one specific channel instead: pass the channel_id from pending_action.alternatives. Equivalent to choice_id 'use_channel:<id>'. |
quote_id | string | optional | Required for 'accept_quote': the quote_id from pending_action. |
total | number | optional | Required for 'accept_quote': the quoted total the user agreed to. |
value | any | optional | Optional value for the choice. |
cancel_task
Cancel a task, immediately and in this call. The result is the task's final state; there is nothing to poll afterwards. The moment the user corrects an order, changes their mind, or says anything like 'cancel', call this first and re-place afterwards if they still want something. Do not ask them to confirm the cancellation while the kitchen keeps cooking, and do not try to amend a placed order: cancel, then create a new task with the corrected details. Cancelling is free until the business starts preparing. After that the merchant's own cancellation window applies, and if it has passed the result explains why in `reason`.
Cancel wins over anything queued. If we have already sent a message, the task closes cancelled and no further messages go out.
| Field | Type | ||
|---|---|---|---|
task_id | string | required |
find_businesses
Discover AI-Ready businesses in the directory before booking.
The AI-Ready directory. Filter by vertical and area. Businesses here take structured bookings and orders, so outcomes are confirmations rather than conversations.
| Field | Type | ||
|---|---|---|---|
vertical | string (restaurant, service, delivery) | optional | |
area | string | optional | |
ai_ready | boolean | optional |
get_capabilities
Get one business's capability manifest (services, hours, rules, zones).
What one business actually accepts: task types, hours, services or menu, and its rules. Read this before composing a task if you want to avoid a declined outcome.
| Field | Type | ||
|---|---|---|---|
business_id | string | required |