---
title: "API"
description: "Manage agents, knowledge and conversations from your own code: keys, errors, limits and every operation."
source: https://hiy.ai/docs/api
---

# API

Manage your Support and Team Agents from your own code: create them, change their settings safely, add knowledge, teach answers, read conversations and ask questions.

The API is on Growth and Scale. On Free and Starter, API keys are locked.

**Note:** The API is rolling out to selected workspaces first. Until yours is on the list, calls answer `404 not_found`. Ask at [hello@hiy.ai](mailto:hello@hiy.ai) to be added early.

## Keys and requests

Every call goes to `https://api.hiy.ai/v1` with an [API key](/docs/api-keys) in the `Authorization` header. Never put a key in the URL: hiy refuses it.

```bash
curl https://api.hiy.ai/v1/workspace \
  -H "Authorization: Bearer $HIY_API_KEY"
```

A key acts as the person who made it, on the agents they own, and only with its access: Read only, Build and manage, Zapier or Custom. Send bodies as JSON. Fields are `snake_case`, ids are UUIDs and times are ISO 8601 in UTC.

Version 1 only grows: new fields and operations are added, and none is renamed or removed. A change that would break your code comes as `/v2`.

## Answers and errors

A call that works answers `{ "data": … }`. A list answers 25 at a time (up to 100 with `limit`) and adds `next_cursor`: send it back as `cursor` for the next page. On the last page it is `null`.

A call that fails answers one of the codes below, with a sentence saying what to do, the `field` at fault when there is one, and a `request_id`, also in the `X-Request-Id` header. Quote it when you write to us.

```json
{ "error": { "code": "invalid", "message": "Check limit.", "field": "limit", "request_id": "req_…" } }
```

- `invalid` (400): The body, query or path doesn't fit; `field` names the part.
- `unauthorized` (401): No key, or the key is unknown, revoked or expired, or it was sent in the URL.
- `forbidden` (403): The key lacks the access this needs, or a rule refuses it, such as a confidential source on a public agent.
- `plan_required` (403): The workspace's plan has no API.
- `not_found` (404): It doesn't exist, it isn't yours, or the API isn't on for your workspace yet.
- `conflict` (409): It changed since you read it, it's already done, or an `Idempotency-Key` was reused with a different body.
- `limit_reached` (403): A plan allowance is full: agents, sources, words or keys.
- `rate_limited` (429): Too many calls this minute. Wait the `Retry-After` seconds.
- `credits` (402): The workspace is out of credits.
- `unavailable` (503): Something hiy needs is down, or an ask took over 45 seconds. Try again.
- `internal` (500): A fault on our side. Try again, and quote the `request_id` if it keeps happening.

## Limits and retries

On Growth each key can make 120 reads and 30 writes a minute, counted apart; asks and tests count as writes. Answers carry `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset` (seconds until the minute refills). Past the limit you get `429 rate_limited` with `Retry-After`. There is no monthly cap: Workspace › Developers › API keys counts this period's calls.

Asking an agent costs credits, like a visitor's question. A test uses the free daily test replies and never credits; when they run out, tests stop until 00:00 UTC. Every other call is free.

To retry safely, send an `Idempotency-Key` header with a POST, such as a new UUID for each change. If a call times out, send it again with the same key and body: you get the first answer back with `Idempotent-Replayed: true`, and nothing runs twice, so an ask never spends twice. Keys are kept 24 hours. A failure on our side isn't kept, so a retry runs again.

## Changing an agent

An agent's settings never change in one step: you propose a change, then apply it, and you can undo it later.

1. **See what you can change** — `GET /agents/{agent_id}/change-options` lists each setting you can change, its current value and the arguments it takes.

2. **Propose a change** — `POST /agents/{agent_id}/proposals` with one `op` and its `args` answers the setting before and after. Nothing changes yet.

3. **Apply it** — `POST /proposals/{proposal_id}/apply` makes the change. If the setting changed since, you get `409 conflict`: propose again.

4. **Undo it if you need to** — `POST /agents/{agent_id}/versions/{version_id}/restore` puts back what the change replaced, as a new change.

**Good to know:**

