# Handoff Configuration

> Human Handoff transfers conversations to human operators when a personal touch is needed. Configure it via the API.

Human Handoff enables your AI Agent to automatically transfer conversations to human operators when it detects situations that need a personal touch. **Handoff is AI-driven** — the AI continuously evaluates the conversation against configurable guidelines and triggers a handoff when appropriate, without any manual intervention.

**How automatic handoff works:**
1. During a conversation, the AI evaluates each message against your **generic guidelines** (e.g., user frustration, lack of knowledge) and **custom guidelines** you define
2. When a guideline triggers, the AI shows the visitor a confirmation message asking if they'd like to speak with a human
3. If the visitor confirms, the conversation is transferred to a human operator, with an optional AI-generated summary of the conversation so far
4. If working hours are configured and the request falls outside them, a custom message is shown instead

**Additional handoff methods:**
- **Keyword triggers** — Visitors can type specific phrases (e.g., "speak to human", "agent") to request handoff directly
- **Manual handoff from Dashboard** — Operators can take over any conversation from the Inbox by changing the conversation assignee

**Topic-based Routing** is an advanced feature that routes handoffs to specific operators based on the conversation topic. Each routing profile defines a topic, a description of when it applies, and a list of operators who handle that topic. When a handoff triggers, the AI matches the conversation to the most relevant routing profile and notifies the assigned operators. Configure routing profiles via the `routing_profiles` array in the PUT request.

## Get Handoff Configuration

**Scope: read_all**

`GET https://app.quickchat.ai/v1/api/human_handoff/configuration`

**Shell**

```shell
curl https://app.quickchat.ai/v1/api/human_handoff/configuration \
  -H 'Authorization: Bearer <API_TOKEN>'
```

**Python**

```python
import requests

response = requests.get(
    url="https://app.quickchat.ai/v1/api/human_handoff/configuration",
    headers={"Authorization": "Bearer <API_TOKEN>"},
)
data = response.json()
```

**Response** `200 OK`

The response contains several nested objects:

**`settings`** — Core handoff configuration:

| Field | Description |
|-------|-------------|
| `is_active` <br/> boolean | Whether human handoff is enabled |
| `keywords` <br/> array of strings | Trigger keywords that prompt a handoff (e.g., `["speak to human", "agent"]`) |
| `ai_summary_active` <br/> boolean | Send an AI-generated conversation summary to the human operator when handoff occurs |
| `topic_based_routing_active` <br/> boolean | Whether topic-based routing to specific operators is enabled (read-only, configured via routing profiles) |
| `question_message` <br/> string | Message shown to the visitor asking if they want to be connected to a human |
| `confirmation_message` <br/> string | Message shown after the visitor confirms handoff (max 500 chars) |
| `confirmation_outside_working_hours_message` <br/> string | Message shown when handoff is requested outside working hours (max 500 chars) |
| `working_hours_active` <br/> boolean | Restrict handoff to working hours only |
| `timezone` <br/> string | Timezone for working hours (e.g., `"Europe/London"`) |
| `send_email_notification` <br/> boolean | Send email notifications to operators on handoff |
| `emails` <br/> array of strings | Email addresses to notify |

**`availability`** — Working hours schedule (array of slots):

| Field | Description |
|-------|-------------|
| `id` <br/> integer | Availability slot ID |
| `day_span` <br/> string | Day or day range (e.g., `"monday"`, `"monday-friday"`) |
| `start_time` <br/> string | Start time in `"HH:MM"` format |
| `end_time` <br/> string | End time in `"HH:MM"` format |

**`generic_guidelines`** — Predefined handoff trigger rules (array):

| Field | Description |
|-------|-------------|
| `name` <br/> string | Guideline type: `"user_frustration"`, `"customer_support_suggestion"`, `"lack_of_knowledge"`, `"irrelevant_advice"`, `"media_message"` |
| `description` <br/> string | Description of when this guideline triggers |
| `is_active` <br/> boolean | Whether this guideline is enabled |

**`custom_guidelines`** — User-defined handoff trigger rules (array):

| Field | Description |
|-------|-------------|
| `id` <br/> integer | Guideline ID |
| `name` <br/> string | Custom guideline name (max 100 chars) |
| `description` <br/> string | When this guideline should trigger handoff (max 2000 chars) |
| `is_active` <br/> boolean | Whether this guideline is enabled |

**`routing_profiles`** — Topic-based routing directs handoffs to the right operators based on what the conversation is about.

When a handoff triggers, the AI evaluates the conversation against all active routing profiles and matches it to the most relevant topic. The operators listed in that profile are then notified. If no routing profile matches, the default notification behavior (email list in `settings.emails`) is used.

**Example:** You have a "Billing" routing profile assigned to your finance team and a "Technical Support" profile assigned to engineers. When a customer asks about an invoice and triggers a handoff, the AI matches the conversation to "Billing" and notifies only the finance team — not the engineers.

Configure routing profiles in the Dashboard under **Handoff > Topic-based Routing**, or via the `routing_profiles` array in the [PUT request](/api-reference/conversations/handoff-configuration/#update-handoff-configuration).

| Field | Description |
|-------|-------------|
| `id` <br/> integer | Routing profile ID |
| `name` <br/> string | Topic name (e.g., "Billing", "Technical Support") (max 100 chars) |
| `description` <br/> string | When this profile should match — describe the types of conversations that should route to these operators (max 2000 chars) |
| `is_active` <br/> boolean | Whether this routing profile is enabled |
| `user_ids` <br/> array of integers | IDs of operators who should be notified when this profile matches |

## Update Handoff Configuration

**Scope: write_all**

`PUT https://app.quickchat.ai/v1/api/human_handoff/configuration`

:::caution
PUT replaces the entire handoff configuration atomically. You must include all sections (`settings`, `availability`, `generic_guidelines`, `custom_guidelines`, `routing_profiles`) in the request body. Omitting a section or providing partial data will result in validation errors. To make incremental changes, first GET the current configuration, modify the fields you need, and PUT the full object back.
:::

**Shell**

```shell
# First, fetch the current configuration
CONFIG=$(curl -s https://app.quickchat.ai/v1/api/human_handoff/configuration \
  -H 'Authorization: Bearer <API_TOKEN>')

# Modify and PUT back (example: enable handoff)
echo "$CONFIG" | jq '.settings.is_active = true' | \
curl -X PUT https://app.quickchat.ai/v1/api/human_handoff/configuration \
  -H 'Authorization: Bearer <API_TOKEN>' \
  -H 'Content-Type: application/json' \
  -d @-
```

**Python**

```python
import requests

headers = {"Authorization": "Bearer <API_TOKEN>"}

# Fetch current configuration
config = requests.get(
    url="https://app.quickchat.ai/v1/api/human_handoff/configuration",
    headers=headers,
).json()

# Modify and PUT back
config["settings"]["is_active"] = True

response = requests.put(
    url="https://app.quickchat.ai/v1/api/human_handoff/configuration",
    headers=headers,
    json=config,
)
data = response.json()
```

**Response** `200 OK` — Returns the updated handoff configuration.

---
