> ## Documentation Index
> Fetch the complete documentation index at: https://platform.doodocs.kz/llms.txt
> Use this file to discover all available pages before exploring further.

# Загрузка своего документа

> Отправить на подписание PDF, который у вас уже есть

Документ не обязан рождаться из шаблона Doodocs. Если внешняя система уже
сформировала PDF — приказ из 1С, договор из CRM, скан, — загрузите его и пустите
по маршруту как обычный документ.

Загрузка идёт мимо API: сервер выдаёт presigned-форму, файл вы отправляете прямо
в хранилище, затем подтверждаете загрузку и создаёте документ по `file_id`.
Все три шага покрывает область `documents:write`.

<Frame caption="От файла до отправленного документа">
  ```mermaid theme={null}
  %%{init: {'theme':'neutral'}}%%
  sequenceDiagram
      participant C as Ваш код
      participant A as Doodocs People API
      participant S as Хранилище
      C->>A: POST /files (имя, тип, размер)
      A-->>C: file.id + presigned-форма
      C->>S: POST формы с байтами
      S-->>C: 204
      C->>A: POST /files/{id}/_confirm
      A-->>C: status UPLOADED
      C->>A: POST /documents (file_id)
      A-->>C: документ, status DRAFT
      C->>A: PUT /documents/{id}/route → _send
  ```
</Frame>

## Шаг 1. Зарезервировать файл

`POST /developer/v1/files` создаёт запись и возвращает форму для загрузки.

```bash theme={null}
curl -X POST -H "X-API-Key: ddp_ВАШ_КЛЮЧ" -H "Content-Type: application/json" \
  https://app.doodocs.kz/api/developer/v1/files \
  -d '{
    "filename": "prikaz-o-prieme.pdf",
    "content_type": "application/pdf",
    "size_bytes": 148392
  }'
```

```json theme={null}
{
  "file": {
    "id": "01a0235f-697e-7ce1-ba86-bcde95928a68",
    "filename": "prikaz-o-prieme.pdf",
    "content_type": "application/pdf",
    "size_bytes": 148392,
    "status": "FILE_UPLOAD_STATUS_PENDING",
    "create_time": "2026-08-21T09:30:00Z"
  },
  "upload": {
    "url": "https://storage.doodocs.kz/people-files",
    "fields": {
      "key": "…/documents/01a0235f…",
      "Content-Type": "application/pdf",
      "policy": "eyJleHBpcmF0aW9uIjoi…",
      "x-amz-signature": "9f2c…"
    },
    "expires_at": "2026-08-21T09:45:00Z"
  }
}
```

<Note>
  `size_bytes` — точный размер байтов. Политика подписи не пропустит объект
  больше заявленного, а `_confirm` сверит размер в хранилище с тем, что вы
  объявили.
</Note>

## Шаг 2. Отправить байты в хранилище

Форма отправляется как `multipart/form-data`: сначала все поля из `fields`
без изменений, файл — последним полем `file`.

```bash theme={null}
curl -X POST "https://storage.doodocs.kz/people-files" \
  -F "key=…/documents/01a0235f…" \
  -F "Content-Type=application/pdf" \
  -F "policy=eyJleHBpcmF0aW9uIjoi…" \
  -F "x-amz-signature=9f2c…" \
  -F "file=@prikaz-o-prieme.pdf"
```

Успешная загрузка — `204` без тела. Ключ `X-API-Key` сюда передавать не нужно:
подпись в форме уже авторизует запрос. Форма живёт до `expires_at`; после этого
резервируйте файл заново.

## Шаг 3. Подтвердить загрузку

Пока загрузка не подтверждена, файл нельзя прикрепить к документу.

```bash theme={null}
curl -X POST -H "X-API-Key: ddp_ВАШ_КЛЮЧ" -H "Content-Type: application/json" \
  https://app.doodocs.kz/api/developer/v1/files/01a0235f-697e-7ce1-ba86-bcde95928a68/_confirm \
  -d '{}'
```

```json theme={null}
{
  "file": {
    "id": "01a0235f-697e-7ce1-ba86-bcde95928a68",
    "status": "FILE_UPLOAD_STATUS_UPLOADED",
    "size_bytes": 148392
  }
}
```

Повторный `_confirm` по уже подтверждённому файлу ничего не меняет и возвращает
`200` — повторить запрос после таймаута безопасно.

## Шаг 4. Создать документ из файла

В `POST /documents` вместо `template_id` передайте `file_id`. Файл становится
PDF документа — именно его увидят согласующие и подпишут подписанты.

```bash theme={null}
curl -X POST -H "X-API-Key: ddp_ВАШ_КЛЮЧ" -H "Content-Type: application/json" \
  https://app.doodocs.kz/api/developer/v1/documents \
  -d '{
    "title": "Приказ о приёме — Каныш Сатпаев",
    "type_id": "t1…",
    "file_id": "01a0235f-697e-7ce1-ba86-bcde95928a68",
    "subject_employee_ids": ["3f2a9c7e-…"]
  }'
```

<Warning>
  `template_id` и `file_id` взаимоисключающие: указать оба или ни одного — ошибка
  `DEVELOPER.INVALID_ARGUMENT`. Поле `template_values` без `template_id` тоже
  отклоняется, а не игнорируется молча.
</Warning>

Дальше — обычный путь: [маршрут, отправка и
подписание](/ru/guides/documents/signing). Инициатором становится владелец
ключа, как и при создании из шаблона.

## Ограничения

| Что              | Значение                                                   |
| ---------------- | ---------------------------------------------------------- |
| Формат           | только `application/pdf`                                   |
| Размер           | до 50 МБ                                                   |
| Неподтверждённых | не больше 10 одновременно на владельца ключа               |
| Одна привязка    | подтверждённый файл прикрепляется ровно к одному документу |

<Note>
  Конвертации нет: DOCX или картинку API не примет — файл уходит на подписание
  ровно таким, каким вы его прислали. Приводите документ к PDF на своей стороне.
</Note>

Лимит неподтверждённых загрузок считается по владельцу ключа и общий с
веб-приложением: интеграция, которая резервирует файлы и не подтверждает их,
займёт квоту этого сотрудника и в интерфейсе.

## Ошибки

| `code`                           | Когда возникает                                            |
| -------------------------------- | ---------------------------------------------------------- |
| `FILE.INVALID_CONTENT_TYPE`      | `content_type` не `application/pdf`                        |
| `FILE.INVALID_SIZE`              | `size_bytes` нулевой, отрицательный или больше лимита      |
| `FILE.PENDING_LIMIT_EXCEEDED`    | Слишком много неподтверждённых загрузок                    |
| `FILE_NOT_FOUND`                 | Файла нет, он принадлежит другому владельцу или id не UUID |
| `FILE.NOT_UPLOADED`              | `_confirm` вызван, но байты в хранилище не пришли          |
| `FILE.SIZE_MISMATCH`             | В хранилище объект больше, чем было заявлено               |
| `FILE.INVALID_STATUS_TRANSITION` | `file_id` передан в `POST /documents` до подтверждения     |
| `FILE.ALREADY_LINKED`            | Файл уже прикреплён к другому документу                    |

<Note>
  Документ из файла не получает номер автоматически: нумерация привязана к
  шаблонам. Передайте `number` в `POST /documents`, если он вам нужен.
</Note>