- A key works on the agents its maker owns, in the workspace it was made in.
- A list returns at most 100 a page, and a body can be up to 1 MB.
- An ask that takes over 45 seconds answers `503 unavailable`.
- A proposal expires after 24 hours, and an agent holds at most 20 open proposals from the API.
- A Team Agent's conversations are never readable through the API.

## Reference

Every operation below comes from the API's own [OpenAPI file](https://api.hiy.ai/v1/openapi.json), so it matches what the API does. Give the file to any OpenAPI tool to make a client.

**Workspace.** The workspace a key belongs to, its access and its limits.

### Get the workspace

`GET /workspace`

Read the workspace this key belongs to, its access and its limits. Any key works.

Request:

```bash
curl https://api.hiy.ai/v1/workspace \
  -H "Authorization: Bearer $HIY_API_KEY"
```

Answer, 200:

```json
{
  "data": {
    "id": "3f6c1a52-8d4e-4b7a-9c21-5e0d7f4a2b10",
    "name": "Acme Dental",
    "role": "owner",
    "scopes": [
      "agents:read",
      "agents:write",
      "knowledge:read",
      "knowledge:write",
      "conversations:read",
      "ask"
    ],
    "limits": {
      "reads_per_minute": 120,
      "writes_per_minute": 30,
      "calls_this_period": 1240,
      "period_resets_at": "2026-12-01T00:00:00Z",
      "test_replies_left_today": 47
    }
  }
}
```

Errors: `401 unauthorized` · `403 forbidden, plan_required` · `404 not_found` · `429 rate_limited` · `500 internal` · `503 unavailable`

**Agents.** Your Support and Team Agents: list, read, create, publish, ask and test.

### List agents

`GET /agents`

List this workspace's Support and Team Agents. Needs the agents:read scope.

Query:

- `limit` (integer, optional): How many to return. 1 to 100. Default 25.
- `cursor` (string, optional): The next_cursor of the page before. Leave it out for the first page. Up to 500 characters.
- `kind` (string, optional): One of: support, team.
- `status` (string, optional): One of: draft, in_review, live, off, rejected.

Request:

```bash
curl "https://api.hiy.ai/v1/agents?kind=support&status=live" \
  -H "Authorization: Bearer $HIY_API_KEY"
```

Answer, 200:

```json
{
  "data": [
    {
      "id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
      "name": "Front desk",
      "kind": "support",
      "status": "live",
      "slug": "acme-front-desk",
      "channels": [
        "web",
        "email"
      ],
      "created_at": "2026-11-02T10:00:00Z"
    }
  ],
  "next_cursor": null
}
```

Errors: `400 invalid` · `401 unauthorized` · `403 forbidden, plan_required` · `404 not_found` · `429 rate_limited` · `500 internal` · `503 unavailable`

### Create an agent

`POST /agents`

Create a draft agent from one web page. Needs the agents:write scope.

Header:

- `Idempotency-Key` (string, optional): Send the same value again to get the first answer back instead of running the call twice. Kept 24 hours. 1 to 255 visible characters.

Body:

- `kind` (string, required): One of: support, team.
- `name` (string, required): 2 to 60 characters.
- `url` (string, required): Up to 2000 characters. An https:// link.
- `slug` (string, optional): The agent's address on hiy.ai. Made from the name when left out.
- `confirm_ownership` (boolean, required): Send true to confirm the agent represents you, or a product or organisation you own, and that you have the rights to its content. Must be true.

Request:

```bash
curl -X POST https://api.hiy.ai/v1/agents \
  -H "Authorization: Bearer $HIY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "kind": "support",
  "name": "Front desk",
  "url": "https://acmedental.com/help",
  "confirm_ownership": true
}'
```

Answer, 202:

```json
{
  "data": {
    "id": "b2c3d4e5-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
    "status": "draft",
    "training": {
      "state": "queued"
    }
  }
}
```

Errors: `400 invalid` · `401 unauthorized` · `403 forbidden, plan_required, limit_reached` · `404 not_found` · `409 conflict` · `429 rate_limited` · `500 internal` · `503 unavailable`

### Get an agent

`GET /agents/{agent_id}`

Read one agent, its training and its main settings. Needs the agents:read scope.

Path:

- `agent_id` (string (uuid), required): The agent's id.

Request:

```bash
curl https://api.hiy.ai/v1/agents/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d \
  -H "Authorization: Bearer $HIY_API_KEY"
```

