# Assign an agent to a TikTok account

> POST https://api.nabrah.ai/api/ext/omni_v2/tiktok/assign_chatbot

Group: TikTok. Page: https://www.nabrah.ai/en/docs/api-reference/tiktok/assign-an-agent-to-a-tiktok-account

Attach an AI agent to one of the project's TikTok accounts so it automatically replies to incoming TikTok direct messages on that account. You bind an existing agent (by `agent_id`) and configure, for this account, whether the bot may escalate to a human, who it hands over to, when idle conversations close, and where conversation events are sent. The response returns the bound agent's full configuration plus this account's `text_chatbot_settings`.

## How auto-reply works

Once assigned, incoming TikTok direct messages on that account are handled by the chosen agent, which generates and sends replies automatically.

- **agent_id**: The UUID of an existing text/basic agent in this project that should answer messages. Fields: `agent_id`.
- **name**: The bot's display name. It is shared by every TikTok account this agent answers on. Fields: `name`.
- **Human handoff**: Set `can_refer_to_human` to true to let the bot escalate a conversation, then describe who it reaches in `human_emails` (see below). Fields: `can_refer_to_human`, `human_emails`.

Use GET /api/ext/omni_v2/tiktok/get_chatbot to inspect the current assignment and DELETE /api/ext/omni_v2/tiktok/unassign_chatbot to remove it.

## One agent, several accounts

Assigning adds this account to the agent. The agent keeps answering on its other accounts, and their settings stay as they are.

- **Per-account settings**: These apply to the selected account only. Fields: `can_refer_to_human`, `human_emails`, `auto_resolve_hours`, `webhook_url`, `webhook_hmac_secret`.
- **Settings left out**: Leaving out `can_refer_to_human` turns handoff off, and leaving out `human_emails` sends an empty list, which hands over to a random project member who can see this account's conversations. Leaving out `auto_resolve_hours`, `webhook_url` or `webhook_hmac_secret` keeps this account's current value, also when the request replaces the account's agent. On a account with no agent, every setting left out is copied from the agent's first account when the agent already answers on another account, and starts empty otherwise. Fields: `can_refer_to_human`, `human_emails`, `auto_resolve_hours`, `webhook_url`, `webhook_hmac_secret`.
- **Replacing an agent**: A account has one agent at a time. Assigning a different agent to a account replaces the previous one there; ongoing conversations on that account continue with the new agent, which does not see the previous agent's replies. The account keeps its own settings, except those sent in the request and the handoff rule above.
- **inbox_ids**: `text_chatbot_settings.inbox_ids` in the response lists every TikTok account the agent now answers on. Fields: `inbox_ids`.

## Choosing who the bot hands over to

`human_emails` accepts three shapes. Working hours are optional on any destination; when they are set, only destinations inside their window are eligible and one of them is picked at random.

- **Anyone available** (human_emails: []): An empty list refers the conversation to a random project member who can see this account's conversations. Working hours are ignored on this path. Fields: `human_emails`.
- **Specific people** (human_emails: ["a@example.com", { "email": "b@example.com", "hours": { ... } }]): A list of addresses. Each item is either a bare string (always available) or an object with an optional `hours` window. Fields: `human_emails`.
- **By department** (human_emails: { "IT": { "desc": "...", "emails": [ ... ] } }): A category map. `desc` is required and is the only text the assistant sees when deciding which department fits, so make it specific. The assistant must pass a category on every call; if none of the descriptions match, nobody is contacted. Fields: `human_emails`.
- **hours** ({ "days": [1,2,3,4,5], "start": "09:00", "end": "17:00", "timezone": "Asia/Riyadh" }): `days` are ISO weekdays, 1 = Monday through 7 = Sunday; an empty list means every day. `start` and `end` are zero-padded 24-hour times, and a window whose start is later than its end wraps past midnight. `timezone` is an IANA zone and defaults to Asia/Riyadh. Fields: `human_emails`.

Addresses that do not belong to a project member who can see this account's conversations still open the conversation, but it is left unassigned.

## Choosing the TikTok account

A project can connect more than one TikTok account. `inbox_id` selects the account this call works on.

- **One account**: `inbox_id` is optional; the project's only TikTok account is used.
- **More than one account**: `inbox_id` is required and the call returns 400 without it. An id that is not one of the project's TikTok accounts returns 404. Fields: `inbox_id`.

List the accounts and their ids with GET /api/ext/omni_v2/tiktok/inboxes.

## Errors

- **409 Conflict**: Another change to the same account's agent, or to the same agent on another account, is still being saved. Wait a moment, then try again; GET /api/ext/omni_v2/tiktok/get_chatbot shows the result once it is saved.

## Event webhooks

Set `webhook_url` to receive a POST for each chatbot event on this account. Leave the field out to keep the current value, or send null to turn webhooks off.

