# Connect with an API key

Source: https://docs.havilo.ai/mcp/api-keys

An API key reaches the same MCP server as the Claude and ChatGPT connectors, with no browser sign-in.
Use it when the caller is a program: your own MCP server, a scheduled job, or an agent running
without a person at a browser.

If you are an agent setting this up, follow the steps in order. Step 1 needs a person. You can do
everything after it.

## 1. Create a key

A workspace member with the Manage API Keys permission does this once.

1. In Havilo, open **Settings → Advanced → API Keys**.
2. Select **Create API key**, name it after where it will run, and change the preset to
   **AI Assistant**.
3. Copy the key. It is shown once.

The key acts as the person who created it. It can do only what both that person and the key are
allowed, and it stops working if that person leaves the workspace. If the page says API access
isn't enabled for this workspace, ask your Havilo contact.

Store the key as `HAVILO_API_KEY`. Never put it in a prompt, a file you commit, or a URL.

## 2. Connect

Server URL:

```text
https://havilo.ai/api/mcp
```

Send the key as a bearer token on every request:

```text
Authorization: Bearer <HAVILO_API_KEY>
```

**Claude Code:**

```bash
claude mcp add --transport http havilo https://havilo.ai/api/mcp \
  --header "Authorization: Bearer $HAVILO_API_KEY"
```

**Your own server**, with the TypeScript MCP SDK:

```ts
import { Client } from '@modelcontextprotocol/sdk/client/index.js'
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'

const havilo = new Client({ name: 'my-server', version: '1.0.0' })

await havilo.connect(
  new StreamableHTTPClientTransport(new URL('https://havilo.ai/api/mcp'), {
    requestInit: { headers: { Authorization: `Bearer ${process.env.HAVILO_API_KEY}` } },
  })
)

const { tools } = await havilo.listTools()

const found = await havilo.callTool({
  name: 'crm_records_search',
  arguments: { query: 'Jane Doe', limit: 5 },
})
// found.structuredContent.records, or found.isError with the reason in found.content[0].text
```

Any other MCP client works the same way: Streamable HTTP transport, that URL, that header.

## 3. Check the connection

Call `workspace_whoami`. `client_id` starts with `api-key:` and `workspace_id` is the workspace the
key was created in. Then call `workspace_capabilities`. The Engine tools need `AI_FEATURE_ACCESS` in
that list.

## 4. Install the skill

The skill teaches an agent when to look a record up and when to commission the Engine, and how to
follow a run to its result. Save it into your agent's skills folder. For Claude Code:

```bash
mkdir -p .claude/skills/havilo
curl -fsSL https://havilo.ai/skills/havilo/SKILL.md -o .claude/skills/havilo/SKILL.md
```

A server that exposes Havilo to its own clients passes the same text on: in its MCP `instructions`, or in the system prompt of the agent it runs.

## 5. Try it

Ask for a person you know is in the workspace:

> Use Havilo to find Jane Doe.

Then a question about a whole group:

> Use Havilo to find mentors with fintech experience who have worked in Japan.

The second one takes a few minutes. The agent starts a run, waits for it, and links the table it
produces.

## What a key can reach

| Tool                                         | Use                                            |
| -------------------------------------------- | ---------------------------------------------- |
| `workspace_whoami`, `workspace_capabilities` | Which workspace, and what the key may do       |
| `crm_schema_get`                             | Entity types, fields, relationships and counts |
| `crm_records_search`, `crm_records_get`      | Find a named person, company or fund; read it  |
| `crm_notes_search`, `crm_notes_read`         | Find and read notes                            |
| `crm_records_query`                          | A question over field values, as a table       |
| `crm_artifacts_save`                         | Save a queried table, or unsave it             |
| `ai_understand`, `ai_plan`, `ai_run`         | Commission the AI Engine                       |
| `jobs_get`, `crm_artifacts_get`              | Follow a run and read the table it saved       |

A key cannot create, change or delete records, notes or drafts. `ai_run` saves the tables it makes
to the workspace; `crm_records_query` writes its table unsaved, and `crm_artifacts_save` saves it.
The AI tools spend the workspace's credits. Inputs
and results are in the [tool reference](https://docs.havilo.ai/mcp/tools.md).

## Limits

* 100 requests a minute per key.
* A workspace has a cap on runs in flight at once and a daily cost cap, set by its plan. `ai_run`
  refuses a run past either and says which cap and its limit.
* Every tool call is recorded in the workspace audit log with the tool it called and whether it
  worked.

Revoke a key from the same Settings page.

## Errors

A refused connection returns JSON with `error` and `error_description`:

| Status | Meaning                                                                 |
| ------ | ----------------------------------------------------------------------- |
| 401    | The key is wrong, revoked or expired, or its creator left the workspace |
| 403    | The workspace has no API access, or the key is a system key             |
| 429    | More than 100 requests in a minute; wait and retry                      |

A tool that refuses returns a normal MCP result with `isError: true` and a sentence naming what was
missing.