Answer, 200:

```json
{
  "data": {
    "id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
    "name": "Front desk",
    "kind": "support",
    "status": "live",
    "audience": "public",
    "slug": "acme-front-desk",
    "channels": [
      "web",
      "email"
    ],
    "training": {
      "state": "ready",
      "sources": 42,
      "words": 182400
    },
    "settings": {
      "greeting": "Hi! Ask me about bookings.",
      "reply_length": "normal",
      "scope_strictness": "strict"
    }
  }
}
```

Errors: `400 invalid` · `401 unauthorized` · `403 forbidden, plan_required` · `404 not_found` · `429 rate_limited` · `500 internal` · `503 unavailable`

### Publish an agent

`POST /agents/{agent_id}/publish`

Publish a draft agent; it may wait for a person's review first. Needs the agents:write scope.

Path:

- `agent_id` (string (uuid), required): The agent's id.

Header:

- `Idempotency-Key` (string, optional): Send the same value again to get the first answer back instead of running the call twice. Kept 24 hours. 1 to 255 visible characters.

Body:

- `confirm` (boolean, required): Send true to publish. Must be true.

Request:

```bash
curl -X POST https://api.hiy.ai/v1/agents/b2c3d4e5-6f7a-4b8c-9d0e-1f2a3b4c5d6e/publish \
  -H "Authorization: Bearer $HIY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "confirm": true
}'
```

Answer, 200:

```json
{
  "data": {
    "id": "b2c3d4e5-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
    "status": "live"
  }
}
```

Errors: `400 invalid` · `401 unauthorized` · `403 forbidden, plan_required, limit_reached` · `404 not_found` · `409 conflict` · `429 rate_limited` · `500 internal` · `503 unavailable`

### Ask an agent

`POST /agents/{agent_id}/ask`

Ask an agent a question, as a visitor would; it costs credits like a chat. Needs the ask scope.

Path:

- `agent_id` (string (uuid), required): The agent's id.

Header:

- `Idempotency-Key` (string, optional): Send the same value again to get the first answer back instead of running the call twice. Kept 24 hours. 1 to 255 visible characters.

Body:

- `question` (string, required): Up to 2000 characters.
- `conversation_id` (string (uuid) or null, optional): Continue a conversation this API started. Leave it out to start a new one.

Request:

```bash
curl -X POST https://api.hiy.ai/v1/agents/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d/ask \
  -H "Authorization: Bearer $HIY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "question": "Are you open on Saturday?"
}'
```

Answer, 200:

```json
{
  "data": {
    "answer": "Yes, 9am to 1pm.",
    "citations": [
      {
        "title": "Opening times",
        "url": "https://acmedental.com/hours"
      }
    ],
    "conversation_id": "1b8c9d0e-2f3a-4b4c-9d5e-7f8091a2b3c4"
  }
}
```

Errors: `400 invalid` · `401 unauthorized` · `402 credits` · `403 forbidden, plan_required, limit_reached` · `404 not_found` · `409 conflict` · `429 rate_limited` · `500 internal` · `503 unavailable`

### Test an agent

`POST /agents/{agent_id}/tests`

Ask an agent a test question; it uses the free daily test replies and never credits. Needs the ask scope.

Path:

- `agent_id` (string (uuid), required): The agent's id.

Header:

- `Idempotency-Key` (string, optional): Send the same value again to get the first answer back instead of running the call twice. Kept 24 hours. 1 to 255 visible characters.

Body:

- `question` (string, required): Up to 2000 characters.

Request:

```bash
curl -X POST https://api.hiy.ai/v1/agents/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d/tests \
  -H "Authorization: Bearer $HIY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "question": "Do you whiten teeth?"
}'
```

Answer, 200:

```json
{
  "data": {
    "answer": "Yes. Whitening takes two visits.",
    "citations": [],
    "test_replies_left_today": 46
  }
}
```

Errors: `400 invalid` · `401 unauthorized` · `402 credits` · `403 forbidden, plan_required, limit_reached` · `404 not_found` · `409 conflict` · `429 rate_limited` · `500 internal` · `503 unavailable`

**Changes.** Propose a change to an agent's settings, apply it, and undo it later.

### List change options

`GET /agents/{agent_id}/change-options`