- **Events**: `message.received`: every incoming customer message on the account, including chats a person has taken over. `message.replied`: a reply sent by the bot. `message.sent`: a reply sent by a person or through the API. `conversation.status_changed`: a handoff to a person, the bot ending the chat, or a manual status change. `conversation.auto_resolved`: the chat was closed after the auto-resolve window. Fields: `webhook_url`.
- **Payload** ({ "event", "occurred_at", "project_id", "agent_id", "conversation_id", "data" }): For message events, `data` has `conversation_id`, `content`, `content_type`, `created_at`, `message_type` (0 = incoming, 1 = outgoing) and `attachments` (each with `file_type` and `data_url`). For status events, `data` has `conversation_id`, `status`, `previous_status` (can be null) and `reason` (`refer_to_human`, `end_chat`, `auto_resolve` or `manual`).
- **Signature** (X-Nabrah-Signature: sha256=<hex digest>): When `webhook_hmac_secret` is set, each request has `X-Nabrah-Timestamp` (Unix seconds) and `X-Nabrah-Signature`: `sha256=` followed by the hex HMAC-SHA256 of `<timestamp>.<raw request body>`, keyed with your secret. Verify it against the raw body, compare in constant time, and reject old timestamps. Every request also has `X-Nabrah-Event` with the event name. Fields: `webhook_hmac_secret`.
- **Delivery**: Each event is sent once with a 5-second timeout. Failed or non-2xx deliveries are not retried, and events have no event ID. One status change can arrive as two events, for example `conversation.auto_resolved` and then `conversation.status_changed`. Keep your handler idempotent, and use GET /api/ext/omni_v2/conversation/conversation/{id}/messages to fill any gaps.

Events are only sent while a chatbot is assigned to the account. GET /api/ext/omni_v2/tiktok/get_chatbot returns `webhook_url` and `has_webhook_hmac_secret`; the secret itself is never returned.

## Authorization

- `X-API-Key` (string, header, required): your workspace API key.

## Query parameters

- `inbox_id` (string, optional): The `id` of the TikTok account to use, from GET /api/ext/omni_v2/tiktok/inboxes. Use `inboxes[].id` (a UUID), not the numeric `inboxes[].inbox_id`. Optional while the project has one TikTok account; required once it has more than one.

## Body (application/json)

### Example: Specific people

A flat list of addresses, always available.

```json
{
  "agent_id": "00000000-0000-4000-8000-000000000000",
  "name": "TikTok Support Bot",
  "can_refer_to_human": true,
  "human_emails": [
    "support@example.com"
  ]
}
```

### Example: With working hours

Only reachable Monday to Friday, 09:00-17:00 Riyadh time.

```json
{
  "agent_id": "00000000-0000-4000-8000-000000000000",
  "name": "TikTok Support Bot",
  "can_refer_to_human": true,
  "human_emails": [
    "support@example.com",
    {
      "email": "oncall@example.com",
      "hours": {
        "days": [
          1,
          2,
          3,
          4,
          5
        ],
        "start": "09:00",
        "end": "17:00",
        "timezone": "Asia/Riyadh"
      }
    }
  ]
}
```

### Example: By department

The assistant picks a department from the descriptions.

```json
{
  "agent_id": "00000000-0000-4000-8000-000000000000",
  "name": "TikTok Support Bot",
  "can_refer_to_human": true,
  "human_emails": {
    "IT": {
      "desc": "Bugs, outages, login and password problems",
      "emails": [
        "it@example.com"
      ]
    },
    "Sales": {
      "desc": "Pricing, quotes and product demos",
      "emails": [
        "sales@example.com",
        {
          "email": "nightshift@example.com",
          "hours": {
            "days": [],
            "start": "22:00",
            "end": "06:00",
            "timezone": "UTC"
          }
        }
      ]
    }
  }
}
```

### Example: Anyone available

An empty list refers to a random project member who can see this account's conversations.

```json
{
  "agent_id": "00000000-0000-4000-8000-000000000000",
  "name": "TikTok Support Bot",
  "can_refer_to_human": true,
  "human_emails": []
}
```

### Example: With event webhook

Send chatbot events to your endpoint, signed with a shared secret.

```json
{
  "agent_id": "00000000-0000-4000-8000-000000000000",
  "name": "TikTok Support Bot",
  "can_refer_to_human": true,
  "human_emails": [
    "support@example.com"
  ],
  "webhook_url": "https://example.com/nabrah/events",
  "webhook_hmac_secret": "replace-with-a-long-random-secret"
}
```

## Response

### 200 Successful Response

Content type: `application/json`

