AliBord API v1
Публичный REST API для интеграции вашего бизнеса с AliBord. Создавайте объявления, получайте статистику, управляйте каталогом.
Введение
AliBord API — это REST-интерфейс. Базовый URL: https://www.alibord.com
Все запросы и ответы в формате JSON в кодировке UTF-8.
Все даты — в часовом поясе Europe/Kyiv в формате ISO 8601.
Как получить API-ключ
- Зайдите в свой личный кабинет AliBord.
- Откройте раздел «Настройки» → «API и интеграции».
- Нажмите «Создать ключ», выберите нужные scopes и добавьте whitelist.
- Скопируйте ключ сразу — после закрытия окна он больше не показывается.
Аутентификация
Каждый запрос должен содержать заголовок Authorization с Bearer-токеном:
Authorization: Bearer sk_live_abcdef1234567890abcdef1234567890abcdef1234567890
Whitelist (IP / домены)
Для безопасности каждый API-ключ должен иметь whitelist. Доступ к API возможен только с указанных IP-адресов и доменов.
| Поле | Роль | Пример |
|---|---|---|
allowed_ips | Белый список IP — обязателен, проверяется сервером | 192.0.2.10, 203.0.113.5 |
allowed_domains | Разрешённые домены — используются для CORS (браузерные запросы) | my-shop.com, api.my-shop.com |
Origin / Referer легко подделать из curl/сервера, поэтому домен — не замок, а лишь CORS-настройка для браузерных запросов.Сервер-сайд: если IP клиента не в whitelist — сразу 403 ip_not_whitelisted. Если whitelist пустой — 403 whitelist_incomplete.
Для браузера: добавьте ваш домен (например, my-shop.com) в whitelist — иначе браузер заблокирует запрос из-за CORS.
Scopes (права доступа)
Scopes — это «разрешения», ограничивающие, что именно может делать ключ. Назначайте только нужные — по принципу минимальных прав.
| Scope | Разрешает |
|---|---|
listings:read | Читать свои объявления, категории, атрибуты, города |
listings:write | Создавать и редактировать объявления, загружать медиа |
Если у ключа не хватает scope — API возвращает 403 scope_required с названием необходимого scope в поле hint.
Лимиты запросов
В зависимости от типа аккаунта ключ имеет разные лимиты в минуту и в сутки.
| Лимит | Личный аккаунт | Бизнес-аккаунт |
|---|---|---|
| Запросов в минуту | 60 | 600 |
| Запросов в сутки | 5 000 | 100 000 |
При превышении — 429 rate_limit_exceeded или 429 daily_limit_exceeded. Текущее состояние можно смотреть в /api/v1/ping.
HTTP-методы
API использует стандартные HTTP-методы.
| Метод | Назначение | Тело | Идемпотентный |
|---|---|---|---|
GET | Получение данных (read-only) | — | да |
POST | Создание сущности / выполнение действия | JSON | нет |
PUT / PATCH | Полное / частичное обновление | JSON | да |
DELETE | Удаление | — | да |
Заголовки запроса
| Заголовок | Обязательный | Пример |
|---|---|---|
Authorization | да | Bearer sk_live_... |
Accept | рекомендуется | application/json |
Content-Type | для POST/PUT/PATCH | application/json; charset=utf-8 |
Origin / Referer | автоматически (браузер) | используется для проверки whitelist |
User-Agent | опционально | для диагностики в логах |
Тело запроса
Для POST/PUT/PATCH тело передаётся в формате JSON с заголовком Content-Type: application/json.
Для GET параметры передаются в query-строке.
Пример:
POST /api/v1/listings
Authorization: Bearer sk_live_...
Content-Type: application/json
{
"title": "iPhone 17 Pro Max 256Gb",
"price": 55000,
"currency": "UAH",
"condition": "new",
"city_ref": "db5c88d0-391c-11dd-90d9-001a92567626",
"photos": ["https://cdn.example.com/1.jpg", "https://cdn.example.com/2.jpg"]
}
Формат ответа
Все ответы — JSON с полем ok. true — успех, false — ошибка.
Успех
{
"ok": true,
...
}
Ошибка
{
"ok": false,
"error": "error_code",
"hint": "...",
...
}
Для коллекций используется поле count и массив с названием сущности:
{
"ok": true,
"count": 2,
"listings": [ { ... }, { ... } ]
}
HTTP-коды ответа
| Код | Значение |
|---|---|
200 OK | Успешный запрос |
201 Created | Сущность создана |
204 No Content | Успех без тела ответа |
400 Bad Request | Ошибка в формате запроса (невалидный JSON, отсутствуют поля) |
401 Unauthorized | Невалидный / отсутствующий токен |
402 Payment Required | Недостаточно средств на балансе (для платных действий) |
403 Forbidden | Доступ запрещён (whitelist / scope / статус ключа) |
404 Not Found | Ресурс не найден |
405 Method Not Allowed | Метод не разрешён для этого endpoint |
413 Payload Too Large | Размер тела превышает лимит |
415 Unsupported Media Type | Невалидный Content-Type |
422 Unprocessable Entity | Данные прошли валидацию формата, но не прошли бизнес-правила |
429 Too Many Requests | Превышен лимит запросов |
500 Internal Server Error | Внутренняя ошибка сервера |
Коды ошибок
При ошибке тело содержит поле error с машинным кодом и hint с человеческим пояснением.
{ "ok": false, "error": "error_code", ... }
| HTTP | Code | Описание |
|---|---|---|
| 401 | missing_bearer_token | Заголовок Authorization отсутствует или не содержит Bearer-токен |
| 401 | invalid_key | Ключ не найден, деактивирован или имеет неверный формат |
| 403 | key_suspended / key_revoked | Ключ временно приостановлен или удалён владельцем |
| 403 | whitelist_incomplete | У ключа не задан whitelist — доступ запрещён |
| 403 | ip_not_whitelisted | IP запроса не в whitelist ключа |
| 403 | scope_required | У ключа нет необходимого scope — см. hint |
| 429 | rate_limit_exceeded | Превышен лимит запросов в минуту |
| 429 | daily_limit_exceeded | Превышен суточный лимит запросов |
GET /api/v1/ping
Проверка ключа и быстрый взгляд на лимиты / scopes / IP клиента.
Ответ
{
"ok": true,
"message": "pong",
"key_id": 1,
"key_prefix": "sk_live_abcdef12",
"user_id": 36,
"account_type": "personal",
"scopes": ["listings:read", "listings:write"],
"scopes_granted": ["listings:read", "listings:write"],
"rate_limit_per_minute": 60,
"daily_limit": 5000,
"total_requests": 42,
"server_time": "2026-04-20T12:34:56+03:00",
"your_ip": "203.0.113.5"
}
GET /api/v1/my/listings
Список своих объявлений с пагинацией по курсору. Scope: listings:read.
Query-параметры
| Параметр | Default | Описание |
|---|---|---|
lang | uk | Язык ответа: uk, ru, en |
status | active | active, sold, archived, inactive, all |
limit | 20 | Размер страницы, 1–100 |
cursor | — | ID последнего объявления предыдущей страницы |
fields | все поля | Список полей через запятую — чтобы получить только нужные (экономия трафика) |
Ответ
{
"ok": true,
"lang": "uk",
"count": 2,
"next_cursor": 118,
"listings": [
{
"id": 123,
"slug": "iphone-17-pro-max-256gb",
"title": "iPhone 17 Pro Max 256Gb",
"price": 55000,
"currency": "UAH",
"condition": "new",
"city": "Київ",
"status": "active",
"views": 248,
"vip": true,
"top": false,
"vip_until": "2026-05-20 00:00:00",
"top_until": null,
"photo": "https://cdn.alibord.com/listings/3/abc.webp",
"photos": [
"https://cdn.alibord.com/listings/3/abc.webp",
"https://cdn.alibord.com/listings/3/def.webp"
],
"url": "https://alibord.com/uk/board/iphone-17-pro-max-256gb",
"created_at": "2026-04-15 10:22:01"
}
]
}
Значение next_cursor передавайте в параметр cursor следующего запроса. Если страница не полная — next_cursor отсутствует.
Поля
| Поле | Тип | Описание |
|---|---|---|
id | int | ID объявления |
slug | string | SEO-адрес |
title | string | Заголовок на выбранном языке |
price | number | Цена, может быть дробной |
currency | string | UAH, USD, EUR |
condition | string \| null | new, used |
city | string \| null | Название города на выбранном языке |
status | string | active, sold, archived, inactive |
views | int | Количество просмотров |
vip, top | bool | Активно ли VIP / TOP продвижение |
vip_until, top_until | datetime \| null | До какой даты действует продвижение |
photo | string \| null | Главное фото (первое из массива) |
photos | array | Все фото объявления |
url | string | Прямая ссылка на страницу объявления |
created_at | datetime | Дата создания |
fields и limit — ответ будет меньше, и лимиты расходуются экономнее.GET /api/v1/my/listings/{id}
Полные данные одного объявления, включая описание, атрибуты, контакты и статус модерации. Scope: listings:read.
Ответ
{
"ok": true,
"lang": "uk",
"listing": {
"id": 123,
"slug": "iphone-17-pro-max-256gb",
"title": "iPhone 17 Pro Max 256Gb",
"description": "...",
"price": 55000,
"currency": "UAH",
"condition": "new",
"city": "Київ",
"city_ref": "e71f8bb8-4b33-11e4-ab6d-005056801329",
"category_id": 42,
"status": "pending",
...
},
"moderation": {
"decision": "pending",
"reason": null,
"reviewed_at": null
}
}
Блок moderation возвращается только для объявлений в состоянии pending или blocked. В reason будет причина блокировки, если модератор её оставил.
POST /api/v1/my/listings
Создание нового объявления. Scope: listings:write.
pending, публикация — после одобрения модератором.Тело запроса (JSON)
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
title | string | да | Заголовок, 5–120 символов |
description | string | да | Описание, 20–5000 символов |
price | number | да* | Цена. Необязательно если price_type = exchange / free |
price_type | string | нет | sell, exchange, free |
currency | string | нет | UAH, USD, EUR |
category_id | int | да | ID категории (см. /categories) |
condition | string | нет | new / used |
city_ref | string | да* | UUID города из /cities/search |
photos | array<string> | нет | URL фото (до 12). Получить можно через /upload/photo |
photos_wm | array<string> | нет | URL фото с водяным знаком, в том же порядке что и photos |
photos_3d | array<string> | нет | URL кадров 3D-обзора (см. 3D-виджет) |
video_url / video_thumbnail | string | нет | URL видео и его превью (см. /upload/video) |
attributes | object | нет | Объект с атрибутами категории (см. /categories/{id}/attributes) |
contact_name / contact_phone | string | нет | Имя и телефон (если не указать — берутся из профиля) |
hide_phone | bool | нет | Скрыть телефон в объявлении |
Ответ
HTTP/1.1 201 Created
{
"ok": true,
"listing_id": 2468,
"slug": "iphone-17-pro-max-256gb",
"status": "active",
"url": "https://alibord.com/uk/board/iphone-17-pro-max-256gb"
}
422 duplicate.PUT PATCH /api/v1/my/listings/{id}
Частичное редактирование объявления. Передавайте только те поля, которые нужно обновить — остальные остаются как были. Scope: listings:write.
Тело (JSON, все поля опциональные)
{
"title": "iPhone 17 Pro Max 256Gb",
"description": "...",
"price": 52000,
"currency": "UAH",
"condition": "new",
"category_id": 42,
"city_ref": "e71f8bb8-...",
"contact_name": "...",
"contact_phone": "+380...",
"hide_phone": false,
"delivery": { ... },
"photos": ["https://...", "..."],
"photos_wm": ["https://...", "..."],
"photos_3d": ["https://...", "..."],
"video_url": "https://...",
"video_thumbnail": "https://...",
"attributes": { "brand": "apple", "memory_gb": 256 }
}
photos, photos_3d или video_url — это полная замена соответствующего набора. Чтобы оставить прежнее — не передавайте поле вовсе.active, после обновления автоматически переводится в pending и проходит проверку заново — как на сайте.{ "ok": true, "listing_id": 2468, "status": "pending" }
POST /api/v1/my/listings/{id}/status
Смена статуса объявления — активировать или деактивировать. Scope: listings:write. Действия «продано» и «удалить» через API намеренно недоступны — выполняйте их с сайта или админки.
Тело (JSON)
{ "status": "inactive" }
Возможные значения
| Значение | Что делает |
|---|---|
active | Вернуть в публикацию (разрешено только из inactive/sold) |
inactive | Деактивировать — объявление скрывается из каталога |
active разрешён только из состояния inactive. Из pending / blocked / sold активировать через API нельзя — это делает модератор/админ на сайте.GET /api/v1/categories
Дерево категорий для создания объявления. Названия — на выбранном языке (?lang=uk|ru|en). Scope: listings:read.
{
"ok": true,
"lang": "uk",
"categories": [
{
"id": 1,
"slug": "electronics",
"name": "Електроніка",
"children": [
{ "id": 11, "slug": "phones", "name": "Телефони", "children": [...] }
]
}
]
}
GET /api/v1/categories/{id}/attributes
Атрибуты конкретной категории — нужны в поле attributes при создании объявления. Scope: listings:read.
{
"ok": true,
"category_id": 11,
"attributes": [
{
"code": "brand",
"name": "Виробник",
"type": "select",
"required": true,
"options": [
{ "value": "apple", "label": "Apple" },
{ "value": "samsung", "label": "Samsung" }
]
},
{ "code": "memory_gb", "name": "Пам'ять, ГБ", "type": "number" }
]
}
Типы: text, number, select, boolean, range. Для select значение передаётся как value из массива options.
GET /api/v1/cities/search
Поиск городов для поля city_ref. Возвращает ref Новой Почты. Scope: listings:read.
Query-параметры
| Параметр | Default | Описание |
|---|---|---|
q | — | Строка поиска (min 2 символа) |
lang | uk | Язык названия: uk, ru, en |
limit | 10 | Максимум результатов (1–50) |
{
"ok": true,
"cities": [
{
"ref": "e71f8bb8-4b33-11e4-ab6d-005056801329",
"name": "Київ",
"type": "м.",
"region": "Київська",
"label": "м. Київ, Київська",
"warehouses": 1823
}
]
}
POST /api/v1/ai/suggest-category
AI-подсказка категории по заголовку и описанию. Удобно для автозаполнения формы. Scope: listings:write.
{
"title": "iPhone 17 Pro Max 256Gb",
"description": "...",
"lang": "uk"
}
Успех
{
"ok": true,
"category_id": 117,
"category_path": "Електроніка › Телефони › Apple",
"category_slug": "apple"
}
POST /api/v1/upload/photo
Загрузка фото на CDN — получить URL для поля photos при создании объявления. Scope: listings:write.
Формат: multipart/form-data, поле file. Лимит — 12 MB. Поддерживаются JPG, PNG, WebP, HEIC. Автоматически конвертируется в WebP и уменьшается до 1600px.
curl -X POST "https://www.alibord.com/api/v1/upload/photo" \
-H "Authorization: Bearer sk_live_..." \
-F "file=@/path/to/image.jpg"
HTTP/1.1 201 Created
{
"ok": true,
"url": "https://pub-...r2.dev/listings/36/1776203001_123.webp",
"url_wm": "https://pub-...r2.dev/pub/36/abc123...webp",
"width": 1200,
"height": 1600
}
url — оригинал, url_wm — с водяным знаком. При создании объявления используйте оба набора соответственно в photos / photos_wm.POST /api/v1/upload/video
Загрузка короткого видео (до 60 сек) для объявления. Scope: listings:write.
- Форматы: MP4, MOV, WebM (H.264 или H.265)
- Макс. размер: 50 MB, макс. длительность: 60 сек
- На объявление — одно видео
HTTP/1.1 201 Created
{
"ok": true,
"url": "https://pub-...r2.dev/listings/36/1776213111_456.mp4",
"thumbnail": "https://pub-...r2.dev/listings/36/1776213111_456_thumb.webp"
}
3D-виджет
Готовый виджет для захвата 3D-обзора товара через камеру устройства. Встраивается одной строкой, загружает фото через ваш серверный прокси (чтобы не раскрывать API-ключ).
Встраивание
<script src="https://www.alibord.com/widget/capture3d.js"></script>
<button onclick="startCapture()">3D</button>
<script>
function startCapture() {
AliBord.capture3d({
uploadEndpoint: '/my-proxy/upload-photo',
lang: 'uk',
onComplete: (urls) => console.log(urls.length),
onCancel: () => {},
onError: (err) => console.error(err),
});
}
</script>
Как работает
- Пользователь нажимает кнопку «3D»
- Виджет просит доступ к камере и открывает fullscreen
- Снимается серия кадров (автоматически или по нажатию)
- Кадры отправляются POST-запросами на ваш
uploadEndpoint - Ваш сервер пересылает их на
/api/v1/upload/photoс API-ключом - В колбэк
onComplete(urls)возвращается массив URL — передавайте его в полеphotos_3dпри создании объявления
/api/v1/upload/photo напрямую из браузера — это раскрывает API-ключ. Всегда используйте серверный прокси.Пример серверного прокси (PHP)
<?php
$API_KEY = getenv('ALIBORD_API_KEY');
if (empty($_FILES['file'])) {
http_response_code(400);
echo json_encode(['ok'=>false, 'error'=>'no_file']); exit;
}
$ch = curl_init('https://www.alibord.com/api/v1/upload/photo');
$cfile = new CURLFile($_FILES['file']['tmp_name'], $_FILES['file']['type'], $_FILES['file']['name']);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $API_KEY],
CURLOPT_POSTFIELDS => ['file' => $cfile],
CURLOPT_TIMEOUT => 60,
]);
$resp = curl_exec($ch);
http_response_code((int)curl_getinfo($ch, CURLINFO_HTTP_CODE));
header('Content-Type: application/json; charset=utf-8');
echo $resp;
Модерация
Все объявления, созданные через API, проходят ту же модерацию, что и объявления с сайта.
- Объявления из безопасных категорий обычно публикуются автоматически — сразу
active. - Остальные переходят в
pendingи проверяются модератором (~15 мин в рабочее время).
| Status | Что делает |
|---|---|
pending | Ожидает проверки модератором |
active | Опубликовано и видно в каталоге |
blocked | Отклонено модератором — см. moderation.reason |
sold | Отмечено проданным |
archived | Перенесено в архив по сроку |
inactive | Деактивировано владельцем |
Чтобы следить за состоянием, запрашивайте GET /my/listings/{id} — в блоке moderation будет решение и причина (если есть).
Пример: cURL
# Список своих объявлений (на английском)
curl -H "Authorization: Bearer sk_live_..." \
"https://www.alibord.com/api/v1/my/listings?lang=en&limit=20"
# Только нужные поля — экономим трафик
curl -H "Authorization: Bearer sk_live_..." \
"https://www.alibord.com/api/v1/my/listings?fields=id,title,price,currency,photo&limit=50"
# Создание нового объявления
curl -X POST "https://www.alibord.com/api/v1/my/listings" \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"title": "iPhone 17 Pro Max 256Gb",
"description": "...",
"price": 55000,
"currency": "UAH",
"category_id": 42,
"condition": "new",
"city_ref": "e71f8bb8-4b33-11e4-ab6d-005056801329",
"photos": ["https://my-shop.com/images/iphone-1.jpg"],
"contact_phone": "+380501234567"
}'
Пример: PHP
<?php
$API_BASE = 'https://www.alibord.com';
$API_KEY = 'sk_live_...';
$ch = curl_init($API_BASE . '/api/v1/my/listings?lang=en&limit=10&fields=id,title,price,currency,city,photo');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $API_KEY,
'Accept: application/json',
],
]);
$body = curl_exec($ch);
$data = json_decode($body, true);
curl_close($ch);
if (!empty($data['ok'])) {
foreach ($data['listings'] as $l) {
echo $l['title'] . ' — ' . $l['price'] . ' ' . $l['currency'] . "\n";
}
} else {
echo 'Error: ' . ($data['error'] ?? 'unknown');
}
Пример: JavaScript (fetch)
// ВНИМАНИЕ: в браузере напрямую — только через ваш серверный прокси! Ключ не должен попасть во фронтенд.
const params = new URLSearchParams({
lang: 'uk', limit: '20',
fields: 'id,title,price,currency,city,photo,url'
});
const r = await fetch('https://www.alibord.com/api/v1/my/listings?' + params, {
headers: { 'Authorization': 'Bearer sk_live_...' }
});
const data = await r.json();
if (data.ok) {
data.listings.forEach(l => console.log(l.title, l.price, l.currency, l.city));
} else {
console.error(data.error);
}
allowed_domains ключа. Иначе браузер заблокирует ответ.