Set an assistant’s tools
PUT/api/v1/assistants/{id}/tools
scope
assistants:writeGrants and revokes tools in one call. Send only the tools you have an opinion about — anything you omit falls back to the catalogue default rather than being switched off, so an empty list resets the assistant to defaults rather than disarming it. gated tool ids stop for a human approval before running; tools with sensitivity: critical do that regardless. PUT rather than PATCH because both lists are replaced wholesale.
Path parameters
| Name | Type | Description |
|---|---|---|
idrequired | string (uuid) | Assistant id |
Body
application/json| Name | Type | Description |
|---|---|---|
toolsrequired | map<string, boolean> | Tool id to on or off. Omitted tools take the catalogue default |
gated_toolsoptional | string[] | Tool ids that must raise a human approval first. Replaces the whole list |
Request
curl -X PUT "https://your-crm.example.com/api/v1/assistants/8f2c1d3e-4a5b-4c6d-9e0f-1a2b3c4d5e6f/tools" \
-H "Authorization: Bearer $RAABTA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tools": {
"bookings.create": true,
"bookings.cancel": true,
"contacts.search": true
},
"gated_tools": [
"bookings.cancel"
]
}'Response · 200 OK
{
"data": [
{
"id": "bookings.create",
"group": "booking",
"group_label": "Bookings",
"title": "create",
"description": "Book an appointment for a contact.",
"sensitivity": "write",
"enabled": true,
"gated": false,
"default_enabled": true,
"explicit": true
}
]
}Response
Wrapped in { data: … }| Name | Type | Description |
|---|---|---|
idrequired | string | Tool id |
grouprequired | string | Catalogue group id |
group_labelrequired | string | Group name as shown in the dashboard |
titlerequired | string | Short human name |
descriptionrequired | string | What the tool does |
sensitivityrequired | string (enum) | A critical tool always raises an approval, whatever `gated` saysreadwritecritical |
enabledrequired | boolean | Whether this assistant may use it, with the catalogue default already applied |
gatedrequired | boolean | Whether it pauses for a human approval before running |
default_enabledrequired | boolean | What it would be if the assistant said nothing |
explicitrequired | boolean | True when the assistant states an opinion, false when it is taking the default |
Errors
| Status | Code | When |
|---|---|---|
| 400 | bad_request | The request could not be parsed: malformed JSON, an invalid cursor, or a query parameter of the wrong shape. |
| 400 | validation_error | The body or query failed validation. `details` lists each failing field with a `path` and a `message`. |
| 401 | unauthorized | No usable API key: the Authorization header is missing or malformed, or the key is unknown, revoked or expired. The three are deliberately indistinguishable. |
| 403 | forbidden | The key is valid but lacks the scope this endpoint requires, or the request came from an address outside the key’s IP allowlist. The message says which. |
| 403 | account_suspended | The account this key belongs to is suspended. Rotating the key will not help; contact support. |
| 404 | not_found | No such resource in this account. A resource that exists in another account also returns this. |
| 422 | unprocessable | The request was well-formed but cannot be carried out. `reason` is a stable string saying why (for example `outside_window` or `stage_not_in_pipeline`). |
| 429 | rate_limited | The per-key budget, or the per-IP budget for failed authentication, is exhausted. Honour `Retry-After` before retrying. |
| 500 | internal | Something failed on our side. Safe to retry with the same Idempotency-Key; quote `request_id` if it persists. |