```json
{
  "agent": {
    "agent_id": "00000000-0000-4000-8000-000000000000",
    "project_id": "00000000-0000-4000-8000-000000000000",
    "created_by_email": "string",
    "created_at": "2026-01-15T12:00:00.000Z",
    "last_update": "2026-01-15T12:00:00.000Z",
    "name": "string",
    "start_first": false,
    "first_sentence": "string",
    "agent_type": "basic",
    "who_are_you": "string",
    "goal": "string",
    "steps": "string",
    "allow_interruptions": false,
    "voice": "dania",
    "support_data": "string",
    "languages": [
      "ar"
    ],
    "stack": "latest",
    "speech_speed": 0.7,
    "variables": [
      {
        "name": "string",
        "type": "string",
        "default_value": "string"
      }
    ],
    "pre_call_callback": {
      "url": "string",
      "parameters": [
        {
          "name": null,
          "location": null,
          "data_type": null,
          "value": null
        }
      ]
    },
    "post_call_callback": {
      "url": "string",
      "parameters": [
        {
          "name": null,
          "location": null,
          "data_type": null,
          "value": null
        }
      ]
    },
    "post_analysis_callback": {
      "url": "string",
      "parameters": [
        {
          "name": null,
          "location": null,
          "data_type": null,
          "value": null
        }
      ]
    },
    "tools": [
      {
        "id": "00000000-0000-4000-8000-000000000000",
        "name": "string"
      }
    ],
    "knowledge_bases": [
      {
        "id": "00000000-0000-4000-8000-000000000000",
        "project_id": "00000000-0000-4000-8000-000000000000",
        "name": "string",
        "key": "string",
        "desc": "string",
        "kind": "unstructured",
        "document_count": 0,
        "created_at": "2026-01-15T12:00:00.000Z",
        "updated_at": "2026-01-15T12:00:00.000Z"
      }
    ],
    "system_tools": [
      {
        "id": "00000000-0000-4000-8000-000000000000",
        "name": "string",
        "config": {},
        "created_at": "2026-01-15T12:00:00.000Z",
        "updated_at": "2026-01-15T12:00:00.000Z",
        "when_to_use": "string"
      }
    ],
    "analysis_groups": [
      {
        "id": "00000000-0000-4000-8000-000000000000",
        "name": "string"
      }
    ],
    "background_ambient": false,
    "background_ambient_volume": 0,
    "thinking_sound": false,
    "thinking_sound_volume": 0
  },
  "text_chatbot_settings": {
    "can_refer_to_human": false,
    "human_emails": [
      "string"
    ],
    "name": "string",
    "created_at": "2026-01-15T12:00:00.000Z",
    "auto_resolve_hours": 0,
    "webhook_url": "string",
    "has_webhook_hmac_secret": false,
    "inbox_ids": [
      "00000000-0000-4000-8000-000000000000"
    ]
  }
}
```

### 422 Validation Error

Content type: `application/json`

```json
{
  "detail": [
    {
      "loc": [
        "string"
      ],
      "msg": "string",
      "type": "string"
    }
  ]
}
```

## Request examples

### cURL

```bash
curl --request POST \
  --url 'https://api.nabrah.ai/api/ext/omni_v2/tiktok/assign_chatbot' \
  --header 'X-API-Key: <your-api-key>' \
  --header 'Content-Type: application/json' \
  --data '{
  "agent_id": "00000000-0000-4000-8000-000000000000",
  "name": "TikTok Support Bot",
  "can_refer_to_human": true,
  "human_emails": [
    "support@example.com"
  ]
}'
```

### Python

```python
import requests

url = "https://api.nabrah.ai/api/ext/omni_v2/tiktok/assign_chatbot"
headers = {
    "X-API-Key": "<your-api-key>",
}
payload = {
    "agent_id": "00000000-0000-4000-8000-000000000000",
    "name": "TikTok Support Bot",
    "can_refer_to_human": True,
    "human_emails": [
        "support@example.com"
    ]
}

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()
print(response.json())
```

### JavaScript

```javascript
const response = await fetch("https://api.nabrah.ai/api/ext/omni_v2/tiktok/assign_chatbot", {
  method: "POST",
  headers: {
    "X-API-Key": "<your-api-key>",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "agent_id": "00000000-0000-4000-8000-000000000000",
    "name": "TikTok Support Bot",
    "can_refer_to_human": true,
    "human_emails": [
      "support@example.com"
    ]
  }),
});

const data = await response.json();
console.log(data);
```

### Go

```go
package main

import (
	"fmt"
	"io"
	"net/http"
	"strings"
)

func main() {
	payload := strings.NewReader(`{
  "agent_id": "00000000-0000-4000-8000-000000000000",
  "name": "TikTok Support Bot",
  "can_refer_to_human": true,
  "human_emails": [
    "support@example.com"
  ]
}`)

	req, _ := http.NewRequest("POST", "https://api.nabrah.ai/api/ext/omni_v2/tiktok/assign_chatbot", payload)
	req.Header.Set("X-API-Key", "<your-api-key>")
	req.Header.Set("Content-Type", "application/json")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	out, _ := io.ReadAll(res.Body)
	fmt.Println(string(out))
}
```