List the changes you can propose to this agent, with their current values. Needs the agents:read scope.

Path:

- `agent_id` (string (uuid), required): The agent's id.

Request:

```bash
curl https://api.hiy.ai/v1/agents/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d/change-options \
  -H "Authorization: Bearer $HIY_API_KEY"
```

Answer, 200:

```json
{
  "data": [
    {
      "op": "greeting.set",
      "label": "Greeting",
      "field": "greeting",
      "args": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          }
        },
        "required": [
          "text"
        ],
        "additionalProperties": false
      },
      "current": "Hi! Ask me about bookings."
    }
  ]
}
```

Errors: `400 invalid` · `401 unauthorized` · `403 forbidden, plan_required` · `404 not_found` · `429 rate_limited` · `500 internal` · `503 unavailable`

### Propose a change

`POST /agents/{agent_id}/proposals`

Propose one change to an agent's settings; nothing changes until it is applied. Needs the agents:write scope.

Path:

- `agent_id` (string (uuid), required): The agent's id.

Header:

- `Idempotency-Key` (string, optional): Send the same value again to get the first answer back instead of running the call twice. Kept 24 hours. 1 to 255 visible characters.

Body:

- `op` (string, required): A change from List change options. One of: greeting.set, starters.replace, starters.add, starters.remove, length.set, offlimits.add, offlimits.remove, scope.add, scope.remove, scope.strictness.set, gap.message.set, gap.link.set, handover.trigger.set, handover.sentence.set, handover.signals.set.
- `args` (object, required): The change's arguments, in the shape List change options shows.

Request:

```bash
curl -X POST https://api.hiy.ai/v1/agents/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d/proposals \
  -H "Authorization: Bearer $HIY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "op": "greeting.set",
  "args": {
    "text": "Hello! I can help with bookings and opening times."
  }
}'
```

Answer, 201:

```json
{
  "data": {
    "id": "c3d4e5f6-7a8b-4c9d-8e0f-2a3b4c5d6e7f",
    "status": "proposed",
    "op": "greeting.set",
    "field": "greeting",
    "title": "New greeting",
    "before": "Hi! Ask me about bookings.",
    "after": "Hello! I can help with bookings and opening times.",
    "expires_at": "2026-11-03T10:00:00Z",
    "tests": {
      "last_run": {
        "passed": 18,
        "total": 20,
        "finished_at": "2026-11-02T02:30:00Z"
      }
    }
  }
}
```

Errors: `400 invalid` · `401 unauthorized` · `403 forbidden, plan_required, limit_reached` · `404 not_found` · `409 conflict` · `429 rate_limited` · `500 internal` · `503 unavailable`

### Get a proposal

`GET /proposals/{proposal_id}`

Read one proposal and where it stands. Needs the agents:read scope.

Path:

- `proposal_id` (string (uuid), required): The proposal's id.

Request:

```bash
curl https://api.hiy.ai/v1/proposals/c3d4e5f6-7a8b-4c9d-8e0f-2a3b4c5d6e7f \
  -H "Authorization: Bearer $HIY_API_KEY"
```

Answer, 200:

```json
{
  "data": {
    "id": "c3d4e5f6-7a8b-4c9d-8e0f-2a3b4c5d6e7f",
    "status": "proposed",
    "op": "greeting.set",
    "field": "greeting",
    "title": "New greeting",
    "before": "Hi! Ask me about bookings.",
    "after": "Hello! I can help with bookings and opening times.",
    "expires_at": "2026-11-03T10:00:00Z",
    "tests": {
      "last_run": {
        "passed": 18,
        "total": 20,
        "finished_at": "2026-11-02T02:30:00Z"
      }
    }
  }
}
```

Errors: `400 invalid` · `401 unauthorized` · `403 forbidden, plan_required` · `404 not_found` · `429 rate_limited` · `500 internal` · `503 unavailable`

### Apply a proposal

`POST /proposals/{proposal_id}/apply`

Apply a proposal; it fails if the setting changed since. Needs the agents:write scope.

Path:

- `proposal_id` (string (uuid), required): The proposal's id.

Header:

- `Idempotency-Key` (string, optional): Send the same value again to get the first answer back instead of running the call twice. Kept 24 hours. 1 to 255 visible characters.

Request:

