Popular categories
Regions
Nothing found
Popular queries
Table of contents

AliBord API v1

Public REST API to integrate your business with AliBord. Create listings, get analytics, manage your catalog.

Introduction

AliBord API is a REST interface. Base URL: https://www.alibord.com

All requests and responses use JSON in UTF-8 encoding.

All dates are in the Europe/Kyiv timezone, ISO 8601 format.

API version v1. The version is part of the URL path. We commit to keep backwards compatibility within a single version — new fields may be added, existing ones will not change.

How to get an API key

  1. Sign in to your AliBord account.
  2. Open «Settings» → «API & integrations».
  3. Click «Create key», pick the required scopes and add a whitelist.
  4. Copy the key immediately — it is shown only once, after the dialog closes it is hidden.

Authentication

Every request must include an Authorization header with a Bearer token:

Authorization: Bearer sk_live_abcdef1234567890abcdef1234567890abcdef1234567890
Never expose your key in frontend code. Use a server-side proxy or your backend. You can deactivate the key in the dashboard at any time.

Whitelist (IP / domains)

For security, every API key must have a whitelist. API access is only available from listed IPs and domains.

FieldRoleExample
allowed_ipsIP whitelist — required, checked server-side192.0.2.10, 203.0.113.5
allowed_domainsAllowed domains — used for CORS (browser requests)my-shop.com, api.my-shop.com
IP is the only reliable gate. The Origin / Referer headers are trivial to forge from curl/server, so the domain is not a lock — only a CORS hint for browser requests.

Server-side: if the client IP is not in the whitelist — 403 ip_not_whitelisted is returned immediately. If the whitelist is empty — 403 whitelist_incomplete.

For browsers: add your domain (e.g. my-shop.com) to the whitelist — otherwise the browser will block the response due to CORS.

Scopes (permissions)

Scopes are «permissions» that limit what the key can do. Grant only what is needed — principle of least privilege.

ScopeAllows
listings:readRead your listings, categories, attributes, cities
listings:writeCreate / edit listings, upload media

If the key is missing a scope — the API returns 403 scope_required with the required scope name in hint.

Rate limits

Depending on the account type, keys have different per-minute and per-day limits.

LimitPersonal accountBusiness account
Requests per minute60600
Requests per day5 000100 000

On exceeding — 429 rate_limit_exceeded or 429 daily_limit_exceeded. Current counters are visible via /api/v1/ping.

HTTP methods

The API uses standard HTTP methods.

MethodPurposeBodyIdempotent
GETFetch data (read-only)yes
POSTCreate entity / trigger actionJSONno
PUT / PATCHFull / partial updateJSONyes
DELETEDeletionyes

Request headers

HeaderRequiredExample
AuthorizationyesBearer sk_live_...
Acceptrecommendedapplication/json
Content-Typefor POST/PUT/PATCHapplication/json; charset=utf-8
Origin / Refererautomatic (browser)used for whitelist checks
User-Agentoptionalfor diagnostic logs

Request body

For POST/PUT/PATCH the body is JSON with a Content-Type: application/json header.

For GET, parameters are passed via the query string.

Example:

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"]
}

Response format

All responses are JSON with an ok field. true — success, false — error.

Success

{
  "ok": true,
  ...
}

Error

{
  "ok": false,
  "error": "error_code",
  "hint": "...",
  ...
}

Collections use a count field and an array named after the entity:

{
  "ok": true,
  "count": 2,
  "listings": [ { ... }, { ... } ]
}

HTTP status codes

CodeMeaning
200 OKSuccessful request
201 CreatedResource created
204 No ContentSuccess, no response body
400 Bad RequestMalformed request (invalid JSON, missing fields)
401 UnauthorizedInvalid / missing token
402 Payment RequiredInsufficient balance (for paid actions)
403 ForbiddenAccess denied (whitelist / scope / key status)
404 Not FoundResource not found
405 Method Not AllowedMethod not allowed for this endpoint
413 Payload Too LargeRequest body exceeds size limit
415 Unsupported Media TypeInvalid Content-Type
422 Unprocessable EntityData passed schema validation but failed business rules
429 Too Many RequestsRate limit exceeded
500 Internal Server ErrorInternal server error

