> ## Documentation Index
> Fetch the complete documentation index at: https://docs.visitoai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom AI Tools

> Register backend actions that Visito's AI can call during conversations.

Custom tools let Visito call your backend when the AI needs live business data or needs to trigger an approved action. Common examples include looking up an order status, creating a support ticket, checking loyalty points, or updating a customer profile.

All endpoints use the M2M base URL:

```bash theme={null}
https://platform-api.visitoai.com/m2m/v1
```

## Tool Model

A tool describes what the AI can call, the JSON input it should provide, and the HTTP endpoint Visito will invoke.

```json theme={null}
{
  "name": "get_order_status",
  "description": "Look up the latest status for a customer order.",
  "parameters": {
    "type": "object",
    "required": ["order_number"],
    "properties": {
      "order_number": {
        "type": "string",
        "description": "The customer's order number, for example A-1003."
      }
    }
  },
  "endpoint": {
    "url": "https://example.com/visito/tools/get-order-status",
    "method": "POST",
    "timeoutMs": 10000
  },
  "auth": {
    "type": "bearer",
    "value": "tool_backend_secret"
  },
  "active": true,
  "readOnly": true,
  "allowInPlayground": true,
  "propertyIds": []
}
```

`parameters` should be a JSON Schema object. Visito uses it to decide when the tool is relevant and to shape the input sent to your endpoint.

## What Visito Sends to Your Endpoint

For a `GET` tool, Visito converts tool arguments into query parameters. Primitive values are sent as strings; objects and arrays are JSON-encoded.

```http theme={null}
GET /visito/tools/get-order-status?order_number=A-1003
Accept: application/json
```

For a `POST` tool, Visito sends the arguments together with conversation metadata:

```json theme={null}
{
  "arguments": {
    "order_number": "A-1003"
  },
  "meta": {
    "tenantId": "tenant_123",
    "conversationKey": "tenant_123:whatsapp:525512345678:phone_number_id",
    "conversationId": "conv_123",
    "channel": "whatsapp",
    "eventId": "toolreq_123"
  }
}
```

Your endpoint should return a JSON object with only the fields the assistant needs. Non-object JSON responses are normalized into an object before the result is returned to the assistant.

Configured authentication is added by Visito:

* `bearer` sends `Authorization: Bearer <configured secret>`.
* `api_key` sends the configured secret in `auth.headerName`.
* Stored secrets are redacted from invocation logs and are never returned by the API.

## Create a Tool

```http theme={null}
POST /m2m/v1/tools HTTP/1.1
Host: platform-api.visitoai.com
Authorization: Bearer visito_m2m_...
Content-Type: application/json
```

Requires the `tools:write` scope.

```json theme={null}
{
  "name": "get_order_status",
  "description": "Look up the latest status for a customer order.",
  "parameters": {
    "type": "object",
    "required": ["order_number"],
    "properties": {
      "order_number": {
        "type": "string",
        "description": "The customer's order number."
      }
    }
  },
  "endpoint": {
    "url": "https://example.com/visito/tools/get-order-status",
    "method": "POST"
  },
  "auth": {
    "type": "api_key",
    "headerName": "X-Tool-Key",
    "value": "secret_value"
  },
  "active": true,
  "readOnly": true
}
```

```json theme={null}
{
  "tool": {
    "toolId": "tool_...",
    "tenantId": "tenant_...",
    "name": "get_order_status",
    "description": "Look up the latest status for a customer order.",
    "parameters": {},
    "endpoint": {
      "url": "https://example.com/visito/tools/get-order-status",
      "method": "POST"
    },
    "auth": {
      "type": "api_key",
      "headerName": "X-Tool-Key",
      "secretLastFour": "alue",
      "configured": true
    },
    "active": true,
    "readOnly": true,
    "allowInPlayground": true,
    "propertyIds": [],
    "createdAt": "2026-07-12T00:00:00.000Z",
    "updatedAt": "2026-07-12T00:00:00.000Z"
  }
}
```

Secrets are not returned after creation. Responses only include whether auth is configured and the last four characters when available.

### Create and Update Rules

