Медиа
Эндпоинты медиатеки сайта — загрузка, список, поиск, чтение и удаление вложений; как картинки попадают на страницы, написано на странице «Медиа».
Во всех примерах API — https://onpress.pro/api/v2, SITE — id сайта (SITE_ID), OP_TOKEN — токен op_XXXX.
Все эндпоинты — под $API/site/$SITE/media. Принимаются файлы до 32 МБ: картинки jpg, jpeg, png, webp, gif и svg (тип узнаётся по содержимому), шрифты woff и woff2 и остальные типы, разрешённые на сайте, например pdf и mp4. Файлы, которые браузер исполнил бы на домене сайта, — html, js, php, xml, svgz и подобные — не принимаются никогда. К каждой картинке сайт сам делает уменьшенные размеры и WebP-копии.
Короткий адрес
У каждого файла медиатеки есть короткий адрес: /media/ и путь файла внутри медиатеки сайта. Например, /media/2026/09/ccae29ae_1778004215.png. Путь берется с папкой месяца: имя файла уникально только внутри нее. Поля url, path, webp, thumb и адреса в sizes отдаются короткими, url — с доменом. По короткому адресу сервер сразу отдает файл, без редиректа, с типом файла и теми же заголовками кэша. Адреса без расширения файла, например /media/ и его подстраницы, остаются адресами страниц сайта. Публикация markdown и свойство image принимают короткий адрес, выгрузка GET /pages/{ref}/markdown печатает его же. Пустой alt картинки на сайте заменяется названием страницы. В выгрузке он остается пустым.
POST /media
Загружает файл в медиатеку: по адресу, строкой base64 или файлом в multipart/form-data. Загрузка идемпотентна: повтор с тем же адресом или теми же байтами возвращает уже загруженное вложение с deduped: true и deduped_by (source_url или sha256). Например, загрузить картинку по адресу:
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
url | string | — | адрес источника, http или https, не локальный и не внутренний |
data | string | — | содержимое в base64 или data:-URI; вместе с url нельзя |
filename | string | — | имя файла; обязательно с data |
alt, title | string | — | альтернативный текст и заголовок; применяются только при создании |
lang | string | — | язык вложения, если у сайта медиа переводятся; только при создании |
Файлы больше 7,5 МБ шлите как multipart/form-data: часть file с файлом и, по желанию, alt, title, lang, filename — тело JSON с base64 упирается в предел запроса в 10 МБ.
curl -s -X POST "$API/site/$SITE/media" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"url": "https://onpress.pro/media/2026/05/ccae29ae_1778004215.png", "alt": "Схема сборки страницы", "title": "schema"}'
{
"success": true,
"site_id": "x9HTLHECq",
"id": 6449,
"url": "https://test.onpress.pro/media/2026/09/ccae29ae_1778004215.png",
"path": "/media/2026/09/ccae29ae_1778004215.png",
"mime": "image/png",
"width": 1400,
"height": 1207,
"filesize": "…",
"webp": "/media/2026/09/ccae29ae_1778004215.webp",
"sizes": {
"medium": { "path": "/media/2026/09/ccae29ae_1778004215-300x259.png", "width": 300, "height": 259, "mime": "image/png", "webp": "/media/2026/09/ccae29ae_1778004215-300x259.webp" },
"onpress_sm": { "path": "…-768x662.png", "width": 768, "height": 662, "mime": "image/png", "webp": "…-768x662.webp" }
},
"alt": "Схема сборки страницы",
"title": "schema",
"lang": null,
"source_urls": ["https://onpress.pro/media/2026/05/ccae29ae_1778004215.png"],
"sha256": "…",
"deduped": false
}
| Код | HTTP | Когда | Что делать |
|---|---|---|---|
source_required | 400 | нет ни url, ни data, ни части file | передайте один источник |
source_ambiguous | 400 | и url, и data | оставьте один |
filename_required | 400 | data без filename | добавьте имя с расширением |
bad_url | 400 | адрес не http(s), с логином или ведёт на локальный хост | дайте публичный адрес |
bad_data | 400 | data не base64 | перекодируйте |
bad_multipart | 400 | тело multipart/form-data не разобралось | проверьте форму запроса |
bad_field | 400 | alt, title или lang не строка | — |
unknown_language | 400 | языка lang нет на сайте | возьмите язык из GET /data/site.languages |
empty_file | 400 или 422 | файл пустой | — |
file_too_large | 413 | больше 32 МБ | уменьшите файл |
unsupported_type | 415 | тип не разрешён на сайте, файл без расширения и не картинка или содержимое не совпадает с расширением | сохраните в png, jpg, webp, gif или svg; в сообщении — список разрешённых расширений |
unsafe_svg | 422 | в SVG скрипты, обработчики on*=, ссылки javascript:, встроенные объекты или внешние <use> | очистите SVG |
source_not_found | 422 | адрес отвечает 404 | проверьте адрес |
download_failed | 422 | файл по адресу не скачался | проверьте адрес и повторите |
sideload_failed | 422 | сайт не смог сохранить файл | повторите запрос |
tmp_failed | 500 | сайт не смог записать временный файл | повторите запрос |
media_failed | 502 | сайт ответил ошибкой | повторите запрос |
media_unavailable | 502 или 503 | сайт не ответил | повторите через минуту |
GET /media
Без source_url и sha256 возвращает медиатеку сайта постранично. Например, последнее загруженное вложение:
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
page | number | 1 | страница выдачи |
per_page | number | 50 | до 100 |
search | string | — | имя файла, заголовок, подпись, описание; до 200 символов |
type | string | — | image, video, audio, document, other или точный mime (image/png) |
lang | string | — | слаг языка, default или all; работает, если у сайта медиа переводятся (lang_filter: true) |
orderby | string | date | date, name, size, id |
order | string | desc | desc, asc |
curl -s -H "Authorization: Bearer $OP_TOKEN" "$API/site/$SITE/media?per_page=1"
{
"success": true,
"site_id": "ef7QmgyEc",
"page": 1,
"per_page": 1,
"total": 116,
"pages": 116,
"mime_groups": { "image": 113, "video": 3, "audio": 0, "document": 0, "other": 0 },
"lang": null,
"lang_filter": false,
"languages": [{ "slug": "ru", "name": "Русский", "default": true }],
"items": [
{ "id": 6331, "url": "https://onpress.pro/media/2026/10/onpress-logo-white-256.png", "path": "/media/2026/10/onpress-logo-white-256.png", "filename": "onpress-logo-white-256.png", "title": "onpress-logo-white-256", "mime": "image/png", "width": 256, "height": 256, "filesize": 11477, "date": "2026-10-02 11:15:03", "modified": "2026-10-02 11:15:03", "alt": "OnPress", "lang": "ru", "thumb": "https://onpress.pro/media/2026/10/onpress-logo-white-256.png", "webp": "/media/2026/10/onpress-logo-white-256.webp" }
]
}
date и modified — в UTC. mime_groups — сколько вложений каждого вида во всей медиатеке, lang — применённый фильтр языка, languages — языки сайта. Размеры и источники в список не входят — за ними идите в GET /media/{id}.
| Код | HTTP | Когда | Что делать |
|---|---|---|---|
bad_page, bad_per_page | 400 | не целое положительное число | — |
bad_search | 400 | длиннее 200 символов | сократите |
bad_type | 400 | не группа и не mime | — |
bad_lang | 400 | не слаг языка | — |
unknown_language | 400 | языка нет на сайте; languages | возьмите язык из languages |
bad_orderby, bad_order | 400 | значение вне списка | — |
Поиск по источнику
GET /media?source_url=<адрес> или GET /media?sha256=<64 hex> находит вложение, загруженное с этого адреса или с этими байтами, и отвечает в форме POST /media с deduped: false. Так перед загрузкой проверяют, нет ли файла на сайте. Например:
curl -s -G -H "Authorization: Bearer $OP_TOKEN" "$API/site/$SITE/media" \
--data-urlencode "source_url=https://onpress.pro/media/2026/05/ccae29ae_1778004215.png"
| Код | HTTP | Когда | Что делать |
|---|---|---|---|
media_not_found | 404 | такого файла нет | загрузите его POST /media |
bad_source_url | 400 | адрес не http(s) или локальный | — |
bad_sha256 | 400 | не 64 шестнадцатеричных символа | — |
GET /media/{id}
Возвращает любое вложение сайта со всеми размерами, в форме ответа POST /media. У файлов, загруженных не через API, source_urls пуст, а sha256 — null. Например:
curl -s -H "Authorization: Bearer $OP_TOKEN" "$API/site/$SITE/media/6449"
| Код | HTTP | Когда | Что делать |
|---|---|---|---|
bad_id | 400 | {id} не целое положительное число | — |
media_not_found | 404 | вложения нет | — |
DELETE /media/{id}
Удаляет вложение: файл, все его размеры и WebP-копии. Страницы, где картинка стоит, не правятся — уберите её из текста сами. Например:
curl -s -X DELETE "$API/site/$SITE/media/6449" -H "Authorization: Bearer $OP_TOKEN"
{ "success": true, "site_id": "x9HTLHECq", "id": 6449, "deleted": true }
| Код | HTTP | Когда | Что делать |
|---|---|---|---|
bad_id | 400 | {id} не целое положительное число | — |
media_not_found | 404 | вложения нет | — |
delete_failed | 500 | сайт не удалил файл | повторите запрос |