# Уникальные ссылки

## Наборы и ссылки

### 123. Наборы и ссылки

*Метод в API с 2026-09-29.*

| Действие | HTTP | Ответ |
|---|---|---|
| Наборы опроса, новые сверху | `GET /quiz/{id}/unique-links` | `{status, quiz_id, total, groups: Group[]}` |
| Создать набор со ссылками | `POST /quiz/{id}/unique-links` | `{status, quiz_id, group: {...Group, created_links: Link[]}}` |
| Один набор | `GET /quiz/{id}/unique-links/{groupId}` | `{status, quiz_id, group}` |
| Изменить набор | `POST /quiz/{id}/unique-links/{groupId}` | `{status, quiz_id, group}` |
| Прогноз нового лимита | `POST /quiz/{id}/unique-links/{groupId}?dry_run=1` | `{status, quiz_id, dry_run: true, becomes_used}` |
| Удалить набор со ссылками | `DELETE /quiz/{id}/unique-links/{groupId}` | `{status, quiz_id, group_id, deleted: true}` |
| Ссылки набора по странице | `GET /quiz/{id}/unique-links/{groupId}/links?page=&per_page=&search=&show=` | `{status, quiz_id, links: Link[], meta}` |
| Добавить ссылки | `POST /quiz/{id}/unique-links/{groupId}/links` | `{status, quiz_id, added, links: Link[]}` |
| Изменить ссылку | `POST /quiz/{id}/unique-links/links/{linkId}` | `{status, quiz_id, link}` |
| Включить / выключить / удалить несколько | `POST /quiz/{id}/unique-links/{groupId}/links/bulk` | `{status, quiz_id, affected}` |
| Файл со ссылками | `GET /quiz/{id}/unique-links/{groupId}/export?format=csv\|xlsx` | файл |

Тела запросов — как у кабинета:

```json
POST /quiz/18547/unique-links
{ "name": "Филиалы", "labels": ["Казань", "Самара"], "max_uses": null }

POST /quiz/18547/unique-links/12
{ "expires_at": "2026-12-31T21:00:00Z", "password_mode": "own", "password": "секрет" }

POST /quiz/18547/unique-links/links/501
{ "own_max_uses": true, "max_uses": 3, "params": [{ "name": "dept", "value": "sales" }] }

POST /quiz/18547/unique-links/12/links/bulk
{ "action": "delete", "filter": { "search": "", "show": "no_answers" } }
```

Изменение набора и ссылки идёт методом `POST`, как у остальных методов v3.

#### Ошибки

- `403` `{"status": false, "code": "blocked_by_tariff", "blocked_by_tariff": true, "option": "publication.unique_links"}` —
  у тарифа нет опции уникальных ссылок: создание набора, добавление ссылок и изменение чего-либо, кроме `active`.
  Смотреть, выгружать, включать, выключать и удалять уже выпущенное можно и без опции.
- `422` — машинный код в `errors.<field>[0]`: `{"message": "…", "errors": {"max_uses": ["max_uses_above_group"]}}`.
- `404` `{"status": false, "code": "unique_link_group_not_found"}` — набора нет, он удалён или из другого опроса;
  `unique_link_not_found` — то же для ссылки; `unique_link_password_not_found` — нет такого своего пароля ссылки.
- `403` `{"status": false, "blocked_by_access": true}` — нет права.

## Ответы и отчёт

- `GET /quiz/{id}/answers` принимает `unique_link_group_id` и `unique_link_ids[]` (§8, [answers.md](/dev/api/answers)),
  а у каждого ответа есть поле `unique_link` — `{id, label, group_id, group_name}` или `null`.
- `POST /quiz/{id}/report` принимает те же два поля (§34, [reports.md](/dev/api/reports-extra)).
- Сохранённый набор фильтров (`POST /quiz/{id}/filters`) хранит оба ключа на любом тарифе, и выгрузки ответов по
  сохранённому фильтру их учитывают.

Срез работает на любом тарифе. Без `unique_link_group_id` список `unique_link_ids` не учитывается.