* `name` must start with a letter or underscore, contain only letters, numbers, and underscores, and be at most `64` characters.
* `description` is required and can be at most `2000` characters.
* `parameters` must be a JSON Schema object. Visito sets `type: "object"` and `additionalProperties: false` when they are omitted.
* `endpoint.url` must be an HTTP or HTTPS URL.
* `endpoint.method` must be `GET` or `POST`.
* `endpoint.timeoutMs`, when provided, must be an integer from `500` to `30000`.
* `auth.type` must be `none`, `bearer`, or `api_key`.
* `allowInPlayground` defaults to `false`.
* Omitting `auth.value` during a patch preserves the existing secret. Setting `auth.type` to `none` removes it.

## List and Read Tools

```http theme={null}
GET /m2m/v1/tools HTTP/1.1
Authorization: Bearer visito_m2m_...
```

Requires `tools:read`.

```json theme={null}
{
  "tools": [
    {
      "toolId": "tool_...",
      "name": "get_order_status",
      "active": true,
      "readOnly": true
    }
  ]
}
```

Read one tool:

```http theme={null}
GET /m2m/v1/tools/{toolId}
```

## Update or Delete a Tool

Update one or more fields:

```http theme={null}
PATCH /m2m/v1/tools/{toolId}
Authorization: Bearer visito_m2m_...
Content-Type: application/json
```

Requires `tools:write`.

```json theme={null}
{
  "active": false,
  "endpoint": {
    "timeoutMs": 15000
  }
}
```

Delete a tool:

```http theme={null}
DELETE /m2m/v1/tools/{toolId}
Authorization: Bearer visito_m2m_...
```

```json theme={null}
{
  "ok": true,
  "toolId": "tool_...",
  "changed": true
}
```

## Test a Tool

Use the test endpoint before enabling a tool in production conversations.

```http theme={null}
POST /m2m/v1/tools/{toolId}/test HTTP/1.1
Authorization: Bearer visito_m2m_...
Content-Type: application/json
```

Requires `tools:execute`.

```json theme={null}
{
  "input": {
    "order_number": "A-1003"
  }
}
```

```json theme={null}
{
  "ok": true,
  "output": {
    "order_number": "A-1003",
    "status": "delivered",
    "estimated_delivery": "2026-07-10",
    "tracking_url": "https://example.com/orders/A-1003"
  },
  "durationMs": 248
}
```

## Execution Logs

Use logs to audit AI tool calls and diagnose backend failures.

```http theme={null}
GET /m2m/v1/tools/logs?toolId=tool_...&limit=25
Authorization: Bearer visito_m2m_...
```

Requires `tools:logs:read`.

```json theme={null}
{
  "logs": [
    {
      "logId": "log_...",
      "toolId": "tool_...",
      "toolName": "get_order_status",
      "conversationId": "conv_...",
      "status": "completed",
      "method": "POST",
      "url": "https://example.com/visito/tools/get-order-status",
      "responseStatus": 200,
      "durationMs": 248,
      "startedAt": "2026-07-12T00:00:00.000Z",
      "completedAt": "2026-07-12T00:00:00.248Z"
    }
  ]
}
```

Read one log:

```http theme={null}
GET /m2m/v1/tools/logs/{logId}
```

## Endpoint Requirements

* Your endpoint must be reachable from Visito's backend.
* Supported methods are `GET` and `POST`.
* Return JSON whenever possible.
* Return a `2xx` response for success. A non-`2xx` response is recorded as `custom_tool_http_error`.
* Keep tool responses concise and structured for AI use.
* Use `readOnly: true` for lookup tools that should never mutate state.
* Use tool-specific auth secrets instead of broad internal credentials.
* Make mutating endpoints idempotent using a business identifier from `arguments` or `meta.eventId`.
* Do not rely on the assistant to hide sensitive fields returned by your endpoint; omit secrets and unnecessary personal data from the response.

## Production Checklist

1. Create the tool with `active: false`.
2. Test representative success, validation, timeout, and upstream-failure cases.
3. Confirm request headers are redacted in **Build → Tool calls → Logs**.
4. Keep the response small and stable so the assistant can interpret it reliably.
5. Set `readOnly: false` for mutations and require your own authorization and idempotency checks.
6. Enable the tool, then review invocation logs after the first real conversations.
