# Connections

> Letting the AI read and write calendars and customer records during a call, and notifying Slack and others afterwards: preset connectors, custom connections, and the embeddable connect page for your customers.

Source: https://voicast.jp/en/docs/connectors

With connections, the AI can check free slots in Google Calendar and book them, or find a customer in kintone by phone number, during the call. After the call it posts the summary and collected fields to Slack or Teams. Unlike [tools](https://voicast.jp/en/docs/tools.md), you do not need to build an API.

## Where connections live

| Scope | Use it when | How to connect |
| --- | --- | --- |
| Tenant connection | Each business (tenant) connects its own calendar or Slack | The business opens the [embeddable connect page](#embeddable-connect-page) |
| Environment connection | Your whole service shares one booking system or notification target | Connect it in the dashboard (Connections) |

During a call, the tenant's connection is used first. If the tenant has one (even one that needs reconnecting), voicast does not fall back to the environment connection.

voicast stores credentials (OAuth tokens, API keys, webhook URLs) encrypted and never returns them in API responses or sends them to the voice server.

## Presets

| Connector | Name | Kind | How it connects | Actions the AI can use |
| --- | --- | --- | --- | --- |
| `google_calendar` | Google Calendar | Scheduling | Google sign-in | `find_free_slots`, `create_event`, `cancel_event`, `find_events_by_phone_or_name` |
| `m365_calendar` | Microsoft 365 Calendar | Scheduling | Microsoft sign-in | The same four as Google Calendar |
| `google_sheets` | Google Sheets | Customer records | Google sign-in (creates a ledger sheet) | `find_row_by_phone`, `append_row` |
| `kintone` | kintone | Customer records | kintone OAuth (a client registered on the customer's own domain) | `find_record_by_phone`, `create_record`, `update_record` |
| `hubspot` | HubSpot | Customer records | HubSpot sign-in | `find_contact_by_phone`, `create_contact`, `log_call` |
| `slack` | Slack | Notifications | Slack sign-in (pick a channel) | Notifications only |
| `chatwork` | Chatwork | Notifications | Chatwork sign-in (pick a room) | Notifications only |
| `lineworks` | LINE WORKS | Notifications | LINE WORKS OAuth (an app and bot created in the customer's Developer Console) | Notifications only |
| `teams` | Microsoft Teams | Notifications | Paste a Teams Workflows webhook URL | Notifications only |
| `shannon_booking` | SHANNON booking system | Scheduling | Base URL and API key (environment connection only) | `get_clinic_info`, `find_free_slots`, `find_patient`, `list_reservations`, `create_reservation`, `change_reservation`, `cancel_reservation` |

`GET /v1/connectors` (MCP: `list_connectors`) lists each action's description, the inputs asked for before connecting, and the tool names shown to the AI (such as `gcal_find_free_slots`). Connectors with `available: false` cannot be used yet.

### What the actions do

- **Google Calendar and Microsoft 365**: `find_free_slots { date_from, date_to?, duration_minutes? }` returns up to 8 free slots within 14 days, respecting opening hours, buffers and existing events. Also `create_event { start, name, phone?, note?, duration_minutes? }`, `cancel_event { event_id }` and `find_events_by_phone_or_name { phone?, name? }` (without a phone number it uses the caller's). After connecting, choose the calendar, the booking length (5–480 minutes, default 30), the buffer, opening hours per weekday and the event title. Keep medical conditions and the like out of the title; the purpose goes only into the event notes.
- **Google Sheets**: `find_row_by_phone { phone? }` and `append_row { name?, phone?, note? }`. Choose the sheet and the phone, name, note and date columns.
- **kintone**: `find_record_by_phone { phone? }`, `create_record { name?, phone?, note? }` and `update_record { record_id, name?, note? }`. Choose the app and the phone, name and note fields.
- **HubSpot**: `find_contact_by_phone { phone? }`, `create_contact { name, phone? }` and `log_call { summary, contact_id? }` (logged as an inbound call).
- **Notifications (Slack, Chatwork, LINE WORKS, Teams)**: after the call (once the summary is ready), voicast posts the summary, category, collected fields and a dashboard link. Failed notifications are retried without holding up the others.

## Using connections in an agent

List connections in the agent's `connectors`.

```json
"connectors": [
  { "connector": "google_calendar", "actions": ["find_free_slots", "create_event", "cancel_event"] },
  { "connector": "slack" },
  { "connection": "con_…", "actions": ["*"] }
]
```

| Field | Description |
| --- | --- |
| `connector` | A preset name. Uses the tenant's connection, or the environment's if the tenant has none |
| `connection` | A specific connection ID (`con_…`). Use this for custom connections (MCP servers, URL and API key) |
| `actions` | Action names, or `"*"` for all. Omit for notification-only connectors |
| `confirm` | Extra actions that need the caller's confirmation (for read actions) |

- Actions that change data (creating or cancelling a booking) always require reading the details back and getting the caller's agreement. This cannot be turned off.
- Only actions of connections in the `active` state are given to the AI.
- Each connector may appear once, up to 10 entries. If a tool name shown to the AI (such as `gcal_create_event`) clashes with a name in `tools`, you get 422.

## Embeddable connect page

A page where a business (tenant) connects its own Google Calendar, Slack and so on. It does not show the voicast name, so it can appear as part of your product.

### Creating a link

```bash
curl https://api.voicast.jp/v1/tenants/ten_…/connect-links \
  -H "Authorization: Bearer $VOICAST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "connectors": ["google_calendar", "slack"], "frame_origin": "https://app.example.com" }'
```

```json
{ "url": "https://app.voicast.jp/connect/vcl_…", "expires_at": 1790000900000 }
```

| Input | Description |
| --- | --- |
| `connectors` | Connectors to show (all if omitted). `shannon_booking` and custom connections cannot be shown |
| `frame_origin` | The https origin of the parent page when embedding in an iframe. Not needed for a new tab |

- Links expire after 15 minutes. Create a fresh one on your server each time the business opens its settings.
- Add `?lang=ja` or `?lang=en` to the `url` to choose the language (otherwise the browser's language).
- No sign-in is needed. The link's token limits the page to that tenant's connections.

### Embedding

```html
<iframe src="https://app.voicast.jp/connect/vcl_…?lang=en" title="Connections" style="width: 100%; height: 720px; border: 0"></iframe>
```

"Connect" opens the provider's sign-in in a small popup window (Google and others do not allow sign-in inside an iframe). When it finishes, the page notifies the parent with `postMessage`.

```js
window.addEventListener('message', (e) => {
  if (e.origin !== 'https://app.voicast.jp' || e.data?.type !== 'voicast.connect') return;
  // { type: 'voicast.connect', result: 'ok' | 'error', error, connector, connection }
  if (e.data.result === 'ok') refreshConnections();
});
```

Connectors that need setup, such as Google Calendar, ask for the calendar and opening hours on the same page after connecting. Until then the connection is `needs_setup` and is not given to the AI.

## Connecting with an API key or URL

Teams, the SHANNON booking system and custom "URL and API key" connections can be created with `POST /v1/connections`. voicast makes one test call before saving and returns 422 `verify_failed` if it fails.

```bash
curl https://api.voicast.jp/v1/connections \
  -H "Authorization: Bearer $VOICAST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "connector": "teams", "tenant_id": "ten_…", "secret": "https://….logic.azure.com/workflows/…" }'
```

## Custom connections

Services without a preset are connected in the dashboard under Connections → "+ Connect an API". Custom connections are environment connections, and you can add as many as you like (so is the SHANNON booking system: passing `tenant_id` returns 422 `invalid_request`; route per tenant with the `tenant` (`external_id`) sent with each request). Reference them in the agent as `{ "connection": "con_…", "actions": [...] }`; their tool names get a per-connection prefix (`mcp1_…`, `api2_…`).

### URL and API key (http)

Call your own or a third-party REST API with a base URL and an API key.

```bash
curl https://api.voicast.jp/v1/connections \
  -H "Authorization: Bearer $VOICAST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "connector": "http", "secret": "<API key>", "input": { "base_url": "https://api.example.com", "header": "Authorization" } }'
```

- With `header: "Authorization"` the key is sent as `Bearer <key>`; with any other header (such as `X-API-Key`) the key is sent as is.
- The connection starts as `needs_setup`; save up to 10 tools with `PATCH /v1/connections/{id}` to make it usable.

```json
{
  "config": {
    "tools": [
      {
        "name": "find_customer",
        "description": "電話番号で顧客を探す",
        "method": "GET",
        "path": "/customers/search",
        "params": [{ "name": "phone", "description": "電話番号（数字だけ）", "required": true }],
        "confirm": false
      }
    ]
  }
}
```

- Arguments are always strings: query parameters for GET, a JSON body for POST (up to 10). `path` must stay under the connected base URL.
- Each request carries an `idempotency-key` derived from the call and the tool call.
- JSON responses are passed to the AI as is; anything else is passed as text (long text is cut).

### MCP server (mcp)

Connect a remote MCP server (Streamable HTTP) that supports MCP authorization (OAuth). Enter its URL in the dashboard and the server's sign-in opens. After connecting, choose which tools the AI may use and which need confirmation (by default, every tool not declared read-only needs confirmation).

- Servers that need no sign-in, and local MCP servers, cannot be connected.
- Tools that require arguments other than strings, numbers and booleans cannot be selected.

### Allowed URLs

URLs called by connections (MCP servers, HTTP, the booking system, Teams) must be https. Literal IP addresses, `localhost`, `.local`, `.internal`, dotless host names and URLs with a user name or password are rejected. Redirects (3xx) are not followed.

## Connection status

| `status` | Meaning |
| --- | --- |
| `active` | Usable |
| `needs_setup` | Connected, but setup (such as choosing a calendar) is not finished. Not given to the AI |
| `needs_reauth` | The token expired; connect again |

When a connection breaks, the `connection.needs_reauth` webhook arrives. For tenant connections it includes `tenant`, so you can show that business a new connect-page link.

Deleting a tenant also revokes its connections. Deleting a connection (`DELETE /v1/connections/{id}`) revokes the provider's token too.
