API Reference
API Reference
Техническая документация для разработчиков внешних систем, интегрирующихся с CallMeAI.
Базовый URL
https://callmeai.ru/api/orpc
Все endpoints доступны через POST-запросы к этому базовому URL.
Аутентификация
Все запросы требуют Bearer-токен в заголовке Authorization:
Authorization: Bearer mai_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Получить токен можно в настройках API токенов. Подробнее: Документация API токенов.
Формат запросов
- Метод: POST
- Content-Type:
application/json(для большинства endpoints) - Content-Type:
multipart/form-data(для загрузки файлов)
Тело запроса
Все параметры передаются в JSON-формате:
{
"where": { ... },
"include": { ... },
"take": 10,
"skip": 0
}
Формат ответов
Успешный ответ
{
"result": { ... }
}
Ошибка
{
"error": {
"code": "UNAUTHORIZED",
"message": "API token has expired"
}
}
Параметры запросов
Все endpoints используют стандартные параметры Prisma для фильтрации, сортировки и пагинации.
where — фильтрация
Объект where позволяет фильтровать записи по полям. Поддерживаются операторы сравнения:
| Оператор | Описание | Пример |
|---|---|---|
equals | Точное совпадение | { "id": 1 } или { "id": { "equals": 1 } } |
not | Не равно | { "id": { "not": 1 } } |
in | Входит в список | { "id": { "in": [1, 2, 3] } } |
notIn | Не входит в список | { "id": { "notIn": [1, 2] } } |
lt | Меньше | { "duration": { "lt": 5 } } |
lte | Меньше или равно | { "duration": { "lte": 5 } } |
gt | Больше | { "duration": { "gt": 2 } } |
gte | Больше или равно | { "duration": { "gte": 2 } } |
contains | Содержит подстроку | { "name": { "contains": "клиент" } } |
startsWith | Начинается с | { "name": { "startsWith": "Звонок" } } |
endsWith | Заканчивается на | { "name": { "endsWith": "2024" } } |
Логические операторы:
{
"where": {
"AND": [{ "duration": { "gte": 2 } }, { "duration": { "lte": 10 } }]
}
}
{
"where": {
"OR": [{ "source": "SIPUNI" }, { "source": "ORIGINAL" }]
}
}
orderBy — сортировка
Сортировка по одному или нескольким полям:
{
"orderBy": { "createdAt": "desc" }
}
{
"orderBy": [{ "createdAt": "desc" }, { "name": "asc" }]
}
Значения: "asc" (по возрастанию) или "desc" (по убыванию).
take и skip — пагинация
| Параметр | Описание |
|---|---|
take | Количество записей для возврата |
skip | Количество записей для пропуска |
Пример пагинации (страница 3 по 20 записей):
{
"take": 20,
"skip": 40
}
include — связанные данные
Включение связанных сущностей в ответ:
{
"include": {
"messages": true,
"Report": true,
"manager": true
}
}
Можно также фильтровать включаемые данные:
{
"include": {
"Report": {
"take": 1,
"orderBy": { "createdAt": "desc" }
}
}
}
select — выбор полей
Вместо include можно использовать select для выбора конкретных полей:
{
"select": {
"id": true,
"name": true,
"createdAt": true,
"Report": {
"select": {
"temperature": true,
"summary": true
}
}
}
}
include и select одновременно на одном уровне.Endpoints
read:conversations
Список разговоров
POST /api/orpc/conversation/getConversations
Получение списка разговоров пользователя.
Поля модели Conversation:
| Поле | Тип | Описание |
|---|---|---|
id | number | Уникальный ID разговора |
name | string | Название/заголовок разговора |
duration | number | Длительность в минутах |
createdAt | datetime | Дата создания |
source | enum | Источник: SIPUNI, ORIGINAL |
managerId | number? | ID менеджера (если привязан) |
recordingUrl | string? | URL записи (если есть) |
Связанные данные (include):
| Поле | Описание |
|---|---|
messages | Список сообщений (реплик) разговора |
Report | Отчёты анализа |
manager | Данные менеджера |
MarketingInsight | Маркетинговые инсайты |
Примеры запросов:
Получить последние 10 разговоров:
{
"take": 10,
"orderBy": { "createdAt": "desc" }
}
Разговоры за январь 2024 длительностью более 2 минут:
{
"where": {
"createdAt": {
"gte": "2024-01-01T00:00:00Z",
"lte": "2024-01-31T23:59:59Z"
},
"duration": { "gte": 2 }
},
"orderBy": { "createdAt": "desc" }
}
Разговоры конкретного менеджера с отчётами:
{
"where": { "managerId": 5 },
"include": {
"Report": {
"select": {
"id": true,
"temperature": true,
"summary": true
}
},
"manager": true
}
}
Поиск по названию:
{
"where": {
"name": { "contains": "продажа" }
}
}
Пример ответа:
{
"result": [
{
"id": 1,
"name": "Звонок с клиентом",
"duration": 5.2,
"createdAt": "2024-01-15T10:30:00.000Z",
"source": "SIPUNI",
"managerId": 1,
"Report": [
{
"id": 1,
"temperature": "HOT",
"summary": "Клиент заинтересован в покупке"
}
],
"manager": {
"id": 1,
"name": "Иван Петров"
}
}
]
}
Детали разговора
POST /api/orpc/conversation/getConversation
Получение одного разговора по ID с полной информацией.
Обязательные параметры:
| Параметр | Тип | Описание |
|---|---|---|
where.id | number | ID разговора |
Поля модели Message (при include):
| Поле | Тип | Описание |
|---|---|---|
id | number | ID сообщения |
content | string | Текст реплики |
name | string | Имя говорящего |
speaker_role | enum | Роль: MANAGER, CLIENT |
createdAt | datetime | Время создания |
Поля модели Report (при include):
| Поле | Тип | Описание |
|---|---|---|
id | number | ID отчёта |
temperature | enum | Температура: HOT, WARM, COLD |
summary | string | Краткое резюме разговора |
createdAt | datetime | Дата создания отчёта |
Примеры запросов:
Разговор с сообщениями:
{
"where": { "id": 123 },
"include": { "messages": true }
}
Разговор с отчётом и результатами по критериям:
{
"where": { "id": 123 },
"include": {
"messages": true,
"Report": {
"include": {
"Result_Criterias": {
"include": {
"criteria": true
}
}
}
}
}
}
Пример ответа:
{
"result": {
"id": 123,
"name": "Звонок с клиентом",
"duration": 5.2,
"createdAt": "2024-01-15T10:30:00.000Z",
"source": "SIPUNI",
"messages": [
{
"id": 1,
"content": "Здравствуйте, компания CallMeAI!",
"name": "Менеджер",
"speaker_role": "MANAGER"
},
{
"id": 2,
"content": "Добрый день! Меня интересует ваш продукт.",
"name": "Клиент",
"speaker_role": "CLIENT"
}
],
"Report": [
{
"id": 1,
"temperature": "HOT",
"summary": "Клиент заинтересован в покупке, готов к следующему шагу",
"Result_Criterias": [
{
"id": 1,
"value": 95,
"comment": "Отличное приветствие",
"criteria": {
"id": 1,
"name": "Приветствие"
}
}
]
}
]
}
}
analyze:calls
Загрузка и анализ звонка
POST /api/orpc/uploadCall
Загрузка аудиофайла для анализа. Возвращает поток событий (Server-Sent Events).
Content-Type: multipart/form-data
Обязательные параметры:
| Параметр | Тип | Описание |
|---|---|---|
file | File | Аудиофайл для анализа |
criteriaFolderId | number | ID папки критериев для оценки |
Опциональные параметры:
| Параметр | Тип | Описание |
|---|---|---|
managerId | number | ID менеджера для привязки звонка |
Поддерживаемые форматы файлов:
| Формат | MIME-тип |
|---|---|
| MP3 | audio/mpeg |
| WAV | audio/wav |
| M4A | audio/mp4 |
| OGG | audio/ogg |
| WEBM | audio/webm |
Ограничения:
- Максимальный размер файла: 100 МБ
- Максимальная длительность: 60 минут
- Минимальная длительность: 30 секунд
- Требуется наличие минут на балансе
Пример запроса (curl):
curl -X POST https://callmeai.ru/api/orpc/uploadCall \
-H "Authorization: Bearer mai_xxxxx" \
-F "file=@call.mp3" \
-F "criteriaFolderId=1" \
-F "managerId=5"
Пример запроса (JavaScript):
const formData = new FormData();
formData.append("file", audioFile);
formData.append("criteriaFolderId", "1");
formData.append("managerId", "5");
const response = await fetch("https://callmeai.ru/api/orpc/uploadCall", {
method: "POST",
headers: {
Authorization: "Bearer mai_xxxxx",
},
body: formData,
});
Поток ответа (SSE):
Endpoint возвращает поток событий с прогрессом обработки:
data: {"type": "chunk", "choices": [{"delta": {"content": "..."}}]}
data: {"type": "chunk", "choices": [{"delta": {"content": "..."}}]}
...
data: {"type": "conversation", "data": {"id": 456, "name": "Новый звонок", ...}}
Финальный объект conversation содержит:
| Поле | Тип | Описание |
|---|---|---|
id | number | ID созданного разговора |
name | string | Автоматически сгенерированное название |
duration | number | Длительность в минутах |
createdAt | datetime | Дата создания |
messages | array | Транскрибированные реплики |
Обработка SSE в JavaScript:
const response = await fetch(url, options);
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const text = decoder.decode(value);
const lines = text.split("\n");
for (const line of lines) {
if (line.startsWith("data: ")) {
const data = JSON.parse(line.slice(6));
if (data.type === "conversation") {
console.log("Готово!", data.data);
}
}
}
}
Возможные ошибки:
| Ошибка | Причина |
|---|---|
Недостаточно минут | На балансе меньше минут, чем длительность аудио |
Файл слишком большой | Превышен лимит 100 МБ |
Неподдерживаемый формат | Файл не является аудио |
Папка критериев не найдена | Неверный criteriaFolderId |
read:criteria
Список критериев
POST /api/orpc/criteria/getCriterias
Получение списка критериев оценки.
Поля модели Criteria:
| Поле | Тип | Описание |
|---|---|---|
id | number | Уникальный ID критерия |
name | string | Название критерия |
description | string | Описание — что именно оценивается |
criteriaFolderId | number | ID папки критериев |
createdAt | datetime | Дата создания |
updatedAt | datetime | Дата последнего обновления |
Связанные данные (include):
| Поле | Описание |
|---|---|
CriteriaFolder | Папка, к которой принадлежит критерий |
Фильтрация (where):
| Поле | Описание |
|---|---|
id | По ID критерия |
name | По названию (contains, startsWith и т.д.) |
criteriaFolderId | По ID папки |
createdAt | По дате создания |
Примеры запросов:
Все критерии из папки:
{
"where": { "criteriaFolderId": 1 }
}
Поиск критериев по названию:
{
"where": {
"name": { "contains": "приветствие" }
}
}
Критерии с информацией о папке:
{
"include": { "CriteriaFolder": true }
}
Пример ответа:
{
"result": [
{
"id": 1,
"name": "Приветствие",
"description": "Менеджер представился и поздоровался",
"criteriaFolderId": 1,
"createdAt": "2024-01-10T08:00:00.000Z",
"updatedAt": "2024-01-10T08:00:00.000Z"
},
{
"id": 2,
"name": "Выявление потребностей",
"description": "Менеджер задал вопросы о потребностях клиента",
"criteriaFolderId": 1,
"createdAt": "2024-01-10T08:00:00.000Z",
"updatedAt": "2024-01-10T08:00:00.000Z"
}
]
}
Детали критерия
POST /api/orpc/criteria/getCriteria
Получение одного критерия по ID.
Обязательные параметры:
| Параметр | Тип | Описание |
|---|---|---|
where.id | number | ID критерия |
Пример запроса:
{
"where": { "id": 1 }
}
Пример ответа:
{
"result": {
"id": 1,
"name": "Приветствие",
"description": "Менеджер представился и поздоровался",
"criteriaFolderId": 1,
"createdAt": "2024-01-10T08:00:00.000Z",
"updatedAt": "2024-01-10T08:00:00.000Z"
}
}
write:criteria
Создание критерия
POST /api/orpc/criteria/createCriteria
Создание нового критерия оценки.
Обязательные поля в data:
| Поле | Тип | Описание |
|---|---|---|
name | string | Название критерия (макс. 255 символов) |
description | string | Описание — что именно оценивается |
CriteriaFolder.connect.id | number | ID папки для привязки критерия |
getCriterias — в ответе каждый критерий содержит criteriaFolderId.Пример запроса:
{
"data": {
"name": "Закрытие сделки",
"description": "Менеджер предложил оформить заказ и назвал следующий шаг",
"CriteriaFolder": {
"connect": { "id": 1 }
}
}
}
Пример ответа:
{
"result": {
"id": 15,
"name": "Закрытие сделки",
"description": "Менеджер предложил оформить заказ и назвал следующий шаг",
"criteriaFolderId": 1,
"createdAt": "2024-01-20T14:30:00.000Z",
"updatedAt": "2024-01-20T14:30:00.000Z"
}
}
Обновление критерия
POST /api/orpc/criteria/updateCriteria
Обновление существующего критерия. Можно обновить только название, только описание или оба поля.
Обязательные параметры:
| Параметр | Тип | Описание |
|---|---|---|
where.id | number | ID критерия для обновления |
Опциональные поля в data:
| Поле | Тип | Описание |
|---|---|---|
name | string | Новое название |
description | string | Новое описание |
Примеры запросов:
Обновить только название:
{
"where": { "id": 1 },
"data": {
"name": "Приветствие клиента"
}
}
Обновить название и описание:
{
"where": { "id": 1 },
"data": {
"name": "Приветствие клиента",
"description": "Менеджер представился, назвал компанию и поприветствовал клиента"
}
}
Пример ответа:
{
"result": {
"id": 1,
"name": "Приветствие клиента",
"description": "Менеджер представился, назвал компанию и поприветствовал клиента",
"criteriaFolderId": 1,
"createdAt": "2024-01-10T08:00:00.000Z",
"updatedAt": "2024-01-20T15:00:00.000Z"
}
}
Удаление критерия
POST /api/orpc/criteria/deleteCriteria
Удаление критерия. Операция необратима.
Обязательные параметры:
| Параметр | Тип | Описание |
|---|---|---|
where.id | number | ID критерия для удаления |
Пример запроса:
{
"where": { "id": 15 }
}
Пример ответа:
{
"result": {
"id": 15,
"name": "Закрытие сделки",
"description": "Менеджер предложил оформить заказ и назвал следующий шаг",
"criteriaFolderId": 1,
"createdAt": "2024-01-20T14:30:00.000Z",
"updatedAt": "2024-01-20T14:30:00.000Z"
}
}
Коды ошибок
| Код | HTTP | Описание |
|---|---|---|
UNAUTHORIZED | 401 | Токен отсутствует, неверный или просрочен |
FORBIDDEN | 403 | Токен не имеет необходимого скоупа |
NOT_FOUND | 404 | Запрашиваемый ресурс не найден |
BAD_REQUEST | 400 | Неверный формат запроса |
INTERNAL_SERVER_ERROR | 500 | Внутренняя ошибка сервера |
Примеры ошибок:
{
"error": {
"code": "UNAUTHORIZED",
"message": "API token has expired"
}
}
{
"error": {
"code": "FORBIDDEN",
"message": "Missing required scope. Need one of: read:conversations"
}
}
Примеры на разных языках
JavaScript (fetch)
const response = await fetch(
"https://callmeai.ru/api/orpc/conversation/getConversations",
{
method: "POST",
headers: {
Authorization: "Bearer mai_xxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({
take: 10,
orderBy: { createdAt: "desc" },
}),
},
);
const data = await response.json();
console.log(data.result);
Python (requests)
import requests
response = requests.post(
'https://callmeai.ru/api/orpc/conversation/getConversations',
headers={
'Authorization': 'Bearer mai_xxxxx',
'Content-Type': 'application/json'
},
json={
'take': 10,
'orderBy': {'createdAt': 'desc'}
}
)
data = response.json()
print(data['result'])
Python (загрузка файла)
import requests
with open('call.mp3', 'rb') as f:
response = requests.post(
'https://callmeai.ru/api/orpc/uploadCall',
headers={
'Authorization': 'Bearer mai_xxxxx'
},
files={'file': f},
data={
'criteriaFolderId': 1,
'managerId': 5
}
)
Rate Limiting
В данный момент лимиты на количество запросов не установлены. При большой нагрузке рекомендуется:
- Делать паузы между запросами (100-500мс)
- Использовать пагинацию для больших объёмов данных
- Кешировать данные на стороне клиента
Часто задаваемые вопросы
Как получить criteriaFolderId?
Используй endpoint getCriterias без фильтра — в ответе будет criteriaFolderId для каждого критерия.
Можно ли получить все разговоры за период?
Да, используй параметр where:
{
"where": {
"createdAt": {
"gte": "2024-01-01T00:00:00Z",
"lte": "2024-01-31T23:59:59Z"
}
}
}
Как обрабатывать SSE для uploadCall?
Endpoint возвращает поток событий. В JavaScript используй ReadableStream:
const response = await fetch(url, options);
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
console.log(chunk);
}
Что дальше?
- API токены — создание и управление токенами
- Критерии оценки — настройка критериев для анализа
- Банк звонков — работа с загруженными звонками