Admin API: офферы
Методы Admin API для офферов: список, создание и изменение, копии для сотрудников, группы, загрузка архива, файлы и версии локального оффера.
На странице 22 метода для работы с офферами. Все они требуют токен с доступом Полный доступ (full). Авторизация описана на странице Admin API: обзор и авторизация, формат запросов и общие коды ошибок — на странице Формат запросов, ответов и ошибок.
Объект оффера
Методы списка, чтения, создания, изменения и копирования возвращают оффер в одном виде.
| Поле | Тип | Описание |
|---|---|---|
id | строка, UUID | Идентификатор оффера. Используется в адресах методов |
seq | число | Порядковый номер оффера в панели |
name | строка | Название |
network_id | строка или null | Идентификатор партнёрской сети |
url | строка | Ссылка внешнего оффера |
storage | строка | external — внешняя ссылка, local — файлы хранятся в трекере. По умолчанию external |
delivery_type | строка | Тип доставки: redirect, meta, js, direct, double_meta. По умолчанию redirect |
payout | число | Фиксированная выплата. По умолчанию 0 |
payout_type | строка | Модель выплаты: cpa, cpc, crg, revshare. По умолчанию cpa |
payout_from_param | логическое | true — брать выплату из параметра постбека. По умолчанию false |
payout_param | строка | Имя параметра с выплатой. По умолчанию payout |
currency | строка | Код валюты из трёх букв. По умолчанию USD |
country | строка или null | Код страны из двух букв |
daily_cap | число или null | Лимит продаж в сутки, целое от 0. null — без лимита |
cap_timezone | строка | Часовой пояс лимита в формате IANA, например Europe/Warsaw. По умолчанию UTC |
overflow_offer_id | строка или null | Резервный оффер, который получает клики после достижения лимита |
state | строка | Статус: active, paused, archived. По умолчанию active |
values | массив | Значения оффера: объекты {"name": "...", "value": "..."} для макроса {offer_value:имя}. По умолчанию [] |
group_name | строка | Название группы. Пустая строка — без группы |
owner_id | строка или null | Пользователь, которому принадлежит оффер |
php_network | логическое | PHP с доступом в сеть для локального оффера. По умолчанию false |
Значения типов доставки, моделей выплаты и статусов разобраны на странице Офферы, лимит и резервный оффер — на странице Суточный лимит продаж и резервный оффер, php_network — на странице PHP в локальных страницах и доступ в сеть.
Если оффера с указанным id нет, любой метод с {id} в адресе отвечает 404 с кодом not_found. На id не в формате UUID ответ — 400 с кодом bad_request.
Офферы
Список офферов
GET /api/v1/offers
Возвращает массив офферов, новые первыми. Параметров и постраничности нет. Удалённые офферы в список не входят. Ответ — код 200.
Получить оффер
GET /api/v1/offers/{id}
Возвращает один оффер. Ответ — код 200.
Создать оффер
POST /api/v1/offers
Создаёт оффер. Владельцем становится пользователь, создавший токен.
| Поле | Тип | Обязательность | Описание |
|---|---|---|---|
name | строка | да | Название |
url | строка | да, если storage не local | Ссылка оффера |
storage | строка | нет | external или local |
daily_cap | число или null | нет | Не меньше 0 |
cap_timezone | строка | нет | Пояс IANA до 64 символов. Значение Local не принимается |
overflow_offer_id | строка или null | нет | Другой оффер этой команды в статусе active |
Остальные поля из раздела Объект оффера, кроме id, seq и owner_id, передаются по желанию. Пропущенные получают значения по умолчанию.
curl -X POST https://panel.example.com/api/v1/offers \
-H "Api-Key: <токен>" \
-H "Content-Type: application/json" \
-d '{"name":"Offer PL","url":"https://offer.example.com/?sub={subid}","payout":12.5,"country":"PL","daily_cap":50,"cap_timezone":"Europe/Warsaw"}'Ответ — код 201 и созданный оффер.
Ошибки с кодом 422 и validation:
| Сообщение | Причина |
|---|---|
name is required | Пустое название |
url is required for external offer | У внешнего оффера нет ссылки |
daily_cap must be non-negative | Отрицательный лимит |
cap_timezone must be a valid IANA time zone | Неизвестный часовой пояс |
overflow_offer_id must identify another offer | В резервном указан сам оффер или не UUID |
overflow offer must belong to this workspace | Резервный оффер не найден |
overflow offer must be active | Резервный оффер не в статусе active |
Изменить оффер
PUT /api/v1/offers/{id}
Меняет переданные поля. Поля, которых нет в теле, сохраняют текущие значения. Переданный null очищает country, daily_cap, network_id и overflow_offer_id. Группа снимается пустой строкой в group_name, значения — пустым массивом в values. Пустая строка в storage, delivery_type, payout_type, payout_param, currency и state оставляет прежнее значение, в cap_timezone — возвращает UTC.
Поля и ошибки те же, что при создании. Проверки применяются к итоговому офферу. Ответ — код 200 и обновлённый оффер.
Удалить оффер
DELETE /api/v1/offers/{id}
Перемещает оффер и его файлы в корзину. Ответ — код 204 без тела. Восстановление — на странице Admin API: корзина.
Копии и доступ
Клонировать оффер
POST /api/v1/offers/{id}/clone
Создаёт копию оффера. К названию добавляется « (копия)». У локального оффера копируются и файлы.
| Поле | Тип | Обязательность | Описание |
|---|---|---|---|
owner_id | строка | нет | Кому назначить копию. Без поля копия достаётся создателю токена |
Ответ — код 201 и новый оффер.
Раздать копии сотрудникам
POST /api/v1/offers/{id}/share-clone
Создаёт отдельную копию оффера каждому сотруднику из списка. Название копии совпадает с исходным, файлы локального оффера копируются.
| Поле | Тип | Обязательность | Описание |
|---|---|---|---|
user_ids | массив строк | да | Идентификаторы пользователей, не меньше одного |
Ответ — код 200 и объект с массивом results. В каждом элементе — user_id, login и offer_id новой копии. Если копию создать не удалось, вместо offer_id приходит error: «пользователь не найден», «не удалось клонировать» или «не удалось скопировать файлы».
Пустой список даёт 422 с сообщением «не выбран ни один сотрудник».
Кому открыт оффер
GET /api/v1/offers/{id}/shares
Возвращает объект с массивом user_ids — пользователи, которым оффер открыт для просмотра. Ответ — код 200.
Открыть оффер пользователям
POST /api/v1/offers/{id}/shares
Заменяет список целиком. Пустой массив закрывает доступ всем.
| Поле | Тип | Обязательность | Описание |
|---|---|---|---|
user_ids | массив строк | да | Новый полный список. Пользователи другой команды пропускаются |
Ответ — код 204 без тела.
Группы офферов
Группа — это значение поля group_name. Чтобы добавить оффер в группу, передайте название в group_name при создании или изменении оффера. Отдельные методы переименовывают и удаляют группу сразу у всех её офферов.
Переименовать группу
PUT /api/v1/offer-groups?name=<текущее название>
| Поле | Тип | Обязательность | Описание |
|---|---|---|---|
name в адресе | строка | да | Текущее название группы |
name в теле | строка | да | Новое название |
curl -X PUT "https://panel.example.com/api/v1/offer-groups?name=Nutra" \
-H "Api-Key: <токен>" \
-H "Content-Type: application/json" \
-d '{"name":"Nutra PL"}'Ответ — код 200 и {"updated": 4}, где число — сколько офферов изменено.
Удалить группу
DELETE /api/v1/offer-groups?name=<название>
Снимает группу с офферов. Сами офферы остаются. Тело не нужно. Ответ — код 200 и {"updated": N}.
Ошибки обоих методов — 422 с кодом validation: «name обязателен», если нет параметра в адресе. У переименования ещё две: «некорректное тело запроса», если тело не JSON-объект, и «новое имя группы обязательно», если в теле пустое название.
Файлы локального оффера
Пути файлов указываются относительно папки оффера, через /, например css/style.css. После первой загрузки архива, файла или сохранения файла оффер переходит в storage: local. Как трекер отдаёт такие страницы — на странице Локальный хостинг.
Загрузить архив
POST /api/v1/offers/{id}/upload
Принимает ZIP в формате multipart/form-data и заменяет им все файлы оффера. Журнал лидов оффера при этом сохраняется.
| Поле | Тип | Обязательность | Описание |
|---|---|---|---|
archive | файл | да | ZIP без пароля |
curl -X POST https://panel.example.com/api/v1/offers/7c9e6679-7425-40de-944b-e07fc1f90ae7/upload \
-H "Api-Key: <токен>" \
-F "[email protected]"Если у оффера уже были файлы, перед заменой они сохраняются как версия.
Ответ — код 200 и объект с массивом files. Элемент списка: path — путь, size — размер в байтах, dir — всегда false. Список отсортирован по пути, папки отдельными строками не выводятся.
Если архив не принят, прежние файлы оффера остаются на месте. Лимиты и ошибки — в разделе Лимиты и ошибки загрузки.
Список файлов
GET /api/v1/offers/{id}/files
Возвращает объект с массивом files в том же виде. У оффера без файлов массив пустой. Ответ — код 200.
Догрузить файлы
POST /api/v1/offers/{id}/files
Добавляет файлы к уже загруженным, формат — multipart/form-data. Файл с тем же путём заменяется, остальные не затрагиваются.
| Поле | Тип | Обязательность | Описание |
|---|---|---|---|
files | файл, можно несколько | да | Файлы. Сохраняется только имя файла, без папок из исходного пути |
dir | строка | нет | Папка внутри оффера. Без поля файлы попадают в корень |
Ответ — код 200 и объект: files — полный список файлов, saved — пути сохранённых, storage — local.
Прочитать файл
GET /api/v1/offers/{id}/file?path=<путь>
Возвращает содержимое файла размером до 5 МБ.
| Поле | Тип | Обязательность | Описание |
|---|---|---|---|
path в адресе | строка | да | Путь файла |
Ответ — код 200 и объект: path, content — содержимое строкой, utf8 — false, если файл не текст в UTF-8.
Сохранить файл
PUT /api/v1/offers/{id}/file
Создаёт или перезаписывает текстовый файл. Тело — JSON.
| Поле | Тип | Обязательность | Описание |
|---|---|---|---|
path | строка | да | Путь файла. Недостающие папки создаются |
content | строка | нет | Содержимое, до 5 МБ |
create | логическое | нет | true — только создание: если файл уже есть, ответ 409 «файл с таким путём уже есть» |
Ответ — код 200 и {"ok": true, "storage": "local"}.
Удалить файл
DELETE /api/v1/offers/{id}/file?path=<путь>
Удаляет один файл. Ответ — код 204 без тела.
Переименовать файл
POST /api/v1/offers/{id}/rename
Переименовывает файл или переносит его в другую папку. Файл, который уже есть по новому пути, не перезаписывается. Журнал лидов leads.php и имена с точкой в начале не переименовываются: ответ — 400.
| Поле | Тип | Обязательность | Описание |
|---|---|---|---|
from | строка | да | Текущий путь |
to | строка | да | Новый путь |
Ответ — код 200 и {"ok": true}. Без одного из полей — 400 с сообщением «нужны исходный и новый путь».
Ошибки методов с файлами
| Код | Сообщение | Причина |
|---|---|---|
422 | path is required | Не передан путь |
404 | «файл не найден» | Чтение или удаление: файла с таким путём нет |
400 | «недопустимый путь» | Путь выходит за пределы папки оффера |
400 | «скрытые файлы (начинающиеся с точки) не поддерживаются» | В пути есть имя, которое начинается с точки |
413 | «файл больше 5 МБ — Редактор такие не открывает и не сохраняет; замените его загрузкой файла или архива» | Чтение или сохранение файла больше 5 МБ |
413 | «слишком много файлов» | Новый файл, когда в оффере уже 10 000 файлов |
Версии и архив
Версия — сохранённая копия файлов оффера. Трекер хранит 10 последних версий оффера, более старые удаляются при сохранении новой. Журнал лидов и файлы с точкой в начале имени в версии и в архив не попадают. Сохранение версии и скачивание архива рассчитаны на оффер, у которого есть файлы. Работа с версиями в панели — на странице Редактор файлов, версии и экспорт.
Список версий
GET /api/v1/offers/{id}/versions
Возвращает массив версий, новые первыми. Поля: id, created_at — время создания в UTC, size — размер в байтах. Если версий нет, массив пустой. Ответ — код 200.
Сохранить версию
POST /api/v1/offers/{id}/versions
Сохраняет текущие файлы как новую версию. Тело не нужно. Ответ — код 201 и объект версии.
Восстановить версию
POST /api/v1/offers/{id}/versions/{version}/restore
Заменяет файлы оффера файлами версии. В {version} подставьте id из списка версий. Перед заменой текущие файлы сохраняются как новая версия. Журнал лидов остаётся на месте. Тело не нужно. Ответ — код 200 и {"ok": true}.
Восстановление заменяет все текущие файлы оффера. Хранится только 10 версий: после нескольких восстановлений и загрузок подряд старые версии удаляются.
Скачать архив
GET /api/v1/offers/{id}/archive
Отдаёт текущие файлы оффера одним ZIP-файлом page.zip. Ответ — код 200 с типом application/zip.
curl https://panel.example.com/api/v1/offers/7c9e6679-7425-40de-944b-e07fc1f90ae7/archive \
-H "Api-Key: <токен>" \
-o page.zipСохранение версии и скачивание архива отвечают 413, если в оффере больше 10 000 файлов или больше 1 ГБ.
Лимиты и ошибки загрузки
| Что ограничено | Предел |
|---|---|
| Размер одного запроса загрузки | 1 ГБ |
| Один файл | 1 ГБ |
| Все файлы архива после распаковки | 1 ГБ |
| Число файлов в архиве и в оффере | 10 000 |
Файл для чтения и сохранения через /file | 5 МБ |
Требования к архиву — на странице Локальный хостинг.
| Код | Сообщение | Причина |
|---|---|---|
413 | «превышен лимит загрузки 1 ГБ» | Запрос больше 1 ГБ |
413 | «файл слишком большой (лимит 1 ГБ на файл, 1 ГБ на распакованный архив)» | Файл или распакованный архив больше предела |
413 | «слишком много файлов» | В архиве или в оффере больше 10 000 файлов |
422 | «ожидался файл в поле archive» | В форме нет поля archive |
422 | «ожидались файлы в поле files» | В форме нет поля files |
422 | «нечего сохранять» | Ни у одного файла нет имени |
422 | «файл не является корректным .zip» | Загружен не ZIP |
422 | «архив сжат неподдерживаемым методом (LZMA, AES-шифрование и т.п.) — пересоберите обычным ZIP без пароля» | Архив с паролем или нестандартным сжатием |
422 | «архив повреждён — пересоберите его и загрузите заново» | Архив не читается до конца |
400 | «не удалось прочитать форму (загрузка прервана или повреждена)» | Передача оборвалась или тело не multipart/form-data |