```bash
curl -X POST https://api.hiy.ai/v1/proposals/c3d4e5f6-7a8b-4c9d-8e0f-2a3b4c5d6e7f/apply \
  -H "Authorization: Bearer $HIY_API_KEY"
```

Answer, 200:

```json
{
  "data": {
    "proposal_id": "c3d4e5f6-7a8b-4c9d-8e0f-2a3b4c5d6e7f",
    "status": "applied",
    "version_id": "d4e5f6a7-8b9c-4d0e-9f1a-3b4c5d6e7f80"
  }
}
```

Errors: `400 invalid` · `401 unauthorized` · `403 forbidden, plan_required` · `404 not_found` · `409 conflict` · `429 rate_limited` · `500 internal` · `503 unavailable`

### Discard a proposal

`POST /proposals/{proposal_id}/discard`

Discard a proposal. Needs the agents:write scope.

Path:

- `proposal_id` (string (uuid), required): The proposal's id.

Header:

- `Idempotency-Key` (string, optional): Send the same value again to get the first answer back instead of running the call twice. Kept 24 hours. 1 to 255 visible characters.

Request:

```bash
curl -X POST https://api.hiy.ai/v1/proposals/c3d4e5f6-7a8b-4c9d-8e0f-2a3b4c5d6e7f/discard \
  -H "Authorization: Bearer $HIY_API_KEY"
```

Answer, 200:

```json
{
  "data": {
    "proposal_id": "c3d4e5f6-7a8b-4c9d-8e0f-2a3b4c5d6e7f",
    "status": "declined"
  }
}
```

Errors: `400 invalid` · `401 unauthorized` · `403 forbidden, plan_required` · `404 not_found` · `409 conflict` · `429 rate_limited` · `500 internal` · `503 unavailable`

### List changes

`GET /agents/{agent_id}/versions`

List an agent's setting and knowledge changes, newest first. Needs the agents:read scope.

Path:

- `agent_id` (string (uuid), required): The agent's id.

Query:

- `limit` (integer, optional): How many to return. 1 to 100. Default 25.
- `cursor` (string, optional): The next_cursor of the page before. Leave it out for the first page. Up to 500 characters.

Request:

```bash
curl https://api.hiy.ai/v1/agents/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d/versions \
  -H "Authorization: Bearer $HIY_API_KEY"
```

Answer, 200:

```json
{
  "data": [
    {
      "id": "d4e5f6a7-8b9c-4d0e-9f1a-3b4c5d6e7f80",
      "field": "greeting",
      "title": "Greeting",
      "actor": "api",
      "key_name": "Ops script",
      "before": "Hi! Ask me about bookings.",
      "after": "Hello! I can help with bookings and opening times.",
      "undone": false,
      "created_at": "2026-11-02T10:02:00Z"
    }
  ],
  "next_cursor": "eyJzIjo4OH0"
}
```

Errors: `400 invalid` · `401 unauthorized` · `403 forbidden, plan_required` · `404 not_found` · `429 rate_limited` · `500 internal` · `503 unavailable`

### Undo a change

`POST /agents/{agent_id}/versions/{version_id}/restore`

Undo one change by making a new one that puts back what it replaced. Needs the agents:write scope.

Path:

- `agent_id` (string (uuid), required): The agent's id.
- `version_id` (string (uuid), required): The change's id, from List changes.

Header:

- `Idempotency-Key` (string, optional): Send the same value again to get the first answer back instead of running the call twice. Kept 24 hours. 1 to 255 visible characters.

Request:

```bash
curl -X POST https://api.hiy.ai/v1/agents/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d/versions/d4e5f6a7-8b9c-4d0e-9f1a-3b4c5d6e7f80/restore \
  -H "Authorization: Bearer $HIY_API_KEY"
```

Answer, 200:

```json
{
  "data": {
    "version_id": "e5f6a7b8-9c0d-4e1f-8a2b-4c5d6e7f8091",
    "restores": "d4e5f6a7-8b9c-4d0e-9f1a-3b4c5d6e7f80",
    "field": "greeting",
    "after": "Hi! Ask me about bookings."
  }
}
```

Errors: `400 invalid` · `401 unauthorized` · `403 forbidden, plan_required` · `404 not_found` · `409 conflict` · `429 rate_limited` · `500 internal` · `503 unavailable`

