
qrpayment
📋 Přehled
Tato dokumentace popisuje REST API pro práci s články, kategoriemi, tagy, uživateli, produkty, e-shop pouze pro čtení vrstva a parametry v CMS systému linkcms1. API je navrženo s důrazem na bezpečnost a multi-site podporu.
Základní URL:https://{domain}{BASEPATH}/api/v1Neversonovaný fakturační webhook
Vedle REST API v1 existuje jeden systémový webhook mimo /api/v1, který je výhradně pro integraci fakturace s Fakturoidem:
| Metoda | Cesta | Účel | Autentizace |
|---|---|---|---|
POST | /webhook/fakturoid/tariff | Synchronizace stavu tarifních faktur ( paid, cancelled, sent, open) do billing domény webu | X-FAKTUROID-WEBHOOK-SECRETnebo X-SignatureHMAC SHA-256 |
Webhook není určen pro veřejné klienty. Slouží k automatickému změně stavu , , a auditnímu zápisu do . sitetariffinvoicessitetarifforderssitetariffsubscriptionssitetarifffakturoidsynclog
Bezhlavá integrace domény API ( )apidomain
Pro weby obsluhované přes systémovou doménuweb-{site lze nastavit konfiguraci (v ). id}.{SYSTEMBASEDOMAIN}apidomainsiteconfigurations
- Trigger: request na API endpoint (
/api/...) přijatý přes systémovou doménu. - Chování: backend v API response přepíše veřejné URL tak, aby směřovaly na místo systémové domény.
apidomain - Rozsah přepisu: generované URL (
url, pagination links) a absolutní odkazy uvnitř HTMLbodyu článků/produktů. - Běžné weby na vlastní doméně se tímto nastavením neovlivní.
Hlavní funkce API
✅ Články (4 koncové body)
- Vytváření článků s médii, kategoriemi, tagy a parametry
- Získání detailu článku s autorem, kategoriemi a souvisejícím obsahem
- Seznam článků s filtrováním podle kategorie, statusu, dat
- Fulltextové vyhledávání
✅ Kategorie (3 koncové body)
- Hierarchický strom všech kategorií
- Načtení podkategorií konkrétní kategorie
- Detail kategorie s články a navigací
✅ Tagy a kategorie tagů (3 koncové body)
- Seznam všech značek s počtem článků + filtrování podle kategorií
- Detailní tag
- Seznam kategorií tagů (nové)
✅ Uživatelé/Autoři (1 koncový bod)
- Kompletní profil autora včetně bio, sociálních sítí, článků a statistik
✅ Produkty (5 koncových bodů - ČTĚTE A ZÁPIS)
- Seznam produktů s filtrováním podle kategorií, parametrů a produktových polí
- Detail produktu s kompletními informacemi včetně dynamických polí
- Vytvoření, aktualizace a soft-delete produktu přes API
- Flexibilní filtrování pomocí operátorů (eq, gte, lte, like)
✅ E-shop (19 koncových bodů)
- Seznam prodejných produktů z existujícího katalogu
- Detail prodávaného produktu včetně cen a inventárního bloku
- Přehled varianty produktu seskupených do variantní rodiny
- Dostupnost produktu včetně rezervovaného množství a stavu objednávek
- API košíku (načtení košíku, přidání položky, změna množství, odebrání položky)
- API kupónů (aplikace kupónu na košík, odebrání kupónu)
- API pokladna a objednávek (
POST /eshop/checkout,GET /eshop/orders/{id}) - API doprav a plateb (
GET /eshop/shipping-methods,GET /eshop/payment-methods) - API transakce (
GET/POST /eshop/orders/{id}/transactions,GET /eshop/transactions/{id}) - API webhooků platebních bran (
POST /eshop/webhooks/{provider}) — veřejný koncový bod - API exportů (
POST /eshop/export) pro ruční spuštění exportního běhu - Automatická rezervace skladu při práci s košíkem
- Spotřeba rezervace při pokladně a převodu košíku do stavu
converted - Automatický přechod objednávky do stavu
paidzachycení plateb - E-shop vrstev respektuje
productatypes.config.iseshopenabledsiteid
✅ Parametrie (1 koncový bod)
- Definice vlastních parametrů pro různé typy obsahu
- Podporuje 14 datových typů (text, celé číslo, soubor, obrázek, url atd.)
✅ Analýza obsahu (4 koncové body)
- Konfigurace na úrovni webu GA4/GSC v
siteconfigurations(nikolivsites.configurations) - Statistiky zobrazení konkrétních stránek/článku/produktu za období i za celou dobu
- Rozpad zobrazení podle kanálů (
sessionDefaultChannelGroup) - Vstupní klíčová slova stránek z Google Search Console
Bezpečnostní mechanismy
🔒 Tokenová autentizace s vazbou na 🔒 Automatická filtrace dat podle webu 🔒 Omezení sazby (1000/h čtení, 100/h zápis) 🔒 Pouze HTTPS 🔒 Kompletní protokol auditu všech požadavků 🔒 Oprávnění na úrovni tokenu (rozsahy) siteid
🔐 Autentizace
Všechny koncové body API vyžadují autentizaci pomocí tokenu API . Token je vázán na konkrétnísiteid a umožňuje přístup pouze k datům daného webu.
Autentizační metoda
Žeton na doručitele (doporučeno)Authorization: Bearer {yourtoken}Struktura API tokenu
API token je uložen v databázové tabulceapitokens :
| Pól | Typ | Popis |
|---|---|---|
id | INT | ID tokenu |
userid | INT | ID uživatele |
siteid | INT | ID webu, ke kterému token patří |
tokenhash | VARCHAR(64) | SHA-256 hash tokenu (plain token se ukládá pouze při vytvoření) |
name | VARCHAR(255) | Popis tokenu |
scopes | JSON | Oprávnění (např. articles:read, products:write, ) |
expiresat | DATUM A ČAS | Datum vypršení (NULL = neexpiruje). Ukládá se a vyhodnocuje v UTC . |
lastusedat | DATUM A ČAS | Poslední použití |
createdat | ČASOVÉ RAZÍTKO | Datum vytvoření |
updatedat | ČASOVÉ RAZÍTKO | Aktualizace data |
Rozsahový systém a hierarchické oprávnění
API používá hierarchický rozsah systému ve formátu {resource}:{action}:
(ADMIN ALL) - plný přístup ke všem API endpointům
articles:write- vytváření, editace, mazání článků (implicitně zahrnujearticles:read)articles:read- pouze čtení článkůproducts:write- vytváření, editace, mazání produktů (implicitně zahrnujeproducts:read)products:read- pouze čtení produktůeshop:write- správa e-shopu provozní vrstvy (implicitně zahrnujeeshop:read)eshop:read- čtení e-shop koncových bodů pouze pro čtení (/api/v1/eshop/...)categories:write- správa kategorií (implicitně zahrnujecategories:read)categories:read- čtení kategoriítags:write- správa tagů (implicitně zahrnujetags:read)tags:read- čtení tagůusers:write- správa uživatelů (implicitně zahrnujeusers:read)users:read- čtení uživatelůparameters:write- správa parametrů (implicitně zahrnujeparameters:read)parameters:read- čtení parametrůforms:write- správa formulářů (implicitně zahrnujeforms:read)forms:read- čtení formulátorůmessages:write- správa zpráv z formulářů (implicitně zahrnujemessages:read)messages:read- čtení zpráv z formulářůsections:write- správa katalogu sekcí a stránek stavitele (implicitně zahrnujesections:read)sections:read- čtení katalogu sekcí, tvůrce stránek, náhledy a verzesection-pipeline:write- vytváření a správa AI pipeline jobů (implicitně zahrnujesection-pipeline:read)section-pipeline:read- čtení AI pipeline jobů a výsledků
(ADMIN ALL) má přístup ke všem endpointům{resource}:writemá přístup k zápisu operacím + automaticky ik čtení operacím{resource}:readmá přístup pouze k read operacímarticles:writemá přístup k:- POST /api/v1/articles (vytvoření článku)
- PUT /api/v1/articles/{id} (editace článku)
- DELETE /api/v1/articles/{id} (smazání článku)
- GET /api/v1/articles (čtení článků) - automaticky zahrnuto
- GET /api/v1/articles/{id} (detail článku) - automaticky zahrnuto
Generování tokenu
Token se vrací pouze při vytvoření (plain token). V DB se ukládá pouze . tokenhash
Timezone pravidlo pro expiraci tokenů
expiresatje interně vyhodnocováno v UTC .- Pokud token vytváříte mimo API (seed/import), ukládejte jako UTC datum/čas.
expiresat - API odpověď vrací ISO 8601 datum s timezone offsetem; při porovnávání vždy porovnávejte jako časový okamžik (ne jako lokální string bez timezone).
Ověření tokenu (middleware)
// Pseudokód pro middleware
function verifyApiToken($token) { $tokenHash = hash('sha256', $token); $utcNow = gmdate('Y-m-d H:i:s'); $tokenRecord = ApiToken::where('tokenhash', $tokenHash) ->where(function($query) { $query->whereNull('expiresat') ->orWhere('expiresat', '>', $utcNow); }) ->first();
if (!$tokenRecord) { return ['error' => 'Invalid or expired token', 'code' => 401]; }
// Aktualizace lastusedat $tokenRecord->lastusedat = $utcNow; $tokenRecord->save();
// Nastavení globálního siteid pro další requesty $SERVER['APISITEID'] = $tokenRecord->siteid;
return ['success' => true, 'siteid' => $tokenRecord->siteid]; }
Koncový bod autorizace (v1)
POST /api/v1/auth/register
POST /api/v1/auth/password/forgot POST /api/v1/auth/password/reset POST /api/v1/auth/login GET /api/v1/auth/me PUT /api/v1/auth/me PUT /api/v1/auth/me/password POST /api/v1/auth/logout GET /api/v1/auth/tokens DELETE /api/v1/auth/tokens/{id}
POST /api/v1/auth/registervytváří nový účet a spouští ověřovací e-mail. POST /api/v1/auth/password/forgotpošlete reset hesla na pevně daný e-mailový účet. POST /api/v1/auth/password/resetnastavím nové heslo přes jednorázový klíč. GET /api/v1/auth/mevrací aktuální autentizační kontext včetně uživatele, rolí, rozsahu a metadat tokenu. PUT /api/v1/auth/meupravuje vlastní profil a PUT /api/v1/auth/me/passwordmění vlastní heslo.Poznámka: správa tokenů je dostupná také v administraci (AJAX) na URL /admin/api.
Chybové odpovědi pro autentizaci
{
"error": "Unauthorized", "message": "Invalid or missing API token", "code": 401 }
{
"error": "Forbidden", "message": "Token does not have required permissions", "code": 403 }
📈 API pro analýzu obsahu (GA4 + GSC)
Endpointy slouží pro analytiku konkrétních stránek (nebo konkrétního článku/produktu přes mapování do urls).
Konfigurace je výhradně per-site v tabulkáchconfigurationsdefinitions + . siteconfigurations
Rozsah požadavků
analytics:read- čtení konfigurace a statistikyanalytics:write- změna konfigurace
Hierarchie platí standardně: analytics:writezahrnuje analytics:read, zahrnuje vše.
Konfigurační klíče ( konfigurace stránek)
analyticsga4enabled(0|1)analyticsga4propertyid(např.123456789)analyticsgscenabled(0|1)analyticsgscsiteurl(např.https://example.com/)analyticsgoogleserviceaccountjson(JSON service accountu s přístupem pouze pro čtení)
Koncový bod
GET /api/v1/admin/content-analytics/config
PUT /api/v1/admin/content-analytics/config GET /api/v1/admin/content-analytics/page
GET /api/v1/admin/content-analytics/pagepodporuje tři způsoby cílených stránek:url=/konkretni-strankanebo absolutní URLarticleid={id}productid={id}
Volitelné datumové parametry:
from=YYYY-MM-DD(výchozí posledních 30 dní)to=YYYY-MM-DD(výchozí dnešek)
Odpověď obsahuje:
views.period.total+views.period.bychannel[]views.alltime.total+views.alltime.bychannel[]keywords.items[](dotaz, kliky, imprese, CTR, pozice)
🧱 API pro tvorbu sekcí
Section Builder je nový kanonický subsystém pro správu katalogu sekcí, builder stránek, publikování workflow, verzování a AI pipeline HTML → sekce. Tato vrstva je navržena jako stránka JSON + katalog sekcí, nikoli jako volný HTML editor.
Datový model
sectiondefinitions- katalog dostupných sekcísectiondefinitionversions- verze schémat a render konfigurační sekcísectionpages- stavitel stránek svázané seurlssectioninstances- konkrétní instance sekcí v regionech stránkysectionpageversions- publikovat snapshoty s historií vrácení změnsectionpipelinejobs- asynchronní AI pipeline job
Rozsah požadavků
sections:read- čtení definic, stránek, náhledů a verzísections:write- CRUD definic, CRUD stránky, publikování, restaurování, správa instancísection-pipeline:read- čtení pipeline jobssection-pipeline:write- zakládání projektů potrubí
Výčet stavů
developmentactivesuspend
Regionální stránky
Základní regiony první implementace:
headermainsidebarfooter
1. Seznam definic sekcí
0. Sekce katalogu
GET /api/v1/sections/catalogParametry dotazu:
category- filtr podle kategorie sekcesearch- plný text přesname,keyname,descriptionincludedevelopment-1|0, výchozí1(0vrací se jenactive)
Response vrací normalizovaný katalog s aktuálními verzemi sekce (currentversion ) pro admin knihovnu sekcí.
GET /api/v1/sections/definitionsParametry dotazu:
status- filtr podle statusucategory- filtr podle kategorieincludeglobal-1|0, výchozí1
2. Vytvoření definice sekce
POST /api/v1/sections/definitionsTělo požadavku:
{
"keyname": "herosplit", "name": "Hero Split", "category": "content", "description": "Hero sekce s obrázkem a CTA", "status": "development", "isglobal": false, "schema": { "fields": [ {"key": "title", "type": "text", "required": true}, {"key": "body", "type": "richtext", "required": false} ] }, "uischema": { "groups": [ {"key": "content", "label": "Obsah"} ] }, "validationrules": { "requiredregions": [] }, "bindings": [ "displayData.title" ], "renderconfig": { "partial": "sections/hero-split.twig" } }
Pravidla pro : pageprofile
- povolené hodnoty:
contentpage, , , , , ,articledetailproductdetailhomepagesectionbuilder - při nepovolené hodnotě API vrací
400 Validation Failed.
3. Podrobná definice sekce
GET /api/v1/sections/definitions/{id}4. Aktualizace definice sekce
PUT /api/v1/sections/definitions/{id}Aktualizace metadat definice bez vytvoření nové verze schématu.
5. Nová verze definice sekce
POST /api/v1/sections/definitions/{id}/versionsVytvoří nový snímek schématu a nastaví ho jako current. versionid
6. Seznam tvůrců stránek
6a. Profily stránek s metadaty
GET /api/v1/sections/page-profilesVrací editor metadat pro:
key- identifikátor profilu,label- uživatelský název,allowedregions- region povoleny pro profil,recommendedsections- doporučené sekce key pro profil.
Endpoint je určen primárně pro admin editor (výběry profilu/regionu + UI guide).
GET /api/v1/sections/pagesParametry dotazu:
statuspageprofilesearch
7. Vytvoření stránek builderu
POST /api/v1/sections/pagesTělo požadavku:
{
"title": "O nás", "slug": "o-nas", "pageprofile": "contentpage", "layoutkey": "default", "status": "development", "urlbindingmode": "newurl", "metadata": { "metatitle": "O nás", "metadescription": "Představení společnosti" }, "urlbinding": { "path": "/o-nas" } }
urlbindingmodepodporuje 3 varianty:generic- typová/generická stránka bez veřejné URL vazby,urlidzůstanenull,newurl- backend vytvoří nový záznam vurlsa naváže ho na stránku,existingurl- backend naváže stránku na existující URL vybranou přes vyhledávací koncový bod.
Pravidla:
generic: nevyžaduje ,urlbindingnewurlvyžaduji ,urlbinding.pathexistingurlvyžaduji ,urlbinding.urlid- běžný klient nemá používat
urlidpřímo jako top-level vstup, - pro
newurlaexistingurlbackend interně nastavuje Section Page routing do tabulkyurls.
Response obsahuje vedle urlid i čitelné metadata vazby:
urlbindingmode,urlbinding.isgeneric,urlbinding.url(id,domain,path,handler,model,modelid,label).
Pravidla pro regionkey:
contentpage,articledetail,productdetail,sectionbuilder:header,main,sidebar,footer,homepage:header,main,footer,- nepovolený region vrací
400 Validation Failed.
8. Vyhledání existujících URL pro builder
GET /api/v1/sections/pages/url-search?q=o-nasQuery parametry:
q- fulltext prefix/substring pro URL cestu,limit- volitelný limit, default 10, max 25.
Response:
[
{ "id": 123, "domain": "loc-dom9.cz", "path": "/o-nas", "handler": "getArticleDetails", "model": "articles", "modelid": 456, "label": "loc-dom9.cz/o-nas" } ]
9. Detail builder stránky
GET /api/v1/sections/pages/{id}Vrací stránku včetně instancí seskupených do regionů.
10. Aktualizace builder stránky
PUT /api/v1/sections/pages/{id}Podporuje optimistic locking pro autosave. Klient může poslat:
expectedupdatedat(ISO 8601)expectedstatehash(SHA-256 hash posledního načteného stavu stránky)
Aktualizace podporuje stejný kontrakt urlbindingmode + urlbinding jako create.
Při konfliktu server vrací 409 Edit Conflict.
11. Přidání instance sekce do stránky
POST /api/v1/sections/pages/{id}/instancesRequest body:
{
"sectiondefinitionid": 15, "sectiondefinitionversionid": 42, "regionkey": "main", "sortorder": 10, "instancekey": "hero01", "mode": "static", "status": "development", "props": { "title": "Vítejte", "body": "Obsah sekce" }, "bindings": {}, "meta": { "cssclass": "hero hero--large" } }
Klíče objektu regions musí používat pouze regiony povolené pro pageprofile dané stránky.
Validační chování:
- backend validuje
propsprotischema.fieldsavalidationrulesvybranésectiondefinitionversion, - navíc aplikuje DB pravidla z
sectionvalidationrules(scope site/definition/version, levelerrornebowarning), - při chybě vrací
400 Validation Faileds polemerrors, - warningy neblokují zápis a vrací se v
meta.validationwarnings, - neznámá pole mimo schema může vrátit v poli
warnings.
11. Aktualizace instance sekce
PUT /api/v1/sections/pages/{id}/instances/{instanceId}Při update se znovu aplikuje validace proti navázané sectiondefinitionversionid instance.
Podporuje optimistic locking pro autosave. Klient může poslat:
expectedupdatedat(ISO 8601)expectedstatehash(SHA-256 hash posledního načteného stavu instance)
Při konfliktu server vrací 409 Edit Conflict.
12. Reorder instancí na stránce
POST /api/v1/sections/pages/{id}/instances/reorderRequest body:
{
"regions": { "header": [1], "main": [2, 3, 4], "sidebar": [], "footer": [5] } }
13. Publish stránky
POST /api/v1/sections/pages/{id}/publishVytvoří snapshot do sectionpageversions, aktualizuje publishedjson a currentversionid.
Publish je blokován, pokud některá instance na stránce neprojde schema/validation kontrolou. V takovém případě API vrátí 400 Validation Failed s detailním rozpisem chyb po instancích a volitelným polem warnings.
14. Obnova verze stránky
POST /api/v1/sections/pages/{id}/restore/{versionId}Obnoví snapshot jako nový draft a znovu zkonstruuje sectioninstances.
15. Seznam verzí stránky
GET /api/v1/sections/pages/{id}/versions16. Preview stránky
GET /api/v1/sections/pages/{id}/previewVrací runtime payload pro builder preview. První implementace vrací JSON payload, ne renderovaný HTML dokument.
17. Seznam AI pipeline jobů
GET /api/v1/sections/pipeline/jobsQuery parametry:
status- filtr podle stavu (queued,processing,completed,failed,cancelled)sectionpageid- filtr podle builder stránkylimit- počet vrácených položek (1-200, default 50)
Runtime metadata workeru mohou být vrácena v result.runtime:
attemptcount- počet zpracovaných pokusů,nextattemptat- ISO timestamp dalšího automatického retry,lasterror- poslední chyba workeru,lastfailedat- čas posledního selhání,detailedsteps- detailní stav pipeline kroků (cleaninghtml,parsingdom,splittingblocks,detectingsections,classifyingsections,mappingprops,generatingjson,validatingjson,generatingtwig,rendering,completed|failed|retrywait),aiprovider- použitý provider klasifikace (heuristicnebofireworks).aimodel- konkrétní model použitý pro klasifikaci (pokud provider=fireworks).aiattempts- seznam pokusů/modelů při policy routingu (primary/escalation/fallback).
18. Vytvoření AI pipeline jobu
POST /api/v1/sections/pipeline/jobsRequest body:
{
"sectionpageid": 77, "sourcetype": "html", "sourcepayload": { "html": "..." } }
Dedup chování:
- backend vypočítá deterministický hash vstupu (
siteid,sectionpageid,sourcetype, canonicalsourcepayload), - pokud už existuje job se stejným hashem ve stavu
queuedneboprocessing, nový job se nevytváří, - endpoint vrátí existující job s HTTP
200ameta.deduphit=true+meta.reusedjobid, - při standardním vytvoření vrací HTTP
201.
19. Detail AI pipeline jobu
GET /api/v1/sections/pipeline/jobs/{id}Vrací stav jobu, current step, confidence score, result payload a error message.
Součástí response může být:
detailedsteps- flattened výpis kroků pipeline (pro UI observability),runtime- kompletní runtime metadata workeru.suggestedsections[].meta.validationwarnings- seznam logických/UX warningů pro sekci,suggestedsections[].meta.validationerrors- seznam validačních chyb sekce,suggestedsections[].meta.validationskipped=true- sekce byla vynechána pro render/apply fázi.
20. Retry AI pipeline jobu
POST /api/v1/sections/pipeline/jobs/{id}/retryVrátí existující job zpět do stavu queued a vyčistí errormessage, startedat, finishedat.
Pokud job používá retry/backoff runtime metadata, resetuje i result.runtime.nextattemptat a result.runtime.lasterror.
21. Aplikace výsledku pipeline do stránky
POST /api/v1/sections/pipeline/jobs/{id}/applyPouze pro completed job navázaný na sectionpageid.
Request body (volitelný):
{
"mode": "replace", "dryrun": false }
mode:replace(default) neboappenddryrun: pokudtrue, endpoint vrátí plán změn bez zápisu do DB
Co endpoint provede:
- načte
resultjson.suggestedsections - přemapuje
sectionkeynasectiondefinitions.keyname(site nebo global) - každou navrženou sekci znovu validuje proti cílové
sectiondefinitionversion - vytvoří nové
sectioninstancesdo draftu stránky - přepočítá
draftjson
Response obsahuje applyresult (createdinstances, skippedinstances, warnings, plannedpreview). Nevalidní sekce se přeskočí a vrátí jako warning.
📝 1. Přidání článku
Vytvoří nový článek v systému.
Endpoint
POST /api/v1/articlesOprávnění
- Token musí mít scope:
articles:write
Request Headers
Content-Type: application/json
Authorization: Bearer YOURAPITOKEN
Request Body
{
HTML obsah článku "title": "Název článku", "subtitle": "Podtitul článku (volitelné)", "shorttext": "Krátký úvodní text", "snippet": "Snippet pro seznam článků (volitelné)", "body": "
Popis polí
| Pole | Typ | Povinné | Popis |
|---|---|---|---|
title | string | ✅ | Název článku |
subtitle | string | ❌ | Podtitul |
shorttext | string | ❌ | Krátký úvodní text |
snippet | string | ❌ | Snippet pro seznam |
body | string | ✅ | HTML obsah článku |
status | enum | ❌ | development, active, schedule, suspend. Pokud chybí, uloží se development. Status schedule automaticky přiřadí publishat na nejbližší volný publikační slot (pokud je publishat prázdné). Pokud žádný slot není k dispozici, status se uloží jako development. |
categoryid | int | ❌ | Hlavní kategorie článku. Podmíněně povinné: Alespoň jedno z categoryid nebo categoryids musí být zadáno. |
categoryids | array[int] | ❌ | Alternativní pole ID kategorií. Fallback logika: Pokud categoryid chybí, vezme se categoryids[0] jako hlavní kategorie. |
tagids | array[int] | ❌ | Pole existujících ID tagů. Create endpoint aktuálně neumí přijmout názvy tagů v poli tags. |
meta | object | ❌ | Metadata článku |
images | object | ❌ | Obrázky - podporuje URL stahování nebo fileid již nahraných souborů |
images.articleDetail | object | ❌ | Hlavní obrázek článku (banner, hero image) |
images.articleDetail.url | string | ❌ | URL adresa obrázku ke stažení (alternativa k fileid) |
images.articleDetail.fileid | integer | ❌ | ID již nahraného souboru (preferováno před URL) |
images.articles | object | ❌ | Náhledový obrázek pro výpisy článků (list image) |
images.articles.url | string | ❌ | URL adresa obrázku ke stažení (alternativa k fileid) |
images.articles.fileid | integer | ❌ | ID již nahraného souboru (preferováno před URL) |
images.gallery | array[object] | ❌ | Pole objektů s URL adresami nebo fileid fotogalerie |
images.gallery[].url | string | ❌ | URL adresa obrázku ke stažení (alternativa k fileid) |
images.gallery[].fileid | integer | ❌ | ID již nahraného souboru (preferováno před URL) |
parameters | object | ❌ | Hodnoty parametrů (klíč = parameterid, hodnota podle datatype) |
parametervalues | object | ❌ | Legacy alias pro parameters (pro zpětnou kompatibilitu). Pokud jsou poslány oba, použije se parameters. |
Poznámky k polím
Automaticky generovaná pole (není třeba posílat v requestu):id- AUTOINCREMENTsiteid- automaticky z API tokenu (viz autentizace)createdat- automaticky CURRENTTIMESTAMPupdatedat- automaticky ON UPDATE CURRENTTIMESTAMPdeletedat- používá se pro soft delete (null = není smazáno)meta.mainCatid- backend ho doplní podle hlavní kategorie
development- Článek je v režimu vývoje (viditelný pouze pro administrátory)active- Článek je aktivní a veřejně dostupnýsuspend- Článek je pozastaven (není veřejně přístupný)
deletedat timestamp, nikoli změnou statusu. Pro smazání článku použijte DELETE endpoint. Body vs Snippet:bodyje přiPOST /api/v1/articlespovinnésnippetje volitelné doplňkové pole pro výpisy
url- create controller vždy generuje URL automaticky z URL hlavní kategorie a slugu ztitleuserid- autor se bere z tokenu (APIUSERID)publishat,publishendat,manualupdateat- POST create je aktuálně nepersistujefiles- create controller zatím neukládá přílohy článkurelatedcontent- create controller zatím nevytváří související vazbytags- pole názvů tagů se při create nevyhodnocuje; použijtetagidscategories- starší polecategoriesse při create nevyhodnocuje; použijtecategoryida/nebocategoryidsnavigationid- create endpoint ho nepřijímá; pokud potřebujete vybírat kategorie jen z jedné navigace, nejdřív použijteGET /api/v1/categories/tree?navigationid={id}a z výsledku vybertecategoryid/categoryids
parameters / parametervalues):- API přijímá primárně
parameters(objektparameterid => hodnota). - Pro zpětnou kompatibilitu přijímá i
parametervalues. - Pokud pošlete oba klíče, prioritu má
parameters. - Při
PUT /api/v1/articles/{id}hodnotanullnebo prázdný string ("") vymaže existující hodnotu parametru. - Nenumerické klíče parameterid jsou ignorovány a request pokračuje.
Logika generování URL a Slugu
Create endpoint aktuálně nepoužívá klientem zaslané pole url. URL se vždy vygeneruje automaticky:
title se vytvoří slug (odstranění diakritiky, převod na malá písmena, mezery na pomlčky).categoryid nebo fallback categoryids[0]). Lookup je tolerantní k doméně — zkouší postupně aktuální doménu (SITEDOMAIN), původní interní doménu (SITEDOMAINORIGINAL, relevantní u headless webů s apidomain), wildcard a nakonec záznam bez ohledu na doménu (kategorie je již ověřena na siteid).{urlhlavnikategorie}/{slug}.html.{slug}-abc.html).urls vždy pod interní doménou webu (doména URL záznamu hlavní kategorie, fallback SITEDOMAINORIGINAL). U headless webů se veřejná doména (apidomain) používá pouze pro generované absolutní URL v API odpovědích, nikoli pro záznamy v urls.Zpracování obrázků a souborů
API podporuje automatické stahování obrázků z URL adres (doporučená metoda).
Stahování obrázků z URL
Podporované klíče pro obrázky
API očekává následující klíče v objektu images:
| Klíč | Účel | Typ variant |
|---|---|---|
articleDetail | Hlavní obrázek článku (banner, detail, hero image) | articleDetail |
articles | Náhledový obrázek pro seznamy článků | articles |
gallery | Fotogalerie (pole obrázků) | gallery |
bannerimage, listimage, galleryimages NEJSOU implementovány v ArticleController.php a nebudou fungovat!Příklad kompletního requestu s obrázky:
{
Obsah "title": "Testovací článek", "body": "
Implementace v kódu
Viz www/api/v1/controllers/ArticleController.php metoda store():
// Banner image (hlavní obrázek) - klíč: articleDetail $bannerData = isset($data['images']['articleDetail']) ? $data['images']['articleDetail'] : null; if ($bannerData && isset($bannerData['url'])) { $result = UploadedFile::downloadAndProcessFromUrl($bannerData['url']); $article->assignImage($result['id'], 'articleDetail'); }
// List image (náhledový obrázek) - klíč: articles $listData = isset($data['images']['articles']) ? $data['images']['articles'] : null; if ($listData && isset($listData['url'])) { $result = UploadedFile::downloadAndProcessFromUrl($listData['url']); $article->assignImage($result['id'], 'articles'); }
// Gallery - klíč: gallery (pole) if (isset($data['images']['gallery']) && isarray($data['images']['gallery'])) { foreach ($data['images']['gallery'] as $galleryImage) { if (isset($galleryImage['url'])) { $result = UploadedFile::downloadAndProcessFromUrl($galleryImage['url']); $article->assignImage($result['id'], 'gallery'); } } }
Typy obrázků
API rozlišuje 3 typy obrázků, každý s vlastní variantou uložení:
articleDetail (hlavní obrázek článku):- Varianta:
articleDetail - Použití: Detail článku, náhled při sdílení na sociálních sítích, hlavní vizuál, hero image
- Volitelné: Ano
- Příklad použití: Banner/hero image na detailu článku
- Varianta:
articles - Použití: Seznam článků, sidebar, související články, karty článků
- Volitelné: Ano
- Příklad použití: Thumbnail v seznamu článků
- Varianta:
gallery - Použití: Fotogalerie v těle článku, lightbox
- Volitelné: Ano (pole může obsahovat 0-N obrázků)
- Příklad použití: Fotogalerie produktu, obrazová příloha
Technické specifikace
Limity stahování:- Časový limit: 30 sekund na stažení jednoho obrázku
- Velikost souboru: Maximum 15 MB (15,728,640 bytů)
- Podporované formáty: JPEG, PNG, WebP (validace po stažení)
- User-Agent:
MiniWeb-CMS/1.0 - SSL verifikace: Zapnuto (CURLOPTSSLVERIFYPEER=true)
- Follow redirects: Zapnuto (CURLOPTFOLLOWLOCATION=true)
image/jpeg, image/png, image/webp)uploadedfiles → získání nového ID (např. 1450)imagevariantsarticleimages pivot tabulka)banner: 1500×635 pxarticleDetail: 800×600 pxarticles: 400×300 pxgalleryThumbnail: 300×200 pxthumbnail: 150×150 px- ... a další (celkem 17 variant)
Zpracování chyb
API implementuje continue-on-failure strategii:
- Pokud stažení jednoho obrázku selže, zpracování pokračuje s dalšími
- Podporuje partial success (část obrázků úspěšná, část s chybou)
- Každý obrázek má vlastní try-catch blok
- Detailní informace v poli
imagesprocessedv odpovědi
| Chyba | Příčina | Chybová zpráva (česky) |
|---|---|---|
| Timeout | Stahování trvalo > 30s | "Časový limit stahování překročen (30s)" |
| File too large | Soubor > 15MB | "Soubor je příliš velký (limit 15MB)" |
| DNS failure | Neplatná doména | "Neplatná doména nebo DNS selhání" |
| Invalid MIME | Není JPEG/PNG/WebP | "Nepodporovaný typ obrázku: {mime}" |
| HTTP error | HTTP status ≠ 200 | "HTTP chyba {code}" |
| Empty content | Prázdný response | "Stažený obsah je prázdný" |
| Download failed | Obecná cURL chyba | "Stahování selhalo: {error}" |
Příklad requestu s obrázky
{
Obsah článku "title": "Testovací článek s obrázky", "body": "
Příklad odpovědi s imagesprocessed
{
Obsah článku "success": true, "data": { "id": 1234, "title": "Testovací článek s obrázky", "body": "
imagesprocessed obsahuje:type: Typ obrázku (articleDetail,articles,gallery[index])status:"success"nebo"failed"url: Původní URL adresa obrázkufileid: ID nahraného souboru v DB (pouze při úspěchu)publicurl: Veřejná URL adresa v GCS (pouze při úspěchu)error: Chybová zpráva v češtině (pouze při selhání)
Poznámky k implementaci
Partial success scénář:V příkladu výše vidíte typický případ částečného úspěchu:
articleDetail: ✅ Úspěšně stažen a zpracovánarticles: ✅ Úspěšně stažen a zpracovángallery[0]: ✅ Úspěšně stažengallery[1]: ❌ Selhalo (timeout) - ale zpracování pokračovalogallery[2]: ✅ Úspěšně stažen
Článek byl vytvořen se 4 obrázky (banner + list + 2 galerie), přestože jeden obrázek selhal.
Logování:Všechny operace jsou logovány:
- INFO: Úspěšné stažení a zpracování
- WARNING: Selhání stažení obrázku (s pokračováním)
- ERROR: Kritická chyba v pipeline (s výjimkou)
Pro každý úspěšně nahraný obrázek:
- 1 záznam v
uploadedfiles(originál) - 17 záznamů v
imagevariants(různé velikosti) - 1 záznam v
articleimages(vazba article ↔ image)
Metoda 2: Použití fileid (preferováno)
Kdy použít fileid místo URL:- ✅ Soubory již nahrané přes admin rozhraní
- ✅ Rychlejší operace (bez stahování a zpracování)
- ✅ Opětovné použití stejného obrázku pro více článků
- ✅ Garant konzistence (soubor již prošel pipeline)
- ✅ Žádné vytváření nových záznamů - pouze reference na existující soubor
POST /api/v1/articles
{ "title": "Článek s již nahranými obrázky", "subtitle": "Rychlé přiřazení existujících souborů", "body": "Obsah článku...", "status": "active", "categories": [15, 23], "images": { "articleDetail": { "fileid": 1303 }, "articles": { "fileid": 1304 }, "gallery": [ { "fileid": 1305 }, { "fileid": 1306 }, { "fileid": 1307 } ] } }
{
"success": true, "article": { "id": 894, "title": "Článek s již nahranými obrázky", "subtitle": "Rychlé přiřazení existujících souborů", "body": "Obsah článku...", "status": "active", "url": "https://example.com/clanek-s-jiz-nahranymi-obrazky", "categories": [ { "id": 15, "title": "electronics", "displayname": "Electronics" }, { "id": 23, "title": "smartphones", "displayname": "Smartphones" } ], "images": [ { "id": 1303, "name": "banner-existing.webp", "filepath": "example.com/banner-existing.webp", "publicurl": "https://storage.googleapis.com/bucket/example.com/banner-existing.webp", "mimetype": "image/webp", "size": 45678, "variant": "articleDetail", "createdat": "2025-01-20T14:22:00Z" }, { "id": 1304, "name": "thumb-existing.webp", "filepath": "example.com/thumb-existing.webp", "publicurl": "https://storage.googleapis.com/bucket/example.com/thumb-existing.webp", "mimetype": "image/webp", "size": 12345, "variant": "articles", "createdat": "2025-01-20T14:23:00Z" }, { "id": 1305, "name": "gallery1-existing.webp", "filepath": "example.com/gallery1-existing.webp", "publicurl": "https://storage.googleapis.com/bucket/example.com/gallery1-existing.webp", "mimetype": "image/webp", "size": 34567, "variant": "gallery", "createdat": "2025-01-20T14:24:00Z" }, { "id": 1306, "name": "gallery2-existing.webp", "filepath": "example.com/gallery2-existing.webp", "publicurl": "https://storage.googleapis.com/bucket/example.com/gallery2-existing.webp", "mimetype": "image/webp", "size": 38901, "variant": "gallery", "createdat": "2025-01-20T14:25:00Z" }, { "id": 1307, "name": "gallery3-existing.webp", "filepath": "example.com/gallery3-existing.webp", "publicurl": "https://storage.googleapis.com/bucket/example.com/gallery3-existing.webp", "mimetype": "image/webp", "size": 41234, "variant": "gallery", "createdat": "2025-01-20T14:26:00Z" } ], "createdat": "2025-01-23T11:15:00Z", "updatedat": "2025-01-23T11:15:00Z" }, "imagesprocessed": [ { "type": "articleDetail", "status": "success", "source": "existingfile", "fileid": 1303, "publicurl": "https://storage.googleapis.com/bucket/example.com/banner-existing.webp" }, { "type": "articles", "status": "success", "source": "existingfile", "fileid": 1304, "publicurl": "https://storage.googleapis.com/bucket/example.com/thumb-existing.webp" }, { "type": "gallery[0]", "status": "success", "source": "existingfile", "fileid": 1305, "publicurl": "https://storage.googleapis.com/bucket/example.com/gallery1-existing.webp" }, { "type": "gallery[1]", "status": "success", "source": "existingfile", "fileid": 1306, "publicurl": "https://storage.googleapis.com/bucket/example.com/gallery2-existing.webp" }, { "type": "gallery[2]", "status": "success", "source": "existingfile", "fileid": 1307, "publicurl": "https://storage.googleapis.com/bucket/example.com/gallery3-existing.webp" } ] }
Chování při kombinaci fileid + URL
Priorita: fileid > URLPokud zadáte obojí, API použije fileid a url bude ignorováno:
{
"images": { "articleDetail": { "fileid": 1303, "url": "https://example.com/ignored.jpg" // ← BUDE IGNOROVÁNO } } }
V logu uvidíte:
INFO: Přiřazování banner obrázku z existujícího souboru [fileid: 1303]
DEBUG: URL ignorováno kvůli přítomnosti fileid
Chybové stavy při použití fileid
1. fileid neexistuje:{
"images": { "articleDetail": { "fileid": 99999 } } }
Response:
{
"imagesprocessed": [ { "type": "articleDetail", "status": "failed", "source": "existingfile", "fileid": 99999, "error": "Soubor s ID 99999 nebyl nalezen nebo nepatří k této stránce" } ] }
{
"images": { "articles": { "fileid": 5678 // Patří siteid=2, aktuální požadavek je siteid=7 } } }
Response:
{
"imagesprocessed": [ { "type": "articles", "status": "failed", "source": "existingfile", "fileid": 5678, "error": "Soubor s ID 5678 nebyl nalezen nebo nepatří k této stránce" } ] }
API vždy validuje:
$file = UploadedFile::where('id', $fileId)
->where('siteid', $siteId) ->first();
Kombinované použití (mix fileid + URL)
Můžete v jednom requestu kombinovat oba přístupy:
{
"images": { "articleDetail": { "fileid": 1303 // ← Existující soubor }, "articles": { "url": "https://new.jpg" // ← Nový soubor ke stažení }, "gallery": [ { "fileid": 1305 }, // ← Existující { "url": "https://new2.jpg" }, // ← Nový { "fileid": 1306 } // ← Existující ] } }
Response bude obsahovat:
{
"imagesprocessed": [ { "type": "articleDetail", "status": "success", "source": "existingfile", // ← fileid "fileid": 1303 }, { "type": "articles", "status": "success", "source": "downloaded", // ← URL "url": "https://new.jpg", "fileid": 1450 // ← Nově vytvořený }, { "type": "gallery[0]", "status": "success", "source": "existingfile", // ← fileid "fileid": 1305 }, { "type": "gallery[1]", "status": "success", "source": "downloaded", // ← URL "url": "https://new2.jpg", "fileid": 1451 // ← Nově vytvořený }, { "type": "gallery[2]", "status": "success", "source": "existingfile", // ← fileid "fileid": 1306 } ] }
source vám umožní rozlišit:"existingfile"= použit fileid (žádný nový soubor)"downloaded"= staženo z URL (vytvořen nový soubor)
Srovnání URL vs fileid metod
| Aspekt | URL metoda | fileid metoda |
|---|---|---|
| Vstup | URL string (např. https://example.com/image.jpg) | Integer (např. 1303) |
| Co se stane | 1. Stáhne soubor 2. Zpracuje (WebP, komprese) 3. Nahraje do GCS 4. Vytvoří nový záznam v DB 5. Vygeneruje 17 variant 6. Přiřadí k článku | 1. Ověří, že fileid existuje 2. Ověří siteid 3. Přiřadí existující záznam k článku |
| Vytvoří nový soubor v DB? | ✅ ANO - vždy nové ID | ❌ NE - používá existující |
| Opětovné použití | ❌ Při každém volání nový soubor | ✅ Neomezené použití stejného ID |
| Čas zpracování | 5-15 sekund | < 100 ms |
| DB operace | +1 uploadedfiles+17 imagevariants+1 articleimages | +1 articleimages (pouze propojení) |
| GCS operace | +18 nahrání souborů | 0 (soubor již existuje) |
| TinyPNG API volání | 1 (komprese) | 0 |
| Použití v response | "fileid": 1450 (nové) | "fileid": 1303 (stejné jako vstup) |
| Pole source | "downloaded" | "existingfile" |
URL metoda (3× volání):
Článek 1 → URL → stáhne → fileid: 1450 Článek 2 → URL → stáhne → fileid: 1451 ← NOVÝ SOUBOR Článek 3 → URL → stáhne → fileid: 1452 ← NOVÝ SOUBOR Výsledek: 3 soubory v GCS, 3 záznamy v DB
fileid metoda (3× volání): Článek 1 → fileid: 1303 → přiřadí existující Článek 2 → fileid: 1303 → přiřadí existující ← STEJNÝ SOUBOR Článek 3 → fileid: 1303 → přiřadí existující ← STEJNÝ SOUBOR Výsledek: 1 soubor v GCS, 1 záznam v DB, 3 propojení
Metoda 1: URL (doporučeno) - Legacy dokumentace
> POZNÁMKA: Sekce níže obsahuje starší dokumentaci. Pro aktuálně verifikovaný create kontrakt POST /api/v1/articles je potvrzené pouze JSON tělo přes getJsonBody() a obrázky v images.articleDetail, images.articles, images.gallery s url nebo fileid. Zpracování files, Base64 a multipart uploadu není v aktuálním create controlleru verifikováno jako podporované.
Backend automaticky stáhne soubor z URL, zpracuje ho a nahraje do Google Cloud Storage.
Obrázky:- Stažení z URL
- Konverze na WebP formát
- Komprese přes TinyPNG API
- Nahrání do GCS
- Generování variant (banner, articleDetail, thumbnail, gallery...)
- Propojení s článkem
- Historická dokumentace. Aktuální create controller je při
POST /api/v1/articlesneukládá.
{
"images": { "articleDetail": { "url": "https://example.com/images/banner.jpg" }, "articles": { "url": "https://example.com/images/list-thumbnail.jpg" }, "gallery": [ { "url": "https://cdn.example.com/img1.png" }, { "url": "https://cdn.example.com/img2.jpg" } ] }, "files": [ { "url": "https://example.com/docs/file.pdf", "name": "Název souboru", "type": "attachment" } ] }
Metoda 2: Base64 (pro menší soubory < 5MB) - Legacy
> POZNÁMKA: Historická sekce. Aktuální create controller tuto metodu nemá v kanonicky verifikovaném flow potvrzenou.
Vhodné pro mobilní aplikace nebo když máte soubor už v paměti.
Legacy struktura (pro zpětnou kompatibilitu):{
"images": { "main": { "base64": "data:image/jpeg;base64,/9j/4AAQSkZJRg...", "alt": "Popisek", "title": "Titulek", "filename": "photo.jpg" } }, "files": [ { "base64": "data:application/pdf;base64,JVBERi0xLj...", "name": "Dokument", "filename": "file.pdf", "type": "attachment" } ] }
{
"images": { "articleDetail": { "base64": "data:image/jpeg;base64,/9j/4AAQSkZJRg...", "filename": "banner.jpg" }, "articles": { "base64": "data:image/jpeg;base64,/9j/4AAQSkZJRg...", "filename": "thumbnail.jpg" }, "gallery": [ { "base64": "data:image/jpeg;base64,/9j/4AAQSkZJRg...", "filename": "gallery1.jpg" } ] }, "files": [ { "base64": "data:application/pdf;base64,JVBERi0xLj...", "name": "Dokument", "filename": "file.pdf", "type": "attachment" } ] }
Metoda 3: Multipart Upload (pro velké soubory > 5MB) - Legacy
> POZNÁMKA: Historická sekce. Aktuální create controller čte JSON body a multipart flow zde není kanonicky verifikovaný.
Pro velké soubory použijte multipart/form-data:
POST /api/v1/articles
Content-Type: multipart/form-data Authorization: Bearer YOURAPITOKEN
--boundary Content-Disposition: form-data; name="data" Content-Type: application/json
{ "title": "Název článku", "body": "Obsah
", "categories": [15], "status": "active", "userid": 42, "url": "/clanek" } --boundary Content-Disposition: form-data; name="mainimage"; filename="banner.jpg" Content-Type: image/jpeg
[binary data] --boundary Content-Disposition: form-data; name="galleryimage1"; filename="gallery1.jpg" Content-Type: image/jpeg
[binary data] --boundary Content-Disposition: form-data; name="file1"; filename="attachment.pdf" Content-Type: application/pdf
[binary data] --boundary--
POST /api/v1/articles Content-Type: multipart/form-data Authorization: Bearer YOURAPITOKEN
--boundary Content-Disposition: form-data; name="data" Content-Type: application/json
{ "title": "Název článku", "body": "
Obsah
", "categories": [15], "status": "active", "userid": 42, "url": "/clanek" } --boundary Content-Disposition: form-data; name="articleDetail"; filename="banner.jpg" Content-Type: image/jpeg [binary data] --boundary Content-Disposition: form-data; name="articles"; filename="thumbnail.jpg" Content-Type: image/jpeg
[binary data] --boundary Content-Disposition: form-data; name="gallery[]"; filename="gallery1.jpg" Content-Type: image/jpeg
[binary data] --boundary Content-Disposition: form-data; name="gallery[]"; filename="gallery2.jpg" Content-Type: image/jpeg
[binary data] --boundary Content-Disposition: form-data; name="file1"; filename="attachment.pdf" Content-Type: application/pdf
[binary data] --boundary--
Zpracování na backendu
Backend provede následující kroky:
Pro obrázky:{sitedomain}/{uniqueid}-{normalizedfilename}.webp- banner: dle bannerw × bannerh - articleDetail: dle articleDetailw × articleDetailh - galleryThumbnail: dle galleryThumbnailw × galleryThumbnailh - atd.
{sitedomain}/thumb/{variant}/{filename}uploadedfiles a imagevariantsarticleimages{sitedomain}/{uniqueid}-{normalizedfilename}uploadedfilesarticlefiles- URL musí začínat
http://nebohttps:// - URL musí být dostupná (HTTP 200)
- Maximální velikost stahovaného souboru: 50 MB
- Timeout: 30 sekund
- Podporované formáty obrázků: JPEG, PNG, WebP, GIF, SVG
- Podporované formáty souborů: PDF, DOC, DOCX, XLS, XLSX, ZIP, RAR
{
"success": false, "error": "Image Processing Error", "message": "Nepodařilo se stáhnout obrázek z URL", "details": { "url": "https://invalid.com/image.jpg", "reason": "Connection timeout" } }
{
"success": false, "error": "Validation Error", "message": "Nepodporovaný formát souboru", "details": { "url": "https://example.com/file.exe", "mimetype": "application/x-msdownload", "allowedtypes": ["image/", "application/pdf", "application/msword", ...] } }
Response (Success - 201 Created)
{
HTML obsah článku "success": true, "data": { "id": 866, "title": "Název článku", "subtitle": "Podtitul článku", "shorttext": "Krátký úvodní text", "snippet": "Snippet pro seznam", "body": "
Response (Error - 400 Bad Request)
{
"type": "/errors/validation", "title": "Validation Failed", "status": 400, "detail": "The request contains invalid data.", "instance": "/api/v1/articles", "errors": { "title": ["Title is required"], "body": ["Body is required"], "categoryid": ["Main category ID (categoryid) is required for URL generation"] } }
Response (Poznámka ke kolizi URL)
Create endpoint běžně nevrací 409 Conflict kvůli duplicitní URL. Kolizi řeší automatickým přidáním náhodného suffixu k vygenerovanému slugu. Pokud by backend ani po více pokusech nedokázal najít unikátní URL, vrátí chybu 500.
📖 2. Zobrazení detailu článku
Načte kompletní detail konkrétního článku včetně všech vztahů.
Endpoint
GET /api/v1/articles/{idOrSlug}Oprávnění
- Token musí mít scope:
articles:read
URL Parameters
| Parametr | Typ | Popis | |
|---|---|---|---|
idOrSlug | integer\ | string | ID článku (číselné, např. 899) nebo plný slug (textový, např. "blog/cista-fasada"). Backend automaticky rozpozná typ pomocí isnumeric(). |
Query Parameters
| Parametr | Typ | Výchozí | Popis |
|---|---|---|---|
include | string | all | Comma-separated: categories, tags, images, files, parameters, author, relatedarticles, readalso |
Request Example
GET /api/v1/articles/866?include=categories,tags,images,relatedarticles,readalso
GET /api/v1/articles/blog/cista-fasada?include=all Authorization: Bearer YOURAPITOKEN
Response (Success - 200 OK)
{
"success": true, "data": { "id": 866, "title": "Název článku", "subtitle": "Podtitul", "shorttext": "Krátký popisek", "snippet": "Snippet", "body": "
HTML obsah článku
", "status": "active", "siteid": 7, "publishat": "2026-01-15T10:00:00Z", "publishendat": null, "manualupdateat": "2026-01-15T14:30:00Z", "url": "https://domain.cz/clanky/nazev-clanku", "createdat": "2026-01-10T09:00:00Z", "updatedat": "2026-01-15T14:30:00Z",
"meta": { "title": "SEO titulek", "description": "SEO popis", "keywords": "klíčová, slova", "contenttyp": "article", "mainCatid": 15, "autorname": "", "zdroj": "" },
"author": { "id": 42, "email": "[email protected]", "fullname": "John Doe", "bio": "Bio autora", "avatarurl": "https://...", "url": "/autor/john-doe" },
"categories": [ { "id": 15, "name": "Technologie", "url": "/technologie" }, { "id": 23, "name": "Software", "url": "/technologie/software" } ],
"tags": [ { "id": 5, "name": "php", "slug": "tag/php" }, { "id": 12, "name": "webový vývoj", "slug": "tag/webovy-vyvoj" } ],
"images": { "main": { "id": 456, "filename": "article-banner.webp", "publicurl": "https://storage.googleapis.com/.../article-banner.webp", "variants": { "banner": { "url": "https://.../banner/article-banner.webp", "width": 1500, "height": 635 }, "articleDetail": { "url": "https://.../articleDetail/article-banner.webp", "width": 800, "height": 600 } } }, "gallery": [ { "id": 789, "filename": "gallery-1.webp", "publicurl": "https://...", "variants": {} } ] },
"files": [ { "id": 101, "filename": "priloha.pdf", "publicurl": "https://.../priloha.pdf", "mimetype": "application/pdf", "filesize": 2048576 } ],
"parameters": [ { "id": 2, "name": "Doba čtení", "datatype": "integer", "value": 5 }, { "id": 5, "name": "Autor článku (externí)", "datatype": "string", "value": "Jan Novák" } ],
"relatedarticles": [ { "id": 123, "title": "První související článek", "slug": "blog/prvni-souvisejici-clanek", "subtitle": "Podtitul souvisejícího článku", "shorttext": "Krátký popisek souvisejícího článku", "snippet": "Snippet souvisejícího článku...", "status": "active", "siteid": 7, "publishat": "2026-01-10T10:00:00Z", "url": "https://domain.cz/blog/prvni-souvisejici-clanek", "author": { "id": 42, "email": "[email protected]", "details": { "fullname": "John Doe", "bio": "Bio autora", "avatar": { "variants": { "usricosmall": { "publicurl": "https://storage.googleapis.com/.../usricosmall/john.webp", "width": 32, "height": 32 }, "usricobig": { "publicurl": "https://storage.googleapis.com/.../usricobig/john.webp", "width": 64, "height": 64 } } } } }, "tags": [ { "id": 5, "name": "php", "slug": "tag/php" } ], "images": { "articles": { "id": 789, "filename": "article-thumb.webp", "publicurl": "https://storage.googleapis.com/.../article-thumb.webp", "alt": "Název obrázku", "title": "Název obrázku", "variants": { "articles": { "publicurl": "https://storage.googleapis.com/.../articles/thumb.webp", "width": 1000, "height": 486 }, "articleDetail": { "publicurl": "https://storage.googleapis.com/.../articleDetail/thumb.webp", "width": 1300, "height": 530 }, "galleryThumbnail": { "publicurl": "https://storage.googleapis.com/.../galleryThumbnail/thumb.webp", "width": 500, "height": 414 }, "imglistarticles": { "publicurl": "https://storage.googleapis.com/.../imglistarticles/thumb.webp", "width": 1000, "height": 486 }, "imgdetailarticleheader": { "publicurl": "https://storage.googleapis.com/.../imgdetailarticleheader/thumb.webp", "width": 1300, "height": 530 }, "imgdetailarticlepost": { "publicurl": "https://storage.googleapis.com/.../imgdetailarticlepost/thumb.webp", "width": 1920, "height": 1282 }, "imgrecentarticles": { "publicurl": "https://storage.googleapis.com/.../imgrecentarticles/thumb.webp", "width": 339, "height": 165 }, "imgrelatedpost": { "publicurl": "https://storage.googleapis.com/.../imgrelatedpost/thumb.webp", "width": 360, "height": 214 }, "imgctvercovy": { "publicurl": "https://storage.googleapis.com/.../imgctvercovy/thumb.webp", "width": 400, "height": 400 } } } } } ],
"readalso": [ { "id": 456, "title": "Čtěte také článek 1", "slug": "blog/ctete-take-1", "subtitle": "Podtitul", "shorttext": "Krátký popisek", "snippet": "Snippet článku", "author": { "id": 42, "email": "[email protected]", "details": { "fullname": "John Doe", "bio": "Bio autora", "avatar": { "variants": { "usricosmall": { "publicurl": "https://storage.googleapis.com/.../usricosmall/john.webp", "width": 32, "height": 32 }, "usricobig": { "publicurl": "https://storage.googleapis.com/.../usricobig/john.webp", "width": 64, "height": 64 } } } } }, "tags": [ { "id": 5, "name": "php", "slug": "tag/php" } ], "images": { "articles": { "id": 789, "filename": "article-thumb.webp", "publicurl": "https://storage.googleapis.com/.../article-thumb.webp", "alt": "Název obrázku", "title": "Název obrázku", "variants": { "articles": { "publicurl": "https://storage.googleapis.com/.../articles/thumb.webp", "width": 1000, "height": 486 }, "articleDetail": { "publicurl": "https://storage.googleapis.com/.../articleDetail/thumb.webp", "width": 1300, "height": 530 }, "galleryThumbnail": { "publicurl": "https://storage.googleapis.com/.../galleryThumbnail/thumb.webp", "width": 500, "height": 414 }, "imglistarticles": { "publicurl": "https://storage.googleapis.com/.../imglistarticles/thumb.webp", "width": 1000, "height": 486 }, "imgdetailarticleheader": { "publicurl": "https://storage.googleapis.com/.../imgdetailarticleheader/thumb.webp", "width": 1300, "height": 530 }, "imgdetailarticlepost": { "publicurl": "https://storage.googleapis.com/.../imgdetailarticlepost/thumb.webp", "width": 1920, "height": 1282 }, "imgrecentarticles": { "publicurl": "https://storage.googleapis.com/.../imgrecentarticles/thumb.webp", "width": 339, "height": 165 }, "imgrelatedpost": { "publicurl": "https://storage.googleapis.com/.../imgrelatedpost/thumb.webp", "width": 360, "height": 214 }, "imgctvercovy": { "publicurl": "https://storage.googleapis.com/.../imgctvercovy/thumb.webp", "width": 400, "height": 400 } } } } }, { "id": 457, "title": "Čtěte také článek 2", "slug": "blog/ctete-take-2", "subtitle": null, "shorttext": null, "snippet": "Snippet druhého článku", "author": {...}, "tags": [...], "images": { "articles": {...} } } ] } }
Odpověď (Chyba - 404 Nenalezeno)
{
"success": false, "error": "Not Found", "message": "Článek s ID 866 nebyl nalezen nebo nepatří k tomuto webu" }
✏️ 2.1 Aktualizace článku
Aktualizuje existující článek v systému. Podporuje částečnou aktualizaci (PATCH semantiku) - je možné odeslat pouze pole, která se mají změnit.
Koncový bod
PUT /api/v1/articles/{id}Oprávnění
- Token musí mít rozsah:
articles:write
Parametry URL
| Parametr | Typ | Popis |
|---|---|---|
id | celé číslo | ID článku k aktualizaci |
Záhlaví požadavků
Content-Type: application/json
Authorization: Bearer YOURAPITOKEN
Tělo požadavku
Struktura request body je identická jako u POST /api/v1/articles. Všechna pole jsou volitelná - odešlete pouze pole, která chcete aktualizovat.
{
Nový HTML obsah článku "title": "Aktualizovaný název článku", "body": "
Popis polí
Všechna pole mají stejný popis a validační pravidla jako u POST /api/v1/articles (viz sekce 1).
Důležité poznámky k aktualizaci :images : Při aktualizaci obrázků platí následující pravidla:- článekDetail a články : Nahradí existující obrázek nový (vztah 1:1) - galerie : Přidání nové obrázky do existující galerie (vztah 1:N) - Duplicitní se automaticky přeskakují - Pokud nechcete měnit obrázky, prostě je vynechejte z požadavku fileid
categories : Při aktualizaci kategorií se celé pole nahradí novým (ne append)tags : Při aktualizaci tagů se celé pole nahradí novým (ne append)shorttext asnippet : Při aktualizaci se ukládají přímo do tabulkyarticles.parameters/ parametervalues:- při aktualizaci se hodnoty ukládají do tabulkyparametervalues - je záložní alias pro starší integraci - nebo prázdný řetězec ( ) smaže existující hodnotu parametru parametervaluesnull""
Příklad požadavku 1: Minimální aktualizace
PUT /api/v1/articles/866
Content-Type: application/json Authorization: Bearer YOURAPITOKEN
{ "title": "Nový název článku", "status": "suspend" }
Příklad požadavku 2: Aktualizace s novými obrázky
PUT /api/v1/articles/866
Content-Type: application/json Authorization: Bearer YOURAPITOKEN
{ "title": "Článek s aktualizovanými obrázky", "images": { "articleDetail": { "url": "https://example.com/new-banner.jpg" }, "gallery": [ { "url": "https://example.com/gallery/photo-new-1.jpg" }, { "url": "https://example.com/gallery/photo-new-2.jpg" } ] } }
Odpověď (Úspěch - 200 OK)
Struktura response je identická jako u POST /api/v1/articles.
{
"success": true, "data": { "id": 866, "title": "Aktualizovaný název článku", "url": "https://domain.cz/clanky/aktualizovany-nazev-clanku", "status": "active", "createdat": "2026-01-10T09:00:00Z", "updatedat": "2026-01-16T15:45:00Z", "articleDetail": { "id": 1302, "url": "https://storage.googleapis.com/.../banner/new-banner.webp", "variants": { "banner": { "url": "https://storage.googleapis.com/.../banner/new-banner.webp", "width": 1300, "height": 530 }, "thumbnail": { "url": "https://storage.googleapis.com/.../thumb/new-banner.webp", "width": 300, "height": 200 } } }, "gallery": [ { "id": 1303, "url": "https://storage.googleapis.com/.../gallery/photo-new-1.webp", "variants": {...} }, { "id": 1304, "url": "https://storage.googleapis.com/.../gallery/photo-new-2.webp", "variants": {...} } ] }, "imagesprocessed": [ { "type": "articleDetail", "status": "success", "url": "https://example.com/new-banner.jpg", "fileid": 1302, "publicurl": "https://storage.googleapis.com/.../banner/new-banner.webp" }, { "type": "gallery[0]", "status": "success", "url": "https://example.com/gallery/photo-new-1.jpg", "fileid": 1303, "publicurl": "https://storage.googleapis.com/.../gallery/photo-new-1.webp" }, { "type": "gallery[1]", "status": "failed", "url": "https://example.com/gallery/photo-new-2.jpg", "error": "Časový limit stahování překročen (30s)" } ] }
imagesprocessed: Zobrazuje se pouze pokud byly zpracovány nějaké obrázky z URL. Obsahuje detailní informace o úspěchu/selhání každého obrázku. Viz detaily v sekci 1 "Pole obrázky zpracovány".Odpověď (Chyba - 404 Nenalezeno)
{
"success": false, "error": "Not Found", "message": "Článek s ID 866 nebyl nalezen nebo nepatří k tomuto webu" }
Odpověď (Chyba - 400 Špatný požadavek)
{
"success": false, "error": "Validation Error", "message": "Chybná validace dat", "errors": { "title": ["Pole title musí obsahovat alespoň 3 znaky"], "status": ["Neplatná hodnota status. Povolené: active, development, suspend"] } }
Odpověď (Chyba - 409 Konflikt)
Pokud se pokusíte změnit URL na hodnotu, která už existuje:
{
"success": false, "error": "Conflict", "message": "URL již existuje pro tento web", "details": { "url": "/clanky/jiny-clanek", "existingarticleid": 123 } }
📚 3. Seznam článků
Načtete seznam článků s různými filtry a možnostmi.
3.1 Všechny články
GET /api/v1/articles3.2 Nejnovější X články
GET /api/v1/articles?limit=10&sort=newest3.3 Všechny články v kategorii
GET /api/v1/articles?categoryid=153.4 X článků v kategorii se stránkováním
GET /api/v1/articles?categoryid=15&limit=20&page=2Parametry dotazu
| Parametr | Typ | Východí | Popis |
|---|---|---|---|
categoryid | celé číslo | - | Filtrovat podle ID kategorie |
limit | celé číslo | 20 | Počet článků na stránce (max 100) |
page | celé číslo | 1 | Číslo stránky |
sort | řetězec | nejnovější | newest, oldest, updated, title,popular |
tag | řetězec | - | Filtr podle tagu (slug) |
authorid | celé číslo | - | Filtr podle autora |
search | řetězec | - | Fulltextové vyhledávání (viz bod 4) |
active. Parametr statusbyl odstraněn.Odpověď (Úspěch - 200 OK)
{
"success": true, "data": { "articles": [ { "id": 866, "title": "Název článku", "slug": "/clanky/nazev-clanku", "subtitle": "Podtitul", "snippet": "Krátký úryvek z článku pro seznam...", "publishat": "2026-01-15T10:00:00.000000Z", "manualupdateat": "2026-01-20T14:30:00.000000Z", "categories": [ { "id": 15, "title": "technologie", "displayname": "Technologie", "slug": "/kategorie/technologie", "parentid": null, "order": 1, "image": { "publicurl": "https://storage.googleapis.com/.../category.webp", "imagename": "category.webp", "alt": "Technologie", "title": "Kategorie Technologie", "variants": { "banner": { "publicurl": "https://storage.googleapis.com/.../banner/category.webp", "width": 1500, "height": 400 }, "thumbnail": { "publicurl": "https://storage.googleapis.com/.../thumb/category.webp", "width": 300, "height": 200 } } }, "children": [] } ], "author": { "id": 42, "email": "[email protected]", "details": { "fullname": "John Doe", "signature": "Senior Tech Writer & AI Specialist", "jobtitle": "Senior Content Manager", "companyname": "Tech Media s.r.o.", "website": "https://johndoe.com", "publicemail": "[email protected]", "allowpublicprofile": true, "displaysignature": true, "iscontributor": false, "socials": [ { "platform": "twitter", "url": "https://twitter.com/johndoe", "username": "@johndoe" }, { "platform": "linkedin", "url": "https://linkedin.com/in/johndoe" } ], "links": [ { "title": "Portfolio", "url": "https://johndoe.com/portfolio" } ], "avatar": { "publicurl": "https://storage.googleapis.com/.../avatar.webp", "imagename": "avatar.webp", "alt": "John Doe", "title": "John Doe - Avatar", "variants": { "thumbnail": { "publicurl": "https://storage.googleapis.com/.../thumb/avatar.webp", "width": 150, "height": 150 } } } } }, "tags": [ { "id": 5, "name": "Umělá inteligence", "slug": "tag/umela-inteligence", "articlescount": 42 } ], "images": { "articles": { "publicurl": "https://storage.googleapis.com/.../articles/image.webp", "width": 400, "height": 300, "imagename": "image.webp", "alt": "Článek náhled", "title": "Název článku", "variants": { "banner": { "publicurl": "https://storage.googleapis.com/.../banner/image.webp", "width": 1500, "height": 635 }, "thumbnail": { "publicurl": "https://storage.googleapis.com/.../thumb/image.webp", "width": 300, "height": 200 } } }, "articleDetail": { "publicurl": "https://storage.googleapis.com/.../articleDetail/image.webp", "width": 800, "height": 600, "imagename": "image.webp", "alt": "Článek detail", "title": "Název článku", "variants": {} }, "gallery": [ { "publicurl": "https://storage.googleapis.com/.../gallery/img1.webp", "width": 1200, "height": 800, "imagename": "img1.webp", "alt": "Galerie obrázek 1", "title": "První obrázek galerie", "variants": { "galleryThumbnail": { "publicurl": "https://storage.googleapis.com/.../thumb/img1.webp", "width": 300, "height": 200 } } } ] } }, { "id": 865, "title": "Další článek", "slug": "/clanky/dalsi-clanek", "subtitle": null, "snippet": "Popis dalšího článku...", "publishat": "2026-01-14T08:00:00.000000Z", "manualupdateat": null, "categories": [], "author": { "id": 42, "email": "[email protected]", "details": { "fullname": "John Doe", "signature": null, "jobtitle": null, "companyname": null, "website": null, "publicemail": null, "allowpublicprofile": false, "displaysignature": false, "iscontributor": false, "socials": [], "links": [], "avatar": null } }, "tags": [], "images": { "articles": null, "articleDetail": null, "gallery": [] } } ], "pagination": { "total": 156, "perpage": 20, "currentpage": 2, "lastpage": 8, "from": 21, "to": 40, "prevpageurl": "/api/v1/articles?page=1", "nextpageurl": "/api/v1/articles?page=3" }, "meta": { "totalarticles": 156, "filteredby": { "categoryid": 15 } } } }
🔍 4. Vyhledávání článků
Fulltextové vyhledávání v článcích.
Koncový bod
GET /api/v1/articles/searchParametry dotazu
| Parametr | Typ | Povinné | Popis |
|---|---|---|---|
q | řetězec | ✅ | Hledaný řetězec (min. 3 znaky) |
fields | řetězec | vše | title, body, shorttext,all |
categoryid | celé číslo | ❌ | Omezení na kategorii |
limit | celé číslo | ❌ | Počet výsledků (výchozí 20, max. 100) |
page | celé číslo | ❌ | Stránka |
Příklad požadavku
GET /api/v1/articles/search?q=umělá inteligence&fields=title,body&limit=10
Authorization: Bearer YOURAPITOKEN
Odpověď (Úspěch - 200 OK)
{
"success": true, "data": { "query": "umělá inteligence", "results": [ { "id": 866, "title": "Umělá inteligence v roce 2026", "url": "https://domain.cz/clanky/umela-inteligence-2026", "excerpt": "...text obsahující umělá inteligence v kontextu...", "relevancescore": 0.95, "publishat": "2026-01-15T10:00:00Z", "image": { "url": "https://.../thumbnail/ai-thumb.webp" } }, { "id": 723, "title": "Budoucnost AI", "url": "https://domain.cz/clanky/budoucnost-ai", "excerpt": "...diskuse o umělé inteligenci a jejích aplikacích...", "relevancescore": 0.78, "publishat": "2026-01-10T14:00:00Z", "image": null } ], "pagination": { "total": 15, "perpage": 10, "currentpage": 1, "lastpage": 2 } } }
Odpověď (Chyba - 400 Špatný požadavek)
{
"success": false, "error": "Validation Error", "message": "Hledaný řetězec musí mít alespoň 3 znaky" }
🌲 5. Strom všech kategorií
Načte hierarchickou strukturu všech kategorií webu.
Koncový bod
GET /api/v1/categories/treeParametry dotazu
| Parametr | Typ | Východí | Popis |
|---|---|---|---|
navigationid | celé číslo | nulové | Volitelný filtr na jednu konkrétní navigaci; vrátí pouze kategorie s danýmnavigationid |
activeonly | booleovská | věrný | Pokud je true, vrátí se pouze aktivní kategorie; vrátím se falsei neaktivní |
Příklad požadavku
GET /api/v1/categories/tree?navigationid=1&activeonly=true
Authorization: Bearer YOURAPITOKEN
Odpověď (Úspěch - 200 OK)
{
"success": true, "data": { "categories": [ { "id": 1, "title": "Technologie", "displayname": "Technologie", "url": "/technologie", "parentid": null, "level": 0, "isactive": "active", "ordercat": 1, "navigationid": 1, "articlecount": 45, "image": { "url": "https://storage.googleapis.com/bucket/images/technologie.webp", "variants": { "banner": { "id": 10508, "originalimageid": 1260, "variantname": "banner", "imagename": "696ab4fbbb108technologie.webp", "width": 1500, "height": 635, "publicurl": "https://storage.googleapis.com/bucket/images/banner/technologie.webp", "createdat": "2026-01-16T22:00:29.000000Z", "updatedat": "2026-01-16T22:00:29.000000Z" }, "articleDetail": { "id": 10510, "originalimageid": 1260, "variantname": "articleDetail", "imagename": "696ab4fdf1b56technologie.webp", "width": 1300, "height": 530, "publicurl": "https://storage.googleapis.com/bucket/images/articleDetail/technologie.webp", "createdat": "2026-01-16T22:00:30.000000Z", "updatedat": "2026-01-16T22:00:30.000000Z" } } }, "children": [ { "id": 15, "title": "Software", "displayname": "Software", "url": "/technologie/software", "parentid": 1, "level": 1, "isactive": "active", "ordercat": 2, "navigationid": 1, "articlecount": 23, "image": { "url": "https://storage.googleapis.com/bucket/images/software.webp", "variants": { "banner": { "id": 10520, "originalimageid": 1262, "variantname": "banner", "imagename": "696ab4fbbb108software.webp", "width": 1500, "height": 635, "publicurl": "https://storage.googleapis.com/bucket/images/banner/software.webp", "createdat": "2026-01-16T22:00:29.000000Z", "updatedat": "2026-01-16T22:00:29.000000Z" }, "articleDetail": { "id": 10522, "originalimageid": 1262, "variantname": "articleDetail", "imagename": "696ab4fdf1b56software.webp", "width": 1300, "height": 530, "publicurl": "https://storage.googleapis.com/bucket/images/articleDetail/software.webp", "createdat": "2026-01-16T22:00:30.000000Z", "updatedat": "2026-01-16T22:00:30.000000Z" } } }, "children": [ { "id": 23, "title": "Web Development", "displayname": "Webový vývoj", "url": "/technologie/software/web-development", "parentid": 15, "level": 2, "isactive": true, "articlecount": 12, "children": [] } ] }, { "id": 16, "title": "Hardware", "displayname": "Hardware", "url": "/technologie/hardware", "parentid": 1, "level": 1, "isactive": true, "articlecount": 18, "children": [] } ] }, { "id": 2, "title": "Lifestyle", "displayname": "Životní styl", "url": "/lifestyle", "parentid": null, "level": 0, "isactive": true, "articlecount": 67, "children": [ { "id": 25, "title": "Zdraví", "displayname": "Zdraví", "url": "/lifestyle/zdravi", "parentid": 2, "level": 1, "isactive": true, "articlecount": 34, "children": [] } ] } ], "meta": { "totalcategories": 8, "maxdepth": 3, "totalarticles": 112 } } }
🧭 5.1 Seznam navigací
Vrací seznam navigace aktuálního webu. Slouží externím systémem (např. publikační pipeline) k výběru navigace, strom kategorií se má použít pro zařazování článků — ID navigace lze následně použít jako filtr u . navigationidGET /api/v1/categories/tree
Koncový bod
GET /api/v1/navigationsRozsah: categories:readParametry dotazu
| Parametr | Typ | Východí | Popis |
|---|---|---|---|
activeonly | booleovská | věrný | Pokud je true, vrátí pouze aktivní navigaci; ignorováno, pokud tabulka nemá sloupecisactive |
Příklad požadavku
GET /api/v1/navigations
Authorization: Bearer YOURAPITOKEN
Odpověď (Úspěch - 200 OK)
{
"success": true, "data": [ { "id": 1, "name": "Hlavní menu", "description": "Primární navigace webu", "isactive": true }, { "id": 2, "name": "Patička", "description": null, "isactive": true } ], "meta": { "total": 2 } }
📡 5.2 Datový kanál
Pojmenované datové zdroje vrací kanonické seznamy položek pro aktuální web (siteid ).
Koncový bod
GET /api/v1/feeds/{key}Autorizace
- Veřejný feed ( ) je dostupný bez tokenu.
ispublic=1 - Neveřejný zdroj (
ispublic=0) vyžaduje Bearer token a případně feedu.requiredscope
Parametry dotazu
| Parametr | Typ | Východí | Popis |
|---|---|---|---|
page | celé číslo | 1 | Stránka výsledků |
categoryid | celé číslo | — | Kategorie volitelného filtru |
tagid | celé číslo | — | Volitelný filtr tagu |
Příklad požadavku
GET /api/v1/feeds/homepagearticles?page=1
Authorization: Bearer YOURAPITOKEN
Odpověď (Úspěch - 200 OK)
{
"success": true, "data": [], "meta": { "pagination": { "currentpage": 1, "perpage": 20, "total": 0, "lastpage": 0 }, "feed": { "key": "homepagearticles", "entitytype": "articles", "ispublic": true } } }
🌿 6. Strom podkategorií
Načte hierarchickou strukturu podkategorií konkrétní kategorie.
Koncový bod
GET /api/v1/categories/{id}/childrenParametry URL
| Parametr | Typ | Popis |
|---|---|---|
id | celé číslo | ID nadřazené kategorie |
Parametry dotazu
| Parametr | Typ | Východí | Popis |
|---|---|---|---|
recursive | booleovská | věrný | Načíst rekurzivně všechny potomky |
includecounts | booleovská | falešný | Zahrnout počet článků |
Příklad požadavku
GET /api/v1/categories/1/children?recursive=true&includecounts=true
Authorization: Bearer YOURAPITOKEN
Odpověď (Úspěch - 200 OK)
{
"success": true, "data": { "parentcategory": { "id": 1, "title": "Technologie", "displayname": "Technologie", "url": "/technologie", "image": { "url": "https://storage.googleapis.com/bucket/images/technologie.webp", "variants": { "banner": { "id": 10508, "originalimageid": 1260, "variantname": "banner", "imagename": "696ab4fbbb108technologie.webp", "width": 1500, "height": 635, "publicurl": "https://storage.googleapis.com/bucket/images/banner/technologie.webp", "createdat": "2026-01-16T22:00:29.000000Z", "updatedat": "2026-01-16T22:00:29.000000Z" }, "articleDetail": { "id": 10510, "originalimageid": 1260, "variantname": "articleDetail", "imagename": "696ab4fbbb108technologie.webp", "width": 1300, "height": 530, "publicurl": "https://storage.googleapis.com/bucket/images/articleDetail/technologie.webp", "createdat": "2026-01-16T22:00:29.000000Z", "updatedat": "2026-01-16T22:00:29.000000Z" } } } }, "children": [ { "id": 15, "title": "Software", "displayname": "Software", "url": "/technologie/software", "parentid": 1, "level": 1, "articlecount": 23, "image": { "url": "https://storage.googleapis.com/bucket/images/software.webp", "variants": { "banner": { "id": 10520, "originalimageid": 1265, "variantname": "banner", "imagename": "696ab4fbbb108software.webp", "width": 1500, "height": 635, "publicurl": "https://storage.googleapis.com/bucket/images/banner/software.webp", "createdat": "2026-01-16T22:01:15.000000Z", "updatedat": "2026-01-16T22:01:15.000000Z" }, "articleDetail": { "id": 10522, "originalimageid": 1265, "variantname": "articleDetail", "imagename": "696ab4fbbb108software.webp", "width": 1300, "height": 530, "publicurl": "https://storage.googleapis.com/bucket/images/articleDetail/software.webp", "createdat": "2026-01-16T22:01:15.000000Z", "updatedat": "2026-01-16T22:01:15.000000Z" } } }, "children": [ { "id": 23, "title": "Web Development", "displayname": "Webový vývoj", "url": "/technologie/software/web-development", "parentid": 15, "level": 2, "articlecount": 12, "children": [] }, { "id": 24, "title": "Mobile Development", "displayname": "Mobilní vývoj", "url": "/technologie/software/mobile-development", "parentid": 15, "level": 2, "articlecount": 8, "children": [] } ] }, { "id": 16, "title": "Hardware", "displayname": "Hardware", "url": "/technologie/hardware", "parentid": 1, "level": 1, "articlecount": 18, "children": [] } ], "meta": { "totalchildren": 4, "maxdepth": 2 } } }
Odpověď (Chyba - 404 Nenalezeno)
{
"success": false, "error": "Not Found", "message": "Kategorie s ID 1 nebyla nalezena" }
📂 7. Kategorie detailů
Načtete kompletní informace o konkrétní kategorii.
Koncový bod
GET /api/v1/categories/{id}Parametry URL
| Parametr | Typ | Popis |
|---|---|---|
id | celé číslo | ID kategorie |
Parametry dotazu
| Parametr | Typ | Východí | Popis |
|---|---|---|---|
includearticles | booleovská | falešný | Zahrnout seznam článků |
articleslimit | celé číslo | 10 | Počet článků (pokud obsahují články=true) |
includebreadcrumb | booleovská | věrný | Zahrnout strouhanku cestou |
Příklad požadavku
GET /api/v1/categories/15?includearticles=true&articleslimit=5
Authorization: Bearer YOURAPITOKEN
Odpověď (Úspěch - 200 OK)
{
Úvodní text kategorie Závěrečný text kategorie "success": true, "data": { "id": 15, "title": "software", "displayname": "Software", "url": "/technologie/software", "parentid": 1, "level": 1, "isactive": "active", "ordercat": 10, "navigationid": 1, "toptext": "
🏷️ 8. Seznam tagů
Načtete všechny značky pro daný web. Podporuje filtrování podle kategorie štítku.
Koncový bod
GET /api/v1/tagsParametry dotazu
| Parametr | Typ | Východí | Popis |
|---|---|---|---|
sort | řetězec | title | Řazení: title, popular,newest |
categoryid | celé číslo | — | Nové v 1.6: Filtrovat tagy podle ID kategorie štítku |
categoryslug | řetězec | — | Filtrovat tagy podle slugu kategorie štítku |
Příklad požadavku
GET /api/v1/tags?sort=popular
Authorization: Bearer YOURAPITOKEN
GET /api/v1/tags?categoryid=5
Authorization: Bearer YOURAPITOKEN
Odpověď (Úspěch - 200 OK)
{
"success": true, "data": [ { "id": 15, "name": "Umělá inteligence", "slug": "tag/umela-inteligence", "status": "active", "headline": "Vše o umělé inteligenci", "metatitle": "Umělá inteligence — články a novinky", "metadescription": "Přehled článků a produktů označených štítkem umělá inteligence.", "articlescount": 47, "productscount": 12, "itemscount": 59, "categories": [ { "id": 3, "title": "Technologie", "slug": "technologie", "isdefault": true } ] } ], "meta": { "total": 1 } }
🏷️ 8a. Kategorie tagů (nové v 1.6)
Načtete všechny kategorie štítků pro daný web. Slouží pro filtrování tagů a správu organizací.
Koncový bod
GET /api/v1/tag-categoriesAutorizace
Vyžaduje rozsah tags:read.
Odpověď (Úspěch - 200 OK)
{
"success": true, "data": [ { "id": 1, "title": "Obecné", "slug": "obecne", "isdefault": true, "order": 0, "tagscount": 24 }, { "id": 2, "title": "Technologie", "slug": "technologie", "isdefault": false, "order": 1, "tagscount": 15 } ], "meta": { "total": 2 } }
sort| řetězec | title| Řazení: title,articlescount , | | | řetězec | | Směr řazení: , | | | celé číslo | 50 | Počet tagů (max 200) | | | booleovský | pravda | Zahrnout počty článků | createdatorderascascdesclimitwithcountsPříklad požadavku
GET /api/v1/tags?sort=articlescount&order=desc&limit=20
Authorization: Bearer YOURAPITOKEN
Odpověď (Úspěch - 200 OK)
{
"success": true, "data": { "tags": [ { "id": 15, "name": "Umělá inteligence", "slug": "umela-inteligence", "articlescount": 47, "createdat": "2025-01-10T09:00:00Z", "updatedat": "2026-01-15T10:00:00Z" }, { "id": 23, "name": "Machine Learning", "slug": "machine-learning", "articlescount": 34, "createdat": "2025-02-15T10:00:00Z", "updatedat": "2026-01-14T08:00:00Z" }, { "id": 8, "title": "Python", "slug": "python", "articlescount": 28, "createdat": "2024-12-01T12:00:00Z", "updatedat": "2026-01-13T14:00:00Z" } ], "meta": { "total": 156, "returned": 20 } } }
🏷️ 9. Detail tagu s články
Načtete detail konkrétního tagu včetně seznamu článků.
Koncový bod
GET /api/v1/tags/{idorslug}Parametry URL
| Parametr | Typ | Popis |
|---|---|---|
idorslug | řetězec | ID nebo slug tagu (např. 15nebo umela-inteligence) |
Parametry dotazu
| Parametr | Typ | Východí | Popis |
|---|---|---|---|
includearticles | booleovská | věrný | Zahrnout seznam článků |
articleslimit | celé číslo | 20 | Počet článků (max. 100) |
articlespage | celé číslo | 1 | Články stránky |
sortarticles | řetězec | publishat | Řazení článků: publishat, title,views |
Příklad požadavku
GET /api/v1/tags/umela-inteligence?articleslimit=10
Authorization: Bearer YOURAPITOKEN
Odpověď (Úspěch - 200 OK)
{
"success": true, "data": { "tag": { "id": 15, "name": "Umělá inteligence", "slug": "umela-inteligence", "articlescount": 47, "createdat": "2025-01-10T09:00:00Z", "updatedat": "2026-01-15T10:00:00Z" }, "articles": [ { "id": 866, "title": "Nový článek o AI", "subtitle": "Podtitulek článku", "url": "https://domain.cz/clanky/novy-clanek-o-ai", "shorttext": "Krátký popis článku", "status": "active", "publishat": "2026-01-15T10:00:00Z", "image": { "url": "https://.../thumbnail/article-thumb.webp", "alt": "Alt text obrázku" }, "author": { "id": 42, "name": "John Doe", "avatar": "https://.../avatar/john-doe.webp" }, "categories": [ { "id": 15, "name": "Technologie", "url": "/technologie" } ] } ], "pagination": { "total": 47, "perpage": 10, "currentpage": 1, "lastpage": 5 } } }
Odpověď (Chyba - 404 Nenalezeno)
{
"success": false, "error": "Not Found", "message": "Tag 'umela-inteligence' nebyl nalezen" }
👤 10. Detail autora/uživatele
Načte detail autora včetně jeho článků, bio, sociálních sítí a dalších informací.
Koncový bod
GET /api/v1/users/{id}Parametry URL
| Parametr | Typ | Popis |
|---|---|---|
id | celé číslo | ID uživatele |
Parametry dotazu
| Parametr | Typ | Východí | Popis |
|---|---|---|---|
includearticles | booleovská | věrný | Zahrnout seznam článků autora |
articleslimit | integer | 10 | Počet článků (max 50) |
articlespage | integer | 1 | Stránka článků |
Request Example
GET /api/v1/users/42?includearticles=true&articleslimit=5
Authorization: Bearer YOURAPITOKEN
Response (Success - 200 OK)
{
Jsem vývojář s 10 lety zkušeností... John Doe - Senior Developer "success": true, "data": { "user": { "id": 42, "login": "johndoe", "name": "John Doe", "email": "[email protected]", "phone": "+420 123 456 789", "createdat": "2024-01-10T09:00:00Z", "updatedat": "2026-01-15T10:00:00Z" }, "details": { "fullname": "John Doe", "jobtitle": "Senior Developer", "companyname": "Tech Corp s.r.o.", "website": "https://johndoe.dev", "publicemail": "[email protected]", "biohtml": "
Response (Error - 404 Not Found)
{
"success": false, "error": "Not Found", "message": "Uživatel s ID 42 nebyl nalezen" }
⚙️ 11. Seznam parametrů pro content type
Načte definice parametrů pro daný typ obsahu (articles, products, atd.).
Endpoint
GET /api/v1/parametersQuery Parameters
| Parametr | Typ | Povinné | Popis |
|---|---|---|---|
contenttype | string | ✅ | Typ obsahu: article, catalogue, atd. |
Request Example
GET /api/v1/parameters?contenttype=article
Authorization: Bearer YOURAPITOKEN
Response (Success - 200 OK)
{
"success": true, "data": { "parameters": [ { "id": 1, "name": "difficulty", "datatype": "enum", "settings": { "label": "Obtížnost", "options": ["začátečník", "středně pokročilý", "pokročilý", "expert"], "default": "středně pokročilý" }, "isrequired": false, "isfilterable": true, "issearchable": false, "issortable": true, "sortorder": 1 }, { "id": 2, "name": "readingtime", "datatype": "integer", "settings": { "label": "Doba čtení (minuty)", "min": 1, "max": 120, "unit": "min" }, "isrequired": false, "isfilterable": true, "issearchable": false, "issortable": true, "sortorder": 2 }, { "id": 3, "name": "videourl", "datatype": "youtubeurl", "settings": { "label": "YouTube video", "placeholder": "https://youtube.com/watch?v=..." }, "isrequired": false, "isfilterable": false, "issearchable": false, "issortable": false, "sortorder": 3 }, { "id": 4, "name": "maplocation", "datatype": "mapurl", "settings": { "label": "Mapa lokace", "placeholder": "https://maps.google.com/..." }, "isrequired": false, "isfilterable": false, "issearchable": false, "issortable": false, "sortorder": 4 }, { "id": 5, "name": "attachment", "datatype": "file", "settings": { "label": "Příloha ke stažení", "allowedtypes": ["pdf", "docx", "zip"], "maxsizemb": 10 }, "isrequired": false, "isfilterable": false, "issearchable": false, "issortable": false, "sortorder": 5 }, { "id": 6, "name": "featuredimage", "datatype": "image", "settings": { "label": "Featured obrázek", "allowedtypes": ["jpg", "png", "webp"], "maxsizemb": 5 }, "isrequired": false, "isfilterable": false, "issearchable": false, "issortable": false, "sortorder": 6 } ], "meta": { "contenttype": "article", "totalparameters": 6 } } }
Podporované datatype hodnoty
text- Dlouhý text (WYSIWYG editor)string- Krátký text (1 řádek)htmltext- HTML textinteger- Celé číslofloat- Desetinné čísloboolean- Ano/Nedate- Datumtime- Časdatetime- Datum a časenum- Výběr z možnostífile- Souborimage- Obrázekurl- URL adresayoutubeurl- YouTube URLmapurl- URL mapy (Google Maps, atd.)
🔒 Bezpečnostní mechanismy
1. Token-based autentizace
Každý token je vázán na konkrétní siteid:
-- Příklad ověření při každém requestu
SELECT siteid, permissions FROM apitokens WHERE token = :token AND isactive = 1 AND (expiresat IS NULL OR expiresat > NOW())
2. Automatická filtrace dat podle siteid
Všechny databázové dotazy musí obsahovat filtr podle siteid:
// ❌ ŠPATNĚ - bez filtrace $articles = Article::all();
// ✅ SPRÁVNĚ - s filtrací podle siteid z tokenu $articles = Article::where('siteid', $SERVER['APISITEID'])->get();
3. Validace oprávnění
Před každou operací se kontrolují oprávnění tokenu:
function requirePermission($token, $permission) { $tokenRecord = ApiToken::where('token', $token)->first(); $permissions = jsondecode($tokenRecord->permissions, true);
if (!inarray($permission, $permissions)) { return ['error' => 'Insufficient permissions', 'code' => 403]; }
return true; }
4. Rate limiting
Omezení počtu requestů z jednoho tokenu:
- Read operace: 1000 requestů / hodinu
- Write operace: 100 requestů / hodinu
HTTP/1.1 429 Too Many Requests X-RateLimit-Limit: 1000 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 1642248000
{ "error": "Rate Limit Exceeded", "message": "Překročen limit 1000 requestů za hodinu", "retryafter": 3600 }
5. HTTPS Only
API musí běžet pouze přes HTTPS.
6. Logging všech přístupů
Každý API request se loguje:
CREATE TABLE apilogs (
id INT PRIMARY KEY AUTOINCREMENT, tokenid INT, siteid INT, method VARCHAR(10), endpoint VARCHAR(255), ipaddress VARCHAR(45), useragent TEXT, responsecode INT, responsetimems INT, createdat TIMESTAMP );
📊 Databázové migrace
Vytvoření tabulky apitokens
CREATE TABLE apitokens (
id INT(11) UNSIGNED NOT NULL AUTOINCREMENT, siteid INT(11) UNSIGNED NOT NULL, token VARCHAR(64) NOT NULL, name VARCHAR(255) NOT NULL, permissions JSON NOT NULL COMMENT '["read","write","delete"]', expiresat DATETIME NULL DEFAULT NULL, lastusedat DATETIME NULL DEFAULT NULL, isactive TINYINT(1) NOT NULL DEFAULT 1, createdat TIMESTAMP NOT NULL DEFAULT CURRENTTIMESTAMP, updatedat TIMESTAMP NOT NULL DEFAULT CURRENTTIMESTAMP ON UPDATE CURRENTTIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uniquetoken (token), KEY idxsiteid (siteid), KEY idxisactive (isactive), KEY idxexpiresat (expiresat) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4unicodeci;
⚠️ ZASTARALÉ: Rozšíření ENUM pro status (NEIMPLEMENTOVÁNO)
VAROVÁNÍ: Tato sekce je zastaralá a neodpovídá skutečné implementaci. Aktuální kód (Article.php, Product.php, crony) používá pouze tyto statusy:development, active, suspend.-- ❌ NEPOUŽÍVAT - Tato migrace není implementována v kódu! -- Hodnoty 'hidden' a 'deleted' NEJSOU podporovány v současné implementaci ALTER TABLE articles MODIFY status ENUM('development','active','suspend','hidden','deleted') NOT NULL DEFAULT 'development';
-- Poznámka: Soft delete je preferováno přes deletedat timestamp, -- nikoli přes status='deleted'
Vytvoření tabulky apilogs
CREATE TABLE apilogs (
id BIGINT(20) UNSIGNED NOT NULL AUTOINCREMENT, tokenid INT(11) UNSIGNED NULL DEFAULT NULL, siteid INT(11) UNSIGNED NOT NULL, method VARCHAR(10) NOT NULL, endpoint VARCHAR(255) NOT NULL, queryparams TEXT NULL, requestbody TEXT NULL, ipaddress VARCHAR(45) NOT NULL, useragent TEXT NULL, responsecode INT(3) NOT NULL, responsetimems INT(11) NOT NULL, errormessage TEXT NULL, createdat TIMESTAMP NOT NULL DEFAULT CURRENTTIMESTAMP, PRIMARY KEY (id), KEY idxtokenid (tokenid), KEY idxsiteid (siteid), KEY idxcreatedat (createdat), KEY idxresponsecode (responsecode) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4unicodeci;
🧪 Testování API
cURL Příklady
Získání detailu článku
curl -X GET "https://yourdomain.com/api/v1/articles/866" \
-H "Authorization: Bearer YOURAPITOKEN" \ -H "Accept: application/json"
Vytvoření nového článku
curl -X POST "https://yourdomain.com/api/v1/articles" \
Obsah článku -H "Authorization: Bearer YOURAPITOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Test článek", "body": "
Vyhledávání
curl -X GET "https://yourdomain.com/api/v1/articles/search?q=umělá+inteligence&limit=5" \
-H "Authorization: Bearer YOURAPITOKEN" \ -H "Accept: application/json"
Postman Collection
Doporučujeme vytvořit Postman Collection s příklady všech endpointů.
🚀 Implementační kontrolní seznam
Historický checklist byl archivován. Tento dokument je kanonická specifikace implementovaných endpointů a kontraktů.
📖 Souhrn všech 32 hlavních API endpointů
| # | Metoda | Endpoint | Popis | Oprávnění |
|---|---|---|---|---|
| ČLÁNKY | ||||
| 1 | POST | /api/v1/articles | Vytvoření nového článku | articles:write |
| 2 | GET | /api/v1/articles/{id} | Detail konkrétního článku | articles:read |
| 3 | GET | /api/v1/articles | Seznam článků s filtrováním a paginací | articles:read |
| 4 | GET | /api/v1/articles/search | Fulltextové vyhledávání v článcích | articles:read |
| KATEGORIE | ||||
| 5 | GET | /api/v1/categories/tree | Hierarchický strom všech kategorií | categories:read |
| 6 | GET | /api/v1/categories/{id}/children | Podkategorie konkrétní kategorie | categories:read |
| 7 | GET | /api/v1/categories/{id} | Detail kategorie s články | categories:read |
| TAGY | ||||
| 8 | GET | /api/v1/tags | Seznam všech tagů | tags:read |
| 9 | GET | /api/v1/tags/{idorslug} | Detail tagu s články | tags:read |
| UŽIVATELÉ | ||||
| 10 | GET | /api/v1/users/{id} | Profil autora s články a sociálními sítěmi | users:read |
| DATA FEEDY | ||||
| 10a | GET | /api/v1/feeds/{key} | Pojmenovaný feed položek pro aktuální web | per-feed |
| PRODUKTY (READ & WRITE) | ||||
| 11 | GET | /api/v1/products | Seznam produktů s pokročilým filtrováním | products:read |
| 12 | GET | /api/v1/products/{id} | Detail produktu s kompletními daty | products:read |
| 13 | POST | /api/v1/products | Vytvoření produktu | products:write |
| 14 | PUT | /api/v1/products/{id} | Aktualizace produktu | products:write |
| 15 | DELETE | /api/v1/products/{id} | Soft-delete produktu | products:write |
| E-SHOP (PRODUKTY) | ||||
| 16 | GET | /api/v1/eshop/products | Seznam prodejných produktů | eshop:read |
| 17 | GET | /api/v1/eshop/products/{id} | Detail prodejného produktu | eshop:read |
| 18 | GET | /api/v1/eshop/products/{id}/variants | Varianty produktu | eshop:read |
| 19 | GET | /api/v1/eshop/products/{id}/availability | Dostupnost produktu | eshop:read |
| E-SHOP (KOŠÍK) | ||||
| 20 | GET | /api/v1/eshop/cart | Načtení aktivního košíku | eshop:read |
| 21 | POST | /api/v1/eshop/cart/items | Přidání položky do košíku | eshop:write |
| 22 | PATCH | /api/v1/eshop/cart/items/{id} | Změna množství položky | eshop:write |
| 23 | DELETE | /api/v1/eshop/cart/items/{id} | Odebrání položky z košíku | eshop:write |
| E-SHOP (KUPÓNY) | ||||
| 24 | POST | /api/v1/eshop/cart/coupon | Aplikace kupónu na košík | eshop:write |
| 25 | DELETE | /api/v1/eshop/cart/coupon | Odebrání kupónu z košíku | eshop:write |
| E-SHOP (CHECKOUT A OBJEDNÁVKY) | ||||
| 26 | POST | /api/v1/eshop/checkout | Vytvoření objednávky z aktivního košíku | eshop:write |
| 27 | GET | /api/v1/eshop/orders/{id} | Detail objednávky v rámci siteid | eshop:read |
| E-SHOP (DOPRAVA A PLATBY) | ||||
| 28 | GET | /api/v1/eshop/shipping-methods | Dostupné dopravy pro site/cart | eshop:read |
| 29 | GET | /api/v1/eshop/payment-methods | Dostupné platby (volitelně dle dopravy) | eshop:read |
| E-SHOP (TRANSAKCE A WEBHOOKY) | ||||
| 30 | GET | /api/v1/eshop/orders/{id}/transactions | Výpis transakcí k objednávce | eshop:read |
| 31 | POST | /api/v1/eshop/orders/{id}/transactions | Zahájení platební transakce | eshop:write |
| 32 | GET | /api/v1/eshop/transactions/{id} | Detail transakce | eshop:read |
| 33 | POST | /api/v1/eshop/webhooks/{provider} | Webhook od platební brány | veřejný |
| 34 | POST | /api/v1/eshop/export | Spuštění exportního běhu | eshop:write |
| PARAMETRY | ||||
| 35 | GET | /api/v1/parameters | Definice parametrů pro content type | parameters:read |
Struktura response pro všechny endpointy
Všechny endpointy vrací jednotný formát:
Success (200 OK):{
"success": true, "data": { / data specifická pro endpoint / }, "meta": { / metadata jako pagination, total counts atd. / } }
{
"success": false, "error": "Error Type", "message": "Popis chyby", "code": 400 }
Poznámky k bezpečnosti
Všechny endpointy:- Vyžadují platný API token v hlavičce
- Automaticky filtrují data podle
siteidz tokenu - Logují všechny requesty do
apilogs - Respektují rate limity
- Vrací pouze veřejná data nebo data dle oprávnění
userdetails.phone- viditelné pouze pro adminuserdetails.address- viditelné pouze pro adminarticles.status='development'- viditelné pouze pro admincategories.isactive='development'- viditelné pouze pro admin
� 10. Products API (READ & WRITE)
API pro produkty poskytuje čtení i zápis dat. K dispozici jsou endpointy pro seznam, detail, vytvoření, aktualizaci a soft-delete produktu.
🎯 Klíčové vlastnosti Products API
✅ Kompletní data produktů včetně:
- Dynamických produktových polí (product fields)
- Hodnot parametrů (parameters)
- Obrázků s variantami
- Tagů a autorských informací
- Kategorií
✅ Flexibilní filtrování:
- Podle parametrů s operátory (eq, gte, lte, like)
- Podle produktových polí s operátory
- Podle kategorií a statusu
- Fulltextové vyhledávání
✅ Optimalizované dotazy:
- Eager loading všech vztahů
- Automatické mapování datových typů
- Podpora 15 různých value sloupců
10.1 GET /products
Popis: Načte seznam produktů s možností filtrování. Autorizace: VyžadujeAuthorization: Bearer {token} s oprávněním products:read nebo Query parametry:| Parametr | Typ | Povinný | Popis | Příklad |
|---|---|---|---|---|
status | string | Ne | Filtr podle statusu | active, development, suspend |
categoryid | integer | Ne | ID kategorie | 5 |
producttypeid | integer | Ne | ID typu produktu | 3 |
search | string | Ne | Fulltextové vyhledávání v title, subtitle, body | notebook |
page | integer | Ne | Číslo stránky pro paginaci | 2 |
perpage | integer | Ne | Počet produktů na stránku (max 100) | 20 |
filters[parameter{id}][{operator}] | mixed | Ne | Filtrování podle parametru | filters[parameter5][eq]=red |
filters[field{id}][{operator}] | mixed | Ne | Filtrování podle produktového pole | filters[field8][gte]=100 |
eq- Rovná se (=)gte- Větší nebo rovno (>=)lte- Menší nebo rovno (<=)like- Obsahuje (LIKE %value%)
Produkty s barvou "červená" (parameterid=5)
GET /api/v1/products?filters[parameter5][eq]=červená
Produkty s hmotností >= 100g (parameterid=12)
GET /api/v1/products?filters[parameter12][gte]=100
Produkty s cenou <= 999 Kč (fieldid=8)
GET /api/v1/products?filters[field8][lte]=999
Produkty obsahující "nike" v poli brand (fieldid=3)
GET /api/v1/products?filters[field3][like]=nike Kombinace filtrů
GET /api/v1/products?filters[parameter5][eq]=červená&filters[field8][lte]=999&categoryid=10
{
"success": true, "data": [ { "id": 123, "title": "Běžecké boty Nike Air Zoom", "subtitle": "Profesionální boty pro běžce", "body": "Detailní popis produktu...
", "status": "active", "publishat": "2025-12-01T10:00:00Z", "publishendat": null, "manualupdateat": "2026-01-10T14:30:00Z", "createdat": "2025-11-20T09:00:00Z", "updatedat": "2026-01-15T16:45:00Z", "siteid": 7, "producttypeid": 5, "userid": 42, "url": "http://example.com/katalog/boty/nike-air-zoom.html",
"producttype": { "id": 5, "name": "Sportovní obuv", "description": "Šablona pro sportovní obuv" },
"typefields": [ { "id": 1, "fieldname": "material", "datatype": "string", "settings": { "label": "Materiál", "helptext": "Hlavní materiál svršku" }, "isrequired": true, "sortorder": 1 }, { "id": 2, "fieldname": "size", "datatype": "enum", "settings": { "label": "Velikost", "options": ["39", "40", "41", "42", "43", "44", "45"] }, "isrequired": true, "sortorder": 2 } ],
"fieldvalues": [ { "fieldid": 1, "value": "Syntetická kůže" }, { "fieldid": 2, "value": "42" } ],
"parameters": [ { "id": 5, "name": "color", "datatype": "string", "value": "červená", "isfilterable": true, "issearchable": false }, { "id": 12, "name": "weight", "datatype": "integer", "value": 250, "isfilterable": true, "issearchable": false } ],
"articleDetail": { "id": 456, "filename": "nike-air-zoom-main.webp", "publicurl": "https://storage.googleapis.com/.../nike-air-zoom-main.webp", "alt": "Nike Air Zoom - hlavní foto", "title": "Nike Air Zoom", "order": 0, "variants": { "banner": { "id": 457, "publicurl": "https://storage.googleapis.com/.../banner/nike-air-zoom-main.webp", "width": 1500, "height": 635 }, "articleDetail": { "id": 458, "publicurl": "https://storage.googleapis.com/.../articleDetail/nike-air-zoom-main.webp", "width": 800, "height": 600 }, "galleryThumbnail": { "id": 459, "publicurl": "https://storage.googleapis.com/.../galleryThumbnail/nike-air-zoom-main.webp", "width": 300, "height": 200 } } },
"gallery": [ { "id": 789, "filename": "nike-air-zoom-side.webp", "publicurl": "https://storage.googleapis.com/.../nike-air-zoom-side.webp", "order": 1, "variants": { "gallery": { "id": 790, "publicurl": "https://storage.googleapis.com/.../gallery/nike-air-zoom-side.webp", "width": 800, "height": 600 } } } ],
"categories": [ { "id": 15, "title": "boty", "displayname": "Obuv", "url": "/katalog/boty" }, { "id": 23, "title": "bezecke-boty", "displayname": "Běžecké boty", "url": "/katalog/boty/bezecke" } ],
"tags": [ { "id": 8, "name": "běh", "slug": "beh" }, { "id": 15, "name": "nike", "slug": "nike" } ],
"author": { "id": 42, "email": "[email protected]", "details": { "fullname": "John Doe", "avatar": { "id": 123, "publicurl": "https://storage.googleapis.com/.../avatars/john.webp", "alt": "John Doe", "title": "John Doe" } } } } ], "meta": { "currentpage": 1, "perpage": 20, "total": 156, "lastpage": 8 } }
{
"success": false, "error": "Unauthorized", "message": "API token je neplatný nebo chybí", "code": 401 }
{
"success": false, "error": "Bad Request", "message": "Neplatný formát filtru", "code": 400 }
{
"success": false, "error": "Too Many Requests", "message": "Překročen limit požadavků. Zkuste to znovu za 3600 sekund", "code": 429 }
Základní request
curl -X GET "https://example.com/api/v1/products?categoryid=5&status=active" \ -H "Authorization: Bearer YOURAPITOKEN"
S filtrováním podle parametrů
curl -X GET "https://example.com/api/v1/products?filters[parameter5][eq]=červená&filters[parameter12][gte]=100" \ -H "Authorization: Bearer YOURAPITOKEN"
S fulltextovým vyhledáváním
curl -X GET "https://example.com/api/v1/products?search=nike&categoryid=10" \ -H "Authorization: Bearer YOURAPITOKEN"
S paginací
curl -X GET "https://example.com/api/v1/products?page=2&perpage=50" \ -H "Authorization: Bearer YOURAPITOKEN"
10.2 GET /products/{id}
Popis: Načte detail konkrétního produktu. Autorizace: VyžadujeAuthorization: Bearer {token} s oprávněním products:read nebo Path parametry:| Parametr | Typ | Povinný | Popis |
|---|---|---|---|
id | integer | Ano | ID produktu |
{
"success": true, "data": { "id": 123, "title": "Běžecké boty Nike Air Zoom", "subtitle": "Profesionální boty pro běžce", "body": "Detailní popis produktu s HTML formátováním...
", "status": "active", "publishat": "2025-12-01T10:00:00Z", "publishendat": null, "manualupdateat": "2026-01-10T14:30:00Z", "createdat": "2025-11-20T09:00:00Z", "updatedat": "2026-01-15T16:45:00Z", "siteid": 7, "producttypeid": 5, "userid": 42, "url": "http://example.com/katalog/boty/nike-air-zoom.html",
"producttype": { "id": 5, "name": "Sportovní obuv", "description": "Šablona pro sportovní obuv" },
"typefields": [ { "id": 1, "fieldname": "material", "datatype": "string", "settings": { "label": "Materiál", "helptext": "Hlavní materiál svršku", "maxlength": 255 }, "isrequired": true, "sortorder": 1 }, { "id": 2, "fieldname": "size", "datatype": "enum", "settings": { "label": "Velikost", "options": ["39", "40", "41", "42", "43", "44", "45"] }, "isrequired": true, "sortorder": 2 }, { "id": 3, "fieldname": "brand", "datatype": "string", "settings": { "label": "Značka", "helptext": "Výrobce produktu" }, "isrequired": false, "sortorder": 3 } ],
"fieldvalues": [ { "fieldid": 1, "value": "Syntetická kůže" }, { "fieldid": 2, "value": "42" }, { "fieldid": 3, "value": "Nike" } ],
"parameters": [ { "id": 5, "name": "color", "datatype": "string", "value": "červená", "isfilterable": true, "issearchable": false }, { "id": 12, "name": "weight", "datatype": "integer", "value": 250, "isfilterable": true, "issearchable": false }, { "id": 18, "name": "waterproof", "datatype": "boolean", "value": true, "isfilterable": true, "issearchable": false } ],
"images": { "articles": { "publicurl": "https://storage.googleapis.com/.../nike-air-zoom-main.webp", "width": 1000, "height": 486, "imagename": "nike-air-zoom-main.webp", "alt": "Nike Air Zoom - hlavní foto", "title": "Nike Air Zoom", "variants": { "articles": { "publicurl": "https://storage.googleapis.com/.../articles/nike-air-zoom-main.webp", "width": 1000, "height": 486 }, "banner": { "publicurl": "https://storage.googleapis.com/.../banner/nike-air-zoom-main.webp", "width": 1500, "height": 635 } } }, "articleDetail": { "publicurl": "https://storage.googleapis.com/.../nike-air-zoom-detail.webp", "width": 1300, "height": 530, "imagename": "nike-air-zoom-detail.webp", "alt": "Nike Air Zoom - detail produktu", "title": "Nike Air Zoom Detail", "variants": { "articleDetail": { "publicurl": "https://storage.googleapis.com/.../articleDetail/nike-air-zoom-detail.webp", "width": 1300, "height": 530 } } }, "gallery": [ { "publicurl": "https://storage.googleapis.com/.../nike-air-zoom-side.webp", "width": 500, "height": 414, "imagename": "nike-air-zoom-side.webp", "alt": "Nike Air Zoom - pohled ze strany", "title": "Pohled ze strany", "order": 1, "variants": { "gallery": { "publicurl": "https://storage.googleapis.com/.../gallery/nike-air-zoom-side.webp", "width": 1200, "height": 800 }, "galleryThumbnail": { "publicurl": "https://storage.googleapis.com/.../galleryThumbnail/nike-air-zoom-side.webp", "width": 500, "height": 414 } } }, { "publicurl": "https://storage.googleapis.com/.../nike-air-zoom-sole.webp", "width": 500, "height": 414, "imagename": "nike-air-zoom-sole.webp", "alt": "Nike Air Zoom - detail podrážky", "title": "Detail podrážky", "order": 2, "variants": { "gallery": { "publicurl": "https://storage.googleapis.com/.../gallery/nike-air-zoom-sole.webp", "width": 1200, "height": 800 }, "galleryThumbnail": { "publicurl": "https://storage.googleapis.com/.../galleryThumbnail/nike-air-zoom-sole.webp", "width": 500, "height": 414 } } } ] },
"categories": [ { "id": 15, "title": "boty", "displayname": "Obuv", "url": "/katalog/boty" }, { "id": 23, "title": "bezecke-boty", "displayname": "Běžecké boty", "url": "/katalog/boty/bezecke" } ],
"tags": [ { "id": 8, "name": "běh", "slug": "beh" }, { "id": 15, "name": "nike", "slug": "nike" }, { "id": 22, "name": "sport", "slug": "sport" } ],
"author": { "id": 42, "email": "[email protected]", "details": { "fullname": "John Doe", "bio": "Produktový manažer se zaměřením na sportovní výbavu", "avatar": { "id": 123, "publicurl": "https://storage.googleapis.com/.../avatars/john.webp", "alt": "John Doe", "title": "John Doe" } } } } }
images:images.articles: Hlavní obrázek pro seznam produktů (pochází z pivot variant:articlesnebobanner)images.articleDetail: Obrázek pro detail produktu (pochází z pivot variant:articleDetail)images.gallery: Pole galerie obrázků s polemorder(pochází z pivot variant:gallery)- Varianty obsahují pouze:
publicurl,width,height(bezid,variantname, atd.) - Vynechány jsou uživatelské ikony:
usricosmall,usricobig
{
"success": false, "error": "Not Found", "message": "Produkt s ID 123 nebyl nalezen", "code": 404 }
{
"success": false, "error": "Unauthorized", "message": "API token je neplatný nebo chybí", "code": 401 }
{
"success": false, "error": "Forbidden", "message": "Nemáte oprávnění přistupovat k tomuto produktu", "code": 403 }
curl -X GET "https://example.com/api/v1/products/123" \
-H "Authorization: Bearer YOURAPITOKEN"
10.2A POST /products
Popis: Vytvoří nový produkt pro aktuálnísiteid. Autorizace: Vyžaduje Authorization: Bearer {token} s oprávněním products:write nebo Povinná pole v request body:title(string)producttypeid(integer)
subtitle,body,status,meta,categoryids
- Vrací vytvořený produkt ve stejné struktuře jako detail (
GET /api/v1/products/{id}).
10.2B PUT /products/{id}
Popis: Aktualizuje existující produkt. Autorizace: VyžadujeAuthorization: Bearer {token} s oprávněním products:write nebo Response 200 OK:- Vrací aktualizovaný produkt ve stejné struktuře jako detail (
GET /api/v1/products/{id}).
10.2C DELETE /products/{id}
Popis: Provede soft-delete produktu (status=deleted, deletedat). Autorizace: Vyžaduje Authorization: Bearer {token} s oprávněním products:write nebo Response 200 OK:- Vrací potvrzení s
messageadeletedat.
10.3 Datové typy produktových polí a parametrů
Products API podporuje 15 datových typů pro typefields (produktová pole) a parameters:
| Data Type | Popis | Příklad hodnoty | Sloupec v DB |
|---|---|---|---|
string | Krátký text | "Nike" | valuestring |
text | Delší text | "Popis produktu..." | valuetext |
htmltext | HTML formátovaný text | " | valuehtmltext / valuetext |
integer | Celé číslo | 42 | valueinteger |
float | Desetinné číslo | 99.99 | valuefloat |
boolean | Ano/Ne hodnota | true nebo false | valueboolean |
date | Datum | "2026-01-15" | valuedate |
time | Čas | "14:30:00" | valuetime |
datetime | Datum a čas | "2026-01-15T14:30:00Z" | valuedatetime |
enum | Výběr z možností | "42" (z options: ["39","40","41","42"]) | valueenum |
url | URL adresa | "https://example.com" | valueurl |
youtubeurl | URL na YouTube | "https://youtu.be/..." | valueyoutubeurl / valueurl |
mapurl | URL mapy | "https://maps.google.com/..." | valuemapurl / valueurl |
file | Soubor (PDF, DOCX atd.) | {"fileid": 456} | valuefileid |
image | Obrázek | {"imageid": 789} | valueimageid |
- enum: Možnosti jsou definovány v
settings.optionspole typu - file: Vrací objekt s
fileid, kompletní data souboru lze získat přes Files API - image: Vrací objekt s
imageid, kompletní data obrázku jsou dostupná přes image resource - boolean: Vrací
true/false, v DB uloženo jako 1/0 - date/time/datetime: Formát ISO 8601
10.4 Implementační poznámky
Optimalizace dotazů:- Používá eager loading všech vztahů (
->with([...])) - Automatické mapování
datatypena správnývaluesloupec - Podpora whereHas() pro filtrování podle vztahů
- Filtr
filters[parameter{id}][{operator}]pro parametry - Filtr
filters[field{id}][{operator}]pro produktová pole - Operátory:
eq(=),gte(>=),lte(<=),like(LIKE %value%)
- Automatická filtrace podle
siteidz API tokenu - Pouze produkty se statusem
activejsou veřejné (ostatní jen pro admin) - Rate limiting: 1000 requestů/hodina pro read operace
- Doporučeno vytvořit composite indexy na:
- parametervalues(parameterid, contenttype, contentid) - productfieldvalues(productid, fieldid)
- Eager loading zabraňuje N+1 dotazům
10.5 Datové struktury a schémata
SimplifiedArticleResource
Zjednodušená struktura článku používaná v poli readalso v detailu článku. Obsahuje pouze základní informace potřebné pro zobrazení náhledu článku.
{
"id": 456, "title": "Název článku", "slug": "blog/nazev-clanku", "subtitle": "Podtitul článku", "shorttext": "Krátký popisek článku", "snippet": "Snippet článku", "author": { "id": 42, "email": "[email protected]", "fullname": "John Doe", "bio": "Bio autora", "jobtitle": "Senior Developer", "company": "Tech Corp", "avatar": { "usricosmall": { "id": 123, "publicurl": "https://storage.googleapis.com/.../usricosmall/avatar.webp", "width": 48, "height": 48 }, "usricobig": { "id": 124, "publicurl": "https://storage.googleapis.com/.../usricobig/avatar.webp", "width": 200, "height": 200 } }, "sociallinks": [...], "professionallinks": [...] }, "tags": [ { "id": 5, "name": "php", "slug": "tag/php" } ], "images": { "articles": { "id": 789, "filename": "article-thumb.webp", "publicurl": "https://storage.googleapis.com/.../article-thumb.webp", "alt": "Název obrázku", "title": "Název obrázku", "variants": { "articles": { "publicurl": "https://storage.googleapis.com/.../articles/thumb.webp", "width": 1000, "height": 486 }, "articleDetail": { "publicurl": "https://storage.googleapis.com/.../articleDetail/thumb.webp", "width": 1300, "height": 530 }, "galleryThumbnail": { "publicurl": "https://storage.googleapis.com/.../galleryThumbnail/thumb.webp", "width": 500, "height": 414 }, "imglistarticles": { "publicurl": "https://storage.googleapis.com/.../imglistarticles/thumb.webp", "width": 1000, "height": 486 }, "imgdetailarticleheader": { "publicurl": "https://storage.googleapis.com/.../imgdetailarticleheader/thumb.webp", "width": 1300, "height": 530 }, "imgdetailarticlepost": { "publicurl": "https://storage.googleapis.com/.../imgdetailarticlepost/thumb.webp", "width": 1920, "height": 1282 }, "imgrecentarticles": { "publicurl": "https://storage.googleapis.com/.../imgrecentarticles/thumb.webp", "width": 339, "height": 165 }, "imgrelatedpost": { "publicurl": "https://storage.googleapis.com/.../imgrelatedpost/thumb.webp", "width": 360, "height": 214 }, "imgctvercovy": { "publicurl": "https://storage.googleapis.com/.../imgctvercovy/thumb.webp", "width": 400, "height": 400 } } } } }
| Pole | SimplifiedArticle | ArticleResource |
|---|---|---|
body | ❌ Není | ✅ HTML obsah |
meta | ❌ Není | ✅ SEO + mainCatid |
files | ❌ Není | ✅ Přílohy |
parameters | ❌ Není | ✅ Custom parametry |
categories | ❌ Není | ✅ Kategorie |
images.articleDetail | ❌ Není | ✅ Detail variant |
images.gallery | ❌ Není | ✅ Galerie |
images.articles | ✅ S 9 variantami | ✅ Se všemi 17 variantami |
author | ✅ Kompletní UserDetails | ✅ Kompletní |
tags | ✅ Kompletní | ✅ Kompletní |
Z výkonnostních důvodů jsou z readalso a relatedarticles odstraněny následující varianty:
- ❌
banner,bannerl,banner2l,banner2m,banner2s(bannery pro různé rozlišení) - ❌
usricosmall,usricobig(ikony uživatelů - jsou pouze v author.avatar) - ❌
imghomebanner(homepage banner)
articles (1000×486 px) - seznam článkůarticleDetail (1300×530 px) - detail článku headergalleryThumbnail (500×414 px) - miniatury galerieimglistarticles (1000×486 px) - seznam článkůimgdetailarticleheader (1300×530 px) - detail headerimgdetailarticlepost (1920×1282 px) - detail velký obrázekimgrecentarticles (339×165 px) - nedávné článkyimgrelatedpost (360×214 px) - související příspěvkyimgctvercovy (400×400 px) - čtvercový formát- Pole
readalsov detailu článku (GET /api/v1/articles/{idOrSlug}) - Pole
relatedarticlesv detailu článku (GET /api/v1/articles/{idOrSlug}) - Maximálně 6 náhodných článků ze stejné kategorie (mainCatid) pro readalso
- Varianty optimalizovány pro rychlejší response a menší payload (~47% redukce)
�📞 Podpora
Pro dotazy k API kontaktujte:
- Email: [email protected]
- Dokumentace: https://docs.yourdomain.com/api
- Status: https://status.yourdomain.com
- GitHub Issues: https://github.com/yourdomain/api-issues
Změnový log
Verze 1.8 (23. března 2026) - E-shop Fáze 3 (kupóny)- ✅ Přidány e-shop coupon endpointy:
POST /api/v1/eshop/cart/coupon,DELETE /api/v1/eshop/cart/coupon - ✅ Přidána coupon vrstva pro košík (
eshopcoupons,eshopcouponproducts,eshopcouponredemptions) - ✅ Rozšířena cart response o
coupon,discounttotalwithvat,grandtotalwithvat - ✅ Aktualizován počet endpointů na 64 (včetně 10 e-shop endpointů)
- ✅ Přidány e-shop cart endpointy:
GET /api/v1/eshop/cart,POST /api/v1/eshop/cart/items,PATCH /api/v1/eshop/cart/items/{id},DELETE /api/v1/eshop/cart/items/{id} - ✅ Dokumentace rozšířena o požadované scope pro košík (
eshop:read,eshop:write) - ✅ Aktualizován počet endpointů na 62 (včetně 8 e-shop endpointů)
- ✅ KRITICKÁ OPRAVA #1:
bodyje VŽDY povinné (verifikováno v ArticleController.php:242) - odstraněna zavádějící poznámka o podmíněné povinnosti - ✅ KRITICKÁ OPRAVA #2:
categoryid/categoryidsfallback logika správně zdokumentována - backend vezmecategoryids[0]pokudcategoryidchybí (ArticleController.php:247-254) - ✅ KRITICKÁ OPRAVA #3: Odstraněn neexistující status
hiddenze všech příkladů a dokumentace - skutečné statusy jsoudevelopment,active,suspend,schedule(verifikováno v Article.php, Product.php, cronech) - ✅ KRITICKÁ OPRAVA #4: Tabulka všech endpointů (řádek 3889) opravena na správnou scope terminologii (
articles:writemístowrite) - ✅ KRITICKÁ OPRAVA #5: Opraven počet endpointů v přehledu - tehdejší aktuální počet byl 58 endpointů po přidání e-shop read-only API (verifikováno v index.php)
- ✅ KRITICKÁ OPRAVA #6: ProductResource používá stejné klíče obrázků jako články:
images.articleDetail,images.articles,images.gallery(verifikováno v ProductResource.php:293-333) - ✅ Přidána poznámka o 28 WebBuilder endpointech, které nejsou v této dokumentaci detailně popsány
- ✅ Označena zastaralá sekce s ENUM rozšířením pro
hidden/deletedstatusy (NEIMPLEMENTOVÁNO)
- ✅ Opravena dokumentace oprávnění (scopes) - dokumentace nově správně popisuje hierarchický scope systém
{resource}:{action}dle skutečné implementace vScopes.php - ✅ Přidán kompletní přehled scope hierarchie s příklady (ADMINALL
,articles:write,articles:read, atd.) - ✅ Vysvětlena logika kdy
:writescope automaticky zahrnuje:readpřístup - ✅ Aktualizovány všechny endpointy na správnou scope terminologii (např.
articles:writemísto původního nesprávnéhowrite) - ✅ Dokumentace ověřena proti skutečnému kódu v
ArticleController.phpaScopes.php
- ✅ Opraveny klíče pro obrázky - dokumentace nově správně používá
articleDetail,articles,gallerymísto neexistujícíchbannerimage,listimage,galleryimages - ✅ Aktualizovány všechny příklady kódu s realitou z
ArticleController.php(řádky 386-665) - ✅ Ověřeny skutečné názvy variant obrázků proti produkční implementaci
- ✅ Přidány endpointy pro produkty (seznam, detail, create, update, delete) - READ & WRITE
- ✅ Implementováno pokročilé filtrování produktů s operátory (eq, gte, lte, like)
- ✅ Filtrování podle parametrů (12 datových typů)
- ✅ Filtrování podle produktových polí (dynamická pole podle typu produktu)
- ✅ Přidána podpora pro
typefields(definice polí pro typ produktu) - ✅ Přidána podpora pro
fieldvalues(hodnoty produktových polí) - ✅ Optimalizované eager loading s podporou morfmorfních vztahů
- ✅ Automatické mapování datových typů na správné
valuesloupce - ✅ Aktualizován souhrn na 13 endpointů
- ✅ Dokumentace filtrovacích operátorů s příklady
- ✅ Přidány endpointy pro tagy (seznam, detail s články)
- ✅ Přidán endpoint pro profily uživatelů/autorů s bio, sociálními sítěmi a statistikami
- ✅ Přidán endpoint pro parametry content typů
- ✅ Rozšířena response kategorií o všechna DB pole (
ordercat,csscat,navigationid,createdat,updatedat) - ✅ Přidána podpora pro custom parametry v článcích (14 datových typů)
- ✅ Aktualizován implementační checklist
- ✅ Přidán souhrn všech 11 endpointů
- ✅ Ověřena kompatibilita s aktuální DB strukturou
- 🎉 Iniciální release
- ✅ 4 endpointy pro články
- ✅ 3 endpointy pro kategorie
- ✅ Autentizace pomocí API tokenů
- ✅ Multi-site podpora s
siteidizolací - ✅ Rate limiting
- ✅ Kompletní dokumentace
Plánované funkce (v2.0)
- [ ] POST
/api/v1/categories- Vytvoření kategorie - [ ] PUT
/api/v1/categories/{id}- Aktualizace kategorie - [ ] POST
/api/v1/tags- Vytvoření tagu - [ ] GET
/api/v1/articles/{id}/related- Související články - [ ] GET
/api/v1/stats- Statistiky API použití - [ ] WebHooks - Notifikace o změnách obsahu
- [ ] GraphQL endpoint - Alternativa k REST
- [ ] Bulk operations - Hromadné operace
11. 📝 Formuláře a Zprávy (Forms & Submissions API)
API pro práci s webovými formuláři umožňuje získat konfiguraci formuláře a zpracovat odeslání. Kombinuje veřejný endpoint pro odeslání (bez autentizace) s pokročilou anti-spam ochranou a volitelnými backend side-effecty.
11.1 Získání konfigurace formuláře
🛒 10A. E-shop Products API (READ ONLY)
Read-only e-shop API staví nad existujícím katalogem produktů a vrací pouze produkty, které jsou skutečně prodejné pro aktuální siteid.
Pravidla pro zařazení produktu do e-shop API
Produkt se vrátí pouze pokud platí vše níže:
- produkt patří do aktuálního
siteid producttypes.config.iseshopenabled = true- produkt má
status = active publishatnení v budoucnostipublishendatnení v minulosti- existuje aktivní záznam v
eshopproductprices - produkt je nákupně dostupný podle
eshopproductinventory
10A.1 GET /eshop/products
GET /api/v1/eshop/productsAutorizace: Vyžaduje Authorization: Bearer {token} s oprávněním products:read neboQuery parametry
| Parametr | Typ | Povinný | Popis |
|---|---|---|---|
page | integer | Ne | Číslo stránky (default 1) |
perpage | integer | Ne | Počet položek na stránku (default 20, max 100) |
producttypeid | integer | Ne | Filtr podle typu produktu |
categoryid | integer | Ne | Filtr podle kategorie |
search | string | Ne | Vyhledávání v title, subtitle, sku |
Response 200 OK
{
"success": true, "data": [ { "id": 458, "siteid": 7, "title": "Úhlová bruska BOSCH GWS 1000", "subtitle": "Professional 125mm", "sku": "BOSCH-GWS-1000", "status": "active", "url": "https://example.com/katalog/naradi/uhlova-bruska-bosch-gws-1000.html", "createdat": "2025-01-10T09:00:00+00:00", "updatedat": "2025-01-22T16:45:00+00:00", "producttypeid": 5, "producttype": { "id": 5, "name": "Elektrické nářadí" }, "productkind": "physical", "categories": [ { "id": 11, "title": "naradi", "displayname": "Nářadí", "url": "/katalog/naradi" } ], "pricing": { "currency": "CZK", "basepricewithoutvat": 2478.51, "basepricewithvat": 2999.00, "finalpricewithoutvat": 2313.22, "finalpricewithvat": 2799.00, "vatrate": 21, "issaleactive": true, "salefrom": "2026-03-01T00:00:00+00:00", "saleto": "2026-03-31T23:59:59+00:00" }, "inventory": { "availabilitystatus": "instock", "availablequantity": 12, "reservedquantity": 1, "minsalequantity": 1, "allowbackorder": false, "ispurchasable": true }, "variantgroupid": 3 } ], "meta": { "currentpage": 1, "perpage": 20, "total": 1, "lastpage": 1, "totalpages": 1, "from": 1, "to": 1 } }
10A.2 GET /eshop/products/{id}
GET /api/v1/eshop/products/{id}Autorizace: Vyžaduje eshop:read (kompatibilně i products:read)Parametry cesty
id(povinné, integer): ID produktu
Response 200 OK
Vrací stejnou strukturu jako list endpoint pro jednu položku.
10A.3 GET /eshop/products/{id}/variants
GET /api/v1/eshop/products/{id}/variantsAutorizace: Vyžaduje eshop:read (kompatibilně i products:read)Response 200 OK
{
"success": true, "data": { "productid": 458, "groupid": 3, "primaryproductid": 458, "variantaxes": ["color", "size"], "variants": [ { "id": 458, "sku": "BOSCH-GWS-1000-BLACK", "title": "Úhlová bruska BOSCH GWS 1000 - Black", "pricing": { "currency": "CZK", "finalpricewithvat": 2799.00 }, "inventory": { "availabilitystatus": "instock", "availablequantity": 12, "ispurchasable": true } } ] } }
Pokud produkt nepatří do variantové skupiny, endpoint vrátí groupid = null, variantaxes = [] a prázdné pole variants.
10A.4 GET /eshop/products/{id}/availability
GET /api/v1/eshop/products/{id}/availabilityAutorizace: Vyžaduje eshop:read (kompatibilně i products:read)Response 200 OK
{
"success": true, "data": { "productid": 458, "sku": "BOSCH-GWS-1000", "availabilitystatus": "instock", "availablequantity": 12, "reservedquantity": 1, "minsalequantity": 1, "allowbackorder": false, "ispurchasable": true } }
Chybové stavy
404 Not Found: produkt není prodejný pro aktuální web nebo neexistuje403 Forbidden: token nemáeshop:readani kompatibilníproducts:read
GET /api/v1/forms/{id}/configAutentizace: Bearer token required Oprávnění: forms:readParametry cesty
id(povinné, integer): ID formuláře
Response 200 OK
{
"id": 1, "formname": "Kontaktní formulář", "formfields": { "fields": [ { "slug": "fullname", "label": "Celé jméno", "type": "text", "required": true, "placeholder": "Jan Novák" }, { "slug": "email", "label": "E-mail", "type": "email", "required": true, "placeholder": "[email protected]" }, { "slug": "message", "label": "Zpráva", "type": "textarea", "required": true, "placeholder": "Vaše zpráva..." } ] }, "successmessage": "Děkujeme za vaši zprávu.", "formconfig": { "sendtouser": true, "requirerecaptcha": true, "enablehmac": false } }
ecomailfield u jednotlivých polí a formconfig.ecomailtag se v response nikdy neposílají.Caching pomocí ETag
GET /api/v1/forms/1/config
If-None-Match: "a1b2c3d4"
11.2 Odeslání formuláře
POST /api/v1/forms/{id}/submitAutentizace: Veřejný endpoint (bez tokenu) Security: 5vrstvová anti-spam ochranaBackend side-effects
- Zpráva se nejdřív uloží lokálně do databáze.
- Poté proběhne obsahová spam klasifikace (
EmailWhitelist+SpamDetector). - Pokud je ve
$SERVER['domain']vyplněnoecomailapikeyiecomaillistid, backend se pokusí synchronizovat kontakt do Ecomailu. - Synchronizace do Ecomailu je čistě backendová, fail-safe a nikdy nemění HTTP response submitu.
- Submit označený jako spam neodesílá admin/user emaily a nespouští Ecomail sync.
Request Body
{
"hpfield": "", "formopenedat": 1705320000, "g-recaptcha-response": "03AGdBq25...", "fullname": "Jan Novák", "email": "[email protected]", "message": "Dobrý den..." }
Povinná bezpečnostní pole
| Pole | Typ | Popis |
|---|---|---|
hpfield | string | Honeypot - musí být prázdný |
formopenedat | integer | Unix timestamp (1-3600s před odesláním) |
g-recaptcha-response | string | reCAPTCHA token |
5vrstvá ochrana
| Vrstva | Mechanismus | Chyba |
|---|---|---|
| 1️⃣ | Rate Limiting (10/min/IP) | 429 |
| 2️⃣ | Honeypot (hpfield="") | 400 |
| 3️⃣ | Timestamp (1-3600s) | 400 |
| 4️⃣ | reCAPTCHA (score > 0.5) | 400 |
| 5️⃣ | HMAC (optional) | 403 |
Příklad JavaScript
import { useState } from 'react';
function ContactForm() { const [formOpenedAt] = useState(Math.floor(Date.now() / 1000));
const handleSubmit = async (e) => { e.preventDefault();
const formData = { hpfield: '', formopenedat: formOpenedAt, 'g-recaptcha-response': await getRecaptchaToken(), fullname: e.target.fullname.value, email: e.target.email.value, message: e.target.message.value };
const response = await fetch('/api/v1/forms/1/submit', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(formData) });
if (response.ok) { const result = await response.json(); alert(result.message); } };
return ( ); }
11.3 CORS konfigurace
Whitelist v siteconfigurations:{
"formallowedorigins": { "value": ["https://lovable.app", "https://app.lovable.dev"] } }
- Whitelist nakonfigurován + origin match → Allow
- Whitelist nakonfigurován + origin mismatch → 403 Forbidden
- Whitelist nenakonfigurován → Allow all (fallback)
11.4 Implementační checklist
Frontend:- [ ] Získat API token s
forms:read - [ ] Načíst konfiguraci GET
/forms/{id}/config - [ ] Implementovat honeypot (skrytý, prázdný)
- [ ] Uložit timestamp při načtení
- [ ] Integrovat reCAPTCHA
- [ ] Zpracovat RFC 7807 chyby
- [ ] Vytvořit formulář v admin panelu
- [ ] Nastavit
adminemails - [ ] Nakonfigurovat reCAPTCHA klíče
- [ ] Volitelně:
formallowedoriginswhitelist - [ ] Otestovat rate limiting
Konec specifikace API v2.2
12. User Portal API (v2.3)
12.1 Přehled
User portál je samostatná vrstva oddělená od admin API. Umožňuje přihlášeným uživatelům spravovat vlastní obsah (články, produkty, média), komunikovat (žádosti, komentáře, recenze) a sledovat historii akcí.
Autentizace: stejná jako ostatní endpointy – Bearer token nebo session cookie. Module gating: každý endpoint vyžaduje, aby byl příslušný modul na daném webu povolen(sitemodules tabulka). Pokud modul chybí, API vrátí 403 Forbidden (RFC 7807).
userid == jeho UID(výjimka: admin scope ).
12.2 Scopes (oprávnění)
| Scope | Popis |
|---|---|
user:profile:read | Čtení vlastního profilu |
user:profile:write | Zápis profilu, změna hesla |
user:media:read | Čtení vlastních médií |
user:media:write | Nahrávání / smazání médií |
user:notifications:read | Čtení notifikací |
user:notifications:write | Označení přečteno |
user:requests:read | Čtení žádostí |
user:requests:write | Vytvoření žádosti |
user:comments:read | Čtení komentářů |
user:comments:write | Vytvoření / smazání komentáře |
user:reviews:read | Čtení recenzí |
user:reviews:write | Vytvoření / editace / smazání recenze |
user:articles:read | Čtení vlastních článků |
user:articles:write | CRUD vlastních článků |
user:products:read | Čtení vlastních produktů |
user:products:write | CRUD vlastních produktů |
user:eshop:read | Moje objednávky (zákazník) |
user:seller:read | Objednávky k mým produktům (prodejce) |
user:history:read | Přehled auditního logu |
12.3 Endpointy – Profil a účet
GET /api/v1/user/me
Vrátí profil přihlášeného uživatele.
Scopes:user:profile:readPUT /api/v1/user/me
Aktualizace profilu (firstname, lastname, phone, bio, website).
Scopes:user:profile:writePUT /api/v1/user/me/password
Změna hesla. Vyžaduje currentpassword, newpassword, newpasswordconfirm.
user:profile:writeGET /api/v1/user/me/roles
Role a oprávnění uživatele na aktuálním webu.
Scopes:user:profile:readGET /api/v1/user/me/modules
Povolené moduly pro daný web + tarif.
Scopes:user:profile:read12.4 Endpointy – Notifikace
GET /api/v1/user/notifications
Seznam notifikací. Filtry: ?type=system|content|eshop, ?unread=1, ?page, ?limit.
user:notifications:read | Modul: notificationsPOST /api/v1/user/notifications/read
Označení notifikací jako přečtené. Body: {"id": 5} nebo {"all": true}.
user:notifications:write | Modul: notifications12.5 Endpointy – Články
Modul:articles| Metoda | Endpoint | Popis |
|---|---|---|
| GET | /api/v1/user/articles | Seznam vlastních článků |
| POST | /api/v1/user/articles | Vytvoření článku (status: development) |
| GET | /api/v1/user/articles/{id} | Detail vlastního článku |
| PUT | /api/v1/user/articles/{id} | Editace vlastního článku |
| DELETE | /api/v1/user/articles/{id} | Soft-delete článku |
?page, ?limit, ?status, ?sort, ?dir POST/PUT fields: title (povinný), body, subtitle, shorttext, snippet, categoryid nebo categoryids, volitelně status (development/active/schedule/suspend), tagids, parameters nebo parametervalues12.6 Endpointy – Produkty
Modul:catalogproducts| Metoda | Endpoint | Popis |
|---|---|---|
| GET | /api/v1/user/products | Seznam vlastních produktů |
| POST | /api/v1/user/products | Vytvoření produktu |
| GET | /api/v1/user/products/{id} | Detail produktu |
| PUT | /api/v1/user/products/{id} | Editace produktu |
| DELETE | /api/v1/user/products/{id} | Soft-delete produktu |
title, producttypeid, categoryid nebo categoryids12.7 Endpointy – Média
Modul:media| Metoda | Endpoint | Popis |
|---|---|---|
| GET | /api/v1/user/media | Seznam vlastních souborů |
| POST | /api/v1/user/media | Upload souboru (přes UploadedFile pipeline) |
| GET | /api/v1/user/media/{id} | Detail souboru |
| DELETE | /api/v1/user/media/{id} | Soft-delete souboru |
12.8 Endpointy – Žádosti, komentáře, recenze
Modul:requestsmessages (žádosti) / commentsreviews (komentáře, recenze)| Metoda | Endpoint | Popis |
|---|---|---|
| GET | /api/v1/user/requests | Moje žádosti |
| POST | /api/v1/user/requests | Nová žádost (subject + body) |
| GET | /api/v1/user/requests/{id} | Detail žádosti |
| GET | /api/v1/user/comments | Moje komentáře |
| POST | /api/v1/user/comments | Nový komentář (entitytype, entityid, body) |
| DELETE | /api/v1/user/comments/{id} | Smazání komentáře |
| GET | /api/v1/user/reviews | Moje recenze |
| POST | /api/v1/user/reviews | Nová recenze (entitytype, entityid, rating 1–5) |
| PUT | /api/v1/user/reviews/{id} | Editace recenze |
| DELETE | /api/v1/user/reviews/{id} | Smazání recenze |
12.9 Endpointy – E-shop BASIC
Modul customer:eshopcustomer | Modul seller: eshopseller| Metoda | Endpoint | Popis |
|---|---|---|
| GET | /api/v1/user/orders | Moje objednávky jako zákazník |
| GET | /api/v1/user/orders/{id} | Detail objednávky (items + addresses + events) |
| GET | /api/v1/user/seller/orders | Objednávky s mými produkty (prodejce) |
| GET | /api/v1/user/seller/orders/{id} | Detail – pouze moje items v dané objednávce |
12.9.1 Endpointy – E-shop ADVANCED
Modul customer:eshopcustomer (LEVEL ADVANCED) | Modul seller: eshopseller (LEVEL ADVANCED)| Metoda | Endpoint | Popis |
|---|---|---|
| GET | /api/v1/user/orders/{id}/tracking | Timeline trackingu objednávky (status + shipment události) |
| POST | /api/v1/user/orders/{id}/repeat | Zopakování objednávky do aktivního košíku |
| GET | /api/v1/user/seller/orders/{id}/events | Kompletní timeline událostí objednávky pro prodejce |
| POST | /api/v1/user/seller/orders/{id}/status | Změna stavu objednávky prodejcem |
| POST | /api/v1/user/seller/orders/{id}/tracking | Přidání tracking události pro zásilku |
| POST | /api/v1/user/seller/orders/{id}/message | Interní/customer message pro objednávku |
| GET | /api/v1/user/seller/complaints | Reklamace k produktům přihlášeného prodejce |
| GET | /api/v1/user/seller/complaints/{id} | Detail reklamace k produktu prodejce |
| POST | /api/v1/user/seller/complaints/{id}/status | Aktualizace stavu reklamace prodejcem |
12.10 Endpointy – Historie akcí
GET /api/v1/user/history
Auditní log vlastních akcí. Filtry: ?page, ?limit, ?sort, ?dir.
user:history:read | Modul: audithistory12.11 Module gating – tabulka modulů
| Klíč modulu | Ovlivněné endpointy |
|---|---|
coreaccount | /user/me, /user/me/password, /user/me/roles, /user/me/modules |
notifications | /user/notifications |
articles | /user/articles/ |
catalogproducts | /user/products/ |
media | /user/media/ |
eshopcustomer | /user/orders, /user/orders/{id}/tracking, /user/orders/{id}/repeat |
eshopseller | /user/seller/orders, /user/seller/orders/{id}/events, /user/seller/orders/{id}/status, /user/seller/orders/{id}/tracking, /user/seller/orders/{id}/message, /user/seller/complaints |
commentsreviews | /user/comments/, /user/reviews/ |
requestsmessages | /user/requests/ |
audithistory | /user/history |
OFF (zakázáno, vrátí 403) / BASIC / ADVANCED12.12 Web rozhraní (server-side Twig)
| URL | Šablona | Popis |
|---|---|---|
| GET /user/dashboard | user-portal/dashboard.twig | Přehled účtu |
| GET /user/profile | user-portal/profile.twig | Editace profilu + hesla |
| GET /user/roles | user-portal/roles.twig | Přehled rolí a modulů |
| GET /user/notifications | user-portal/notifications.twig | Notifikace |
| GET /user/articles | user-portal/articles.twig | Seznam článků |
| GET /user/articles/new | user-portal/article-edit.twig | Nový článek |
| GET /user/articles/{id}/edit | user-portal/article-edit.twig | Editace článku |
| GET /user/products | user-portal/products.twig | Seznam produktů |
| GET /user/products/{id}/edit | user-portal/product-edit.twig | Editace produktu |
| GET /user/media | user-portal/media.twig | Galerie médií |
| GET /user/requests | user-portal/requests.twig | Žádosti + formulář |
| GET /user/comments | user-portal/comments.twig | Komentáře |
| GET /user/reviews | user-portal/reviews.twig | Recenze |
| GET /user/history | user-portal/history.twig | Auditní log |
Všechny web stránky vyžadují aktivní session (redirect na /admin/login/ pokud nepřihlášen).
12.13 AJAX endpointy – User Portal (v2.3)
Tyto endpointy jsou volány JavaScriptem z user portal stránek pro dynamické funkce. Všechny vyžadují aktivní session a vrací JSON odpovědi.
GET /user/articles/search-tags
Vyhledávání štítků pro tagování článků.
Parametry:?q=searchquery (minimálně 2 znaky) Odpověď: {"success": true, "tags": [{"id": 1, "title": "název štítku", "displayname": "Zobrazovaný název"}]} Cache: File-based cache s TTL 5 minut, automatická invalidace při změně štítků Rate limit: 10 požadavků/minutu na uživateleGET /user/articles/search-content
Vyhledávání souvisejícího obsahu (články + produkty) pro propojení.
Parametry:?q=searchquery (minimálně 2 znaky) Odpověď: {"success": true, "results": [{"id": 1, "title": "název", "type": "article|product", "url": "/url"}]} Cache: File-based cache s TTL 5 minut Rate limit: 10 požadavků/minutu na uživatele Cache chování:- Cache soubory jsou uloženy v
www/cache/search.json - Klíč cache:
tagssearch{siteId}{md5(query)}nebocontentsearch{siteId}{md5(query)} - TTL: 300 sekund (5 minut)
- Invalidace: Automatická při
Tag::syncTags()nebo ruční při změně obsahu - Fallback: Pokud cache selže, endpoint funguje bez cache
Konec specifikace API v2.3 – User Portal rozšíření
QR Payment Support v Articles API
Přehled
QR payment je volitelná funkce, která umožňuje zobrazit QR kód pro snadnou platbu na články. QR payment data jsou součástí detailu článku jako volitelný blok qrpayment.
QR Payment Response
V odpovědi GET /api/v1/articles/{id} je přidán blok qrpayment:
{
"success": true, "data": { "id": 132, "title": "Název článku", ... "qrpayment": { "mode": "author|general|none", "vs": "1234567890", "text": "Přispěj na podporu", "amounts": [50, 100, 200, 500], "qrurl": "/qr-payment?articleid=132&amount=100" } } }
QR Payment Pole
| Pole | Typ | Popis |
|---|---|---|
mode | string | Režim platby: "author" (IBAN autora), "general" (redakční IBAN), "none" (vypnuto) |
vs | string | Variabilní symbol pro platbu (generován při každé aktivaci) |
text | string | Text z konfigurace (qrpaymenttextauthor nebo qrpaymenttexteditorial) |
amounts | array | Pole doporučených částek [50, 100, 200, 500] |
qrurl | string | URL adresa QR obrázku pro dané množství |
Konfigurace
QR payment se konfiguruje v siteconfigurations:
| Klíč | Typ | Příklad | Popis |
|---|---|---|---|
qrpaymentdefaultmode | string | author | Výchozí režim: author, general, none |
qrpaymentiban | string | CZ1234567890 | IBAN pro redakční platby (general režim) |
qrpaymentamounts | json | [50,100,200,500] | Pole doporučených částek |
qrpaymentmsg | string | Příspěvek na provoz | Zpráva pro QR (volitelný text) |
qrpaymenttextauthor | string | Podpořte autora | Text pro režim author |
qrpaymenttexteditorial | string | Přispěj na provoz | Text pro režim general |
Podmínky
- QR payment se vrací jen když je web na tarifi ENTERPRISE s modulem
CMS Articlesúrovně ADVANCED - Pokud
mode="none", blokqrpaymentvracínull - Pokud se služba nezdaří, vrací se
null(silent fail) - QR payment je vždy READ ONLY ve veřejném API
Tags API Specification
Přehled
Tags API poskytuje přístup k systému štítků (tagů) v CMS s podporou kategorií, obrázků a filtrování.
GET /api/v1/tags
Vrátí seznam všech štítků s paginací a filtrováním.
Oprávnění
- Token musí mít scope:
tags:read
Query Parameters
| Parametr | Typ | Výchozí | Popis |
|---|---|---|---|
page | integer | 1 | Číslo stránky pro paginaci |
perpage | integer | 20 | Počet štítků na stránku (max. 100) |
search | string | - | Hledaný text v názvu štítku |
categoryid | integer | - | Filtrování podle ID kategorie štítku |
sort | string | title | Řazení: title, popular, newest |
Request Example
GET /api/v1/tags?page=1&perpage=10&categoryid=5&search=web
Authorization: Bearer YOURAPITOKEN
Response (Success - 200 OK)
{
"success": true, "data": [ { "id": 13, "name": "PHP", "slug": "tag/php", "status": "active", "categories": [], "articlescount": 42, "productscount": 8 }, { "id": 14, "name": "Web Development", "slug": "tag/web-development", "status": "active", "categories": [ { "id": 1, "title": "Technology", "displayname": "Technologie" } ], "articlescount": 125, "productscount": 15 } ], "meta": { "pagination": { "currentpage": 1, "perpage": 10, "totalpages": 5, "totalcount": 42 } } }
GET /api/v1/tags/{id}
Vrátí detail konkrétního štítku.
Oprávnění
- Token musí mít scope:
tags:read
URL Parameters
| Parametr | Typ | Popis |
|---|---|---|
id | integer | ID štítku |
Request Example
GET /api/v1/tags/13
Authorization: Bearer YOURAPITOKEN
Response (Success - 200 OK)
{
"success": true, "data": { "id": 13, "name": "PHP", "slug": "tag/php", "status": "active", "categories": [ { "id": 1, "title": "Technology", "displayname": "Technologie" } ], "articlescount": 42, "productscount": 8, "relatedtags": [ { "id": 5, "name": "Laravel", "slug": "tag/laravel" }, { "id": 12, "name": "Symfony", "slug": "tag/symfony" } ] } }
GET /api/v1/tag-categories
Vrátí seznam všech kategorií štítků.
Oprávnění
- Token musí mít scope:
tags:read
Request Example
GET /api/v1/tag-categories
Authorization: Bearer YOURAPITOKEN
Response (Success - 200 OK)
{
"success": true, "data": [ { "id": 1, "title": "Technology", "displayname": "Technologie", "isdefault": true, "order": 1 }, { "id": 2, "title": "Business", "displayname": "Byznys", "is_default": false, "order": 2 } ], "meta": { "total": 2 } }
Chybové kódy
| Kód | Popis |
|---|---|
| 401 | Chybný token, vypršel nebo nemá patřičný scope tags:read |
| 403 | Nedostatečná oprávnění |
| 404 | Štítek nebo kategorie neexistuje |
Konec specifikace API v3.2 – Tags & QR Payment rozšíření*