A read-mostly REST API for syndicating Central Asia's news into your surfaces — OEM home feeds, news widgets and companion apps. A personalized, multi-signal-ranked feed plus article detail, search, and the catalog endpoints that drive language, topic and category pickers — filterable by language, country and topic.
All endpoints sit under the /api/v2 prefix on the base URL above. The OpenAPI schema is generated live by the backend and always reflects production — the interactive Swagger explorer (Redoc) above is the source of truth for request/response shapes.
Authentication
Every endpoint requires a per-partner API key sent as a bearer token in the Authorization header on every request. Keys are opaque random tokens (not JWTs) — the server stores only a SHA-256 hash. Rotate from your partner account at any time; the previous key stops working immediately on rotation.
Authorization header
Authorization:Bearer 8f2c4e7a93b1…a91d
Keep keys secret. Never embed a partner key in client-side code or a mobile app — it identifies your whole platform. Proxy requests through your own backend, and pass each end-user's stable id in the user parameter so ranking and engagement stay per-reader. Need a key? Request one →
Quickstart
Fetch a personalized feed for one reader, in Kazakh and Russian. The user is any stable id you assign per device. Pick your language below.
import requests, os
r = requests.get(
"https://api.uzunqulaq.com/api/v2/feed",
params={"user": "u_8f3c", "editions": "kk-kz,ru-kz", "page_size": 20},
headers={"Authorization": f"Bearer {os.environ['UQ_API_KEY']}"},
)
print(r.json()["results"][0]["title"])
Pagination
List endpoints (feed, search) are page-paginated. Pass a 1-based page and a page_size (clamped to 1–100 and your platform's max_page_size). The response echoes page, page_size and count; a page shorter than page_size means you've reached the end.
A personalized, dedup-aware, multi-signal–ranked news feed for one reader. Each card carries a display_rules consent block and a signed reader_url. Use editions for an ordered multi-language feed, or a single lang + country.
GET/api/v2/feed
Query parameters
user
string
required · Opaque reader id you assign (a per-device UUID is fine). Personalizes ranking and anchors engagement events.
editions
string
optional · Ordered CSV of edition codes (e.g. kk-kz,ru-kz, max 10). Replaces lang+country; index 0 is the primary edition.
lang
string
optional · BCP-47 language code, e.g. kk.
country
string
optional · ISO 3166-1 alpha-2 country code, e.g. kz.
category
string
optional · Restrict the feed to a single category code.
include_posts
boolean
optional · Interleave followed-person social posts (companion-app feature; off by default).
page
integer
optional · 1-based page number (default 1).
page_size
integer
optional · Items per page (your platform default; clamped 1–100 and your max_page_size).
Honor display_rules. Each card states what you may show (title, excerpt, image, full text) and whether a backlink and attribution are required. Content you aren't licensed to show is already blanked server-side.
Article detail
Full detail for one article — body, images and up to 5 similar articles. The display_rules block is included and any content you aren't licensed to show is already blanked server-side.
GET/api/v2/article/{article_id}
Path parameters
article_id
integer
required · Article id (from a feed or search id).
Query parameters
user
string
optional · Opaque reader id. When supplied, the call also records the relevant engagement event for this reader.
Response 200 OK
application/json
{
"id": 20413,
"title": "A new rail corridor promises to redraw the map",
"full_content": "<p>The line would cut freight times…</p>",
"short_content": "The line would cut freight times between…",
"reading_time": 6,
"published_at": "2026-06-14T09:30:00Z",
"source": { "domain": "kazinform.kz", "code": "kazinform" },
"category": { "code": "world", "name": "World", "name_kk": "Әлем", "name_ru": "Мир" },
"images": { "desktop": "…/desktop.jpg", "mobile": "…/mobile.jpg", "thumbnail": "…/thumb.jpg" },
"similar_articles": [ { "id": 20390, "title": "Freight volumes hit a record", "similarity": 0.82 } ],
"display_rules": { "title_ok": true, "excerpt_ok": true, "image_ok": true, "full_text_ok": false, "link_required": true, "attribution_required": true, "attribution_label": "Kazinform" }
}
Search
Hybrid search combining semantic (vector) and keyword (full-text) matching, scoped to your platform. Optionally filter by edition (lang + country) and/or category.
GET/api/v2/search
Query parameters
q
string
required · Search query string.
lang
string
optional · BCP-47 language code, e.g. kk.
country
string
optional · ISO 3166-1 alpha-2 country code, e.g. kz.
category
string
optional · Restrict results to a single category code.
page
integer
optional · 1-based page number (default 1).
page_size
integer
optional · Results per page (default 20; clamped 1–100).
user
string
optional · Opaque reader id; when supplied the call records the relevant engagement event.
Every edition (language + country) in the catalog — the vocabulary for language pickers and the editions / lang+country parameters elsewhere. Add ?platform=true to scope to the editions your platform may serve.
GET/api/v2/editions
Query parameters
platform
boolean
optional · When true, return only the editions your platform may serve (falls back to all if none are set).
Topic catalog for a given edition, ordered by recent article volume (most active first) so it doubles as an importance signal. Drives topic pickers and section navigation. lang and country are required.
GET/api/v2/topics
Query parameters
country
string
required · ISO 3166-1 alpha-2 country code, e.g. kz.
lang
string
required · BCP-47 language code, e.g. kk.
limit
integer
optional · Max topics to return (default 100; clamped 1–200).
q
string
optional · Case-insensitive filter on topic name + code.
Your platform's per-category ranking config — weights and how many top items to surface — ordered by weight. Use it to build sections and navigation. Optionally scope to one edition with lang + country.
GET/api/v2/platform/categories
Query parameters
lang
string
optional · BCP-47 language code, e.g. kk.
country
string
optional · ISO 3166-1 alpha-2 country code, e.g. kz.
The configuration for the platform identified by your bearer token: display name, type, page-size limits, hourly rate limit, and the editions you may serve (["all"] if unrestricted).
Report a reader engagement event (impression, click, or read progress) so ranking improves for that reader. Optional but recommended — the event is keyed to the user you pass.
POST/api/v2/track
Request body application/json
user
string
required · The opaque reader id the event belongs to.
article_id
integer
required · The article the event is about.
event
string
required · One of impression, click, read_start, read_progress, read_complete.
time_spent
integer
optional · Seconds spent reading.
scroll_depth
integer
optional · Percent of the article scrolled (0–100).
read_completed
boolean
optional · Whether the reader finished the article.
The API uses conventional HTTP status codes and returns a consistent error envelope. 2xx means success, 4xx a problem with the request, and 5xx an error on our side.
200 OK400 Bad Request401 Unauthorized403 Forbidden404 Not Found429 Too Many Requests500 Server Error
Errors return a single error string describing what went wrong. 401 means a missing/invalid key, 403 that your platform isn't licensed for that content or edition, and 400 a bad parameter.
Error envelope
{
"error": "Unknown edition code(s): 'xx-zz'."
}
Rate limits
Limits are applied per platform (your bearer token), not per IP. Your ceiling is the rate_limit_per_hour value returned by GET /platform. When you exceed it you'll receive a 429 with a Retry-After header (seconds to wait before retrying). Honor it with exponential backoff.
Building something bigger? OEM, browser and enterprise integrations get dedicated quotas, larger page sizes and support. Talk to our partnerships team →