Error codes

On error, the body contains an error field with a machine code and hint with a human-readable explanation.

{ "ok": false, "error": "error_code", ... }
HTTPCodeDescription
401missing_bearer_tokenThe Authorization header is missing or does not contain a Bearer token
401invalid_keyKey not found, deactivated or malformed
403key_suspended / key_revokedKey is temporarily suspended or revoked by its owner
403whitelist_incompleteThe key has no whitelist set — access denied
403ip_not_whitelistedThe request IP is not in the key whitelist
403scope_requiredThe key is missing the required scope — see hint
429rate_limit_exceededPer-minute request limit exceeded
429daily_limit_exceededDaily request limit exceeded

GET /api/v1/ping

Verify the key and get a quick overview of limits / scopes / client IP.

Response

{
  "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

List of your listings, cursor-paginated. Scope: listings:read.

Query parameters

ParameterDefaultDescription
langukResponse language: uk, ru, en
statusactiveactive, sold, archived, inactive, all
limit20Page size, 1–100
cursorID of the last listing from the previous page
fieldsall fieldsComma-separated list of fields — to fetch only what you need (saves bandwidth)

Response

{
  "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"
    }
  ]
}

Pass the next_cursor value into cursor on the next request. If the page is not full — next_cursor is absent.

Fields

FieldTypeDescription
idintListing ID
slugstringSEO slug
titlestringTitle in the selected language
pricenumberPrice, may be decimal
currencystringUAH, USD, EUR
conditionstring \| nullnew, used
citystring \| nullCity name in the selected language
statusstringactive, sold, archived, inactive
viewsintView count
vip, topboolWhether VIP / TOP promotion is active
vip_until, top_untildatetime \| nullDate until the promotion is active
photostring \| nullMain photo (first from the array)
photosarrayAll listing photos
urlstringDirect link to the listing page
created_atdatetimeCreation date
Performance: for lists use fields and limit — response will be smaller and limits will last longer.

GET /api/v1/my/listings/{id}

Full data for a single listing, including description, attributes, contacts and moderation status. Scope: listings:read.

Response

{
  "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
  }
}

The moderation block is returned only for listings in pending or blocked state. reason contains the block reason if the moderator left one.

POST /api/v1/my/listings

Create a new listing. Scope: listings:write.

Moderation: listings created via API go through the same checks as website listings. After creation the status is pending, publication happens after moderator approval.

Body (JSON)

FieldTypeRequiredDescription
titlestringyesTitle, 5–120 chars
descriptionstringyesDescription, 20–5000 chars
pricenumberyes*Price. Optional if price_type = exchange / free
price_typestringnosell, exchange, free
currencystringnoUAH, USD, EUR
category_idintyesCategory ID (see /categories)
conditionstringnonew / used
city_refstringyes*City UUID from /cities/search
photosarray<string>noPhoto URLs (up to 12). Obtain via /upload/photo
photos_wmarray<string>noWatermarked photo URLs, same order as photos
photos_3darray<string>noURLs of 3D tour frames (see 3D widget)
video_url / video_thumbnailstringnoVideo URL and its thumbnail (see /upload/video)
attributesobjectnoObject with category attributes (see /categories/{id}/attributes)
contact_name / contact_phonestringnoName and phone (if omitted — taken from the profile)
hide_phoneboolnoHide phone from the listing

Response

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"
}
Duplicate protection: right after creation the system checks whether the same listing was posted within the last 24 hours. If yes — returns 422 duplicate.

PUT PATCH /api/v1/my/listings/{id}

Partial listing edit. Send only the fields you want to update — the rest stay as they were. Scope: listings:write.

Body (JSON, all fields optional)

{
  "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 }
}
Media: passing photos, photos_3d or video_url is a full replacement of that set. To keep previous media — omit the field entirely.
Moderation: if the listing was active before the edit, it is automatically moved back to pending and re-checked — same as on the website.
{ "ok": true, "listing_id": 2468, "status": "pending" }

POST /api/v1/my/listings/{id}/status

Change a listing status — activate or deactivate. Scope: listings:write. «Sold» and «delete» actions are intentionally unavailable via API — perform them from the website or admin panel.

