# Загрузить файл книги

Файл txt, docx, fb2, fb2.zip или epub — до 20 МБ.

`POST /books/upload` · озвучка

Из fb2 и epub берутся название, автор, аннотация, жанр, серия и обложка. Если в файле указана серия, книга сама встанет
в цикл, а голоса героев придут из прошлых томов (`carried` — каких героев).

Тот же файл второй раз — ответ `409` со ссылкой на уже загруженную книгу; чтобы загрузить копию, добавьте поле `copy=1`.

## Тело запроса

multipart/form-data.

| Поле | Тип | Обязательно | Что это |
|---|---|---|---|
| `file` | файл | да | Файл книги |
| `title` | строка | нет | Своё название вместо названия из файла |
| `copy` | `1` | нет | Загрузить копией, даже если такой файл уже есть |

## Что в ответе

| Поле | Что это |
|---|---|
| `id` | Id книги |
| `title` / `author` | Название и автор |
| `status` | `ready` — можно работать, `importing` — ещё разбирается, `failed` — ошибка разбора |
| `series` | Цикл, в который встала книга, или `null` |
| `carried` | Герои, получившие голоса из прошлых томов |

## Ошибки

| Код | Когда |
|---|---|
| `400` | Файл пустой, больше 20 МБ или в нём нет текста |
| `409` | Этот файл уже загружен: в `detail.duplicate` — книга |

```bash
curl -X POST "https://golosar-kniga.tech/api/v1/books/upload" \
  -H "x-api-key: $KEY" \
  -F "file=@book.fb2"
```

```python
import os, requests

API = "https://golosar-kniga.tech/api/v1"
H = {"x-api-key": os.environ["GOLOSAR_KEY"]}

r = requests.post(f"{API}/books/upload", headers=H, files={"file": open("book.fb2", "rb")})
r.raise_for_status()
print(r.json())
```

```javascript
import { openAsBlob } from "node:fs";
const API = "https://golosar-kniga.tech/api/v1";
const H = { "x-api-key": process.env.GOLOSAR_KEY };

const form = new FormData();
form.append("file", await openAsBlob("book.fb2"), "book.fb2");
const r = await fetch(`${API}/books/upload`, { method: "POST", headers: H, body: form });
if (!r.ok) throw new Error(await r.text());
console.log(await r.json());
```

```json Ответ 200
{
  "book": {
    "id": "01a134d0-dde5-71b2-ac7d-7ee878371d38",
    "title": "skazka",
    "author": "",
    "status": "ready",
    "created_at": "2026-10-13T10:31:05.942943+00:00",
    "language": "ru",
    "subtitle": "",
    "series": "",
    "series_no": "",
    "genre": "",
    "age_rating": "",
    "thoughts": "hero",
    "sound": "studio",
    "check": "auto",
    "reading": "roles",
    "cover_url": null,
    "active_edition_id": "01a134d0-ddf5-7a75-bf2c-56b5425f2377"
  },
  "series": null,
  "carried": []
}
```