**Knowledge.** The sources your agents answer from.

### List sources

`GET /sources`

List the sources in the workspace's knowledge, or one agent's. Needs the knowledge:read scope.

Query:

- `limit` (integer, optional): How many to return. 1 to 100. Default 25.
- `cursor` (string, optional): The next_cursor of the page before. Leave it out for the first page. Up to 500 characters.
- `agent_id` (string (uuid), optional): Only this agent's.

Request:

```bash
curl "https://api.hiy.ai/v1/sources?agent_id=a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d" \
  -H "Authorization: Bearer $HIY_API_KEY"
```

Answer, 200:

```json
{
  "data": [
    {
      "id": "f6a7b8c9-0d1e-4f2a-9b3c-5d6e7f8091a2",
      "type": "url",
      "url": "https://acmedental.com/prices",
      "title": "Prices",
      "confidential": false,
      "words": 1840,
      "state": "ready",
      "used_by": [
        "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
      ]
    }
  ],
  "next_cursor": null
}
```

Errors: `400 invalid` · `401 unauthorized` · `403 forbidden, plan_required` · `404 not_found` · `429 rate_limited` · `500 internal` · `503 unavailable`

### Add a source

`POST /sources`

Add a web page or a text to one agent's knowledge. Needs the knowledge:write scope.

Header:

- `Idempotency-Key` (string, optional): Send the same value again to get the first answer back instead of running the call twice. Kept 24 hours. 1 to 255 visible characters.

Body, type url:

- `type` (string, required): Must be url.
- `url` (string, required): Up to 2000 characters. An https:// link.
- `attach_to` (array of string (uuid), required): The agent to add it to, as a list of one id. Exactly 1.

Body, type text:

- `type` (string, required): Must be text.
- `title` (string, required): Up to 200 characters.
- `text` (string, required): Up to 100000 characters.
- `attach_to` (array of string (uuid), required): The agent to add it to, as a list of one id. Exactly 1.

Request:

```bash
curl -X POST https://api.hiy.ai/v1/sources \
  -H "Authorization: Bearer $HIY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "type": "url",
  "url": "https://acmedental.com/insurance",
  "attach_to": [
    "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
  ]
}'
```

Answer, 202:

```json
{
  "data": {
    "id": "f6a7b8c9-0d1e-4f2a-9b3c-5d6e7f8091a2",
    "state": "queued",
    "attached_to": [
      "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
    ]
  }
}
```

Errors: `400 invalid` · `401 unauthorized` · `403 forbidden, plan_required, limit_reached` · `404 not_found` · `409 conflict` · `429 rate_limited` · `500 internal` · `503 unavailable`

### Read a source again

`POST /sources/{source_id}/refetch`

Read a source's web page again. Needs the knowledge:write scope.

Path:

- `source_id` (string (uuid), required): The source's id.

Header:

- `Idempotency-Key` (string, optional): Send the same value again to get the first answer back instead of running the call twice. Kept 24 hours. 1 to 255 visible characters.

Request:

```bash
curl -X POST https://api.hiy.ai/v1/sources/f6a7b8c9-0d1e-4f2a-9b3c-5d6e7f8091a2/refetch \
  -H "Authorization: Bearer $HIY_API_KEY"
```

Answer, 200:

```json
{
  "data": {
    "id": "f6a7b8c9-0d1e-4f2a-9b3c-5d6e7f8091a2",
    "result": "updated"
  }
}
```

Errors: `400 invalid` · `401 unauthorized` · `403 forbidden, plan_required` · `404 not_found` · `409 conflict` · `429 rate_limited` · `500 internal` · `503 unavailable`

### Use a source

`PUT /agents/{agent_id}/sources/{source_id}`

Let an agent use a source from the workspace's knowledge. Needs the knowledge:write scope.

Path:

- `agent_id` (string (uuid), required): The agent's id.
- `source_id` (string (uuid), required): The source's id.

Request:

```bash
curl -X PUT https://api.hiy.ai/v1/agents/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d/sources/f6a7b8c9-0d1e-4f2a-9b3c-5d6e7f8091a2 \
  -H "Authorization: Bearer $HIY_API_KEY"
```

Answer, 200:

```json
{
  "data": {
    "agent_id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
    "source_id": "f6a7b8c9-0d1e-4f2a-9b3c-5d6e7f8091a2",
    "attached": true
  }
}
```

Errors: `400 invalid` · `401 unauthorized` · `403 forbidden, plan_required, limit_reached` · `404 not_found` · `409 conflict` · `429 rate_limited` · `500 internal` · `503 unavailable`

### Stop using a source

`DELETE /agents/{agent_id}/sources/{source_id}`

Stop an agent using a source; the source stays in the knowledge. Needs the knowledge:write scope.

Path:

- `agent_id` (string (uuid), required): The agent's id.
- `source_id` (string (uuid), required): The source's id.

Request:

```bash
curl -X DELETE https://api.hiy.ai/v1/agents/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d/sources/f6a7b8c9-0d1e-4f2a-9b3c-5d6e7f8091a2 \
  -H "Authorization: Bearer $HIY_API_KEY"
```

Answer, 200:

```json
{
  "data": {
    "agent_id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
    "source_id": "f6a7b8c9-0d1e-4f2a-9b3c-5d6e7f8091a2",
    "attached": false
  }
}
```

Errors: `400 invalid` · `401 unauthorized` · `403 forbidden, plan_required` · `404 not_found` · `409 conflict` · `429 rate_limited` · `500 internal` · `503 unavailable`

**Unanswered questions.** Questions an agent couldn't answer, and the answers you teach it.

### List unanswered questions

`GET /agents/{agent_id}/unanswered`

List the questions an agent could not answer. Needs the conversations:read scope.

Path:

- `agent_id` (string (uuid), required): The agent's id.

Query:

- `limit` (integer, optional): How many to return. 1 to 100. Default 25.
- `cursor` (string, optional): The next_cursor of the page before. Leave it out for the first page. Up to 500 characters.

Request:

```bash
curl https://api.hiy.ai/v1/agents/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d/unanswered \
  -H "Authorization: Bearer $HIY_API_KEY"
```

Answer, 200:

```json
{
  "data": [
    {
      "id": "0a7b8c9d-1e2f-4a3b-8c4d-6e7f8091a2b3",
      "question": "Do you take NHS patients?",
      "asked": 7,
      "last_asked_at": "2026-11-01T16:00:00Z",
      "created_at": "2026-10-28T09:00:00Z"
    }
  ],
  "next_cursor": null
}
```

Errors: `400 invalid` · `401 unauthorized` · `403 forbidden, plan_required` · `404 not_found` · `429 rate_limited` · `500 internal` · `503 unavailable`

### Teach an answer

`POST /agents/{agent_id}/answers`

Teach an agent an answer, for a question it could not answer or a new one. Needs the knowledge:write scope.

Path:

- `agent_id` (string (uuid), required): The agent's id.

Header:

- `Idempotency-Key` (string, optional): Send the same value again to get the first answer back instead of running the call twice. Kept 24 hours. 1 to 255 visible characters.

Body:

- `question` (string, required): Up to 2000 characters.
- `answer` (string, required): Up to 10000 characters.
- `gap_id` (string (uuid), optional): The unanswered question this answers, from List unanswered questions.

Request:

```bash
curl -X POST https://api.hiy.ai/v1/agents/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d/answers \
  -H "Authorization: Bearer $HIY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "question": "Do you take NHS patients?",
  "answer": "Yes, for check-ups and fillings.",
  "gap_id": "0a7b8c9d-1e2f-4a3b-8c4d-6e7f8091a2b3"
}'
```

Answer, 201:

```json
{
  "data": {
    "id": "2c9d0e1f-3a4b-4c5d-8e6f-8091a2b3c4d5",
    "version_id": "3d0e1f2a-4b5c-4d6e-9f70-91a2b3c4d5e6"
  }
}
```

Errors: `400 invalid` · `401 unauthorized` · `403 forbidden, plan_required, limit_reached` · `404 not_found` · `409 conflict` · `429 rate_limited` · `500 internal` · `503 unavailable`

**Conversations.** Support Agent conversations, to read.

### List conversations

`GET /conversations`

List Support Agent conversations, newest first. Needs the conversations:read scope.

Query:

- `limit` (integer, optional): How many to return. 1 to 100. Default 25.
- `cursor` (string, optional): The next_cursor of the page before. Leave it out for the first page. Up to 500 characters.
- `agent_id` (string (uuid), optional): Only this agent's.
- `state` (string, optional): One of: answering, handed_over, with_a_person, resolved, snoozed.
- `channel` (string, optional): One of: web, embed, slack, api, email, whatsapp, phone.
- `since` (string (date-time), optional): Only conversations started at or after this time. ISO 8601, UTC.

Request:

```bash
curl "https://api.hiy.ai/v1/conversations?agent_id=a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d&state=handed_over&channel=web" \
  -H "Authorization: Bearer $HIY_API_KEY"
```

Answer, 200:

```json
{
  "data": [
    {
      "id": "1b8c9d0e-2f3a-4b4c-9d5e-7f8091a2b3c4",
      "agent_id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
      "channel": "web",
      "state": "handed_over",
      "first_question": "Can I move my appointment?",
      "contact": {
        "name": "Sam",
        "email": "sam@example.com"
      },
      "started_at": "2026-11-01T09:12:00Z",
      "last_message_at": "2026-11-01T09:15:00Z"
    }
  ],
  "next_cursor": null
}
```

Errors: `400 invalid` · `401 unauthorized` · `403 forbidden, plan_required` · `404 not_found` · `429 rate_limited` · `500 internal` · `503 unavailable`

### Get a conversation

`GET /conversations/{conversation_id}`

Read one conversation with its messages. Needs the conversations:read scope.

Path:

- `conversation_id` (string (uuid), required): The conversation's id.

Request:

```bash
curl https://api.hiy.ai/v1/conversations/1b8c9d0e-2f3a-4b4c-9d5e-7f8091a2b3c4 \
  -H "Authorization: Bearer $HIY_API_KEY"
```

Answer, 200:

```json
{
  "data": {
    "id": "1b8c9d0e-2f3a-4b4c-9d5e-7f8091a2b3c4",
    "agent_id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
    "channel": "web",
    "state": "handed_over",
    "contact": {
      "name": "Sam",
      "email": "sam@example.com"
    },
    "started_at": "2026-11-01T09:12:00Z",
    "messages": [
      {
        "from": "visitor",
        "visitor_text": "Can I move my appointment?",
        "at": "2026-11-01T09:12:00Z"
      },
      {
        "from": "agent",
        "text": "I can hand you to the team for that.",
        "at": "2026-11-01T09:12:05Z"
      }
    ],
    "truncated": false
  }
}
```

Errors: `400 invalid` · `401 unauthorized` · `403 forbidden, plan_required` · `404 not_found` · `429 rate_limited` · `500 internal` · `503 unavailable`

**Insights.** An agent's counts for a window.

### Get insights

`GET /agents/{agent_id}/insights`

Read an agent's counts for a window. Needs the agents:read scope.

Path:

- `agent_id` (string (uuid), required): The agent's id.

Query:

- `window` (string, optional): One of: last_7_days, last_14_days, last_30_days. Default last_30_days.

Request:

```bash
curl "https://api.hiy.ai/v1/agents/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d/insights?window=last_30_days" \
  -H "Authorization: Bearer $HIY_API_KEY"
```

Answer, 200:

```json
{
  "data": {
    "window": "last_30_days",
    "conversations": 412,
    "questions": 655,
    "handed_over": 38,
    "unanswered": 23,
    "resolutions": {
      "confirmed": 120,
      "assumed": 190,
      "handed_over": 38,
      "unresolved": 64
    }
  }
}
```

Errors: `400 invalid` · `401 unauthorized` · `403 forbidden, plan_required` · `404 not_found` · `429 rate_limited` · `500 internal` · `503 unavailable`

**OpenAPI file.** This description of the API.

### Get the OpenAPI file

`GET /openapi.json`

Read this API's OpenAPI 3.1 description. No key needed.

Request:

```bash
curl https://api.hiy.ai/v1/openapi.json
```

Errors: `404 not_found` · `500 internal`

## Related

- [API keys](/docs/api-keys) — Keys that connect hiy to other tools: where to find them, create one, revoke one.

- [The chat API](/docs/developers) — Call your agent from your own code: the chat endpoint, visitor tokens, limits and errors.

- [Zapier](/docs/zapier) — New lead, handoff requested and unanswered-question triggers, connected with an API key.
