# Загрузить по ссылке
Source: https://docs.aigenda.tech/api-reference/audio/by-url
POST https://api.aigenda.tech/api/spaces/{space_id}/audio/by_url/
AiGenda сама скачает файл по прямой ссылке. Отвечает сразу, файл скачивается в фоне.
## Параметры пути
Идентификатор пространства.
## Тело запроса
Прямая ссылка на файл, до 255 символов, без авторизации.
Название до 255 символов, заканчивается расширением файла.
MIME-тип файла.
## Ответ
Успешный ответ: `201`.
После ответа дождитесь `is_uploaded: true` в [Статус загрузки](/api-reference/audio/info), затем [запустите обработку](/api-reference/processing/classify). Подробнее: [Загрузка по ссылке](/upload/url).
```bash cURL theme={null}
curl -X POST "https://api.aigenda.tech/api/spaces/1024/audio/by_url/" \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{
"url": "https://records.example.com/calls/client-call.mp3",
"title": "Звонок с клиентом 17.10.mp3",
"content_type": "audio/mpeg"
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://api.aigenda.tech/api/spaces/1024/audio/by_url/",
headers={"Authorization": "Bearer "},
json={
"url": "https://records.example.com/calls/client-call.mp3",
"title": "Звонок с клиентом 17.10.mp3",
"content_type": "audio/mpeg",
},
timeout=30,
)
response.raise_for_status()
print(response.status_code)
```
```javascript JavaScript theme={null}
const response = await fetch("https://api.aigenda.tech/api/spaces/1024/audio/by_url/", {
method: "POST",
headers: { Authorization: "Bearer ", "Content-Type": "application/json" },
body: JSON.stringify({
"url": "https://records.example.com/calls/client-call.mp3",
"title": "Звонок с клиентом 17.10.mp3",
"content_type": "audio/mpeg"
}),
});
console.log(response.status);
```
# Загрузить с YouTube
Source: https://docs.aigenda.tech/api-reference/audio/by-youtube
POST https://api.aigenda.tech/api/spaces/{space_id}/audio/by_youtube/
AiGenda скачает звуковую дорожку видео с YouTube. Отвечает сразу, видео скачивается в фоне.
## Параметры пути
Идентификатор пространства.
## Тело запроса
Ссылка на видео YouTube, до 2048 символов.
## Ответ
Успешный ответ: `201`.
После ответа дождитесь `is_uploaded: true` в [Статус загрузки](/api-reference/audio/info), затем [запустите обработку](/api-reference/processing/classify).
```bash cURL theme={null}
curl -X POST "https://api.aigenda.tech/api/spaces/1024/audio/by_youtube/" \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{
"url": "https://www.youtube.com/watch?v=VIDEO_ID"
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://api.aigenda.tech/api/spaces/1024/audio/by_youtube/",
headers={"Authorization": "Bearer "},
json={
"url": "https://www.youtube.com/watch?v=VIDEO_ID",
},
timeout=30,
)
response.raise_for_status()
print(response.status_code)
```
```javascript JavaScript theme={null}
const response = await fetch("https://api.aigenda.tech/api/spaces/1024/audio/by_youtube/", {
method: "POST",
headers: { Authorization: "Bearer ", "Content-Type": "application/json" },
body: JSON.stringify({
"url": "https://www.youtube.com/watch?v=VIDEO_ID"
}),
});
console.log(response.status);
```
# Завершить загрузку
Source: https://docs.aigenda.tech/api-reference/audio/complete-upload
POST https://api.aigenda.tech/api/spaces/{space_id}/audio/{audio_id}/complete_upload/
Сообщает AiGenda, что все части файла загружены в хранилище.
## Параметры пути
Идентификатор пространства.
Идентификатор записи.
## Тело запроса
Части файла по порядку загрузки.
Номер части, с единицы.
Заголовок `ETag` из ответа хранилища, вместе с двойными кавычками.
## Ответ
Успешный ответ: `200` с пустым телом.
После ответа дождитесь `is_uploaded: true` в [Статус загрузки](/api-reference/audio/info).
```bash cURL theme={null}
curl -X POST "https://api.aigenda.tech/api/spaces/1024/audio/51234/complete_upload/" \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{
"parts": [
{
"PartNumber": 1,
"ETag": "\"9b2cf535f27731c974343645a3985328\""
}
]
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://api.aigenda.tech/api/spaces/1024/audio/51234/complete_upload/",
headers={"Authorization": "Bearer "},
json={
"parts": [
{
"PartNumber": 1,
"ETag": "\"9b2cf535f27731c974343645a3985328\"",
},
],
},
timeout=30,
)
response.raise_for_status()
print(response.status_code)
```
```javascript JavaScript theme={null}
const response = await fetch("https://api.aigenda.tech/api/spaces/1024/audio/51234/complete_upload/", {
method: "POST",
headers: { Authorization: "Bearer ", "Content-Type": "application/json" },
body: JSON.stringify({
"parts": [
{
"PartNumber": 1,
"ETag": "\"9b2cf535f27731c974343645a3985328\""
}
]
}),
});
console.log(response.status);
```
```text 200 theme={null}
Пустое тело ответа
```
# Создать запись
Source: https://docs.aigenda.tech/api-reference/audio/create
POST https://api.aigenda.tech/api/spaces/{space_id}/audio/
Создаёт запись и выдаёт ссылки для загрузки файла в хранилище. Первый шаг загрузки файла.
## Параметры пути
Идентификатор пространства.
## Тело запроса
Название до 255 символов. **Заканчивается расширением файла**: `.mp3`, `.m4a`, `.wav`, `.ogg`, `.webm`, `.mp4`.
Точный размер файла в байтах.
MIME-тип файла.
## Ответ
Идентификатор записи (`audio_id`).
Ссылки для `PUT` частей файла, по одной на часть. Живут 5 часов.
`false` до завершения загрузки.
Каждый вызов создаёт новую запись. Не повторяйте его вслепую, если ответ потерялся: см. [Надёжная интеграция](/reference/best-practices).
```bash cURL theme={null}
curl -X POST "https://api.aigenda.tech/api/spaces/1024/audio/" \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{
"title": "Планёрка отдела продаж.mp3",
"size": 18874368,
"content_type": "audio/mpeg"
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://api.aigenda.tech/api/spaces/1024/audio/",
headers={"Authorization": "Bearer "},
json={
"title": "Планёрка отдела продаж.mp3",
"size": 18874368,
"content_type": "audio/mpeg",
},
timeout=30,
)
response.raise_for_status()
print(response.json())
```
```javascript JavaScript theme={null}
const response = await fetch("https://api.aigenda.tech/api/spaces/1024/audio/", {
method: "POST",
headers: { Authorization: "Bearer ", "Content-Type": "application/json" },
body: JSON.stringify({
"title": "Планёрка отдела продаж.mp3",
"size": 18874368,
"content_type": "audio/mpeg"
}),
});
const data = await response.json();
console.log(data);
```
```json 201 theme={null}
{
"id": 51234,
"title": "Планёрка отдела продаж.mp3",
"created_at": "2026-10-17T09:30:00Z",
"size": 18874368,
"content_type": "audio/mpeg",
"space_id": 1024,
"is_active": true,
"is_favorite": false,
"is_uploaded": false,
"was_classified": false,
"result_is_ready": false,
"url": [
"https://storage.yandexcloud.net/aigenda/3f6c1e0a.mp3?partNumber=1&uploadId=…&X-Amz-Signature=…"
],
"duration": null
}
```
```json 400 theme={null}
{
"title": [
"This field is required."
]
}
```
# Удалить записи
Source: https://docs.aigenda.tech/api-reference/audio/delete
POST https://api.aigenda.tech/api/spaces/{space_id}/audio/delete_list/
Перемещает записи в корзину пространства.
## Параметры пути
Идентификатор пространства.
## Тело запроса
Идентификаторы записей.
## Ответ
Успешный ответ: `200` с пустым телом.
Записи получают `is_active: false` и видны в [корзине](/api-reference/audio/trash).
```bash cURL theme={null}
curl -X POST "https://api.aigenda.tech/api/spaces/1024/audio/delete_list/" \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{
"audio_ids": [
51234,
51235
]
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://api.aigenda.tech/api/spaces/1024/audio/delete_list/",
headers={"Authorization": "Bearer "},
json={
"audio_ids": [51234, 51235],
},
timeout=30,
)
response.raise_for_status()
print(response.status_code)
```
```javascript JavaScript theme={null}
const response = await fetch("https://api.aigenda.tech/api/spaces/1024/audio/delete_list/", {
method: "POST",
headers: { Authorization: "Bearer ", "Content-Type": "application/json" },
body: JSON.stringify({
"audio_ids": [
51234,
51235
]
}),
});
console.log(response.status);
```
```text 200 theme={null}
Пустое тело ответа
```
# Статус загрузки
Source: https://docs.aigenda.tech/api-reference/audio/info
GET https://api.aigenda.tech/api/spaces/{space_id}/audio/{audio_id}/info/
Запись и её флаги: загружена ли, запускали ли обработку, готов ли результат.
## Параметры пути
Идентификатор пространства.
Идентификатор записи.
## Ответ
Идентификатор записи (`audio_id`).
Название записи с расширением файла.
Временная ссылка на исходный файл в хранилище.
Когда создана запись, ISO 8601 UTC.
Длительность в секундах. `null`, пока AiGenda не прочитала файл.
Размер файла в байтах.
MIME-тип файла.
Пространство, в котором лежит запись.
`false`, если запись в корзине.
Файл получен целиком. Обработку запускают только после `true`.
Обработку запускали.
Результат готов.
```bash cURL theme={null}
curl -X GET "https://api.aigenda.tech/api/spaces/1024/audio/51234/info/" \
-H "Authorization: Bearer "
```
```python Python theme={null}
import requests
response = requests.get(
"https://api.aigenda.tech/api/spaces/1024/audio/51234/info/",
headers={"Authorization": "Bearer "},
timeout=30,
)
response.raise_for_status()
print(response.json())
```
```javascript JavaScript theme={null}
const response = await fetch("https://api.aigenda.tech/api/spaces/1024/audio/51234/info/", {
method: "GET",
headers: { Authorization: "Bearer " },
});
const data = await response.json();
console.log(data);
```
```json 200 theme={null}
{
"id": 51234,
"title": "Планёрка отдела продаж.mp3",
"url": "https://storage.yandexcloud.net/aigenda/3f6c1e0a.mp3?X-Amz-Signature=…",
"created_at": "2026-10-17T09:30:00Z",
"duration": 1837,
"size": 18874368,
"content_type": "audio/mpeg",
"space_id": 1024,
"is_active": true,
"is_favorite": false,
"is_uploaded": true,
"was_classified": true,
"result_is_ready": true
}
```
```html 404 theme={null}
… Not Found …
```
# Список записей
Source: https://docs.aigenda.tech/api-reference/audio/list
GET https://api.aigenda.tech/api/spaces/{space_id}/audio/
Записи пространства с поиском и сортировкой.
## Параметры пути
Идентификатор пространства.
## Параметры запроса
Поиск по названию.
Сортировка. `-created_at`: новые сверху.
Сколько элементов на странице.
Сколько элементов пропустить.
## Ответ
Всего записей по запросу.
Записи, поля как в [Статус загрузки](/api-reference/audio/info).
```bash cURL theme={null}
curl -G "https://api.aigenda.tech/api/spaces/1024/audio/" \
--data-urlencode "search=Планёрка" \
--data-urlencode "ordering=-created_at" \
--data-urlencode "limit=20" \
--data-urlencode "offset=0" \
-H "Authorization: Bearer "
```
```python Python theme={null}
import requests
response = requests.get(
"https://api.aigenda.tech/api/spaces/1024/audio/",
headers={"Authorization": "Bearer "},
params={
"search": "Планёрка",
"ordering": "-created_at",
"limit": 20,
"offset": 0,
},
timeout=30,
)
response.raise_for_status()
print(response.json())
```
```javascript JavaScript theme={null}
const params = new URLSearchParams({
"search": "Планёрка",
"ordering": "-created_at",
"limit": "20",
"offset": "0"
});
const response = await fetch(`https://api.aigenda.tech/api/spaces/1024/audio/?${params}`, {
method: "GET",
headers: { Authorization: "Bearer " },
});
const data = await response.json();
console.log(data);
```
```json 200 theme={null}
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 51234,
"title": "Планёрка отдела продаж.mp3",
"url": "https://storage.yandexcloud.net/aigenda/3f6c1e0a.mp3?X-Amz-Signature=…",
"created_at": "2026-10-17T09:30:00Z",
"duration": 1837,
"size": 18874368,
"content_type": "audio/mpeg",
"space_id": 1024,
"is_active": true,
"is_favorite": false,
"is_uploaded": true,
"was_classified": true,
"result_is_ready": true
}
]
}
```
# Корзина
Source: https://docs.aigenda.tech/api-reference/audio/trash
GET https://api.aigenda.tech/api/spaces/{space_id}/audio/trash/
Записи пространства, перемещённые в корзину.
## Параметры пути
Идентификатор пространства.
## Параметры запроса
Сколько элементов на странице.
Сколько элементов пропустить.
## Ответ
Всего записей в корзине.
Записи, поля как в [Статус загрузки](/api-reference/audio/info).
```bash cURL theme={null}
curl -X GET "https://api.aigenda.tech/api/spaces/1024/audio/trash/?limit=20&offset=0" \
-H "Authorization: Bearer "
```
```python Python theme={null}
import requests
response = requests.get(
"https://api.aigenda.tech/api/spaces/1024/audio/trash/",
headers={"Authorization": "Bearer "},
params={
"limit": 20,
"offset": 0,
},
timeout=30,
)
response.raise_for_status()
print(response.json())
```
```javascript JavaScript theme={null}
const response = await fetch("https://api.aigenda.tech/api/spaces/1024/audio/trash/?limit=20&offset=0", {
method: "GET",
headers: { Authorization: "Bearer " },
});
const data = await response.json();
console.log(data);
```
```json 200 theme={null}
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 51234,
"title": "Планёрка отдела продаж.mp3",
"url": "https://storage.yandexcloud.net/aigenda/3f6c1e0a.mp3?X-Amz-Signature=…",
"created_at": "2026-10-17T09:30:00Z",
"duration": 1837,
"size": 18874368,
"content_type": "audio/mpeg",
"space_id": 1024,
"is_active": false,
"is_favorite": false,
"is_uploaded": true,
"was_classified": true,
"result_is_ready": true
}
]
}
```
# Обновить токен
Source: https://docs.aigenda.tech/api-reference/auth/refresh
POST https://api.aigenda.tech/api/token/refresh/
Выдаёт новый access по refresh. Новый refresh не выдаётся.
## Тело запроса
Токен `refresh` из ответа на вход. Действует 1 сутки.
## Ответ
Новый токен доступа.
Через сутки после входа `refresh` истекает. Тогда получите новую пару через [Получить токен](/api-reference/auth/token).
```bash cURL theme={null}
curl -X POST "https://api.aigenda.tech/api/token/refresh/" \
-H "Content-Type: application/json" \
-d '{
"refresh": "eyJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCJ9.sig"
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://api.aigenda.tech/api/token/refresh/",
json={
"refresh": "eyJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCJ9.sig",
},
timeout=30,
)
response.raise_for_status()
print(response.json())
```
```javascript JavaScript theme={null}
const response = await fetch("https://api.aigenda.tech/api/token/refresh/", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
"refresh": "eyJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCJ9.sig"
}),
});
const data = await response.json();
console.log(data);
```
```json 200 theme={null}
{
"access": "eyJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIn0.sig"
}
```
```json 401 theme={null}
{
"detail": "Given token not valid for any token type",
"code": "token_not_valid"
}
```
# Получить токен
Source: https://docs.aigenda.tech/api-reference/auth/token
POST https://api.aigenda.tech/api/token/
Выдаёт пару JWT по почте и паролю аккаунта AiGenda.
## Тело запроса
Почта аккаунта. Поле называется `username`, но в него кладётся почта.
Пароль аккаунта.
## Ответ
Токен для заголовка `Authorization: Bearer`. Живёт 30 дней.
Токен для обновления `access`. Живёт 1 сутки.
Подробнее о сроках и обновлении: [Авторизация](/authentication).
```bash cURL theme={null}
curl -X POST "https://api.aigenda.tech/api/token/" \
-H "Content-Type: application/json" \
-d '{
"username": "you@example.com",
"password": "ваш-пароль"
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://api.aigenda.tech/api/token/",
json={
"username": "you@example.com",
"password": "ваш-пароль",
},
timeout=30,
)
response.raise_for_status()
print(response.json())
```
```javascript JavaScript theme={null}
const response = await fetch("https://api.aigenda.tech/api/token/", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
"username": "you@example.com",
"password": "ваш-пароль"
}),
});
const data = await response.json();
console.log(data);
```
```json 200 theme={null}
{
"refresh": "eyJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCJ9.sig",
"access": "eyJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIn0.sig"
}
```
```json 401 theme={null}
{
"detail": "No active account found with the given credentials"
}
```
# Справочник API
Source: https://docs.aigenda.tech/api-reference/introduction
Все запросы API AiGenda с параметрами, ответами и примерами.
Каждая страница справочника описывает один запрос: параметры, поля ответа, примеры на cURL, Python и JavaScript. Кнопка **Попробовать** отправляет запрос прямо со страницы.
## Основное
| | |
| - | - |
| Базовый адрес | `https://api.aigenda.tech` |
| Формат тела | `application/json`, UTF-8 |
| Авторизация | `Authorization: Bearer `, кроме [получения](/api-reference/auth/token) и [обновления](/api-reference/auth/refresh) токена |
| Идентификаторы | целые числа: `space_id`, `audio_id` |
| Даты | ISO 8601, UTC: `2026-10-17T09:30:00Z` |
| Длительность и минуты тарифа | секунды |
| Списки | `limit` и `offset`, ответ `{count, next, previous, results}` |
## Как попробовать запрос
1. Получите токен на странице [Получить токен](/api-reference/auth/token): нажмите **Попробовать** и введите почту и пароль.
2. Скопируйте `access` из ответа.
3. На странице нужного запроса вставьте токен в поле авторизации и заполните параметры.
Запросы из песочницы выполняются на рабочем API с вашим аккаунтом. Запуск обработки списывает минуты, а созданные записи появляются в вашем пространстве.
## Карта запросов
| Задача | Запросы |
| - | - |
| Войти | [Получить токен](/api-reference/auth/token), [Обновить токен](/api-reference/auth/refresh) |
| Выбрать пространство | [Список пространств](/api-reference/spaces/list), [Пространство](/api-reference/spaces/get), [Права](/api-reference/spaces/rights) |
| Загрузить файл | [Создать запись](/api-reference/audio/create) → `PUT` в хранилище → [Завершить загрузку](/api-reference/audio/complete-upload) → [Статус загрузки](/api-reference/audio/info) |
| Загрузить по ссылке | [По ссылке](/api-reference/audio/by-url), [С YouTube](/api-reference/audio/by-youtube) |
| Записать встречу | [Отправить бота](/api-reference/meetings/create) |
| Обработать | [Запустить обработку](/api-reference/processing/classify) или [Только расшифровка](/api-reference/processing/classify-transcription) → [Результат](/api-reference/processing/result) |
| Навести порядок | [Список записей](/api-reference/audio/list), [Удалить](/api-reference/audio/delete), [Корзина](/api-reference/audio/trash) |
# Отправить бота на встречу
Source: https://docs.aigenda.tech/api-reference/meetings/create
POST https://api.aigenda.tech/api/space/{space_id}/meeting/
Бот AiGenda подключится к встрече в Zoom, Google Meet или Яндекс Телемосте и запишет её в пространство.
## Параметры пути
Идентификатор пространства.
## Тело запроса
Ссылка-приглашение на встречу, до 255 символов.
## Ответ
Успешный ответ: `201`.
В адресе `space` в единственном числе. Что делать после встречи: [Бот на встречу](/upload/meeting-bot).
```bash cURL theme={null}
curl -X POST "https://api.aigenda.tech/api/space/1024/meeting/" \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{
"link": "https://telemost.yandex.ru/j/12345678901234"
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://api.aigenda.tech/api/space/1024/meeting/",
headers={"Authorization": "Bearer "},
json={
"link": "https://telemost.yandex.ru/j/12345678901234",
},
timeout=30,
)
response.raise_for_status()
print(response.status_code)
```
```javascript JavaScript theme={null}
const response = await fetch("https://api.aigenda.tech/api/space/1024/meeting/", {
method: "POST",
headers: { Authorization: "Bearer ", "Content-Type": "application/json" },
body: JSON.stringify({
"link": "https://telemost.yandex.ru/j/12345678901234"
}),
});
console.log(response.status);
```
# Запустить обработку
Source: https://docs.aigenda.tech/api-reference/processing/classify
POST https://api.aigenda.tech/api/audio/classify/
Запускает обработку записи: протокол, расшифровка, спикеры. Списывает минуты по длительности записи.
## Тело запроса
Идентификатор записи с `is_uploaded: true`.
## Ответ
Идентификатор задачи обработки. Хранить не обязательно.
Статус проверяйте по [Результат обработки](/api-reference/processing/result).
```bash cURL theme={null}
curl -X POST "https://api.aigenda.tech/api/audio/classify/" \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{
"audio_id": 51234
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://api.aigenda.tech/api/audio/classify/",
headers={"Authorization": "Bearer "},
json={
"audio_id": 51234,
},
timeout=30,
)
response.raise_for_status()
print(response.json())
```
```javascript JavaScript theme={null}
const response = await fetch("https://api.aigenda.tech/api/audio/classify/", {
method: "POST",
headers: { Authorization: "Bearer ", "Content-Type": "application/json" },
body: JSON.stringify({
"audio_id": 51234
}),
});
const data = await response.json();
console.log(data);
```
```json 201 theme={null}
{
"request_id": "c0a8012e-7f3d-4b8e-9a51-2d6f0e4b9c17"
}
```
# Только расшифровка
Source: https://docs.aigenda.tech/api-reference/processing/classify-transcription
POST https://api.aigenda.tech/api/audio/classify_only_transcription/
Запускает обработку без протокола: только расшифровка по репликам.
## Тело запроса
Идентификатор записи с `is_uploaded: true`.
## Ответ
Идентификатор задачи обработки.
```bash cURL theme={null}
curl -X POST "https://api.aigenda.tech/api/audio/classify_only_transcription/" \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{
"audio_id": 51234
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://api.aigenda.tech/api/audio/classify_only_transcription/",
headers={"Authorization": "Bearer "},
json={
"audio_id": 51234,
},
timeout=30,
)
response.raise_for_status()
print(response.json())
```
```javascript JavaScript theme={null}
const response = await fetch("https://api.aigenda.tech/api/audio/classify_only_transcription/", {
method: "POST",
headers: { Authorization: "Bearer ", "Content-Type": "application/json" },
body: JSON.stringify({
"audio_id": 51234
}),
});
const data = await response.json();
console.log(data);
```
```json 201 theme={null}
{
"request_id": "c0a8012e-7f3d-4b8e-9a51-2d6f0e4b9c17"
}
```
# Результат обработки
Source: https://docs.aigenda.tech/api-reference/processing/result
GET https://api.aigenda.tech/api/spaces/{space_id}/audio/{audio_id}/result/
Статус и результат обработки. Опрашивайте раз в 10–15 секунд до classified: true.
## Параметры пути
Идентификатор пространства.
Идентификатор записи.
## Ответ
`true`, когда обработка закончена.
`true`, если обработка прошла успешно.
Протокол, реплики и спикеры. `null`, пока обработка идёт.
Протокол в Markdown.
Расшифровка по репликам.
Идентификаторы спикеров и метки вида `SPEAKER_00`.
Кто и когда говорил.
Язык записи.
Идентификатор записи.
Название записи.
Длительность в секундах.
Открыт ли публичный доступ.
| Ответ | Что значит |
| - | - |
| `404` | Обработку не запускали |
| `200`, `classified: false` | Обработка идёт |
| `200`, `classified: true` | Готово |
| `500` дольше 3 минут | Обработка упала, минуты вернутся |
Подробнее: [Статусы и ожидание](/processing/status) и [Структура результата](/processing/result). В примере ответа `result` сокращён.
```bash cURL theme={null}
curl -X GET "https://api.aigenda.tech/api/spaces/1024/audio/51234/result/" \
-H "Authorization: Bearer "
```
```python Python theme={null}
import requests
response = requests.get(
"https://api.aigenda.tech/api/spaces/1024/audio/51234/result/",
headers={"Authorization": "Bearer "},
timeout=30,
)
response.raise_for_status()
print(response.json())
```
```javascript JavaScript theme={null}
const response = await fetch("https://api.aigenda.tech/api/spaces/1024/audio/51234/result/", {
method: "GET",
headers: { Authorization: "Bearer " },
});
const data = await response.json();
console.log(data);
```
```json 200 theme={null}
{
"classified": true,
"success": true,
"audio_id": 51234,
"title": "Планёрка отдела продаж.mp3",
"duration": 1837,
"is_shared": false,
"result": {
"language": "ru",
"protocol": "## Итоги встречи\n\nОбсудили план продаж на ноябрь…"
}
}
```
```html 404 theme={null}
… Not Found …
```
```html 500 theme={null}
… Server Error (500) …
```
# Пространство
Source: https://docs.aigenda.tech/api-reference/spaces/get
GET https://api.aigenda.tech/api/spaces/{space_id}/
Одно пространство со свежим остатком минут. Запрашивайте перед каждой загрузкой.
## Параметры пути
Идентификатор пространства.
## Ответ
Идентификатор пространства.
Название.
Тариф.
Секунд на тарифе за период.
Потрачено секунд.
Осталось секунд.
Подписка активна.
Конец периода, ISO 8601.
```bash cURL theme={null}
curl -X GET "https://api.aigenda.tech/api/spaces/1024/" \
-H "Authorization: Bearer "
```
```python Python theme={null}
import requests
response = requests.get(
"https://api.aigenda.tech/api/spaces/1024/",
headers={"Authorization": "Bearer "},
timeout=30,
)
response.raise_for_status()
print(response.json())
```
```javascript JavaScript theme={null}
const response = await fetch("https://api.aigenda.tech/api/spaces/1024/", {
method: "GET",
headers: { Authorization: "Bearer " },
});
const data = await response.json();
console.log(data);
```
```json 200 theme={null}
{
"id": 1024,
"name": "Личное пространство",
"description": "Main space",
"subscribe": {
"offer": {
"name": "PRO",
"audio_limit": 72000
},
"usage_count": 5400,
"available_usage_count": 66600,
"is_active": true,
"end_date": "2026-11-17T00:00:00Z"
}
}
```
```json 403 theme={null}
{
"detail": "You do not have permission to perform this action."
}
```
# Список пространств
Source: https://docs.aigenda.tech/api-reference/spaces/list
GET https://api.aigenda.tech/api/spaces/
Пространства, в которых вы состоите, с тарифом и остатком минут. Личное отмечено is_main_space: true.
## Параметры запроса
Сколько элементов на странице.
Сколько элементов пропустить.
## Ответ
Всего пространств.
Личное пространство аккаунта.
`space_id` для остальных запросов.
Название.
Тариф и минуты, значения в секундах. См. [Пространства и минуты](/spaces).
Ссылки `next` и `previous` приходят со схемой `http://`. Собирайте следующую страницу сами через `limit` и `offset`.
```bash cURL theme={null}
curl -X GET "https://api.aigenda.tech/api/spaces/?limit=50&offset=0" \
-H "Authorization: Bearer "
```
```python Python theme={null}
import requests
response = requests.get(
"https://api.aigenda.tech/api/spaces/",
headers={"Authorization": "Bearer "},
params={
"limit": 50,
"offset": 0,
},
timeout=30,
)
response.raise_for_status()
print(response.json())
```
```javascript JavaScript theme={null}
const response = await fetch("https://api.aigenda.tech/api/spaces/?limit=50&offset=0", {
method: "GET",
headers: { Authorization: "Bearer " },
});
const data = await response.json();
console.log(data);
```
```json 200 theme={null}
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"is_main_space": true,
"space": {
"id": 1024,
"name": "Личное пространство",
"description": "Main space",
"subscribe": {
"offer": {
"name": "PRO",
"audio_limit": 72000
},
"usage_count": 5400,
"available_usage_count": 66600,
"is_active": true,
"end_date": "2026-11-17T00:00:00Z"
}
}
}
]
}
```
# Права в пространстве
Source: https://docs.aigenda.tech/api-reference/spaces/rights
GET https://api.aigenda.tech/api/spaces/{space_id}/my_rights/
Что вам можно в этом пространстве. Для загрузки нужно write_access: true.
## Параметры пути
Идентификатор пространства.
## Ответ
Можно загружать записи.
Можно открывать публичный доступ к результатам.
Можно приглашать участников.
Можно добавлять пользователей.
Можно создавать группы.
Видны только свои записи.
```bash cURL theme={null}
curl -X GET "https://api.aigenda.tech/api/spaces/1024/my_rights/" \
-H "Authorization: Bearer "
```
```python Python theme={null}
import requests
response = requests.get(
"https://api.aigenda.tech/api/spaces/1024/my_rights/",
headers={"Authorization": "Bearer "},
timeout=30,
)
response.raise_for_status()
print(response.json())
```
```javascript JavaScript theme={null}
const response = await fetch("https://api.aigenda.tech/api/spaces/1024/my_rights/", {
method: "GET",
headers: { Authorization: "Bearer " },
});
const data = await response.json();
console.log(data);
```
```json 200 theme={null}
{
"write_access": true,
"invite_access": true,
"share_access": true,
"create_another_group": true,
"add_user": true,
"view_only_own_records": false
}
```
```json 403 theme={null}
{
"detail": "You do not have permission to perform this action."
}
```
# Текущий пользователь
Source: https://docs.aigenda.tech/api-reference/users/me
GET https://api.aigenda.tech/api/users/me/
Возвращает аккаунт, которому принадлежит токен. Удобно, чтобы проверить токен.
## Ответ
Идентификатор пользователя.
Логин.
Почта.
```bash cURL theme={null}
curl -X GET "https://api.aigenda.tech/api/users/me/" \
-H "Authorization: Bearer "
```
```python Python theme={null}
import requests
response = requests.get(
"https://api.aigenda.tech/api/users/me/",
headers={"Authorization": "Bearer "},
timeout=30,
)
response.raise_for_status()
print(response.json())
```
```javascript JavaScript theme={null}
const response = await fetch("https://api.aigenda.tech/api/users/me/", {
method: "GET",
headers: { Authorization: "Bearer " },
});
const data = await response.json();
console.log(data);
```
```json 200 theme={null}
{
"id": 777,
"username": "you@example.com",
"email": "you@example.com"
}
```
```json 401 theme={null}
{
"detail": "Given token not valid for any token type",
"code": "token_not_valid"
}
```
# Авторизация
Source: https://docs.aigenda.tech/authentication
Как получить токен, сколько он живёт и что делать, когда он истёк.
API принимает JWT. Вы получаете пару токенов по почте и паролю аккаунта AiGenda и передаёте `access` в каждом запросе.
## Получить токен
```bash theme={null}
curl -X POST https://api.aigenda.tech/api/token/ \
-H "Content-Type: application/json" \
-d '{"username": "you@example.com", "password": "ваш-пароль"}'
```
```json Ответ 200 theme={null}
{
"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCJ9.signature",
"access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIn0.signature"
}
```
Поле называется `username`, но в него кладётся почта.
## Передать токен
Добавьте заголовок ко всем запросам, кроме получения и обновления токена:
```http theme={null}
Authorization: Bearer
```
## Сколько живут токены
| Токен | Срок | Как обновить |
| - | - | - |
| `access` | 30 дней | новый вход по почте и паролю или `refresh` |
| `refresh` | 1 сутки | только новым входом |
[Обновление](/api-reference/auth/refresh) по `refresh` возвращает новый `access`, но новый `refresh` не выдаёт. Через сутки после входа обновиться уже нельзя, поэтому проще всего так:
1. Храните `access` и время его истечения. Оно лежит в поле `exp` внутри токена (Unix-время в секундах).
2. Когда до `exp` осталось меньше суток или API ответил `401`, получите новую пару по почте и паролю.
3. Повторите исходный запрос один раз с новым токеном.
```python Срок действия токена theme={null}
import base64, json
def token_expires_at(access: str) -> int:
payload = access.split(".")[1]
payload += "=" * (-len(payload) % 4)
return json.loads(base64.urlsafe_b64decode(payload))["exp"]
```
## Ошибки
| Ответ | Тело | Что делать |
| - | - | - |
| `401` при входе | `{"detail": "No active account found with the given credentials"}` | Проверьте почту и пароль |
| `401` | `{"detail": "Authentication credentials were not provided."}` | Добавьте заголовок `Authorization` |
| `401` | `{"detail": "Given token not valid for any token type", "code": "token_not_valid", ...}` | Токен истёк или испорчен: войдите заново |
Не храните пароль в коде и репозитории. Передавайте его через переменные окружения или хранилище секретов вашей платформы.
Входите в кабинет через Google? У такого аккаунта может не быть пароля. Задайте его на странице [восстановления пароля](https://personal.aigenda.tech/ru/recovery-password), и вход через API заработает.
# Изменения
Source: https://docs.aigenda.tech/changelog
Что нового в API и документации AiGenda.
Опубликована документация API: вход, пространства и минуты, четыре способа загрузки записи, обработка, статусы, структура результата и справочник запросов.
# Документация API
Source: https://docs.aigenda.tech/index
Загружайте записи встреч и звонков из своей системы и получайте протокол и расшифровку.
AiGenda превращает запись встречи в протокол: о чём договорились, кто за что отвечает, кто что сказал. API делает то же, что личный кабинет, только из вашей системы: вы загружаете запись, запускаете обработку и забираете результат.
| | |
| - | - |
| Базовый адрес | `https://api.aigenda.tech` |
| Формат | JSON, кодировка UTF-8 |
| Авторизация | JWT в заголовке `Authorization: Bearer ` |
| Время и длительность | даты в ISO 8601 (UTC), длительность и минуты тарифа в секундах |
## Как проходит запись
1
Токен
POST /api/token/
Получаете по почте и паролю аккаунта AiGenda
2
Пространство
GET /api/spaces/
Выбираете, где лежат записи и с какого тарифа списываются минуты
3
Загрузка
POST …/audio/
Файлом, по ссылке, с YouTube или ботом на встречу
4
Обработка
POST /api/audio/classify/
Запускаете и опрашиваете статус
5
Результат
GET …/result/
Протокол в Markdown, расшифровка по репликам, исходный файл
Первый протокол за шесть запросов curl.
Файл, ссылка, YouTube или бот на встречу.
Что лежит в протоколе и расшифровке.
Скрипт на Python от входа до готового протокола.
## Что понадобится
* **Аккаунт AiGenda с паролем.** Если вы входите в кабинет через Google, задайте пароль на странице [восстановления пароля](https://personal.aigenda.tech/ru/recovery-password).
* **Минуты на тарифе.** Обработка списывает их по длительности записи. Остаток видно в кабинете и в API, см. [Пространства и минуты](/spaces).
Заведите под интеграцию отдельный аккаунт и пригласите его в нужное пространство. Тогда интеграция не зависит от пароля конкретного сотрудника, а записи из API легко отличить в кабинете.
Пишете интеграцию с помощью AI-агента? Дайте ему ссылку на [полную версию документации одним файлом](https://docs.aigenda.tech/llms-full.txt) и готовый промпт со страницы [Интеграция с AI-агентом](/reference/ai-agents).
# Скачивание файлов
Source: https://docs.aigenda.tech/processing/files
Исходная запись, протокол и расшифровка в виде файлов.
| Что | Откуда взять | Формат |
| - | - | - |
| Исходная запись | поле `url` в [`info/`](/api-reference/audio/info) | файл в исходном формате |
| Протокол | `result.protocol` в [`result/`](/api-reference/processing/result) | Markdown |
| Расшифровка | `result.dialog` в [`result/`](/api-reference/processing/result) | JSON |
## Исходная запись
Поле `url` в ответе `info/` содержит временную ссылку на файл в хранилище. Запрашивайте `info/` прямо перед скачиванием, чтобы ссылка была свежей.
```bash theme={null}
URL=$(curl -s "https://api.aigenda.tech/api/spaces/1024/audio/51234/info/" \
-H "Authorization: Bearer " | jq -r .url)
curl -s -o "planerka.mp3" "$URL"
```
Заголовок `Authorization` для скачивания по ссылке не нужен.
## Протокол в Word или PDF
API отдаёт протокол в Markdown. В DOCX или PDF его переводит [Pandoc](https://pandoc.org):
```bash theme={null}
curl -s "https://api.aigenda.tech/api/spaces/1024/audio/51234/result/" \
-H "Authorization: Bearer " | jq -r .result.protocol > protocol.md
pandoc protocol.md -o protocol.docx
pandoc protocol.md -o protocol.pdf --pdf-engine=xelatex -V mainfont="DejaVu Sans"
```
Для PDF с кириллицей нужен шрифт с кириллическими глифами, поэтому в примере указан `mainfont`.
Готовый PDF-конспект можно скачать в [личном кабинете](https://personal.aigenda.tech/ru) на тарифах Start и PRO.
## Расшифровка
`result.dialog` содержит реплики по порядку: текст, таймкоды и спикер. Из них собирается текстовая расшифровка или субтитры в нужном вам формате.
# Структура результата
Source: https://docs.aigenda.tech/processing/result
Что лежит в готовом результате: протокол, реплики, спикеры, язык.
Готовый результат отдаёт [`GET /api/spaces/{space_id}/audio/{audio_id}/result/`](/api-reference/processing/result), когда в ответе `classified: true`.
## Верхний уровень
| Поле | Тип | Что внутри |
| - | - | - |
| `classified` | boolean | `true`, когда обработка закончена |
| `success` | boolean | `true`, если обработка прошла успешно |
| `result` | object | Протокол, реплики и спикеры, см. ниже |
| `audio_id` | integer | Идентификатор записи |
| `title` | string | Название записи |
| `duration` | integer | Длительность записи в секундах |
| `url` | string | Временная ссылка на исходный файл |
| `is_shared` | boolean | Открыт ли публичный доступ к результату |
## Объект result
| Поле | Что внутри |
| - | - |
| `protocol` | Протокол встречи в Markdown: итоги, решения, задачи и ответственные |
| `dialog` | Расшифровка по репликам: текст, таймкоды, спикер |
| `speakers_map` | Соответствие идентификаторов спикеров и меток вида `SPEAKER_00` |
| `speakers_timeline` | Кто и когда говорил по ходу записи |
| `language` | Язык записи, например `ru` |
## Протокол
`protocol` приходит готовым Markdown. Его можно сразу показать в интерфейсе или сохранить в файл.
```markdown Пример протокола theme={null}
## Итоги встречи
Обсудили план продаж на ноябрь и запуск нового тарифа для малого бизнеса.
## Решения
- Запускаем тариф «Старт+» 1 ноября.
- Скидку для текущих клиентов оставляем до конца года.
## Задачи
| Задача | Ответственный | Срок |
|---|---|---|
| Подготовить лендинг тарифа | {101} | 25 октября |
| Обновить скрипт звонка | {102} | 28 октября |
```
Ответственные в протоколе подставлены как идентификаторы спикеров в фигурных скобках: `{101}`. Сопоставьте их по `speakers_map` и подставьте имена, если они у вас есть.
## Спикеры
AiGenda сама разделяет голоса и нумерует спикеров. Спикеры принадлежат пространству: если переименовать голос в кабинете, AiGenda узнает его в следующих записях этого пространства.
# Запуск обработки
Source: https://docs.aigenda.tech/processing/start
Протокол с расшифровкой или только расшифровка.
Загрузка сама обработку не запускает. Когда в [`info/`](/api-reference/audio/info) пришло `is_uploaded: true`, вызовите один из двух запросов.
| Запрос | Что получите |
| - | - |
| [`POST /api/audio/classify/`](/api-reference/processing/classify) | Протокол встречи, расшифровку по репликам, спикеров |
| [`POST /api/audio/classify_only_transcription/`](/api-reference/processing/classify-transcription) | Только расшифровку, без протокола |
```bash theme={null}
curl -X POST https://api.aigenda.tech/api/audio/classify/ \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{"audio_id": 51234}'
```
```json Ответ 201 theme={null}
{ "request_id": "c0a8012e-7f3d-4b8e-9a51-2d6f0e4b9c17" }
```
`space_id` в запросе не нужен: AiGenda знает, в каком пространстве лежит запись. `request_id` сохранять не обязательно, статус проверяется по `audio_id`.
## Минуты
Минуты списываются в момент запуска `classify`: ровно длительность записи в целых секундах. Если обработка упадёт, минуты вернутся сами через пару минут. Перед запуском убедитесь, что [остатка хватает](/spaces).
## Параметры
Язык AiGenda определяет сама и возвращает его в поле `result.language`. Других настроек у запуска нет.
Не запускайте обработку одной записи второй раз, пока не получили результат или ошибку. Дождитесь итога по правилам со страницы [Статусы и ожидание](/processing/status).
# Статусы и ожидание
Source: https://docs.aigenda.tech/processing/status
Как понять, что результат готов, что обработка ещё идёт или упала.
Уведомлений о готовности у API нет, результат нужно опрашивать. Источник правды: ответ [`GET /api/spaces/{space_id}/audio/{audio_id}/result/`](/api-reference/processing/result).
## Состояния
| Ответ `result/` | Поля в `info/` | Что значит | Что делать |
| - | - | - | - |
| `404`, HTML-страница | `was_classified: false` | Обработку не запускали | Вызовите [`classify`](/processing/start) |
| `200`, `classified: false` | `was_classified: true` | Обработка идёт | Ждите, опрашивайте дальше |
| `200`, `classified: true`, `success: true` | `result_is_ready: true` | Готово | Заберите [результат](/processing/result) |
| `500`, HTML-страница, держится больше 3 минут | `was_classified: true`, `result_is_ready: false` | Обработка упала | См. ниже |
Ошибки `404` и `500` приходят HTML-страницей, а не JSON. Проверяйте код ответа до разбора тела.
## Сколько ждать
Короткая запись обрабатывается за 1–4 минуты. Длинные записи и очередь в часы нагрузки добавляют время. Опрашивайте раз в 10–15 секунд и закладывайте общий таймаут не меньше часа.
## Если обработка упала
Сначала обработка идёт как обычно (`200`, `classified: false`), потом `result/` начинает отвечать `500`. Если `500` держится дольше 3 минут подряд, считайте обработку упавшей. Минуты вернутся сами.
Частые причины:
* в `title` нет расширения файла или оно не то, см. [Форматы](/upload/formats);
* в файле нет длительности, см. [Длительность в файле](/upload/formats);
* файл повреждён или в нём нет звука.
Исправьте файл или название и загрузите запись заново.
## Готовый код
```python Python theme={null}
import time
import requests
API = "https://api.aigenda.tech"
def wait_for_result(token: str, space_id: int, audio_id: int, timeout: int = 3600) -> dict:
"""Ждёт результат обработки. Возвращает тело ответа result/ или бросает исключение."""
headers = {"Authorization": f"Bearer {token}"}
url = f"{API}/api/spaces/{space_id}/audio/{audio_id}/result/"
started = time.monotonic()
not_found_since = None
failing_since = None
while time.monotonic() - started < timeout:
r = requests.get(url, headers=headers, timeout=30)
now = time.monotonic()
if r.status_code == 200:
not_found_since = failing_since = None
body = r.json()
if body.get("classified") and body.get("result"):
return body
elif r.status_code == 404:
# сразу после classify статус может обновиться не мгновенно
not_found_since = not_found_since or now
if now - not_found_since > 60:
raise RuntimeError("Обработка не запущена: вызовите classify")
elif r.status_code >= 500:
failing_since = failing_since or now
if now - failing_since > 180:
raise RuntimeError("Обработка упала, минуты вернутся автоматически")
time.sleep(15)
raise TimeoutError("Результат не готов за отведённое время")
```
# Быстрый старт
Source: https://docs.aigenda.tech/quickstart
От токена до готового протокола за шесть запросов.
Пройдём весь путь на коротком файле `planerka.mp3`. Понадобятся `curl` и [`jq`](https://jqlang.org) для разбора JSON.
Передайте почту и пароль аккаунта AiGenda. В ответе придёт пара токенов, для запросов нужен `access`.
```bash theme={null}
export AIGENDA_EMAIL="you@example.com"
export AIGENDA_PASSWORD="ваш-пароль"
TOKEN=$(curl -s -X POST https://api.aigenda.tech/api/token/ \
-H "Content-Type: application/json" \
-d "{\"username\": \"$AIGENDA_EMAIL\", \"password\": \"$AIGENDA_PASSWORD\"}" \
| jq -r .access)
```
Поле называется `username`, но в него кладётся почта. Подробнее: [Авторизация](/authentication).
Записи живут в пространствах. Возьмите своё личное пространство, у него `is_main_space: true`.
```bash theme={null}
SPACE_ID=$(curl -s "https://api.aigenda.tech/api/spaces/?limit=50&offset=0" \
-H "Authorization: Bearer $TOKEN" \
| jq -r '.results[] | select(.is_main_space) | .space.id')
```
Сообщите название, точный размер файла в байтах и MIME-тип. Название обязательно заканчивается расширением файла.
```bash theme={null}
FILE=planerka.mp3
SIZE=$(wc -c < "$FILE" | tr -d ' ')
CREATED=$(curl -s -X POST "https://api.aigenda.tech/api/spaces/$SPACE_ID/audio/" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"title\": \"$FILE\", \"size\": $SIZE, \"content_type\": \"audio/mpeg\"}")
AUDIO_ID=$(echo "$CREATED" | jq -r .id)
UPLOAD_URL=$(echo "$CREATED" | jq -r '.url[0]')
```
В `url` приходит массив ссылок для загрузки, по одной на часть файла. Файлу меньше 1 ГБ хватает одной.
Отправьте файл по ссылке методом `PUT` и сохраните заголовок `ETag` из ответа. Затем сообщите AiGenda, что загрузка закончена.
```bash theme={null}
ETAG=$(curl -s -X PUT "$UPLOAD_URL" --upload-file "$FILE" -D - -o /dev/null \
| grep -i '^etag:' | cut -d' ' -f2 | tr -d '\r')
curl -s -X POST "https://api.aigenda.tech/api/spaces/$SPACE_ID/audio/$AUDIO_ID/complete_upload/" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg etag "$ETAG" '{parts: [{PartNumber: 1, ETag: $etag}]}')"
until curl -s "https://api.aigenda.tech/api/spaces/$SPACE_ID/audio/$AUDIO_ID/info/" \
-H "Authorization: Bearer $TOKEN" | jq -e .is_uploaded > /dev/null; do sleep 2; done
```
`ETag` приходит в двойных кавычках, их нужно передать как есть. Цикл в конце ждёт, пока AiGenda подтвердит файл (`is_uploaded: true`).
```bash theme={null}
curl -s -X POST https://api.aigenda.tech/api/audio/classify/ \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"audio_id\": $AUDIO_ID}"
```
В этот момент с тарифа списываются минуты по длительности записи.
Опрашивайте результат раз в 15 секунд, пока не придёт `classified: true`.
```bash theme={null}
while true; do
RESULT=$(curl -s "https://api.aigenda.tech/api/spaces/$SPACE_ID/audio/$AUDIO_ID/result/" \
-H "Authorization: Bearer $TOKEN")
echo "$RESULT" | jq -e '.classified == true' > /dev/null 2>&1 && break
sleep 15
done
echo "$RESULT" | jq -r .result.protocol > protocol.md
```
Готово: протокол встречи лежит в `protocol.md`.
Этот цикл не отличает упавшую обработку от идущей и будет ждать вечно. В рабочей интеграции обрабатывайте ошибки по правилам со страницы [Статусы и ожидание](/processing/status).
## Что дальше
Файлы больше 1 ГБ, код на Python и JavaScript.
Протокол, реплики, спикеры.
# Интеграция с AI-агентом
Source: https://docs.aigenda.tech/reference/ai-agents
Как дать Claude, Cursor или другому агенту всё нужное, чтобы он написал интеграцию с AiGenda.
Документация доступна агентам в машиночитаемом виде:
| Что | Адрес |
| - | - |
| Вся документация одним файлом | [`https://docs.aigenda.tech/llms-full.txt`](https://docs.aigenda.tech/llms-full.txt) |
| Оглавление со ссылками | [`https://docs.aigenda.tech/llms.txt`](https://docs.aigenda.tech/llms.txt) |
| Любая страница в Markdown | добавьте `.md` к адресу страницы |
Кнопка в шапке каждой страницы копирует её в Markdown или открывает в ChatGPT, Claude, Cursor и VS Code.
## MCP-сервер документации
Подключите документацию к агенту как MCP-сервер: агент сам найдёт нужную страницу, пока пишет код.
```bash Claude Code theme={null}
claude mcp add --transport http aigenda-docs https://docs.aigenda.tech/mcp
```
```json Cursor (.cursor/mcp.json) theme={null}
{
"mcpServers": {
"aigenda-docs": {
"url": "https://docs.aigenda.tech/mcp"
}
}
}
```
```json VS Code (.vscode/mcp.json) theme={null}
{
"servers": {
"aigenda-docs": {
"type": "http",
"url": "https://docs.aigenda.tech/mcp"
}
}
}
```
Сервер только читает документацию. Доступа к вашему аккаунту AiGenda у него нет.
## Промпт
Скопируйте и допишите под свою задачу:
```text Промпт для агента theme={null}
Напиши интеграцию с API AiGenda: загрузка записи встречи, обработка, получение протокола.
Документация: https://docs.aigenda.tech/llms-full.txt. Прочитай её целиком перед тем, как писать код.
Где запись: <файл на диске / ссылка / YouTube / бот на встречу>
Язык и стек:
Куда положить результат: <файл protocol.md / наша база / ...>
Обязательные правила из документации:
1. Токен: POST /api/token/ с полями username (почта) и password. Заголовок Authorization: Bearer .
2. title записи заканчивается расширением файла (.mp3, .m4a, .wav, .ogg, .webm, .mp4).
3. Файл грузится частями по ссылкам из массива url методом PUT; ETag каждой части передаётся в complete_upload с кавычками.
4. Перед classify дождаться is_uploaded: true в GET .../info/.
5. Результат опрашивать раз в 15 секунд: 200 + classified: true = готово; 500 дольше 3 минут = упало; 404 = обработку не запускали.
6. Не повторять вслепую POST создания записи: каждый вызов создаёт новую запись.
7. Почту и пароль брать из переменных окружения AIGENDA_EMAIL и AIGENDA_PASSWORD.
Начни с плана, потом код, потом инструкцию по запуску.
```
## С чего агенту начать
Полный рабочий скрипт на Python лежит на странице [Полный пример](/reference/full-example). Агенту проще всего взять его за основу и переписать под ваш стек.
# Надёжная интеграция
Source: https://docs.aigenda.tech/reference/best-practices
Таймауты, повторы, потерянные ответы и порядок проверок.
## Перед загрузкой
1. Получите свежий остаток минут: [`GET /api/spaces/{space_id}/`](/api-reference/spaces/get), поле `subscribe.available_usage_count`.
2. Убедитесь, что остатка хватает на запись с запасом 5 минут.
3. В командном пространстве проверьте `write_access` в [`my_rights/`](/api-reference/spaces/rights).
## Уникальные названия
Добавляйте в `title` метку, по которой вы найдёте запись: дату, время, идентификатор из вашей системы.
```text theme={null}
Звонок · Иван Петров · 2026-10-17 14:30 · crm-48213.mp3
```
Расширение файла по-прежнему стоит в самом конце.
## Потерянный ответ на создание записи
Если ответ на `POST …/audio/` (или `by_url/`, `by_youtube/`) не пришёл из-за таймаута или обрыва, запись могла создаться. Не повторяйте запрос вслепую:
1. Найдите запись по названию: `GET /api/spaces/{space_id}/audio/?search=&ordering=-created_at`.
2. Нашли с `is_uploaded: false`: создайте запись заново, а найденную пустую [удалите](/api-reference/audio/delete).
3. Не нашли: создайте запись заново.
## Таймауты
| Запрос | Таймаут |
| - | - |
| Запросы к API | 30 секунд |
| `PUT` части файла | по скорости канала: часть до 1 ГБ на 10 Мбит/с грузится около 15 минут |
## Ссылки для загрузки живут 5 часов
Создавайте запись прямо перед загрузкой. Если между созданием и загрузкой прошло больше 5 часов, создайте запись заново, а старую удалите.
## Токен
Получайте новый токен по почте и паролю, когда до истечения `access` осталось меньше суток или API ответил `401`. Подробнее: [Авторизация](/authentication).
## Ответ не в JSON
Изредка API отвечает не JSON, а HTML-страницей ошибки. Проверяйте `Content-Type` перед разбором. Для безопасных запросов (`GET`, вход) повторите запрос через 1–2 секунды.
## Ожидание результата
Опрашивайте `result/` раз в 10–15 секунд, не чаще. Считайте обработку упавшей, если `500` держится дольше 3 минут подряд. Подробнее: [Статусы и ожидание](/processing/status).
# Ошибки
Source: https://docs.aigenda.tech/reference/errors
Коды ответов API и что с ними делать.
Успешные ответы приходят в JSON. Ошибки `400`, `401` и `403` тоже в JSON, а `404` и `500` приходят HTML-страницей. Поэтому сначала проверяйте код ответа и заголовок `Content-Type`, а потом разбирайте тело.
| Код | Когда | Тело | Что делать |
| - | - | - | - |
| `200`, `201` | Успех | JSON. У `complete_upload` и `delete_list` тело пустое | — |
| `400` | Ошибка в данных запроса | `{"title": ["This field is required."]}`: поле и список ошибок | Исправьте поля из ответа |
| `401` | Нет токена, он истёк или неверный | `{"detail": "…"}` | Получите новый токен, см. [Авторизация](/authentication) |
| `403` | Нет прав на пространство или его не существует | `{"detail": "You do not have permission to perform this action."}` | Проверьте `space_id` и [права](/api-reference/spaces/rights) |
| `404` | Нет такого адреса или записи. У `result/`: обработку не запускали | HTML | Проверьте адрес и `audio_id` |
| `500` | Ошибка на стороне AiGenda. У `result/`: обработка упала | HTML | Повторите позже. Для `result/` см. [Статусы](/processing/status) |
## Повторы
| Запрос | Повторять при сбое сети или `5xx`? |
| - | - |
| `GET` любой | Да, с паузой 2, 4, 8 секунд |
| `POST /api/token/` | Да, 1–2 раза через 1–2 секунды |
| `PUT` части файла | Да, по той же ссылке, пока она не истекла |
| `POST …/complete_upload/` | Сначала проверьте `is_uploaded` в `info/`. Если `false`, повторите |
| `POST …/audio/`, `by_url/`, `by_youtube/`, `meeting/` | **Нет.** Каждый вызов создаёт новую запись. Сначала проверьте, не создалась ли она, см. [Надёжная интеграция](/reference/best-practices) |
| `POST /api/audio/classify/` | Нет. Сначала проверьте статус в `result/` |
# Полный пример
Source: https://docs.aigenda.tech/reference/full-example
Скрипт на Python: вход, проверка минут, загрузка, обработка, протокол в файл.
Скрипт загружает файл в личное пространство, ждёт обработку и сохраняет протокол рядом с файлом. Нужен Python 3.9+ и пакет `requests`.
```bash theme={null}
pip install requests
export AIGENDA_EMAIL="you@example.com"
export AIGENDA_PASSWORD="ваш-пароль"
python aigenda_upload.py "Планёрка отдела продаж.mp3" audio/mpeg
```
```python aigenda_upload.py theme={null}
"""Загрузка записи в AiGenda и получение протокола.
Использование: python aigenda_upload.py <файл>
"""
import math
import os
import sys
import time
import requests
API = "https://api.aigenda.tech"
MIN_RESERVE_SECONDS = 5 * 60 # запас минут сверх длительности записи
def login(email: str, password: str) -> str:
for attempt in range(3):
r = requests.post(f"{API}/api/token/", json={"username": email, "password": password}, timeout=30)
if r.status_code == 401:
raise SystemExit("Неверная почта или пароль")
if r.ok and r.headers.get("Content-Type", "").startswith("application/json"):
return r.json()["access"]
time.sleep(1.5)
r.raise_for_status()
raise RuntimeError("Не удалось войти")
def main_space(headers: dict) -> dict:
r = requests.get(f"{API}/api/spaces/", params={"limit": 50, "offset": 0}, headers=headers, timeout=30)
r.raise_for_status()
return next(item["space"] for item in r.json()["results"] if item["is_main_space"])
def available_seconds(headers: dict, space_id: int) -> int:
r = requests.get(f"{API}/api/spaces/{space_id}/", headers=headers, timeout=30)
r.raise_for_status()
return r.json()["subscribe"]["available_usage_count"]
def upload_file(headers: dict, space_id: int, path: str, content_type: str) -> int:
size = os.path.getsize(path)
r = requests.post(
f"{API}/api/spaces/{space_id}/audio/",
headers=headers,
json={"title": os.path.basename(path), "size": size, "content_type": content_type},
timeout=30,
)
r.raise_for_status()
audio = r.json()
part_size = math.ceil(size / len(audio["url"]))
parts = []
with open(path, "rb") as f:
for number, url in enumerate(audio["url"], start=1):
put = requests.put(url, data=f.read(part_size), timeout=900)
put.raise_for_status()
parts.append({"PartNumber": number, "ETag": put.headers["ETag"]})
r = requests.post(
f"{API}/api/spaces/{space_id}/audio/{audio['id']}/complete_upload/",
headers=headers,
json={"parts": parts},
timeout=30,
)
r.raise_for_status()
for _ in range(60):
info = requests.get(f"{API}/api/spaces/{space_id}/audio/{audio['id']}/info/", headers=headers, timeout=30)
if info.ok and info.json().get("is_uploaded"):
return audio["id"]
time.sleep(2)
raise TimeoutError("AiGenda не подтвердила файл за 2 минуты")
def start_processing(headers: dict, audio_id: int) -> None:
r = requests.post(f"{API}/api/audio/classify/", headers=headers, json={"audio_id": audio_id}, timeout=30)
r.raise_for_status()
def wait_for_result(headers: dict, space_id: int, audio_id: int, timeout: int = 3600) -> dict:
url = f"{API}/api/spaces/{space_id}/audio/{audio_id}/result/"
started = time.monotonic()
not_found_since = failing_since = None
while time.monotonic() - started < timeout:
r = requests.get(url, headers=headers, timeout=30)
now = time.monotonic()
if r.status_code == 200:
not_found_since = failing_since = None
body = r.json()
if body.get("classified") and body.get("result"):
return body
elif r.status_code == 404:
not_found_since = not_found_since or now
if now - not_found_since > 60:
raise RuntimeError("Обработка не запущена")
elif r.status_code >= 500:
failing_since = failing_since or now
if now - failing_since > 180:
raise RuntimeError("Обработка упала, минуты вернутся автоматически")
time.sleep(15)
raise TimeoutError("Результат не готов за час")
def main() -> None:
path, content_type = sys.argv[1], sys.argv[2]
token = login(os.environ["AIGENDA_EMAIL"], os.environ["AIGENDA_PASSWORD"])
headers = {"Authorization": f"Bearer {token}"}
space = main_space(headers)
left = available_seconds(headers, space["id"])
print(f"Пространство «{space['name']}», осталось {left // 60} мин")
if left <= MIN_RESERVE_SECONDS:
raise SystemExit("Минут на тарифе почти не осталось")
audio_id = upload_file(headers, space["id"], path, content_type)
print(f"Файл загружен, audio_id={audio_id}")
start_processing(headers, audio_id)
print("Обработка запущена, ждём результат…")
result = wait_for_result(headers, space["id"], audio_id)
out = os.path.splitext(path)[0] + ".protocol.md"
with open(out, "w", encoding="utf-8") as f:
f.write(result["result"]["protocol"])
print(f"Протокол сохранён: {out}")
if __name__ == "__main__":
main()
```
# Пространства и минуты
Source: https://docs.aigenda.tech/spaces
Где лежат записи, откуда списываются минуты и как проверить права.
Пространство объединяет записи, участников и тариф. У каждого аккаунта есть личное пространство. Командные появляются, когда вас приглашают коллеги. Почти все запросы к записям содержат `space_id`.
## Найти space\_id
```bash theme={null}
curl "https://api.aigenda.tech/api/spaces/?limit=50&offset=0" \
-H "Authorization: Bearer "
```
```json Ответ 200 (основные поля) theme={null}
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"is_main_space": true,
"space": {
"id": 1024,
"name": "Личное пространство",
"description": "Main space",
"subscribe": {
"offer": { "name": "PRO", "audio_limit": 72000 },
"usage_count": 5400,
"available_usage_count": 66600,
"is_active": true,
"end_date": "2026-11-17T00:00:00Z"
}
}
},
{
"is_main_space": false,
"space": { "id": 2048, "name": "Отдел продаж", "description": "Записи звонков с клиентами" }
}
]
}
```
Личное пространство отмечено `is_main_space: true`. Его `space.id` и есть `space_id`.
## Минуты
Тариф и остаток лежат в `space.subscribe`. Все значения в **секундах**.
| Поле | Что значит |
| - | - |
| `offer.name` | Название тарифа |
| `offer.audio_limit` | Сколько секунд даёт тариф за период |
| `usage_count` | Сколько уже потрачено |
| `available_usage_count` | Сколько осталось |
| `end_date` | Когда закончится период |
Свежий остаток конкретного пространства отдаёт [`GET /api/spaces/{space_id}/`](/api-reference/spaces/get).
**Когда списываются минуты.** В момент запуска обработки, ровно на длительность записи в целых секундах (запись 71,8 с спишет 71 с). Загрузка без обработки минут не тратит. Если обработка упала, минуты вернутся сами через пару минут.
Перед загрузкой проверьте, что остатка хватает на всю запись с запасом 5 минут. Запись длиннее остатка AiGenda не обработает.
## Права
В командном пространстве у вас может не быть права загружать записи. Проверьте его заранее:
```bash theme={null}
curl "https://api.aigenda.tech/api/spaces/1024/my_rights/" \
-H "Authorization: Bearer "
```
Загружать записи можно, если в ответе `write_access: true`. Полный список полей: [Права в пространстве](/api-reference/spaces/rights).
## Постраничный вывод
Списки (пространства, записи, корзина) отдаются страницами. Управляйте ими параметрами `limit` и `offset`. Ссылки `next` и `previous` в ответе приходят со схемой `http://`, поэтому собирайте адрес следующей страницы сами: `offset = offset + limit`, пока `offset < count`.
# Загрузка файла
Source: https://docs.aigenda.tech/upload/file
Файл любого размера: создаём запись, грузим части в хранилище, подтверждаем загрузку.
Файл уходит не в API, а прямо в объектное хранилище по временным ссылкам. API выдаёт ссылки и принимает подтверждение.
Ваш сервис
API AiGenda
Хранилище
1
POST /audio/
title, size, content\_type
2
id, url\[]
ссылки на части
3
PUT часть
по ссылке url\[i]
4
ETag
в заголовке ответа
5
POST /complete\_upload/
PartNumber и ETag
6
GET /info/
до is\_uploaded: true
1
Ваш сервис → API AiGenda
POST /audio/
title, size, content\_type
2
API AiGenda → Ваш сервис
id, url\[]
ссылки на части
3
Ваш сервис → Хранилище
PUT часть
по ссылке url\[i]
4
Хранилище → Ваш сервис
ETag
в заголовке ответа
5
Ваш сервис → API AiGenda
POST /complete\_upload/
PartNumber и ETag
6
Ваш сервис → API AiGenda
GET /info/
до is\_uploaded: true
## Шаги
```bash theme={null}
curl -X POST https://api.aigenda.tech/api/spaces/1024/audio/ \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{"title": "Планёрка отдела продаж.mp3", "size": 18874368, "content_type": "audio/mpeg"}'
```
| Поле | Правило |
| - | - |
| `title` | До 255 символов. **Заканчивается расширением файла**: `.mp3`, `.m4a`, `.wav`, `.ogg`, `.webm`, `.mp4`. По расширению AiGenda определяет формат |
| `size` | Точный размер файла в байтах |
| `content_type` | MIME-тип: `audio/mpeg`, `audio/mp4`, `audio/wav`, `audio/ogg`, `audio/webm`, `video/mp4` |
```json Ответ 201 theme={null}
{
"id": 51234,
"title": "Планёрка отдела продаж.mp3",
"url": [
"https://storage.yandexcloud.net/aigenda/3f6c1e0a.mp3?partNumber=1&uploadId=…&X-Amz-Signature=…"
],
"created_at": "2026-10-17T09:30:00Z",
"duration": null,
"size": 18874368,
"content_type": "audio/mpeg",
"space_id": 1024,
"is_uploaded": false,
"was_classified": false,
"result_is_ready": false
}
```
`url` всегда массив: по ссылке на каждую часть файла, примерно одна часть на 1 ГБ.
Разделите файл на столько частей, сколько пришло ссылок:
* размер части: `ceil(size / len(url))` байт, последняя часть короче;
* часть с номером `i` (с единицы) уходит на ссылку `url[i-1]`;
* метод `PUT`, тело запроса: байты части, без JSON и multipart-формы;
* из ответа хранилища сохраните заголовок `ETag` вместе с двойными кавычками: `"9b2cf535f27731c974343645a3985328"`.
Ссылки живут **5 часов** с момента создания записи. Хранилище разрешает запросы из браузера (CORS открыт, `ETag` читается), так что грузить можно и с фронтенда.
Передайте номера частей и их `ETag` в том порядке, в котором грузили.
```bash theme={null}
curl -X POST https://api.aigenda.tech/api/spaces/1024/audio/51234/complete_upload/ \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{"parts": [{"PartNumber": 1, "ETag": "\"9b2cf535f27731c974343645a3985328\""}]}'
```
Ответ: `200` с пустым телом.
Опрашивайте [`info/`](/api-reference/audio/info) раз в 2 секунды, пока не придёт `is_uploaded: true`. Обычно это меньше секунды. После этого [запускайте обработку](/processing/start).
## Готовый код
```python Python theme={null}
import math
import os
import time
import requests
API = "https://api.aigenda.tech"
def upload_file(token: str, space_id: int, path: str, content_type: str) -> int:
"""Загружает файл в пространство и возвращает audio_id, когда AiGenda подтвердила файл."""
headers = {"Authorization": f"Bearer {token}"}
size = os.path.getsize(path)
title = os.path.basename(path) # имя с расширением, например «Планёрка.mp3»
r = requests.post(
f"{API}/api/spaces/{space_id}/audio/",
headers=headers,
json={"title": title, "size": size, "content_type": content_type},
timeout=30,
)
r.raise_for_status()
audio = r.json()
urls = audio["url"]
part_size = math.ceil(size / len(urls))
parts = []
with open(path, "rb") as f:
for number, url in enumerate(urls, start=1):
chunk = f.read(part_size)
put = requests.put(url, data=chunk, timeout=900)
put.raise_for_status()
parts.append({"PartNumber": number, "ETag": put.headers["ETag"]})
r = requests.post(
f"{API}/api/spaces/{space_id}/audio/{audio['id']}/complete_upload/",
headers=headers,
json={"parts": parts},
timeout=30,
)
r.raise_for_status()
for _ in range(60):
info = requests.get(
f"{API}/api/spaces/{space_id}/audio/{audio['id']}/info/",
headers=headers,
timeout=30,
).json()
if info.get("is_uploaded"):
return audio["id"]
time.sleep(2)
raise TimeoutError("AiGenda не подтвердила файл за 2 минуты")
```
```javascript JavaScript (Node.js 18+) theme={null}
import { open, stat } from "node:fs/promises";
import { basename } from "node:path";
const API = "https://api.aigenda.tech";
// Загружает файл в пространство и возвращает audioId, когда AiGenda подтвердила файл.
export async function uploadFile(token, spaceId, path, contentType) {
const auth = { Authorization: `Bearer ${token}` };
const json = { ...auth, "Content-Type": "application/json" };
const { size } = await stat(path);
const created = await fetch(`${API}/api/spaces/${spaceId}/audio/`, {
method: "POST",
headers: json,
body: JSON.stringify({ title: basename(path), size, content_type: contentType }),
});
if (!created.ok) throw new Error(`create: ${created.status}`);
const audio = await created.json();
const partSize = Math.ceil(size / audio.url.length);
const parts = [];
const file = await open(path);
try {
for (let i = 0; i < audio.url.length; i++) {
const length = Math.min(partSize, size - i * partSize);
const chunk = Buffer.alloc(length);
await file.read(chunk, 0, length, i * partSize);
const put = await fetch(audio.url[i], { method: "PUT", body: chunk });
if (!put.ok) throw new Error(`part ${i + 1}: ${put.status}`);
parts.push({ PartNumber: i + 1, ETag: put.headers.get("ETag") });
}
} finally {
await file.close();
}
const done = await fetch(`${API}/api/spaces/${spaceId}/audio/${audio.id}/complete_upload/`, {
method: "POST",
headers: json,
body: JSON.stringify({ parts }),
});
if (!done.ok) throw new Error(`complete: ${done.status}`);
for (let attempt = 0; attempt < 60; attempt++) {
const res = await fetch(`${API}/api/spaces/${spaceId}/audio/${audio.id}/info/`, { headers: auth });
const info = await res.json();
if (info.is_uploaded) return audio.id;
await new Promise((resolve) => setTimeout(resolve, 2000));
}
throw new Error("AiGenda не подтвердила файл за 2 минуты");
}
```
## Если что-то пошло не так
| Ситуация | Что делать |
| - | - |
| Хранилище ответило `403` на `PUT` | Ссылки истекли (прошло больше 5 часов). Создайте запись заново, старую [удалите](/api-reference/audio/delete) |
| Ответ на создание записи не пришёл (таймаут, обрыв) | Не создавайте запись вслепую второй раз: каждый вызов добавляет новую запись. Найдите её по названию, см. [Надёжная интеграция](/reference/best-practices) |
| Часть не загрузилась | Повторите `PUT` этой части по той же ссылке, пока ссылки не истекли |
# Форматы и ограничения
Source: https://docs.aigenda.tech/upload/formats
Какие файлы принимает AiGenda и какие правила действуют для названий, размера и длительности.
## Форматы
AiGenda принимает распространённые форматы аудио и видео: **MP3, M4A, WAV, OGG, WebM, MP4**. Из видео берётся звуковая дорожка.
| Формат | `content_type` | Расширение в `title` |
| - | - | - |
| MP3 | `audio/mpeg` | `.mp3` |
| M4A (AAC) | `audio/mp4` | `.m4a` |
| WAV | `audio/wav` | `.wav` |
| OGG (Opus) | `audio/ogg` | `.ogg` |
| WebM | `audio/webm` или `video/webm` | `.webm` |
| MP4 | `video/mp4` | `.mp4` |
## Название записи
**`title` обязан заканчиваться расширением файла.** Формат AiGenda определяет по расширению в названии, а не по `content_type`. Запись без расширения загрузится, но обработка упадёт.
| `title` | Результат |
| - | - |
| `Планёрка 17.10.mp3` | Обработается |
| `Планёрка 17.10` | Упадёт: AiGenda примет `.10` за расширение |
Длина названия до 255 символов вместе с расширением. Слэши, двоеточия и точки внутри названия допустимы.
## Размер и длительность
* `size` указывайте точно, в байтах. Хранилище выдаёт ссылки под этот размер.
* Одна часть файла около 1 ГБ, частей может быть несколько. Подробнее: [Загрузка файла](/upload/file).
* На тарифе должно оставаться больше минут, чем длится запись, с запасом 5 минут.
* Одна запись длится не больше 2,5 часа. Более длинную встречу разделите на части.
## Длительность в файле
AiGenda считает списание и строит таймкоды по длительности, записанной в файле. Обычные WebM обрабатываются, но WebM прямо из `MediaRecorder` в браузере часто сохраняется без длительности. Такой файл получает длительность 0 и не обрабатывается. Перепакуйте его перед загрузкой:
```bash theme={null}
ffmpeg -i recording.webm -c:a libopus -b:a 48k recording.ogg
```
## Моно или стерео
AiGenda сводит звук в моно и разделяет спикеров сама. Стерео не улучшает результат, а файл получается больше. Для речи хватает моно Opus 32–48 кбит/с: час записи весит 15–22 МБ.
# Бот на встречу
Source: https://docs.aigenda.tech/upload/meeting-bot
Отправьте ассистента AiGenda на встречу в Zoom, Google Meet или Телемосте.
Бот подключается к встрече как участник, записывает её и кладёт запись в пространство. Файл загружать не нужно.
```bash theme={null}
curl -X POST https://api.aigenda.tech/api/space/1024/meeting/ \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{"link": "https://telemost.yandex.ru/j/12345678901234"}'
```
В адресе `space` в единственном числе: `/api/space/{space_id}/meeting/`. У остальных запросов `spaces`.
| Поле | Правило |
| - | - |
| `link` | Ссылка-приглашение на встречу в Zoom, Google Meet или Яндекс Телемосте, до 255 символов |
## После встречи
Когда встреча закончится, запись появится в пространстве. Найдите её в [списке записей](/api-reference/audio/list) (новые сверху: `ordering=-created_at`) и проверьте [`info/`](/api-reference/audio/info):
* `was_classified: false`: запустите [обработку](/processing/start) сами;
* `was_classified: true`: обработка уже идёт, опрашивайте [результат](/processing/status).
Участники встречи видят бота в списке. Предупредите их о записи заранее.
Если в кабинете включено подключение бота по календарю, не отправляйте его через API на ту же встречу: получится две записи одной встречи.
# Способы загрузки
Source: https://docs.aigenda.tech/upload/overview
Файл, ссылка, YouTube или бот на встречу: что выбрать.
Любой способ создаёт запись в пространстве. Дальше обработка и результат одинаковые.
| Способ | Когда подходит | Запрос |
| - | - | - |
| [Файл](/upload/file) | Файл у вас на диске или в памяти сервиса | `POST /api/spaces/{space_id}/audio/` и загрузка в хранилище |
| [По ссылке](/upload/url) | Файл лежит по прямой ссылке: облако, телефония, CRM | `POST /api/spaces/{space_id}/audio/by_url/` |
| [YouTube](/upload/youtube) | Видео опубликовано на YouTube | `POST /api/spaces/{space_id}/audio/by_youtube/` |
| [Бот на встречу](/upload/meeting-bot) | Встреча в Zoom, Google Meet или Телемосте ещё идёт или скоро начнётся | `POST /api/space/{space_id}/meeting/` |
## После загрузки
Для файла, ссылки и YouTube порядок одинаковый:
1. Дождитесь `is_uploaded: true` в [`GET …/audio/{audio_id}/info/`](/api-reference/audio/info). Для файла это меньше секунды. Ссылку и YouTube AiGenda скачивает сама, это занимает от нескольких секунд до минут.
2. Запустите [обработку](/processing/start).
3. Опрашивайте [результат](/processing/status).
Не запускайте обработку до `is_uploaded: true`. AiGenda ещё не получила файл целиком, и обработка упадёт.
Ограничения по форматам и названиям общие для всех способов: [Форматы и ограничения](/upload/formats).
# Загрузка по ссылке
Source: https://docs.aigenda.tech/upload/url
AiGenda сама скачает файл по прямой ссылке.
Подходит, когда запись уже лежит в облаке, в телефонии или в CRM. Вы передаёте ссылку, AiGenda скачивает файл в фоне.
```bash theme={null}
curl -X POST https://api.aigenda.tech/api/spaces/1024/audio/by_url/ \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{
"url": "https://records.example.com/calls/2026-10-17/client-call.mp3",
"title": "Звонок с клиентом 17.10.mp3",
"content_type": "audio/mpeg"
}'
```
| Поле | Правило |
| - | - |
| `url` | Прямая ссылка на файл, до 255 символов. Файл должен скачиваться по ней без авторизации, cookies и промежуточных страниц |
| `title` | До 255 символов, **заканчивается расширением файла** |
| `content_type` | MIME-тип файла, например `audio/mpeg` |
## Что дальше
Запрос отвечает сразу, а файл AiGenda скачивает уже после ответа. Поэтому:
1. Возьмите `id` записи из ответа.
2. Опрашивайте [`info/`](/api-reference/audio/info) раз в 3–5 секунд, пока не придёт `is_uploaded: true`.
3. Запустите [обработку](/processing/start).
Загрузка по ссылке сама обработку не запускает. Без вызова `classify` запись так и останется необработанной.
Ссылки из облачных хранилищ с подписью (S3, Яндекс Облако) бывают длиннее 255 символов. Если ссылка не помещается, скачайте файл у себя и загрузите его [файлом](/upload/file).
# Загрузка с YouTube
Source: https://docs.aigenda.tech/upload/youtube
Обработка видео с YouTube по ссылке.
Передайте ссылку на видео, AiGenda скачает звуковую дорожку сама.
```bash theme={null}
curl -X POST https://api.aigenda.tech/api/spaces/1024/audio/by_youtube/ \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{"url": "https://www.youtube.com/watch?v=VIDEO_ID"}'
```
| Поле | Правило |
| - | - |
| `url` | Ссылка на видео YouTube, до 2048 символов. Видео должно открываться без входа в аккаунт |
## Что дальше
Как и при [загрузке по ссылке](/upload/url), файл скачивается после ответа:
1. Возьмите `id` записи из ответа.
2. Опрашивайте [`info/`](/api-reference/audio/info), пока не придёт `is_uploaded: true`. Длинное видео скачивается дольше.
3. Запустите [обработку](/processing/start).