Body (JSON)

{ "status": "inactive" }

Allowed values

ValueEffect
activeBring back to public listing (allowed only from inactive/sold)
inactiveDeactivate — listing is hidden from the catalog
Transition to active is only allowed from the inactive state. From pending / blocked / sold you cannot activate via API — only a moderator/admin on the site can.

GET /api/v1/categories

Category tree for creating listings. Names are in the selected language (?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 for a specific category — needed in the attributes field when creating a listing. 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" }
  ]
}

Types: text, number, select, boolean, range. For select, pass the value from the options array.

GET /api/v1/cities/search

City search for the city_ref field. Returns a Nova Poshta ref. Scope: listings:read.

Query parameters

ParameterDefaultDescription
qSearch string (min 2 chars)
langukName language: uk, ru, en
limit10Max results (1–50)
{
  "ok": true,
  "cities": [
    {
      "ref":   "e71f8bb8-4b33-11e4-ab6d-005056801329",
      "name":  "Київ",
      "type":  "м.",
      "region": "Київська",
      "label": "м. Київ, Київська",
      "warehouses": 1823
    }
  ]
}

POST /api/v1/ai/suggest-category

AI category suggestion based on title and description. Handy for auto-filling the form. Scope: listings:write.

{
  "title": "iPhone 17 Pro Max 256Gb",
  "description": "...",
  "lang": "uk"
}

Success

{
  "ok":            true,
  "category_id":   117,
  "category_path": "Електроніка › Телефони › Apple",
  "category_slug": "apple"
}

POST /api/v1/upload/photo

Upload a photo to the CDN — get a URL for the photos field of a new listing. Scope: listings:write.

Format: multipart/form-data, file field. Limit — 12 MB. Accepts JPG, PNG, WebP, HEIC. Automatically converted to WebP and resized to 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
}
A pair of URLs is returned: url — original, url_wm — watermarked. When creating the listing, pass them correspondingly into photos / photos_wm.

POST /api/v1/upload/video

Upload a short video (up to 60s) for a listing. Scope: listings:write.

  • Formats: MP4, MOV, WebM (H.264 or H.265)
  • Max size: 50 MB, max duration: 60s
  • One video per listing
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 widget

Ready-made widget to capture a 3D tour of a product using the device camera. Embed with one line, it uploads photos via your server-side proxy (so the API key stays secret).

Embedding

<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>

How it works

  • User clicks the «3D» button
  • The widget requests camera access and opens fullscreen
  • A series of frames is captured (automatically or on click)
  • Frames are sent via POST to your uploadEndpoint
  • Your server forwards them to /api/v1/upload/photo with the API key
  • The onComplete(urls) callback receives the array of URLs — pass it in the photos_3d field when creating the listing
Security: never call /api/v1/upload/photo directly from the browser — that leaks the API key. Always use a server-side proxy.

Server proxy example (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;

Moderation

All listings created via API go through the same moderation as listings from the website.

  • Listings in safe categories are usually auto-approved — active right away.
  • The rest go into pending and are checked by a moderator (~15 min during business hours).
StatusEffect
pendingAwaiting moderator review
activePublished and visible in the catalog
blockedRejected by moderator — see moderation.reason
soldMarked as sold
archivedMoved to archive due to expiration
inactiveDeactivated by the owner

To track status, poll GET /my/listings/{id} — the moderation block will carry the decision and reason (if any).

Example: cURL

# List your listings (in English)
curl -H "Authorization: Bearer sk_live_..." \
     "https://www.alibord.com/api/v1/my/listings?lang=en&limit=20"

# Only the fields you need — saves bandwidth
curl -H "Authorization: Bearer sk_live_..." \
     "https://www.alibord.com/api/v1/my/listings?fields=id,title,price,currency,photo&limit=50"

# Create a new listing
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"
  }'

Example: 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');
}

Example: JavaScript (fetch)

// WARNING: never from a browser directly — only via your server-side proxy! The key must not reach the frontend.
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);
}
CORS: for browser requests, the fetch origin domain must be in allowed_domains for the key. Otherwise the browser will block the response.
Profile
Appearance
Light
Light
Dark
System
Language
English