ReČeK · Registr čísel knih · API pro nakladatele
Založení titulu, produktu a přidělení ISBN přes API
Návod pro externí systém nakladatele (ERP, redakční systém). Popisuje, jak se přihlásit, jak načíst číselníky, najít nebo založit autora, nahrát obálku, založit titul a produkt a nakonec produktu přidělit ISBN nebo ISMN z rozsahu nakladatele.
Úvod a konvence
Všechna volání jdou přes API gateway na jednu adresu. V příkladech se používají tři proměnné prostředí, které si nastavíte jednou:
export BASE_URL="{{BASE_URL}}" # adresa API gateway, např. https://api.example.cz
export TENANT="{{TENANT}}" # identifikátor tenanta, lokálně "tritius"
export TOKEN="…" # access token z přihlášení (kapitola 1)
Na lokálním testovacím prostředí platí BASE_URL=http://localhost:8000 a TENANT=tritius. Hodnoty pro testovací a produkční prostředí vám sdělí agentura.
- Cesty jsou bez prefixu modulu – volá se přímo
$BASE_URL/titles,$BASE_URL/productsatd. - Tělo požadavků i odpovědí je JSON v UTF-8 (
Content-Type: application/json), kromě nahrání obálky (multipart). - Identifikátory jsou UUID. Data vydání se zadávají jako text
RRRR,MM.RRRRneboDD.MM.RRRR. - ID z ukázek (UUID) pocházejí z testovacího prostředí. ID číselníkových položek se mezi prostředími mohou lišit – vždy je načtěte z API (kapitola 3), nekódujte je napevno.
- Seznamové endpointy vrací
{"items":[…],"totalRecords":N}a berou parametryquery(CQL),offsetalimit.
Referenční dokumentace (Swagger)
Úplná schémata všech endpointů a objektů najdete ve veřejném Swagger UI: recek-swagger.tritius.cz. Tento dokument je průvodce postupem – schémata neopakuje, ale doplňuje, co Swagger neříká: pořadí volání, skutečně povinná pole a reálné chybové odpovědi.
| Specifikace | Obsah | Soubor |
|---|---|---|
agency-1.3.171 | tituly, produkty, čísla, osoby, číselníky, obálky, prefixy | agency-1.3.171.json |
login-keycloak-3.0.0 | přihlášení, obnova tokenu, odhlášení | login-keycloak-3.0.0.json |
users-1.2.95 | přihlášený uživatel, výběr organizace | users-1.2.95.json |
publishers-1.4.97 | evidence nakladatelů, potvrzení údajů | publishers-1.4.97.json |
U každého endpointu v tomto dokumentu je odkaz Swagger · specifikace · operace ↗. Swagger UI se otevírá s jinou výchozí specifikací: v horní liště vyberte uvedenou specifikaci (Select a definition) a operaci najděte podle jejího názvu.
Swagger označuje jako povinné jen Title.owner, Product.title, ProductNumberAssignRequest.productId + publisherId, NaturalPerson.legalForm a TitleSupportingResource.link + type + mode. Skutečná validace se liší:
- Titul: navíc právě jeden hlavní název (
names[].type.value = "01") s vyplněnýmname; u autorůsequenceNumber, jméno a buďperson, nebounnamedPerson; u nakladatelůrole. - Produkt: navíc
title.version,title.owner.id,primaryContentType,form,composition,publishingStatus; u rozsahuunit, u cenycurrency. - Obálka:
linkoznačený jako povinný při nahraném souboru posílat nemusíte – server ho odvodí zestorageKey. - Číselníkové položky: Swagger je popisuje jako celý objekt; ve skutečnosti stačí, ale musí být,
id+value+version.
Podrobně v tabulkách polí u titulu, produktu a čísla produktu.
Přehled workflow
Pořadí kroků odpovídá tomu, co dělá webové rozhraní nakladatelského portálu. Kroky s přerušovaným kroužkem jsou potřeba jen někdy.
- PřihlášeníPOST /authn/login-with-expiryAccess token (platí 1 h) a refresh token (24 h).
- Zjištění vlastního nakladateleGET /br-users/_self → GET /agency-publishers/by-source-id/{sourceId}Výsledné
idje vlastník titulu (owner.id). - Kontrola předpokladů pro ISBNGET /product-numbers/assign/feasibility/{titleId} · POST /publishers/{id}/confirmData · POST /publisher-prefixes/{id}/last-used-numberPotvrzení údajů nakladatele (1× ročně) a prohlášení o posledním použitém čísle nového prefixu.
- Načtení číselníkůGET /onix-codetable-items?query=onixCodetable.number==NJazyk (74), role autora (17), typ názvu (15), forma produktu (150)… Stačí jednou a uložit do cache.
- Autor: najít, případně založitGET /persons/search-options · POST /natural-personsAutor se na titul napojí přes
titleContributions[].person.id. - Nahrání obálkyPOST /storage/uploadJPEG do 5 MB, vrátí
storageKey. - Založení tituluPOST /titlesNázev, jazyk, autoři, nakladatel, místo vydání, obálka.
- Založení produktu a přidělení číslaPOST /products/create-with-number nebo POST /products → /product-numbers/assign/preview → /product-numbers/assignVazba, brožura, e-kniha… Každý produkt dostane vlastní ISBN.
1. Přihlášení
Přihlašujete se jménem a heslem uživatele, který má v organizaci nakladatele roli Garant nakladatele (PublisherGuarantor). Doporučujeme pro integraci založit samostatný účet (např. erp@nakladatelstvi.cz), aby šlo změny v systému odlišit od práce lidí. Roli přiděluje správce nakladatele (PublisherAdmin) v modulu Uživatelé nebo agentura.
Získání tokenu ověřeno
folioAccessToken a folioRefreshToken.curl -s -c cookies.txt -X POST "$BASE_URL/authn/login-with-expiry" \
-H "x-okapi-tenant: $TENANT" \
-H "Content-Type: application/json" \
-d '{"username":"erp@nakladatelstvi.cz","password":"***"}'
Odpověď 201 Created:
Set-Cookie: folioAccessToken=eyJhbGciOiJSU…; Path=/; Max-Age=3600; Secure; HttpOnly; SameSite=None
Set-Cookie: folioRefreshToken=eyJhbGciOiJIU…; Path=/authn; Max-Age=86400; Secure; HttpOnly; SameSite=None
{"accessTokenExpiration":"2026-09-23T13:55:36Z","refreshTokenExpiration":"2026-09-24T12:55:36Z"}
Hodnota cookie folioAccessToken je access token (JWT). Z cookie souboru ho získáte např. takto:
export TOKEN=$(awk '$6=="folioAccessToken"{print $7}' cookies.txt)
curl -s -X POST "$BASE_URL/authn/login" \
-H "x-okapi-tenant: $TENANT" -H "Content-Type: application/json" \
-d '{"username":"erp@nakladatelstvi.cz","password":"***"}'
HTTP/1.1 201 Created
x-okapi-token: eyJhbGciOiJSU…
Set-Cookie: folioAccessToken=…; Set-Cookie: folioRefreshToken=…
{"okapiToken":"eyJhbGciOiJSU…","refreshToken":"eyJhbGciOiJIU…"}
Chybové odpovědi přihlášení
| Situace | HTTP | Tělo (zkráceno) |
|---|---|---|
| Špatné jméno nebo heslo | 400 | {"errors":[{"message":"Failed to obtain a token","type":"ServiceException","code":"service_error","parameters":[{"key":"cause","value":"… invalid_grant … Invalid user credentials"}]}]} |
Chybí hlavička x-okapi-tenant | 404 | {"message":"no Route matched with those values"} |
Hlavičky dalších volání ověřeno
Každé další volání musí nést tenanta a access token. Token lze předat kterýmkoli z těchto tří způsobů (všechny ověřeny):
| Hlavička | Hodnota | Poznámka |
|---|---|---|
| x-okapi-tenant | $TENANT | Vždy povinná. Bez ní gateway odpoví 404 „no Route matched“. |
| x-okapi-token | $TOKEN | Doporučeno pro serverové integrace. |
| Authorization | Bearer $TOKEN | Alternativa k x-okapi-token. |
| Cookie | folioAccessToken=$TOKEN | Alternativa (např. curl -b cookies.txt). |
| Content-Type | application/json | U volání s JSON tělem. |
Příklady v dalších kapitolách proto začínají takto:
H=(-H "x-okapi-tenant: $TENANT" -H "x-okapi-token: $TOKEN" -H "Content-Type: application/json")
| Situace | HTTP | Tělo |
|---|---|---|
| Chybí nebo neplatný / prošlý token | 401 | {"errors":[{"type":"UnauthorizedException","code":"authorization_error","message":"Unauthorized"}],"total_records":1} |
| Endpoint, na který role Garant nemá oprávnění | 403 | {"errors":[{"type":"ForbiddenException","code":"authorization_error","message":"Access Denied"}],"total_records":1} |
Obnova tokenu a odhlášení ověřeno
Access token platí 1 hodinu, refresh token 24 hodin. Před vypršením access tokenu (čas je v accessTokenExpiration) zavolejte refresh s cookie folioRefreshToken. Pokud vyprší i refresh token, přihlaste se znovu.
curl -s -b cookies.txt -c cookies.txt -X POST "$BASE_URL/authn/refresh" -H "x-okapi-tenant: $TENANT"
# nebo s refresh tokenem z /authn/login:
curl -s -c cookies.txt -X POST "$BASE_URL/authn/refresh" -H "x-okapi-tenant: $TENANT" \
-b "folioRefreshToken=$REFRESH_TOKEN"
HTTP/1.1 201 Created
Set-Cookie: folioAccessToken=…; Max-Age=3600 …
Set-Cookie: folioRefreshToken=…; Path=/authn …
{"accessTokenExpiration":"2026-09-23T13:55:53Z","refreshTokenExpiration":"2026-09-24T12:55:47Z"}
Bez cookie vrací refresh 400 "Required cookie 'folioRefreshToken' … is not present". Odhlášení (zneplatnění refresh tokenu): POST /authn/logout se stejnou cookie → 204.
2. Nakladatel a prefix
Garant jedná vždy za svou aktivní organizaci (nakladatele). Server podle ní kontroluje, že zakládá a upravuje jen tituly a produkty vlastního nakladatele.
Aktivní organizace ověřeno
curl -s "$BASE_URL/br-users/_self" "${H[@]}"
Odpověď 200 (pole permissions vynecháno)
{
"user": {
"username": "api-test-garant@example.cz",
"id": "d0c44300-0000-4000-8000-000000000443",
"shouldChangePassword": false,
"personal": { "firstName": "API", "lastName": "Testovací garant", "email": "api-test-garant@example.cz" }
},
"userOrganizations": [
{ "id": "5b87074c-7496-4f9f-992a-8b017fc85c4d", "name": "Concordia", "source": "PUBLISHERS",
"sourceId": "e545de53-1e28-4e6c-b419-7ecf534b9604", "archived": false, "adminResolved": true, "version": 0 }
],
"activeOrganization": {
"id": "5b87074c-7496-4f9f-992a-8b017fc85c4d", "name": "Concordia", "source": "PUBLISHERS",
"sourceId": "e545de53-1e28-4e6c-b419-7ecf534b9604", "archived": false, "adminResolved": true, "version": 0
},
"activeRoles": [ "PublisherGuarantor" ],
"tenant": "tritius"
}Důležité je activeOrganization.sourceId – identifikátor nakladatele v evidenci nakladatelů. Musí platit activeRoles obsahuje PublisherGuarantor.
Je-li účet členem více organizací, vyberte aktivní organizaci (volba se uloží k účtu):
curl -s -X POST "$BASE_URL/br-users/select-organization" "${H[@]}" \
-d '{"organizationId":"5b87074c-7496-4f9f-992a-8b017fc85c4d"}' # userOrganizations[].id
Odpověď 200 má stejný tvar jako /br-users/_self.
ID nakladatele pro tituly ověřeno
Tituly a produkty neodkazují na sourceId, ale na záznam nakladatele v modulu agentury. Jeho id získáte takto:
curl -s "$BASE_URL/agency-publishers/by-source-id/e545de53-1e28-4e6c-b419-7ecf534b9604" "${H[@]}"
{
"id": "482788d9-8db9-40a4-b6b8-3b33c9560bb4", ← použijte jako owner.id a titlePublishers[].publisher.id
"sourceId": "e545de53-1e28-4e6c-b419-7ecf534b9604",
"name": "Concordia",
"status": "ACTIVE",
"dataConfirmationTime": "2007-08-23T22:00:00Z", ← starší než 1 rok = nelze přidělit ISBN
"publisherType": "COMMON",
"registrations": [ { "registrationAgency": "ISBN", "registrationIntent": "CONTINUOUS", "registrationTime": "1990-05-15T22:00:00Z" } ],
"municipality": "Praha",
…
}
Toto id se nemění – stačí ho zjistit jednou a uložit do konfigurace integrace.
Prefixy nakladatele ověřeno
curl -s -G "$BASE_URL/publisher-prefixes" "${H[@]}" \
--data-urlencode 'query=publisher.id==482788d9-8db9-40a4-b6b8-3b33c9560bb4'
Odpověď 200 (zkráceno)
{
"totalRecords": 3,
"items": [
{ "id": "f3be7602-…", "value": "900124", "status": "CLOSED", "declarationStatus": "NOT_REQUIRED", … },
{ "id": "66328734-…", "value": "901389", "status": "CLOSED", "declarationStatus": "NOT_REQUIRED", … },
{ "id": "0c271993-b753-43ef-a1fc-7b43480a1d6a",
"value": "85997",
"status": "ACTIVE",
"declarationStatus": "PENDING",
"publisherPrefixRange": {
"magnitude": 2, "status": "ACTIVE",
"agencyPrefix": { "value": "80", "internationalPrefix": { "agency": "ISBN", "value": "978" } }
} }
]
}Plný prefix je 978-80-85997 (mezinárodní prefix – prefix agentury – prefix nakladatele). Čísla se přidělují jen z prefixů ve stavu ACTIVE. magnitude je počet číslic pořadového čísla (1 = blok 10 čísel, 2 = 100, 3 = 1000).
Předpoklady pro přidělení ISBN/ISMN
Založit titul a produkt jde vždy. Aby šlo produktu přidělit číslo, musí nakladatel splnit tyto podmínky. Nejrychleji je ověříte voláním feasibility – vrátí konkrétní důvod.
| Podmínka | Důvod ve feasibility | Jak ji splnit |
|---|---|---|
| Nakladatel není ukončen | PUBLISHER_CLOSED | Kontaktujte agenturu. |
| Údaje nakladatele potvrzeny v posledních 12 měsících | DATA_NOT_CONFIRMED | Potvrzení údajů – viz níže. |
| U nového prefixu je podáno prohlášení o posledním použitém čísle | DECLARATION_PENDING | Prohlášení – viz níže. |
| Nakladatel je registrován u agentury (ISBN, pro noty ISMN) | NO_AGENCY_PREFIX | Registrace u agentury. |
| V aktivních prefixech zbývají volná čísla | NO_AVAILABLE_NUMBERS | Požádejte o nový prefix (případně needsNewPrefix, viz kap. 8). |
Potvrzení údajů nakladatele z kódu
{sourceId} = activeOrganization.sourceId. Nastaví datum potvrzení na „teď“; údaje by měl nejprve zkontrolovat člověk (v portálu nebo přes GET /publishers/{sourceId}).curl -s -X POST "$BASE_URL/publishers/e545de53-1e28-4e6c-b419-7ecf534b9604/confirmData" "${H[@]}"
# → 200 OK
Modul evidence nakladatelů nebyl v testovacím prostředí přes gateway dostupný (chyba prostředí). Popis vychází ze specifikace modulu (publishers.yml) a z chování portálu. Dokud údaje potvrzeny nejsou, feasibility vrací DATA_NOT_CONFIRMED a assign 422 "The publisher data confirmation is missing or older than one year" (typ -16) – to ověřeno je.
Prohlášení o posledním použitém čísle ověřeno
Prefix ve stavu declarationStatus: "PENDING" (typicky převzatý prefix, ze kterého nakladatel už čísla používal mimo registr) je zablokovaný, dokud nakladatel neprohlásí, jaké číslo použil jako poslední. Všechna čísla až po toto číslo se tím zablokují, přidělování pokračuje dalším.
curl -s -X POST "$BASE_URL/publisher-prefixes/0c271993-b753-43ef-a1fc-7b43480a1d6a/last-used-number" "${H[@]}" \
-d '{"noNumberUsed": false, "lastUsedNumber": "978-80-85997-45-3"}'
# pokud z prefixu dosud žádné číslo použito nebylo:
# -d '{"noNumberUsed": true}'
| Pole | Typ | Povinné | Poznámka |
|---|---|---|---|
| noNumberUsed | boolean | ano | true = z prefixu nebylo použito žádné číslo; pak lastUsedNumber musí být prázdné (jinak 422 -53). |
| lastUsedNumber | string | při noNumberUsed=false | Celé ISBN/ISMN s pomlčkami nebo bez; musí mít platnou kontrolní číslici (422 -53) a patřit do prefixu (422 -54). |
Odpověď 200 (zkráceno)
{
"publisherPrefix": {
"id": "0c271993-b753-43ef-a1fc-7b43480a1d6a", "value": "85997", "status": "ACTIVE",
"declarationStatus": "DECLARED", "lastUsedNumber": "9788085997453", "noNumberUsed": false, …
},
"blockedCount": 5,
"alreadyBlockedCount": 0,
"createdCount": 0,
"skippedAssignedCount": 41
}Chyba 422 {"errors":[{"message":"lastUsedNumber must be empty when noNumberUsed is true","type":"-53","code":"VALIDATION_ERROR"}]}. Prohlásit lze jen vlastní prefix ve stavu PENDING, jinak 403 (-56).
3. Číselníky ONIX ověřeno
Většina kódovaných polí (typ názvu, jazyk, role autora, forma produktu, měna…) odkazuje na položky číselníků podle standardu ONIX for Books. Číselníky smí číst každý přihlášený uživatel.
Jak číselníky načíst
onixCodetableItems). Filtr: query=number==74 nebo query=name=="Jazyky".# všechny jazyky (číselník 74), seřazené jako v portálu
curl -s -G "$BASE_URL/onix-codetable-items" "${H[@]}" \
--data-urlencode 'query=onixCodetable.number==74 sortBy sortOrder value' \
--data-urlencode 'limit=1000'
# jedna konkrétní položka: čeština
curl -s -G "$BASE_URL/onix-codetable-items" "${H[@]}" \
--data-urlencode 'query=onixCodetable.number==74 and value==cze'
{
"items": [
{ "id": "99828aa9-bb9c-42e6-9dc6-dc7ca4583a21",
"onixCodetable": { "id": "9e3c308d-4c53-4d6c-9392-f8bb0e32529b", "number": 74, "name": "Jazyky", "version": 0 },
"value": "cze",
"description": "čeština",
"version": 0 }
],
"totalRecords": 1
}
Číselník jazyků má 569 položek (kódy ISO 639-2/B, např. cze, slo, eng, ger). Výchozí limit je 1000.
Co se posílá do pole s číselníkem
id, value i version
Kódované pole je objekt položky číselníku. Server ho páruje podle id, validace ale čte value a databázová vrstva vyžaduje version. Nejjednodušší je vložit objekt položky tak, jak ho vrátilo API.
"language": { "id": "99828aa9-bb9c-42e6-9dc6-dc7ca4583a21", "value": "cze", "version": 0 }
| Co pošlete | Výsledek (ověřeno) |
|---|---|
{"id","value","version"} | 201 – správně |
jen {"id"} u typu názvu | 422 -58 „…exactly one main title … none was provided“ – zavádějící, validace nevidí value |
{"id","value"} bez version | 400 s textovou (ne-JSON) zprávou Detached entity … has an uninitialized version value 'null' |
jen {"value"} bez id | 500 TransientPropertyValueException … OnixCodetableItem |
Číselníky, které budete potřebovat
| Číslo | Název | Pole v API | Typické hodnoty |
|---|---|---|---|
| 15 | Typ názvu | titles.names[].type | 01 hlavní název (právě jeden povinný), 03 název v původním jazyce |
| 22 | Jazyk vzhledem k typu obsahu | titles.languages[].role | 01 jazyk textu, 02 původní jazyk překladu |
| 74 | Jazyky | titles.languages[].language, textContents[].language | cze čeština, slo, eng, ger |
| 17 | Typ autorské role | titleContributions[].roles[].role | A01 autor, A12 ilustrátor, B06 překladatel |
| 19 | Typ nepojmenované osoby | titleContributions[].unnamedPerson | 02 anonymní, 04 kolektiv |
| 45 | Nakladatelské role | titlePublishers[].role | 01 nakladatel, 02 spoluvydavatel |
| 28 | Cílová skupina | audiences[].type | 01 obecné/dospělí, 02 děti |
| 153 | Typ textu | textContents[].type | 02 krátká anotace, 03 popis |
| 158 | Typ obsahu podle zdroje | supportingResources[].type | 01 přední strana obálky, 02 zadní strana |
| 159 | Medium | supportingResources[].mode | 03 obrázek |
| 27 | Rejstřík předmětových klasifikací | subjects[].scheme | Thema, MDT, klíčová slova |
| 81 | Typ obsahu produktu | products.primaryContentType | 10 text, 11 notový zápis (→ ISMN) |
| 150 | Formát produktu | products.form | BB vázaná, BC brožovaná, EA e-kniha, AC audio CD |
| 175 | Detaily formátu | products.formDetails[].value | E101 EPUB, E107 PDF |
| 2 | Složení produktu | products.composition | 00 jednosložkový |
| 64 | Stav publikování | products.publishingStatus | 02 připravuje se, 04 aktivní; 01 zrušeno a 03 odloženo = nelze přidělit číslo |
| 23 | Rozsah vzhledem k typu obsahu | products.extents[].type | 06 celkový počet stran |
| 24 | Jednotky rozsahu | products.extents[].unit | 03 strany |
| 58 | Typy cen | products.price.type | 02 maloobchodní cena vč. daně |
| 96 | Měny | products.price.currency | CZK, EUR |
| 51 | Souvislosti mezi produkty | products.productsRelations[].relationType | vazby mezi produkty |
Číselníky se mění zřídka – načtěte je při startu integrace a mapujte si svůj kód (např. „cze“) na objekt položky.
4. Autor
Autoři (a další tvůrci – ilustrátoři, překladatelé) jsou osoby ze společné autoritní databáze. Nejprve zkuste existující osobu najít; novou zakládejte, jen když ji nenajdete. Nově založená osoba má stav PROPOSAL a agentura ji propojí s národní autoritou.
Vyhledání existující osoby ověřeno
nameFilter hledá ve jméně i příjmení bez ohledu na diakritiku (celé jméno „Karel Čapek“ i část „Čapek“). legalForm: NATURAL = fyzická osoba, LEGAL = korporace. Volitelně sourceIdFilter = ID národní autority.curl -s -G "$BASE_URL/persons/search-options" "${H[@]}" \
--data-urlencode 'nameFilter=Karel Čapek' --data-urlencode 'legalForm=NATURAL' --data-urlencode 'limit=5'
[
{ "id": "…", "legalForm": "NATURAL", "firstName": "Karel Matěj", "lastName": "Čapek Chod", "birthDate": "1860", … },
{ "id": "…", "legalForm": "NATURAL", "firstName": "Karel", "lastName": "Čapek", "birthDate": "1890",
"deathDate": "1938", "biographicalNote": "…", "sourceId": "jk01021023" },
…
]
Odpověď je pole (bez obálky items). Rozlišujte osoby podle birthDate, deathDate a biographicalNote. Pro stránkovaný seznam s identifikátory (ISNI, ORCID) lze použít GET /persons?nameFilter=…&identifierFilter=…&offset=0&limit=20 → {"items":[…],"totalRecords":N}.
Založení nové fyzické osoby ověřeno
curl -s -X POST "$BASE_URL/natural-persons" "${H[@]}" -d '{
"legalForm": "NATURAL",
"firstName": "Jana",
"lastName": "Testovací-Autorka",
"birthDate": "1980",
"biographicalNote": "Česká autorka knih pro děti.",
"disclosureConsent": true
}'
Odpověď 201:
{
"id": "00a3b2ab-47bc-4f11-a106-e6c5988501bb", ← použijte v titleContributions[].person.id
"legalForm": "NATURAL",
"status": "PROPOSAL",
"firstName": "Jana",
"lastName": "Testovací-Autorka",
"birthDate": "1980",
"biographicalNote": "Česká autorka knih pro děti.",
"disclosureConsent": true,
"proposer": { "id": "482788d9-8db9-40a4-b6b8-3b33c9560bb4", "name": "Concordia", … },
"version": 0
}
| Pole | Typ | Povinné | Poznámka |
|---|---|---|---|
| legalForm | string | ano (server) | Vždy "NATURAL". Bez něj 400 missing type id property 'legalForm'. |
| firstName | string | ano (portál) | Server to nekontroluje, ale osoba bez jména je nepoužitelná. |
| lastName | string | ano (portál) | Totéž. |
| birthDate / deathDate | string | ne | RRRR, MM.RRRR nebo DD.MM.RRRR; ne v budoucnosti. |
| disclosureConsent | boolean | ano (portál) | Souhlas se zveřejněním údajů; portál vyžaduje true, pokud není vyplněno datum úmrtí. |
| biographicalNote | string | ne | Krátký životopis. |
| identifiers[] | pole | ne | {"type":"ISNI"|"ORCID","identifier":"…"}; formát se kontroluje (422 -27), duplicita 422 -26. |
| naturalAlternativeNames[] | pole | ne | Pseudonymy, jiné podoby jména: {"firstName","lastName"}. |
Korporaci (např. autorský kolektiv, studio) založíte přes POST /legal-persons s tělem {"legalForm":"LEGAL","name":"…"} → 201 ověřeno.
Vlastní dosud nepotvrzené osoby lze opravit (PUT /natural-persons/{id}) nebo smazat (DELETE /natural-persons/{id} → 204, pokud nejsou použité).
Napojení autora na titul
Autor se k titulu přidává v poli titleContributions přímo při založení nebo úpravě titulu (samostatný endpoint neexistuje). Jméno se kopíruje z osoby do příspěvku – musí být vyplněno i při odkazu na osobu.
"titleContributions": [
{ "sequenceNumber": 1,
"person": { "id": "00a3b2ab-47bc-4f11-a106-e6c5988501bb", "legalForm": "NATURAL" },
"firstName": "Jana",
"lastName": "Testovací-Autorka",
"roles": [ { "role": { "id": "244aa3d3-f195-45c1-8aaf-88769f830b6c", "value": "A01", "version": 0 } } ] }
]
| Pole | Povinné | Pravidlo / chyba |
|---|---|---|
| sequenceNumber | ano | Pořadí 1, 2, 3… Bez něj 400 null value in column "sequence_number". |
| person.id | buď – nebo | Přesně jedno z person / unnamedPerson (č. 19); jinak 422 -31. |
| firstName / lastName / name | ano | Aspoň jedno z firstName, lastName, name (korporace) nebo unnamedPerson; jinak 422 -30. |
| roles[].role | ano (portál) | Aspoň jedna role z číselníku 17. Server příspěvek bez role přijme, portál ne. |
| biographicalNote | ne | Poznámka k autorovi v rámci titulu. |
HTTP 422
{"errors":[
{"message":"Title contribution #1 must have at least one of: firstName, lastName, name, or unnamedPerson","type":"-30","code":"VALIDATION_ERROR"},
{"message":"Title contribution #2 must have exactly one of person or unnamedPerson, not both or neither","type":"-31","code":"VALIDATION_ERROR"}]}
5. Obálka ověřeno
Obálka se nahraje jako soubor a pak se k titulu přidá jako doprovodný zdroj (supportingResources). Nahrát ji lze před založením titulu i kdykoli později.
Nahrání souboru
file. Pouze image/jpeg, max. 5 MB. Nenastavujte ručně Content-Type: application/json.curl -s -X POST "$BASE_URL/storage/upload" \
-H "x-okapi-tenant: $TENANT" -H "x-okapi-token: $TOKEN" \
-F "file=@obalka.jpg;type=image/jpeg"
{
"storageKey": "3acf0c5b-850b-4b3d-9a2c-be7a86f1d61f.jpg",
"publicUrl": "{{BASE_URL}}/storage/content/3acf0c5b-850b-4b3d-9a2c-be7a86f1d61f.jpg",
"mimeType": "image/jpeg",
"fileSize": 903
}
| Situace | HTTP | message |
|---|---|---|
| Jiný typ než JPEG (PNG, PDF…) | 400 | Only image/jpeg is supported |
Chybí pole file | 400 | Required part 'file' is not present. |
| Prázdný soubor / větší než 5 MB | 400 / 413 | File is empty / File exceeds 5242880 bytes z kódu |
| Úložiště na serveru není nastaveno | 503 | Storage is not configured on this server… – ohlaste agentuře |
Navázání na titul
Do titulu vložte položku supportingResources se storageKey z uploadu. Odkaz (link) doplní server sám.
"supportingResources": [
{ "type": { "id": "c95fe1c3-3d95-4fd0-8e51-5a82522cfd10", "value": "01", "version": 0 }, ← 158: přední strana obálky
"mode": { "id": "289d847e-1cff-4a3b-a0cd-d702c24a94bb", "value": "03", "version": 0 }, ← 159: obrázek
"storageKey": "3acf0c5b-850b-4b3d-9a2c-be7a86f1d61f.jpg",
"mimeType": "image/jpeg",
"fileSize": 903 }
]
| Pole | Povinné | Poznámka |
|---|---|---|
| type | ano | Číselník 158. Portál zobrazuje jako obálku položku s 01 a mode 03. |
| mode | ano | Číselník 159. Bez něj 400 null value in column "mode_id". |
| storageKey | ano pro nahraný soubor | Z odpovědi /storage/upload. |
| link | ano pro externí URL | Místo storageKey lze uvést vlastní veřejnou http(s) adresu obrázku. |
| mimeType, fileSize | ne | Doporučeno převzít z uploadu. |
Doplnění obálky k existujícímu titulu: načtěte titul (GET /titles/{id}), přidejte položku do supportingResources a pošlete celý titul zpět přes PUT /titles/{id} → 204 ověřeno. PUT nahrazuje celý titul, proto posílejte i stávající obálky – vynechaná položka se z titulu odebere (odebraný soubor server archivuje).
6. Titul ověřeno
Titul je dílo v konkrétním vydání (název, autoři, jazyk, vydání). Jednotlivé formy – vázaná kniha, brožura, e-kniha – jsou jeho produkty a každý dostane vlastní ISBN.
id vnořených položek, hlavička Location: /titles/{id}.curl -s -X POST "$BASE_URL/titles" "${H[@]}" -d @titul.json
titul.json – kompletní ověřený příklad
{
"owner": { "id": "482788d9-8db9-40a4-b6b8-3b33c9560bb4" },
"ownerId": "ERP-2026-0443",
"names": [
{ "type": { "id": "660e4af8-7688-4323-befa-1434928b0106", "value": "01", "version": 0 },
"name": "Jak se API učilo číst",
"subtitle": "Příběh pro malé i velké integrátory" }
],
"editionNumber": 1,
"languages": [
{ "role": { "id": "f4e862e7-ad8a-4f2f-b631-47b2a35d3b1a", "value": "01", "version": 0 },
"language": { "id": "99828aa9-bb9c-42e6-9dc6-dc7ca4583a21", "value": "cze", "version": 0 } }
],
"titleContributions": [
{ "sequenceNumber": 1,
"person": { "id": "00a3b2ab-47bc-4f11-a106-e6c5988501bb", "legalForm": "NATURAL" },
"firstName": "Jana",
"lastName": "Testovací-Autorka",
"roles": [ { "role": { "id": "244aa3d3-f195-45c1-8aaf-88769f830b6c", "value": "A01", "version": 0 } } ] }
],
"titlePublishers": [
{ "publisher": { "id": "482788d9-8db9-40a4-b6b8-3b33c9560bb4" },
"role": { "id": "e66966a3-90eb-4320-95b9-a0beb768600b", "value": "01", "version": 0 } }
],
"publicationPlaces": [ { "city": "Praha" } ],
"audiences": [ { "type": { "id": "1508d530-5511-4da5-9f6a-a918292562e7", "value": "02", "version": 0 } } ],
"textContents": [
{ "type": { "id": "36ea10a4-ffbc-40a3-9efe-4cc9998689dc", "value": "02", "version": 0 },
"text": "Krátká anotace titulu.",
"language": { "id": "99828aa9-bb9c-42e6-9dc6-dc7ca4583a21", "value": "cze", "version": 0 } }
],
"supportingResources": [
{ "type": { "id": "c95fe1c3-3d95-4fd0-8e51-5a82522cfd10", "value": "01", "version": 0 },
"mode": { "id": "289d847e-1cff-4a3b-a0cd-d702c24a94bb", "value": "03", "version": 0 },
"storageKey": "3acf0c5b-850b-4b3d-9a2c-be7a86f1d61f.jpg",
"mimeType": "image/jpeg", "fileSize": 903 }
]
}Odpověď 201 (zkráceno)
{
"id": "9403e266-9a92-4da9-9f97-682390007411",
"owner": { "id": "482788d9-8db9-40a4-b6b8-3b33c9560bb4", "name": "Concordia", … },
"ownerId": "ERP-2026-0443",
"names": [ { "id": "34ad8d4c-…", "type": { "id": "660e4af8-…", "value": "01", "description": "Hlavní název dokumentu (knihy)…", "version": 0 },
"name": "Jak se API učilo číst", "subtitle": "Příběh pro malé i velké integrátory" } ],
"editionNumber": 1,
"languages": [ { "id": "8333383b-…", "role": { "value": "01", "description": "Jazyk textu", … },
"language": { "value": "cze", "description": "čeština", … } } ],
"titleContributions": [ { "id": "da8fb972-…", "sequenceNumber": 1,
"person": { "id": "00a3b2ab-…", "legalForm": "NATURAL", "status": "PROPOSAL", … },
"firstName": "Jana", "lastName": "Testovací-Autorka",
"roles": [ { "id": "e16f45d1-…", "role": { "value": "A01", "description": "Autor", … } } ] } ],
"supportingResources": [ { "id": "201bc40a-…", "type": { "value": "01", … }, "mode": { "value": "03", … },
"link": "{{BASE_URL}}/storage/content/3acf0c5b-850b-4b3d-9a2c-be7a86f1d61f.jpg",
"storageKey": "3acf0c5b-850b-4b3d-9a2c-be7a86f1d61f.jpg", "mimeType": "image/jpeg", "fileSize": 903 } ],
"ownerUnresolved": false,
"version": 0
}Pole titulu
Sloupec Povinné: server = bez pole API vrátí chybu; portál = server pole nevynucuje, ale webový formulář ho vyžaduje a agentura s ním počítá – posílejte ho.
| Pole | Typ | Povinné | Číselník | Poznámka |
|---|---|---|---|---|
| owner.id | UUID | server | – | ID vlastního nakladatele (kap. 2). Chybí nebo je cizí → 403 -28. |
| ownerId | string | ne | – | Vaše vlastní ID titulu (z ERP). Podle něj titul později dohledáte. |
| names[] | pole | server | – | Právě jeden název s type.value = "01"; jinak 422 -58. |
| names[].type | položka | server | 15 | Viz formát položky. |
| names[].name | string | server | – | Text názvu. Bez něj 500 „Could not commit JPA transaction“. |
| names[].subtitle, partNumber, partName, prefix, titleWithoutPrefix | string | ne | – | Podnázev, číslo a název části, člen (např. „The“). |
| languages[] | pole | portál | – | Aspoň jeden jazyk. Server titul bez jazyka přijme. |
| languages[].role | položka | portál | 22 | 01 jazyk textu. Server přijme i bez role. |
| languages[].language | položka | portál | 74 | cze čeština. |
| titleContributions[] | pole | ne | 17, 19 | Autoři – pravidla viz kapitola 4. |
| titlePublishers[] | pole | portál | – | Aspoň vlastní nakladatel s rolí 01. Portál ho předvyplní. |
| titlePublishers[].publisher.id | UUID | server* | – | *Pokud je uveden publisher, musí mít id. |
| titlePublishers[].role | položka | server | 45 | Bez role 500 „Could not commit JPA transaction“. |
| publicationPlaces[].city | string | portál | – | Aspoň jedno místo vydání (portál předvyplní obec sídla). |
| editionNumber | integer | ne | – | Pořadí vydání, ≥ 1. |
| editionStatement | string | ne | – | Údaj o vydání („2., upravené vydání“). |
| textContents[] | pole | ne | 153, 74 | Anotace; každá položka potřebuje type a text. |
| supportingResources[] | pole | ne | 158, 159 | Obálky – viz kapitola 5. |
| audiences[].type | položka | ne | 28 | Cílová skupina. |
| subjects[] | pole | ne | 27, 93xx | scheme povinné; u Thema a MDT i code, u klíčových slov text. |
| titleCollections[] | pole | ne | – | Edice/řada: {"collection":{"id":…},"partNumber":"…"}. |
| ageFrom, ageTo | integer | ne | – | 0–99, ageFrom ≤ ageTo. |
| doi | string | ne | – | Tvar https://doi.org/10.xxxx/…. |
| illustrationsNote, imprint | string | ne | – | Poznámka k ilustracím, imprint. |
| commentForAgency | string | ne | – | Vzkaz pro agenturu; při neprázdné hodnotě jde agentuře e-mail. |
| version | integer | při PUT | – | Optimistický zámek, viz níže. Při POST se ignoruje. |
Úprava titulu
version. Odpověď 204 bez těla.curl -s "$BASE_URL/titles/$TITLE_ID" "${H[@]}" > titul-aktualni.json
jq '.editionStatement = "1. vydání"' titul-aktualni.json > titul-upraveny.json
curl -s -X PUT "$BASE_URL/titles/$TITLE_ID" "${H[@]}" -d @titul-upraveny.json # → 204
Pokud mezitím titul změnil někdo jiný (nebo posíláte starou version), vrátí server 409:
{"errors":[{"message":"Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [Title#9403e266-…]","type":"-1","code":"VALIDATION_ERROR"}]}
Řešení: titul znovu načtěte, změnu aplikujte a pošlete znovu. Po každém úspěšném PUT se version zvýší o 1. Titul s produkty nelze smazat (TITLE_HAS_PRODUCTS, -44).
7. Produkt ověřeno
Produkt je konkrétní forma titulu – vázaná kniha, brožura, e-kniha v EPUB, audiokniha. ISBN se přiděluje produktu. Produkt lze založit samostatně (POST /products) nebo rovnou s číslem (POST /products/create-with-number, kapitola 8B) – tělo produktu je v obou případech stejné.
curl -s -X POST "$BASE_URL/products" "${H[@]}" -d @produkt.json
produkt.json – ověřený příklad (vázaná kniha)
{
"title": { "id": "9403e266-9a92-4da9-9f97-682390007411", "version": 1,
"owner": { "id": "482788d9-8db9-40a4-b6b8-3b33c9560bb4" } },
"ownerId": "ERP-2026-0443-V",
"primaryContentType": { "id": "8b83a3f8-9b80-4014-9256-08b1c7599d74", "value": "10", "version": 0 },
"form": { "id": "09f49c35-a228-4c01-871a-528df0524481", "value": "BB", "version": 0 },
"composition": { "id": "af3594a3-589f-4080-8f31-e30d6797a349", "value": "00", "version": 0 },
"publishingStatus": { "id": "238186fd-1d62-4cd9-9dc9-db1539a49761", "value": "02", "version": 0 },
"publishingDate": "11.2026",
"unitMeasures": { "height": 240, "width": 170, "thickness": 12, "weight": 450 },
"extents": [
{ "type": { "id": "9edc8d2b-3731-45bf-b214-2596e398efb1", "value": "06", "version": 0 },
"value": 128,
"unit": { "id": "8dd20a95-b47b-49ab-9417-97c7d51dffb0", "value": "03", "version": 0 } }
],
"price": {
"type": { "id": "48bbe7b3-0ecf-4ccb-be27-b745f9bb8250", "value": "02", "version": 0 },
"amount": 34900,
"currency": { "id": "d2f3b181-e6da-470c-a45f-86a434030033", "value": "CZK", "version": 0 }
}
}Odpověď 201 obsahuje celý produkt, mimo jiné "id": "554599d0-71c2-4c42-9f24-b747cdea217d", "accessibility": "PRIVATE" a "version": 0.
Pole produktu
| Pole | Typ | Povinné | Číselník | Poznámka |
|---|---|---|---|---|
| title.id | UUID | server | – | Titul, ke kterému produkt patří. |
| title.version | integer | server | – | Aktuální verze titulu (z GET /titles/{id}). Bez ní 400 Detached entity … Title.version. |
| title.owner.id | UUID | server | – | ID vlastního nakladatele; bez něj 403 -25. Nejjednodušší je poslat celý titul z GET. |
| primaryContentType | položka | server | 81 | 10 text → ISBN; 11 notový zápis → ISMN. Všechny produkty titulu musí mít stejný (jinak 422 -52). |
| form | položka | server | 150 | Forma produktu. |
| composition | položka | server | 2 | Obvykle 00 jednosložkový. |
| publishingStatus | položka | server | 64 | Pro přidělení čísla nesmí být 01 (zrušeno) ani 03 (odloženo). |
| publishingDate | string | pro zveřejnění | – | RRRR, MM.RRRR nebo DD.MM.RRRR. Bez data nelze produkt zveřejnit (422 -36). |
| ownerId | string | ne | – | Vaše ID produktu (z ERP). |
| formDetails[].value | položka | ne | 175 | U e-knih formát souboru, např. E101 EPUB. |
| extents[] | pole | ne | 23, 24 | Každá položka potřebuje type, číselné value a unit (bez unit 500 unit is marked non-null). |
| price | objekt | ne | 58, 96 | Pokud je uveden, potřebuje type, amount a currency. amount je celé číslo v haléřích (349,00 Kč = 34900). |
| unitMeasures, cartonMeasures, palletMeasures | objekt | ne | – | height, width, thickness v mm, weight v g. |
| copyrightFrom, copyrightTo | string | ne | – | Roky copyrightu. |
| productsRelations[] | pole | ne | 51 | {"relationType":…,"relatedProductId":"…"}. |
| accessibility | string | ne | – | Výchozí PRIVATE. Zveřejnění: PATCH /products/{id}/accessibility s {"accessibility":"PUBLIC"} z kódu. |
| version | integer | při PUT | – | Optimistický zámek, stejně jako u titulu. |
Když chybí primaryContentType, form, composition nebo publishingStatus, server v této verzi neodpoví 422, ale 500 se zprávou "primaryContentType is marked non-null but is null" (resp. form …). Kontrolujte tato pole před odesláním.
Formu produktu vybírejte podle typu obsahu: pro text (10) formy B* (tištěné), E* (elektronické) a D*. Úprava produktu: GET /products/{id} → změna → PUT /products/{id} (204), 409 při staré verzi.
8. Číslo produktu (ISBN/ISMN)
Číslo se přiděluje automaticky z aktivního prefixu nakladatele – další volné číslo v pořadí. Jsou dvě cesty:
A: krok za krokem
Produkt už existuje. feasibility → preview (rezervuje číslo) → assign. Hodí se, když chcete číslo před potvrzením ukázat uživateli.
B: jedním voláním
POST /products/create-with-number založí produkt a rovnou mu přidělí číslo. Pro integrace nejjednodušší.
A: přidělení z rozsahu krok za krokem ověřeno
1. Lze číslo přidělit?
primaryContentType = value z číselníku 81 (určuje ISBN vs. ISMN).curl -s "$BASE_URL/product-numbers/assign/feasibility/$TITLE_ID?primaryContentType=10" "${H[@]}"
Skutečné odpovědi v pořadí, jak nakladatel postupně plnil podmínky:
{"canAssign":false,"agency":"ISBN","needsNewPrefix":false,"reason":"DATA_NOT_CONFIRMED","prefixes":[]}
{"canAssign":false,"agency":"ISBN","needsNewPrefix":false,"reason":"DECLARATION_PENDING","prefixes":[]}
{"canAssign":true,"agency":"ISBN","needsNewPrefix":false,
"prefixes":[{"publisherPrefixId":"0c271993-b753-43ef-a1fc-7b43480a1d6a","label":"978-80-85997"}]}
| Pole | Význam |
|---|---|
| canAssign | true = číslo lze přidělit. |
| agency | ISBN nebo ISMN. |
| prefixes[] | Použitelné prefixy; label lze poslat jako publisherPrefix. |
| needsNewPrefix | true = nakladatel nemá aktivní prefix; při přidělení je nutné poslat magnitude (1 = 10 čísel, 2 = 100, 3 = 1000) a vznikne nový prefix. |
| reason | PUBLISHER_CLOSED, DATA_NOT_CONFIRMED, DECLARATION_PENDING, NO_AGENCY_PREFIX, NO_AVAILABLE_NUMBERS – viz předpoklady. |
2. Náhled a rezervace čísla
selected: true). Nepotvrzená rezervace se uvolní automaticky po 24 hodinách.curl -s -X POST "$BASE_URL/product-numbers/assign/preview" "${H[@]}" -d '{
"productId": "554599d0-71c2-4c42-9f24-b747cdea217d",
"publisherId": "482788d9-8db9-40a4-b6b8-3b33c9560bb4",
"publisherPrefix": "978-80-85997"
}'
Odpověď 200 (zkráceno)
{
"publisherName": "Concordia",
"publisherId": "482788d9-8db9-40a4-b6b8-3b33c9560bb4",
"title": "Jana Testovací-Autorka: Jak se API učilo číst",
"product": "Text, Vázaná kniha",
"productId": "554599d0-71c2-4c42-9f24-b747cdea217d",
"agency": "ISBN",
"internationalPrefix": { "value": "978", … },
"agencyPrefix": { "id": "ec96fdc3-826f-4eab-8e81-f89a872ceb42", "value": "80" },
"publisherPrefix": { "id": "0c271993-b753-43ef-a1fc-7b43480a1d6a", "value": "85997", "status": "ACTIVE" },
"createNewPublisherPrefix": false,
"publisherPrefixValue": "85997",
"assignedValue": "ISBN 978-80-85997-46-0",
"productNumber": {
"id": "84fc435b-3e54-48e4-b982-c7fd63423bab",
"value": "9788085997460",
"formattedValue": "978-80-85997-46-0",
"fullFormattedValue": "ISBN 978-80-85997-46-0",
"selected": true,
"assigned": false
},
"ready": true
}3. Přidělení
productNumberId z preview – přidělí se právě rezervované číslo.curl -s -X POST "$BASE_URL/product-numbers/assign" "${H[@]}" -d '{
"productId": "554599d0-71c2-4c42-9f24-b747cdea217d",
"publisherId": "482788d9-8db9-40a4-b6b8-3b33c9560bb4",
"publisherPrefix": "978-80-85997",
"productNumberId": "84fc435b-3e54-48e4-b982-c7fd63423bab"
}'
{
"id": "84fc435b-3e54-48e4-b982-c7fd63423bab",
"value": "9788085997460",
"formattedValue": "978-80-85997-46-0",
"fullFormattedValue": "ISBN 978-80-85997-46-0",
"assigned": true,
"selected": false,
"blocked": false,
"publisher": { "id": "482788d9-…", "name": "Concordia", … },
"product": { "id": "554599d0-…", … },
"version": 2
}
| Pole požadavku | Typ | Povinné | Poznámka |
|---|---|---|---|
| productId | UUID | ano | Produkt vlastního nakladatele (jinak 403 -25). |
| publisherId | UUID | ano | ID vlastního nakladatele. |
| publisherPrefix | string | ne | Prefix, ze kterého brát číslo: 978-80-85997, 80-85997 nebo 85997. Bez něj server vybere sám (nejdřív prefix s nejméně volnými čísly). |
| publisherPrefixId | UUID | ne | Totéž jako interní ID (z feasibility.prefixes[]); má přednost před publisherPrefix. |
| productNumberId | UUID | doporučeno | ID rezervovaného čísla z preview. |
| magnitude | integer | jen při needsNewPrefix | 1 / 2 / 3 = nový prefix pro 10 / 100 / 1000 čísel. |
Druhé přidělení témuž produktu vrací 422 {"errors":[{"message":"Product already has an assigned ISBN/ISMN number","type":"-29","code":"VALIDATION_ERROR"}]}. Stav produktu kdykoli zjistíte přes GET /product-numbers/assign/{productId}/by-product-id – pro produkt s číslem vrací "assignBlockedReason":"PRODUCT_ALREADY_HAS_ASSIGNED_NUMBER", "assignedValue":"ISBN 978-80-85997-46-0". ověřeno
Endpoint POST /product-numbers/{id}/deselect vrací roli Garant 403. Pokud rezervované číslo nepoužijete, uvolní se samo do 24 hodin. Proto volejte preview až ve chvíli, kdy chcete číslo opravdu přidělit, nebo použijte cestu B.
B: produkt s číslem jedním voláním ověřeno
curl -s -X POST "$BASE_URL/products/create-with-number" "${H[@]}" -d '{
"product": { …stejné tělo jako POST /products… },
"assignProductNumber": true,
"publisherPrefix": "978-80-85997"
}'
HTTP 201
{
"product": { "id": "68fab90d-9a17-4fe2-a5d4-027e30ee1353", "ownerId": "ERP-2026-0443-B", "form": { "value": "BC", … }, … },
"productNumber": {
"id": "a4b9fa59-34b4-40d3-be13-3f470967bd49",
"value": "9788085997477",
"fullFormattedValue": "ISBN 978-80-85997-47-7",
"assigned": true, …
},
"needsPublisherPrefix": false,
"reason": null
}
| Pole požadavku | Typ | Povinné | Poznámka |
|---|---|---|---|
| product | objekt | ano | Produkt – pole a pravidla viz kapitola 7. |
| assignProductNumber | boolean | ano | true = přidělit číslo. Výchozí false – pak se jen založí produkt. |
| publisherPrefix / publisherPrefixId | string / UUID | ne | Jako u assign. Bez obou server vybere aktivní prefix sám (ověřeno – e-kniha dostala 978-80-85997-48-4). |
| magnitude | integer | jen bez prefixu | Nemá-li nakladatel aktivní prefix: 1/2/3 = založit nový prefix pro 10/100/1000 čísel. Bez něj se číslo nepřidělí a vrátí se needsPublisherPrefix: true. |
Když se číslo nepřidělí
Odpověď je stále 201 a produkt existuje. productNumber je null a reason říká proč:
| reason | needsPublisherPrefix | Co udělat |
|---|---|---|
null | true | Nakladatel nemá aktivní prefix nebo volná čísla – pošlete magnitude, nebo kontaktujte agenturu. |
PUBLISHER_PREFIX_VALUE_NOT_FOUND ověřeno | true | publisherPrefix nepatří nakladateli – opravte hodnotu. |
INVALID_PUBLISHER_PREFIX_SELECTION | true | Zvolený prefix nelze použít (uzavřený, cizí). |
DATA_NOT_CONFIRMED | true | Potvrďte údaje nakladatele. |
DECLARATION_PENDING | true | Podejte prohlášení o posledním čísle. |
PUBLISHER_CLOSED | true | Kontaktujte agenturu. |
PRODUCT_STATUS_NOT_ASSIGNABLE ověřeno | false | Stav publikování je 01 nebo 03 – číslo nelze přidělit. |
Po odstranění příčiny přidělte číslo již založenému produktu cestou A (preview → assign) – nevolejte create-with-number znovu, vznikl by duplicitní produkt.
9. Dohledání vlastních záznamů ověřeno
Seznamy vracejí jen záznamy vlastního nakladatele. Filtruje se jazykem CQL v parametru query.
# titul podle vašeho ERP identifikátoru
curl -s -G "$BASE_URL/titles" "${H[@]}" --data-urlencode 'query=ownerId==ERP-2026-0443'
# produkty titulu
curl -s -G "$BASE_URL/products" "${H[@]}" --data-urlencode "query=title.id==$TITLE_ID"
# čísla přidělená produktům titulu
curl -s "$BASE_URL/product-numbers/by-title/$TITLE_ID" "${H[@]}"
{"items":[{"id":"84fc435b-…","fullFormattedValue":"ISBN 978-80-85997-46-0","assigned":true,"product":{"id":"554599d0-…"}}],"totalRecords":1}
Titul jiného nakladatele vrací 403 "Title not owned by guarantor's publisher" (-28).
10. Chyby a časté problémy
Formát chyb
Chyby aplikace mají tvar {"errors":[{"message","type","code"}]}. type je stabilní číselný kód chyby (záporné číslo jako text), message je anglický popis pro vývojáře. Jedna odpověď může obsahovat více chyb.
{"errors":[{"message":"A title must have exactly one main title (title type code 01), but none was provided","type":"-58","code":"VALIDATION_ERROR"}]}
Chyby gateway a oprávnění (401, 403 „Access Denied“) mají tvar {"errors":[{"type","code","message"}],"total_records":1}. Některé technické chyby (400/500 z databázové vrstvy) vrací tělo {"timestamp","status","error","message","path"} nebo prostý text.
HTTP stavy
| HTTP | Význam | Co dělat |
|---|---|---|
| 200 / 201 / 204 | OK / založeno / uloženo bez těla | – |
| 400 | Chybný formát požadavku, chybějící technicky povinné pole | Opravit tělo; message jmenuje sloupec/pole. |
| 401 | Chybí nebo vypršel token | Refresh, případně nové přihlášení. |
| 403 | Chybí oprávnění role, nebo záznam patří jinému nakladateli | Zkontrolovat owner.id a aktivní organizaci. |
| 404 | Záznam neexistuje, nebo chybí x-okapi-tenant | – |
| 409 | Souběžná změna (stará version) | Načíst znovu a zopakovat. |
| 422 | Porušené obchodní pravidlo | Podle type v tabulce níže. |
| 500 | Neošetřená chyba – v této verzi i některá chybějící povinná pole produktu | Zkontrolovat povinná pole; jinak nahlásit agentuře i s časem volání. |
| 503 | Služba (např. úložiště obálek) není dostupná | Zopakovat později, nahlásit. |
Kódy chyb (type) relevantní pro nakladatele
| type | Název | Kdy nastane |
|---|---|---|
| -15 | PUBLISHER_CLOSED | Nakladatel je ukončen – nelze přidělit číslo. |
| -16 | PUBLISHER_GUARANTOR_DATA_NOT_CONFIRMED | Údaje nakladatele nepotvrzeny 12 měsíců. ověřeno |
| -24 | NO_AVAILABLE_PRODUCT_NUMBER | V prefixu není volné číslo. |
| -25 | PRODUCT_NOT_OWNED_BY_GUARANTOR | Produkt / titul produktu patří jinému nakladateli nebo chybí title.owner.id. ověřeno |
| -26 / -27 | PERSON_IDENTIFIER_ALREADY_EXISTS / _INVALID_FORMAT | ISNI/ORCID osoby už existuje / má chybný formát. |
| -28 | TITLE_NOT_OWNED_BY_GUARANTOR | Titul patří jinému nakladateli nebo chybí owner.id. ověřeno |
| -29 | PRODUCT_ALREADY_HAS_ASSIGNED_NUMBER | Produkt už číslo má. ověřeno |
| -30 | TITLE_CONTRIBUTION_NAME_REQUIRED | Autor v titulu bez jména. ověřeno |
| -31 | TITLE_CONTRIBUTION_PERSON_XOR_UNNAMED | Autor musí mít buď person, nebo unnamedPerson. ověřeno |
| -34 | ONE_OFF_PUBLISHER_CANNOT_CREATE_TITLE | Jednorázový nakladatel nemůže zakládat tituly sám. |
| -36 | PRODUCT_PUBLISHING_DATE_REQUIRED | Zveřejnění produktu bez data vydání. |
| -38 | INVALID_PUBLISHER_PREFIX_SELECTION | Zvolený prefix nelze použít. |
| -44 | TITLE_HAS_PRODUCTS | Mazání titulu, který má produkty. |
| -51 | PRODUCT_PUBLISHING_STATUS_NOT_ASSIGNABLE | Stav publikování 01/03. |
| -52 | PRODUCT_PRIMARY_CONTENT_TYPE_MISMATCH | Jiný typ obsahu než u ostatních produktů titulu. ověřeno |
| -53 / -54 | LAST_USED_NUMBER_INVALID / _NOT_IN_PREFIX | Chybné prohlášení o posledním čísle. ověřeno |
| -55 | PREFIX_DECLARATION_PENDING | Prefix čeká na prohlášení. |
| -56 | DECLARATION_NOT_ALLOWED | Prohlášení u prefixu, který ho nevyžaduje, nebo cizího. |
| -57 | PUBLISHER_PREFIX_VALUE_NOT_FOUND | Hodnota publisherPrefix neodpovídá žádnému prefixu nakladatele. ověřeno |
| -58 | MAIN_TITLE_EXACTLY_ONE | Titul nemá právě jeden hlavní název (01). ověřeno |
| -1 | INTERNAL | Obecná chyba, např. souběžná změna (409). |
Časté chyby integrace
- Číselníková položka jen s
id→ titul „nemá hlavní název“ (422 -58). Posílejteid,valueaversion. - Produkt bez
title.versionnebotitle.owner.id→ 400 / 403. Nejjistější je vložit doproduct.titlecelý titul zGET /titles/{id}. - PUT jen se změněnými poli → pole, která nepošlete, se smažou. PUT vždy s celým objektem.
- Autor bez jména v
titleContributions→ 422 -30, i když odkazuje na osobu. - Obálka v PNG → 400. Převeďte na JPEG.
- Opakované create-with-number po neúspěšném přidělení → duplicitní produkt. Přidělujte cestou A.
- Prošlý token → 401. Obnovujte token před vypršením (1 h).
Pro jednorázové zasílání ONIX zpráv z ERP existuje v systému samostatná role Externí nakladatel s endpointy /titles/receive a /products/receive; ta neumí autory, obálky ani ISBN a tento dokument ji nepopisuje.
11. Stav ověření
Všechny kroky proběhly 23. 9. 2026 jako uživatel s jedinou rolí Garant nakladatele v lokálním prostředí eureka-local (mod-br-agency 1.3.171). Chování serveru je stejné jako na ostatních prostředích se stejnou verzí; adresy, ID nakladatele a ID číselníkových položek se liší.
| Krok | Stav | Poznámka |
|---|---|---|
| Přihlášení, refresh, logout, hlavičky | ověřeno | Přes gateway. |
| _self, select-organization, agency-publishers, publisher-prefixes | ověřeno | Přes gateway. |
Potvrzení údajů nakladatele (/publishers/{id}/confirmData) | z kódu | Modul evidence nakladatelů nebyl v testovacím prostředí přes gateway dostupný. |
| Prohlášení o posledním čísle | ověřeno | Logika ověřena přímým voláním modulu; přes gateway v testovacím prostředí chybělo oprávnění (starší registrace modulu). |
| Číselníky | ověřeno | Přes gateway. |
| Vyhledání a založení autora | ověřeno | Přes gateway. |
| Nahrání obálky a navázání na titul | ověřeno | Veřejné stažení obálky (publicUrl) přes gateway testovacího prostředí nefungovalo (404), přímo z modulu ano. |
| Titul (POST, GET, PUT, 409) | ověřeno | Přes gateway. |
| Produkt, feasibility, preview, assign, create-with-number | ověřeno | Přes gateway. |
Limit 5 MB, -34, -36, -38, needsNewPrefix/magnitude | z kódu | Testovací nakladatel tyto situace neměl. |